1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * I2C access driver for TI TPS65224/TPS6594/TPS6593/LP8764 PMICs
4   *
5   * Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/
6   */
7  
8  #include <linux/crc8.h>
9  #include <linux/i2c.h>
10  #include <linux/module.h>
11  #include <linux/mod_devicetable.h>
12  #include <linux/of_device.h>
13  #include <linux/regmap.h>
14  
15  #include <linux/mfd/tps6594.h>
16  
17  static bool enable_crc;
18  module_param(enable_crc, bool, 0444);
19  MODULE_PARM_DESC(enable_crc, "Enable CRC feature for I2C interface");
20  
21  DECLARE_CRC8_TABLE(tps6594_i2c_crc_table);
22  
tps6594_i2c_transfer(struct i2c_adapter * adap,struct i2c_msg * msgs,int num)23  static int tps6594_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
24  {
25  	int ret = i2c_transfer(adap, msgs, num);
26  
27  	if (ret == num)
28  		return 0;
29  	else if (ret < 0)
30  		return ret;
31  	else
32  		return -EIO;
33  }
34  
tps6594_i2c_reg_read_with_crc(struct i2c_client * client,u8 page,u8 reg,u8 * val)35  static int tps6594_i2c_reg_read_with_crc(struct i2c_client *client, u8 page, u8 reg, u8 *val)
36  {
37  	struct i2c_msg msgs[2];
38  	u8 buf_rx[] = { 0, 0 };
39  	/* I2C address = I2C base address + Page index */
40  	const u8 addr = client->addr + page;
41  	/*
42  	 * CRC is calculated from every bit included in the protocol
43  	 * except the ACK bits from the target. Byte stream is:
44  	 * - B0: (I2C_addr_7bits << 1) | WR_bit, with WR_bit = 0
45  	 * - B1: reg
46  	 * - B2: (I2C_addr_7bits << 1) | RD_bit, with RD_bit = 1
47  	 * - B3: val
48  	 * - B4: CRC from B0-B1-B2-B3
49  	 */
50  	u8 crc_data[] = { addr << 1, reg, addr << 1 | 1, 0 };
51  	int ret;
52  
53  	/* Write register */
54  	msgs[0].addr = addr;
55  	msgs[0].flags = 0;
56  	msgs[0].len = 1;
57  	msgs[0].buf = &reg;
58  
59  	/* Read data and CRC */
60  	msgs[1].addr = msgs[0].addr;
61  	msgs[1].flags = I2C_M_RD;
62  	msgs[1].len = 2;
63  	msgs[1].buf = buf_rx;
64  
65  	ret = tps6594_i2c_transfer(client->adapter, msgs, 2);
66  	if (ret < 0)
67  		return ret;
68  
69  	crc_data[sizeof(crc_data) - 1] = *val = buf_rx[0];
70  	if (buf_rx[1] != crc8(tps6594_i2c_crc_table, crc_data, sizeof(crc_data), CRC8_INIT_VALUE))
71  		return -EIO;
72  
73  	return ret;
74  }
75  
tps6594_i2c_reg_write_with_crc(struct i2c_client * client,u8 page,u8 reg,u8 val)76  static int tps6594_i2c_reg_write_with_crc(struct i2c_client *client, u8 page, u8 reg, u8 val)
77  {
78  	struct i2c_msg msg;
79  	u8 buf[] = { reg, val, 0 };
80  	/* I2C address = I2C base address + Page index */
81  	const u8 addr = client->addr + page;
82  	/*
83  	 * CRC is calculated from every bit included in the protocol
84  	 * except the ACK bits from the target. Byte stream is:
85  	 * - B0: (I2C_addr_7bits << 1) | WR_bit, with WR_bit = 0
86  	 * - B1: reg
87  	 * - B2: val
88  	 * - B3: CRC from B0-B1-B2
89  	 */
90  	const u8 crc_data[] = { addr << 1, reg, val };
91  
92  	/* Write register, data and CRC */
93  	msg.addr = addr;
94  	msg.flags = client->flags & I2C_M_TEN;
95  	msg.len = sizeof(buf);
96  	msg.buf = buf;
97  
98  	buf[msg.len - 1] = crc8(tps6594_i2c_crc_table, crc_data, sizeof(crc_data), CRC8_INIT_VALUE);
99  
100  	return tps6594_i2c_transfer(client->adapter, &msg, 1);
101  }
102  
tps6594_i2c_read(void * context,const void * reg_buf,size_t reg_size,void * val_buf,size_t val_size)103  static int tps6594_i2c_read(void *context, const void *reg_buf, size_t reg_size,
104  			    void *val_buf, size_t val_size)
105  {
106  	struct i2c_client *client = context;
107  	struct tps6594 *tps = i2c_get_clientdata(client);
108  	struct i2c_msg msgs[2];
109  	const u8 *reg_bytes = reg_buf;
110  	u8 *val_bytes = val_buf;
111  	const u8 page = reg_bytes[1];
112  	u8 reg = reg_bytes[0];
113  	int ret = 0;
114  	int i;
115  
116  	if (tps->use_crc) {
117  		/*
118  		 * Auto-increment feature does not support CRC protocol.
119  		 * Converts the bulk read operation into a series of single read operations.
120  		 */
121  		for (i = 0 ; ret == 0 && i < val_size ; i++)
122  			ret = tps6594_i2c_reg_read_with_crc(client, page, reg + i, val_bytes + i);
123  
124  		return ret;
125  	}
126  
127  	/* Write register: I2C address = I2C base address + Page index */
128  	msgs[0].addr = client->addr + page;
129  	msgs[0].flags = 0;
130  	msgs[0].len = 1;
131  	msgs[0].buf = &reg;
132  
133  	/* Read data */
134  	msgs[1].addr = msgs[0].addr;
135  	msgs[1].flags = I2C_M_RD;
136  	msgs[1].len = val_size;
137  	msgs[1].buf = val_bytes;
138  
139  	return tps6594_i2c_transfer(client->adapter, msgs, 2);
140  }
141  
tps6594_i2c_write(void * context,const void * data,size_t count)142  static int tps6594_i2c_write(void *context, const void *data, size_t count)
143  {
144  	struct i2c_client *client = context;
145  	struct tps6594 *tps = i2c_get_clientdata(client);
146  	struct i2c_msg msg;
147  	const u8 *bytes = data;
148  	u8 *buf;
149  	const u8 page = bytes[1];
150  	const u8 reg = bytes[0];
151  	int ret = 0;
152  	int i;
153  
154  	if (tps->use_crc) {
155  		/*
156  		 * Auto-increment feature does not support CRC protocol.
157  		 * Converts the bulk write operation into a series of single write operations.
158  		 */
159  		for (i = 0 ; ret == 0 && i < count - 2 ; i++)
160  			ret = tps6594_i2c_reg_write_with_crc(client, page, reg + i, bytes[i + 2]);
161  
162  		return ret;
163  	}
164  
165  	/* Setup buffer: page byte is not sent */
166  	buf = kzalloc(--count, GFP_KERNEL);
167  	if (!buf)
168  		return -ENOMEM;
169  
170  	buf[0] = reg;
171  	for (i = 0 ; i < count - 1 ; i++)
172  		buf[i + 1] = bytes[i + 2];
173  
174  	/* Write register and data: I2C address = I2C base address + Page index */
175  	msg.addr = client->addr + page;
176  	msg.flags = client->flags & I2C_M_TEN;
177  	msg.len = count;
178  	msg.buf = buf;
179  
180  	ret = tps6594_i2c_transfer(client->adapter, &msg, 1);
181  
182  	kfree(buf);
183  	return ret;
184  }
185  
186  static struct regmap_config tps6594_i2c_regmap_config = {
187  	.reg_bits = 16,
188  	.val_bits = 8,
189  	.max_register = TPS6594_REG_DWD_FAIL_CNT_REG,
190  	.volatile_table = &tps6594_volatile_table,
191  	.read = tps6594_i2c_read,
192  	.write = tps6594_i2c_write,
193  };
194  
195  static const struct of_device_id tps6594_i2c_of_match_table[] = {
196  	{ .compatible = "ti,tps6594-q1", .data = (void *)TPS6594, },
197  	{ .compatible = "ti,tps6593-q1", .data = (void *)TPS6593, },
198  	{ .compatible = "ti,lp8764-q1",  .data = (void *)LP8764,  },
199  	{ .compatible = "ti,tps65224-q1", .data = (void *)TPS65224, },
200  	{}
201  };
202  MODULE_DEVICE_TABLE(of, tps6594_i2c_of_match_table);
203  
tps6594_i2c_probe(struct i2c_client * client)204  static int tps6594_i2c_probe(struct i2c_client *client)
205  {
206  	struct device *dev = &client->dev;
207  	struct tps6594 *tps;
208  	const struct of_device_id *match;
209  
210  	tps = devm_kzalloc(dev, sizeof(*tps), GFP_KERNEL);
211  	if (!tps)
212  		return -ENOMEM;
213  
214  	i2c_set_clientdata(client, tps);
215  
216  	tps->dev = dev;
217  	tps->reg = client->addr;
218  	tps->irq = client->irq;
219  
220  	match = of_match_device(tps6594_i2c_of_match_table, dev);
221  	if (!match)
222  		return dev_err_probe(dev, -EINVAL, "Failed to find matching chip ID\n");
223  	tps->chip_id = (unsigned long)match->data;
224  
225  	if (tps->chip_id == TPS65224)
226  		tps6594_i2c_regmap_config.volatile_table = &tps65224_volatile_table;
227  
228  	tps->regmap = devm_regmap_init(dev, NULL, client, &tps6594_i2c_regmap_config);
229  	if (IS_ERR(tps->regmap))
230  		return dev_err_probe(dev, PTR_ERR(tps->regmap), "Failed to init regmap\n");
231  
232  	crc8_populate_msb(tps6594_i2c_crc_table, TPS6594_CRC8_POLYNOMIAL);
233  
234  	return tps6594_device_init(tps, enable_crc);
235  }
236  
237  static struct i2c_driver tps6594_i2c_driver = {
238  	.driver	= {
239  		.name = "tps6594",
240  		.of_match_table = tps6594_i2c_of_match_table,
241  	},
242  	.probe = tps6594_i2c_probe,
243  };
244  module_i2c_driver(tps6594_i2c_driver);
245  
246  MODULE_AUTHOR("Julien Panis <jpanis@baylibre.com>");
247  MODULE_DESCRIPTION("I2C Interface Driver for TPS65224, TPS6594/3, and LP8764");
248  MODULE_LICENSE("GPL");
249