Skip to content

Commit 059374a

Browse files
jonasjelonekAndi Shyti
authored andcommitted
i2c: rtl9300: separate xfer configuration and execution
So far, the rtl9300_i2c_smbus_xfer code is quite a mess with function calls distributed over the whole function setting different values in different cases. Calls to rtl9300_i2c_config_xfer and rtl9300_i2c_reg_addr_set are used in every case-block with varying values whose meaning is not instantly obvious. In some cases, there are additional calls within these case-blocks doing more things. This is in general a bad design and especially really bad for readability and maintainability because it distributes changes or issues to multiple locations due to the same function being called with different hardcoded values in different places. To have a good structure, setting different parameters based on the desired operation should not be interleaved with applying these parameters to the hardware registers. Or in different words, the parameter site should be mixed with the call site. Thus, separate configuration and execution of an SMBus xfer within rtl9300_i2c_smbus_xfer to improve readability and maintainability. Add a new 'struct rtl9300_i2c_xfer' to carry the required parameters for an xfer which are configured based on the input parameters within a single switch-case block, without having any function calls within this block. The function calls to actually apply these values to the hardware registers then appear below in a single place and just operate on the passed instance of 'struct rtl9300_i2c_xfer'. These are 'rtl9300_i2c_prepare_xfer' which combines applying all parameters of the xfer to the corresponding register, and 'rtl9300_i2c_do_xfer' which actually executes the xfer and does post-processing if needed. Signed-off-by: Jonas Jelonek <jelonek.jonas@gmail.com> Tested-by: Sven Eckelmann <sven@narfation.org> Reviewed-by: Chris Packham <chris.packham@alliedtelesis.co.nz> Tested-by: Chris Packham <chris.packham@alliedtelesis.co.nz> # On RTL9302C based board Tested-by: Markus Stockhausen <markus.stockhausen@gmx.de> Signed-off-by: Andi Shyti <andi.shyti@kernel.org> Link: https://lore.kernel.org/r/20250927101931.71575-7-jelonek.jonas@gmail.com
1 parent d5b4fd6 commit 059374a

1 file changed

Lines changed: 114 additions & 120 deletions

File tree

drivers/i2c/busses/i2c-rtl9300.c

Lines changed: 114 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/mutex.h>
99
#include <linux/platform_device.h>
1010
#include <linux/regmap.h>
11+
#include <linux/unaligned.h>
1112

1213
enum rtl9300_bus_freq {
1314
RTL9300_I2C_STD_FREQ,
@@ -71,6 +72,22 @@ struct rtl9300_i2c {
7172
struct mutex lock;
7273
};
7374

75+
enum rtl9300_i2c_xfer_type {
76+
RTL9300_I2C_XFER_BYTE,
77+
RTL9300_I2C_XFER_WORD,
78+
RTL9300_I2C_XFER_BLOCK,
79+
};
80+
81+
struct rtl9300_i2c_xfer {
82+
enum rtl9300_i2c_xfer_type type;
83+
u16 dev_addr;
84+
u8 reg_addr;
85+
u8 reg_addr_len;
86+
u8 *data;
87+
u8 data_len;
88+
bool write;
89+
};
90+
7491
#define RTL9300_I2C_MST_CTRL1 0x0
7592
#define RTL9300_I2C_MST_CTRL2 0x4
7693
#define RTL9300_I2C_MST_DATA_WORD0 0x8
@@ -95,45 +112,37 @@ static int rtl9300_i2c_select_scl(struct rtl9300_i2c *i2c, u8 scl)
95112
return regmap_field_write(i2c->fields[F_SCL_SEL], 1);
96113
}
97114

98-
static int rtl9300_i2c_config_io(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan)
115+
static int rtl9300_i2c_config_chan(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan)
99116
{
100117
struct rtl9300_i2c_drv_data *drv_data;
101118
int ret;
102119

103-
drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
120+
if (i2c->sda_num == chan->sda_num)
121+
return 0;
104122

105-
ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(chan->sda_num),
106-
BIT(chan->sda_num));
123+
ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq);
107124
if (ret)
108125
return ret;
109126

110-
ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], chan->sda_num);
127+
drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev);
128+
ret = drv_data->select_scl(i2c, 0);
111129
if (ret)
112130
return ret;
113131

114-
ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq);
132+
ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(chan->sda_num),
133+
BIT(chan->sda_num));
115134
if (ret)
116135
return ret;
117136

118-
return drv_data->select_scl(i2c, 0);
119-
}
120-
121-
static int rtl9300_i2c_config_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan,
122-
u16 addr, u16 len)
123-
{
124-
int ret;
125-
126-
if (len < 1 || len > 16)
127-
return -EINVAL;
128-
129-
ret = regmap_field_write(i2c->fields[F_DEV_ADDR], addr);
137+
ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], chan->sda_num);
130138
if (ret)
131139
return ret;
132140

