Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * I2C slave mode testunit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Copyright (C) 2020 by Wolfram Sang, Sang Engineering <wsa@sang-engineering.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  * Copyright (C) 2020 by Renesas Electronics Corporation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <linux/bitops.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <linux/i2c.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) #include <linux/workqueue.h> /* FIXME: is system_long_wq the best choice? */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #define TU_CUR_VERSION 0x01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) enum testunit_cmds {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20) 	TU_CMD_READ_BYTES = 1,	/* save 0 for ABORT, RESET or similar */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21) 	TU_CMD_HOST_NOTIFY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22) 	TU_NUM_CMDS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) enum testunit_regs {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) 	TU_REG_CMD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) 	TU_REG_DATAL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) 	TU_REG_DATAH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 	TU_REG_DELAY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 	TU_NUM_REGS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) enum testunit_flags {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	TU_FLAG_IN_PROCESS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) struct testunit_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 	unsigned long flags;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	u8 regs[TU_NUM_REGS];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 	u8 reg_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	struct i2c_client *client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) 	struct delayed_work worker;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) static void i2c_slave_testunit_work(struct work_struct *work)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 	struct testunit_data *tu = container_of(work, struct testunit_data, worker.work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) 	struct i2c_msg msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) 	u8 msgbuf[256];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 	msg.addr = I2C_CLIENT_END;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 	msg.buf = msgbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) 	switch (tu->regs[TU_REG_CMD]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	case TU_CMD_READ_BYTES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 		msg.addr = tu->regs[TU_REG_DATAL];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 		msg.flags = I2C_M_RD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 		msg.len = tu->regs[TU_REG_DATAH];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	case TU_CMD_HOST_NOTIFY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 		msg.addr = 0x08;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 		msg.flags = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 		msg.len = 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 		msgbuf[0] = tu->client->addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 		msgbuf[1] = tu->regs[TU_REG_DATAL];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 		msgbuf[2] = tu->regs[TU_REG_DATAH];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	if (msg.addr != I2C_CLIENT_END) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 		ret = i2c_transfer(tu->client->adapter, &msg, 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 		/* convert '0 msgs transferred' to errno */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 		ret = (ret == 0) ? -EIO : ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 		dev_err(&tu->client->dev, "CMD%02X failed (%d)\n", tu->regs[TU_REG_CMD], ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 	clear_bit(TU_FLAG_IN_PROCESS, &tu->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) static int i2c_slave_testunit_slave_cb(struct i2c_client *client,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 				     enum i2c_slave_event event, u8 *val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	struct testunit_data *tu = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	switch (event) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	case I2C_SLAVE_WRITE_RECEIVED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 		if (test_bit(TU_FLAG_IN_PROCESS, &tu->flags))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 			return -EBUSY;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 		if (tu->reg_idx < TU_NUM_REGS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 			tu->regs[tu->reg_idx] = *val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 		else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 			ret = -EMSGSIZE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 		if (tu->reg_idx <= TU_NUM_REGS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 			tu->reg_idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 		/* TU_REG_CMD always written at this point */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 		if (tu->regs[TU_REG_CMD] >= TU_NUM_CMDS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 			ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	case I2C_SLAVE_STOP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 		if (tu->reg_idx == TU_NUM_REGS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 			set_bit(TU_FLAG_IN_PROCESS, &tu->flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 			queue_delayed_work(system_long_wq, &tu->worker,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 					   msecs_to_jiffies(10 * tu->regs[TU_REG_DELAY]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 		fallthrough;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	case I2C_SLAVE_WRITE_REQUESTED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 		tu->reg_idx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	case I2C_SLAVE_READ_REQUESTED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	case I2C_SLAVE_READ_PROCESSED:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 		*val = TU_CUR_VERSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 		break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) static int i2c_slave_testunit_probe(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	struct testunit_data *tu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	tu = devm_kzalloc(&client->dev, sizeof(struct testunit_data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	if (!tu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	tu->client = client;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	i2c_set_clientdata(client, tu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 	INIT_DELAYED_WORK(&tu->worker, i2c_slave_testunit_work);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	return i2c_slave_register(client, i2c_slave_testunit_slave_cb);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static int i2c_slave_testunit_remove(struct i2c_client *client)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	struct testunit_data *tu = i2c_get_clientdata(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	cancel_delayed_work_sync(&tu->worker);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	i2c_slave_unregister(client);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) static const struct i2c_device_id i2c_slave_testunit_id[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	{ "slave-testunit", 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	{ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) MODULE_DEVICE_TABLE(i2c, i2c_slave_testunit_id);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) static struct i2c_driver i2c_slave_testunit_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	.driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 		.name = "i2c-slave-testunit",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	.probe_new = i2c_slave_testunit_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	.remove = i2c_slave_testunit_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	.id_table = i2c_slave_testunit_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) module_i2c_driver(i2c_slave_testunit_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) MODULE_AUTHOR("Wolfram Sang <wsa@sang-engineering.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) MODULE_DESCRIPTION("I2C slave mode test unit");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) MODULE_LICENSE("GPL v2");