Skip to content

Commit 2f8d1ed

Browse files
Jiawen Wuwsakernel
authored andcommitted
i2c: designware: Add driver support for Wangxun 10Gb NIC
Wangxun 10Gb ethernet chip is connected to Designware I2C, to communicate with SFP. Introduce the property "wx,i2c-snps-model" to match device data for Wangxun in software node case. Since IO resource was mapped on the ethernet driver, add a model quirk to get regmap from parent device. The exists IP limitations are dealt as workarounds: - IP does not support interrupt mode, it works on polling mode. - Additionally set FIFO depth address the chip issue. Signed-off-by: Jiawen Wu <[email protected]> Reviewed-by: Piotr Raczynski <[email protected]> Reviewed-by: Andy Shevchenko <[email protected]> Acked-by: Jarkko Nikula <[email protected]> Signed-off-by: Wolfram Sang <[email protected]>
1 parent 4f5d68c commit 2f8d1ed

File tree

4 files changed

+111
-5
lines changed

4 files changed

+111
-5
lines changed

drivers/i2c/busses/i2c-designware-common.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,14 @@ int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
575575
unsigned int param;
576576
int ret;
577577

578+
/* DW_IC_COMP_PARAM_1 not implement for IP issue */
579+
if ((dev->flags & MODEL_MASK) == MODEL_WANGXUN_SP) {
580+
dev->tx_fifo_depth = TXGBE_TX_FIFO_DEPTH;
581+
dev->rx_fifo_depth = TXGBE_RX_FIFO_DEPTH;
582+
583+
return 0;
584+
}
585+
578586
/*
579587
* Try to detect the FIFO depth if not set by interface driver,
580588
* the depth could be from 2 to 256 from HW spec.

drivers/i2c/busses/i2c-designware-core.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ struct dw_i2c_dev {
303303
#define MODEL_MSCC_OCELOT BIT(8)
304304
#define MODEL_BAIKAL_BT1 BIT(9)
305305
#define MODEL_AMD_NAVI_GPU BIT(10)
306+
#define MODEL_WANGXUN_SP BIT(11)
306307
#define MODEL_MASK GENMASK(11, 8)
307308

308309
/*
@@ -312,6 +313,9 @@ struct dw_i2c_dev {
312313
#define AMD_UCSI_INTR_REG 0x474
313314
#define AMD_UCSI_INTR_EN 0xd
314315

316+
#define TXGBE_TX_FIFO_DEPTH 4
317+
#define TXGBE_RX_FIFO_DEPTH 0
318+
315319
struct i2c_dw_semaphore_callbacks {
316320
int (*probe)(struct dw_i2c_dev *dev);
317321
void (*remove)(struct dw_i2c_dev *dev);

drivers/i2c/busses/i2c-designware-master.c

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,68 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
354354
return 0;
355355
}
356356

357+
static int i2c_dw_poll_tx_empty(struct dw_i2c_dev *dev)
358+
{
359+
u32 val;
360+
361+
return regmap_read_poll_timeout(dev->map, DW_IC_RAW_INTR_STAT, val,
362+
val & DW_IC_INTR_TX_EMPTY,
363+
100, 1000);
364+
}
365+
366+
static int i2c_dw_poll_rx_full(struct dw_i2c_dev *dev)
367+
{
368+
u32 val;
369+
370+
return regmap_read_poll_timeout(dev->map, DW_IC_RAW_INTR_STAT, val,
371+
val & DW_IC_INTR_RX_FULL,
372+
100, 1000);
373+
}
374+
375+
static int txgbe_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs,
376+
int num_msgs)
377+
{
378+
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
379+
int msg_idx, buf_len, data_idx, ret;
380+
unsigned int val, stop = 0;
381+
u8 *buf;
382+
383+
dev->msgs = msgs;
384+
dev->msgs_num = num_msgs;
385+
i2c_dw_xfer_init(dev);
386+
regmap_write(dev->map, DW_IC_INTR_MASK, 0);
387+
388+
for (msg_idx = 0; msg_idx < num_msgs; msg_idx++) {
389+
buf = msgs[msg_idx].buf;
390+
buf_len = msgs[msg_idx].len;
391+
392+
for (data_idx = 0; data_idx < buf_len; data_idx++) {
393+
if (msg_idx == num_msgs - 1 && data_idx == buf_len - 1)
394+
stop |= BIT(9);
395+
396+
if (msgs[msg_idx].flags & I2C_M_RD) {
397+
regmap_write(dev->map, DW_IC_DATA_CMD, 0x100 | stop);
398+
399+
ret = i2c_dw_poll_rx_full(dev);
400+
if (ret)
401+
return ret;
402+
403+
regmap_read(dev->map, DW_IC_DATA_CMD, &val);
404+
buf[data_idx] = val;
405+
} else {
406+
ret = i2c_dw_poll_tx_empty(dev);
407+
if (ret)
408+
return ret;
409+
410+
regmap_write(dev->map, DW_IC_DATA_CMD,
411+
buf[data_idx] | stop);
412+
}
413+
}
414+
}
415+
416+
return num_msgs;
417+
}
418+
357419
/*
358420
* Initiate (and continue) low level master read/write transaction.
359421
* This function is only called from i2c_dw_isr, and pumping i2c_msg
@@ -559,13 +621,19 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
559621
pm_runtime_get_sync(dev->dev);
560622

561623
/*
562-
* Initiate I2C message transfer when AMD NAVI GPU card is enabled,
624+
* Initiate I2C message transfer when polling mode is enabled,
563625
* As it is polling based transfer mechanism, which does not support
564626
* interrupt based functionalities of existing DesignWare driver.
565627
*/
566-
if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU) {
628+
switch (dev->flags & MODEL_MASK) {
629+
case MODEL_AMD_NAVI_GPU:
567630
ret = amd_i2c_dw_xfer_quirk(adap, msgs, num);
568631
goto done_nolock;
632+
case MODEL_WANGXUN_SP:
633+
ret = txgbe_i2c_dw_xfer_quirk(adap, msgs, num);
634+
goto done_nolock;
635+
default:
636+
break;
569637
}
570638

571639
reinit_completion(&dev->cmd_complete);
@@ -848,7 +916,7 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
848916
return 0;
849917
}
850918