133-
return regmap_field_write(i2c->fields[F_DATA_WIDTH], (len - 1) & 0xf);
141+
i2c->sda_num = chan->sda_num;
142+
return 0;
134143
}
135144

136-
static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
145+
static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, u8 len)
137146
{
138147
u32 vals[4] = {};
139148
int i, ret;
@@ -153,7 +162,7 @@ static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, int len)
153162
return 0;
154163
}
155164

156-
static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, int len)
165+
static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, u8 len)
157166
{
158167
u32 vals[4] = {};
159168
int i;
@@ -176,16 +185,51 @@ static int rtl9300_i2c_writel(struct rtl9300_i2c *i2c, u32 data)
176185
return regmap_write(i2c->regmap, i2c->data_reg, data);
177186
}
178187

179-
static int rtl9300_i2c_execute_xfer(struct rtl9300_i2c *i2c, char read_write,
180-
int size, union i2c_smbus_data *data, int len)
188+
static int rtl9300_i2c_prepare_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer)
181189
{
182-
u32 val;
183190
int ret;
184191

185-
ret = regmap_field_write(i2c->fields[F_RWOP], read_write == I2C_SMBUS_WRITE);
192+
if (xfer->data_len < 1 || xfer->data_len > 16)
193+
return -EINVAL;
194+
195+
ret = regmap_field_write(i2c->fields[F_DEV_ADDR], xfer->dev_addr);
196+
if (ret)
197+
return ret;
198+
199+
ret = rtl9300_i2c_reg_addr_set(i2c, xfer->reg_addr, xfer->reg_addr_len);
200+
if (ret)
201+
return ret;
202+
203+
ret = regmap_field_write(i2c->fields[F_RWOP], xfer->write);
204+
if (ret)
205+
return ret;
206+
207+
ret = regmap_field_write(i2c->fields[F_DATA_WIDTH], (xfer->data_len - 1) & 0xf);
186208
if (ret)
187209
return ret;
188210

211+
if (xfer->write) {
212+
switch (xfer->type) {
213+
case RTL9300_I2C_XFER_BYTE:
214+
ret = rtl9300_i2c_writel(i2c, *xfer->data);
215+
break;
216+
case RTL9300_I2C_XFER_WORD:
217+
ret = rtl9300_i2c_writel(i2c, get_unaligned((const u16 *)xfer->data));
218+
break;
219+
default:
220+
ret = rtl9300_i2c_write(i2c, xfer->data, xfer->data_len);
221+
break;
222+
}
223+
}
224+
225+
return ret;
226+
}
227+
228+
static int rtl9300_i2c_do_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer)
229+
{
230+
u32 val;
231+
int ret;
232+
189233
ret = regmap_field_write(i2c->fields[F_I2C_TRIG], 1);
190234
if (ret)
191235
return ret;
@@ -200,28 +244,24 @@ static int rtl9300_i2c_execute_xfer(struct rtl9300_i2c *i2c, char read_write,
200244
if (val)
201245
return -EIO;
202246

203-
if (read_write == I2C_SMBUS_READ) {
204-
switch (size) {
205-
case I2C_SMBUS_BYTE:
206-
case I2C_SMBUS_BYTE_DATA:
247+
if (!xfer->write) {
248+
switch (xfer->type) {
249+
case RTL9300_I2C_XFER_BYTE:
207250
ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
208251
if (ret)
209252
return ret;
210-
data->byte = val & 0xff;
253+
254+
*xfer->data = val & 0xff;
211255
break;
212-
case I2C_SMBUS_WORD_DATA:
256+
case RTL9300_I2C_XFER_WORD:
213257
ret = regmap_read(i2c->regmap, i2c->data_reg, &val);
214258
if (ret)
215259
return ret;
216-
data->word = val & 0xffff;
217-
break;
218-
case I2C_SMBUS_I2C_BLOCK_DATA:
219-
ret = rtl9300_i2c_read(i2c, &data->block[1], len);
220-
if (ret)
221-
return ret;
260+
261+
put_unaligned(val & 0xffff, (u16*)xfer->data);
222262
break;
223263
default:
224-
ret = rtl9300_i2c_read(i2c, &data->block[0], len);
264+
ret = rtl9300_i2c_read(i2c, xfer->data, xfer->data_len);
225265
if (ret)
226266
return ret;
227267
break;
@@ -237,108 +277,62 @@ static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned s
237277
{
238278
struct rtl9300_i2c_chan *chan = i2c_get_adapdata(adap);
239279
struct rtl9300_i2c *i2c = chan->i2c;
240-
int len = 0, ret;
280+
struct rtl9300_i2c_xfer xfer = {0};
281+
int ret;
282+
283+
if (addr > 0x7f)
284+
return -EINVAL;
241285

242286
mutex_lock(&i2c->lock);
243-
if (chan->sda_num != i2c->sda_num) {
244-
ret = rtl9300_i2c_config_io(i2c, chan);
245-
if (ret)
246-
goto out_unlock;
247-
i2c->sda_num = chan->sda_num;
248-
}
287+
288+
ret = rtl9300_i2c_config_chan(i2c, chan);
289+
if (ret)
290+
goto out_unlock;
291+
292+
xfer.dev_addr = addr & 0x7f;
293+
xfer.write = (read_write == I2C_SMBUS_WRITE);
294+
xfer.reg_addr = command;
295+
xfer.reg_addr_len = 1;
249296

250297
switch (size) {
251298
case I2C_SMBUS_BYTE:
252-
if (read_write == I2C_SMBUS_WRITE) {
253-
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 0);
254-
if (ret)
255-
goto out_unlock;
256-
ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
257-
if (ret)
258-
goto out_unlock;
259-
} else {
260-
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1);
261-
if (ret)
262-
goto out_unlock;
263-
ret = rtl9300_i2c_reg_addr_set(i2c, 0, 0);
264-
if (ret)
265-
goto out_unlock;
266-
}
299+
xfer.data = (read_write == I2C_SMBUS_READ) ? &data->byte : &command;
300+
xfer.data_len = 1;
301+
xfer.reg_addr = 0;
302+
xfer.reg_addr_len = 0;
303+
xfer.type = RTL9300_I2C_XFER_BYTE;
267304
break;
268-
269305
case I2C_SMBUS_BYTE_DATA:
270-
ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
271-
if (ret)
272-
goto out_unlock;
273-
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 1);
274-
if (ret)
275-
goto out_unlock;
276-
if (read_write == I2C_SMBUS_WRITE) {
277-
ret = rtl9300_i2c_writel(i2c, data->byte);
278-
if (ret)
279-
goto out_unlock;
280-
}
306+
xfer.data = &data->byte;
307+
xfer.data_len = 1;
308+
xfer.type = RTL9300_I2C_XFER_BYTE;
281309
break;
282-
283310
case I2C_SMBUS_WORD_DATA:
284-
ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
285-
if (ret)
286-
goto out_unlock;
287-
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, 2);
288-
if (ret)
289-
goto out_unlock;
290-
if (read_write == I2C_SMBUS_WRITE) {
291-
ret = rtl9300_i2c_writel(i2c, data->word);
292-
if (ret)
293-
goto out_unlock;
294-
}
311+
xfer.data = (u8 *)&data->word;
312+
xfer.data_len = 2;
313+
xfer.type = RTL9300_I2C_XFER_WORD;
295314
break;
296-
297315
case I2C_SMBUS_BLOCK_DATA:
298-
ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
299-
if (ret)
300-
goto out_unlock;
301-
if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) {
302-
ret = -EINVAL;
303-
goto out_unlock;
304-
}
305-
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0] + 1);
306-
if (ret)
307-
goto out_unlock;
308-
if (read_write == I2C_SMBUS_WRITE) {
309-
ret = rtl9300_i2c_write(i2c, &data->block[0], data->block[0] + 1);
310-
if (ret)
311-
goto out_unlock;
312-
}
313-
len = data->block[0] + 1;
316+
xfer.data = &data->block[0];
317+
xfer.data_len = data->block[0] + 1;
318+
xfer.type = RTL9300_I2C_XFER_BLOCK;
314319
break;
315-
316320
case I2C_SMBUS_I2C_BLOCK_DATA:
317-
ret = rtl9300_i2c_reg_addr_set(i2c, command, 1);
318-
if (ret)
319-
goto out_unlock;
320-
if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) {
321-
ret = -EINVAL;
322-
goto out_unlock;
323-
}
324-
ret = rtl9300_i2c_config_xfer(i2c, chan, addr, data->block[0]);
325-
if (ret)
326-
goto out_unlock;
327-
if (read_write == I2C_SMBUS_WRITE) {
328-
ret = rtl9300_i2c_write(i2c, &data->block[1], data->block[0]);
329-
if (ret)
330-
goto out_unlock;
331-
}
332-
len = data->block[0];
321+
xfer.data = &data->block[1];
322+
xfer.data_len = data->block[0];
323+
xfer.type = RTL9300_I2C_XFER_BLOCK;
333324
break;
334-
335325
default:
336326
dev_err(&adap->dev, "Unsupported transaction %d\n", size);
337327
ret = -EOPNOTSUPP;
338328
goto out_unlock;
339329
}
340330

341-
ret = rtl9300_i2c_execute_xfer(i2c, read_write, size, data, len);
331+
ret = rtl9300_i2c_prepare_xfer(i2c, &xfer);
332+
if (ret)
333+
goto out_unlock;
334+
335+
ret = rtl9300_i2c_do_xfer(i2c, &xfer);
342336

343337
out_unlock:
344338
mutex_unlock(&i2c->lock);

0 commit comments

Comments
 (0)