851-
static int amd_i2c_adap_quirk(struct dw_i2c_dev *dev)
919+
static int i2c_dw_poll_adap_quirk(struct dw_i2c_dev *dev)
852920
{
853921
struct i2c_adapter *adap = &dev->adapter;
854922
int ret;
@@ -862,6 +930,17 @@ static int amd_i2c_adap_quirk(struct dw_i2c_dev *dev)
862930
return ret;
863931
}
864932

933+
static bool i2c_dw_is_model_poll(struct dw_i2c_dev *dev)
934+
{
935+
switch (dev->flags & MODEL_MASK) {
936+
case MODEL_AMD_NAVI_GPU:
937+
case MODEL_WANGXUN_SP:
938+
return true;
939+
default:
940+
return false;
941+
}
942+
}
943+
865944
int i2c_dw_probe_master(struct dw_i2c_dev *dev)
866945
{
867946
struct i2c_adapter *adap = &dev->adapter;
@@ -917,8 +996,8 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
917996
adap->dev.parent = dev->dev;
918997
i2c_set_adapdata(adap, dev);
919998

920-
if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU)
921-
return amd_i2c_adap_quirk(dev);
999+
if (i2c_dw_is_model_poll(dev))
1000+
return i2c_dw_poll_adap_quirk(dev);
9221001

9231002
if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
9241003
irq_flags = IRQF_NO_SUSPEND;

drivers/i2c/busses/i2c-designware-platdrv.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,15 @@ static inline int dw_i2c_of_configure(struct platform_device *pdev)
168168
}
169169
#endif
170170

171+
static int txgbe_i2c_request_regs(struct dw_i2c_dev *dev)
172+
{
173+
dev->map = dev_get_regmap(dev->dev->parent, NULL);
174+
if (!dev->map)
175+
return -ENODEV;
176+
177+
return 0;
178+
}
179+
171180
static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev)
172181
{
173182
pm_runtime_disable(dev->dev);
@@ -185,6 +194,9 @@ static int dw_i2c_plat_request_regs(struct dw_i2c_dev *dev)
185194
case MODEL_BAIKAL_BT1:
186195
ret = bt1_i2c_request_regs(dev);
187196
break;
197+
case MODEL_WANGXUN_SP:
198+
ret = txgbe_i2c_request_regs(dev);
199+
break;
188200
default:
189201
dev->base = devm_platform_ioremap_resource(pdev, 0);
190202
ret = PTR_ERR_OR_ZERO(dev->base);
@@ -277,6 +289,9 @@ static int dw_i2c_plat_probe(struct platform_device *pdev)
277289
return -ENOMEM;
278290

279291
dev->flags = (uintptr_t)device_get_match_data(&pdev->dev);
292+
if (device_property_present(&pdev->dev, "wx,i2c-snps-model"))
293+
dev->flags = MODEL_WANGXUN_SP;
294+
280295
dev->dev = &pdev->dev;
281296
dev->irq = irq;
282297
platform_set_drvdata(pdev, dev);

0 commit comments

Comments
 (0)