Skip to content

Commit 6062443

Browse files
Heikki KrogerusAndi Shyti
authored andcommitted
i2c: designware: Combine some of the common functions
The adapter can be registered just in the core instead of separately in the master and slave drivers. The same applies to the interrupt. The dedicated "target only" (slave only) configuration for this controller will be removed so that host mode (master mode) will always be supported together with the target mode. Therefore the descrption for the "target only" configuration that appears in the "name" sysfs attribute file is also dropped while at it. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Mika Westerberg <mika.westerberg@linux.intel.com> Signed-off-by: Andi Shyti <andi.shyti@kernel.org> Link: https://lore.kernel.org/r/20260120130729.1679560-2-heikki.krogerus@linux.intel.com
1 parent 2c7aa26 commit 6062443

4 files changed

Lines changed: 126 additions & 143 deletions

File tree

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

Lines changed: 101 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ static int dw_reg_write_word(void *context, unsigned int reg, unsigned int val)
136136
*
137137
* Return: 0 on success, or negative errno otherwise.
138138
*/
139-
int i2c_dw_init_regmap(struct dw_i2c_dev *dev)
139+
static int i2c_dw_init_regmap(struct dw_i2c_dev *dev)
140140
{
141141
struct regmap_config map_cfg = {
142142
.reg_bits = 32,
@@ -458,7 +458,7 @@ u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk,
458458
return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tLOW + tf), MICRO) - 1 + offset;
459459
}
460460

461-
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
461+
static int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev)
462462
{
463463
unsigned int reg;
464464
int ret;
@@ -675,7 +675,7 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev)
675675
return -EIO;
676676
}
677677

678-
int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
678+
static int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev)
679679
{
680680
u32 tx_fifo_depth, rx_fifo_depth;
681681
unsigned int param;
@@ -744,19 +744,113 @@ void i2c_dw_disable(struct dw_i2c_dev *dev)
744744
}
745745
EXPORT_SYMBOL_GPL(i2c_dw_disable);
746746

747+
static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
748+
{
749+
struct dw_i2c_dev *dev = dev_id;
750+
751+
if (dev->mode == DW_IC_SLAVE)
752+
return i2c_dw_isr_slave(dev);
753+
754+
return i2c_dw_isr_master(dev);
755+
}
756+
757+
static const struct i2c_algorithm i2c_dw_algo = {
758+
.xfer = i2c_dw_xfer,
759+
.functionality = i2c_dw_func,
760+
#if IS_ENABLED(CONFIG_I2C_SLAVE)
761+
.reg_slave = i2c_dw_reg_slave,
762+
.unreg_slave = i2c_dw_unreg_slave,
763+
#endif
764+
};
765+
766+
static const struct i2c_adapter_quirks i2c_dw_quirks = {
767+
.flags = I2C_AQ_NO_ZERO_LEN,
768+
};
769+
747770
int i2c_dw_probe(struct dw_i2c_dev *dev)
748771
{
772+
struct i2c_adapter *adap = &dev->adapter;
773+
unsigned long irq_flags;
774+
int ret;
775+
749776
device_set_node(&dev->adapter.dev, dev_fwnode(dev->dev));
750777

778+
ret = i2c_dw_init_regmap(dev);
779+
if (ret)
780+
return ret;
781+
782+
ret = i2c_dw_set_sda_hold(dev);
783+
if (ret)
784+
return ret;
785+
786+
ret = i2c_dw_set_fifo_size(dev);
787+
if (ret)
788+
return ret;
789+
751790
switch (dev->mode) {
752791
case DW_IC_SLAVE:
753-
return i2c_dw_probe_slave(dev);
792+
ret = i2c_dw_probe_slave(dev);
793+
break;
754794
case DW_IC_MASTER:
755-
return i2c_dw_probe_master(dev);
795+
ret = i2c_dw_probe_master(dev);
796+
break;
756797
default:
757-
dev_err(dev->dev, "Wrong operation mode: %d\n", dev->mode);
758-
return -EINVAL;
798+
ret = -EINVAL;
799+
break;
759800
}
801+
if (ret)
802+
return ret;
803+
804+
ret = dev->init(dev);
805+
if (ret)
806+
return ret;
807+
808+
if (!adap->name[0])
809+
strscpy(adap->name, "Synopsys DesignWare I2C adapter");
810+
811+
adap->retries = 3;
812+
adap->algo = &i2c_dw_algo;
813+
adap->quirks = &i2c_dw_quirks;
814+
adap->dev.parent = dev->dev;
815+
i2c_set_adapdata(adap, dev);
816+
817+
/*
818+
* REVISIT: The mode check may not be necessary.
819+
* For now keeping the flags as they were originally.
820+
*/
821+
if (dev->mode == DW_IC_SLAVE)
822+
irq_flags = IRQF_SHARED;
823+
else if (dev->flags & ACCESS_NO_IRQ_SUSPEND)
824+
irq_flags = IRQF_NO_SUSPEND;
825+
else
826+
irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
827+
828+
ret = i2c_dw_acquire_lock(dev);
829+
if (ret)
830+
return ret;
831+
832+
__i2c_dw_write_intr_mask(dev, 0);
833+
i2c_dw_release_lock(dev);
834+
835+
if (!(dev->flags & ACCESS_POLLING)) {
836+
ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr,
837+
irq_flags, dev_name(dev->dev), dev);
838+
if (ret)
839+
return ret;
840+
}
841+
842+
/*
843+
* Increment PM usage count during adapter registration in order to
844+
* avoid possible spurious runtime suspend when adapter device is
845+
* registered to the device core and immediate resume in case bus has
846+
* registered I2C slaves that do I2C transfers in their probe.
847+
*/
848+
ACQUIRE(pm_runtime_noresume, pm)(dev->dev);
849+
ret = ACQUIRE_ERR(pm_runtime_noresume, &pm);
850+
if (ret)
851+
return ret;
852+
853+
return i2c_add_numbered_adapter(adap);
760854
}
761855
EXPORT_SYMBOL_GPL(i2c_dw_probe);
762856

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <linux/completion.h>
1414
#include <linux/errno.h>
1515
#include <linux/i2c.h>
16+
#include <linux/irqreturn.h>
1617
#include <linux/pm.h>
1718
#include <linux/regmap.h>
1819
#include <linux/types.h>
@@ -344,20 +345,18 @@ struct i2c_dw_semaphore_callbacks {
344345
int (*probe)(struct dw_i2c_dev *dev);
345346
};
346347

347-
int i2c_dw_init_regmap(struct dw_i2c_dev *dev);
348348
u32 i2c_dw_scl_hcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk,
349349
u32 tSYMBOL, u32 tf, int offset);
350350
u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk,
351351
u32 tLOW, u32 tf, int offset);
352-
int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev);
353352
u32 i2c_dw_clk_rate(struct dw_i2c_dev *dev);
354353
int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare);
355354
int i2c_dw_acquire_lock(struct dw_i2c_dev *dev);
356355
void i2c_dw_release_lock(struct dw_i2c_dev *dev);
357356
int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev);
358357
int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev);
359-
int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev);
360358
u32 i2c_dw_func(struct i2c_adapter *adap);
359+
irqreturn_t i2c_dw_isr_master(struct dw_i2c_dev *dev);
361360

362361
extern const struct dev_pm_ops i2c_dw_dev_pm_ops;
363362

@@ -397,12 +396,18 @@ void i2c_dw_disable(struct dw_i2c_dev *dev);
397396
extern void i2c_dw_configure_master(struct dw_i2c_dev *dev);
398397
extern int i2c_dw_probe_master(struct dw_i2c_dev *dev);
399398

399+
int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num);
400+
400401
#if IS_ENABLED(CONFIG_I2C_SLAVE)
401402
extern void i2c_dw_configure_slave(struct dw_i2c_dev *dev);
402403
extern int i2c_dw_probe_slave(struct dw_i2c_dev *dev);
404+
irqreturn_t i2c_dw_isr_slave(struct dw_i2c_dev *dev);
405+
int i2c_dw_reg_slave(struct i2c_client *client);
406+
int i2c_dw_unreg_slave(struct i2c_client *client);
403407
#else
404408
static inline void i2c_dw_configure_slave(struct dw_i2c_dev *dev) { }
405409
static inline int i2c_dw_probe_slave(struct dw_i2c_dev *dev) { return -EINVAL; }
410+
static inline irqreturn_t i2c_dw_isr_slave(struct dw_i2c_dev *dev) { return IRQ_NONE; }
406411
#endif
407412

408413
static inline void i2c_dw_configure(struct dw_i2c_dev *dev)

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

Lines changed: 11 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -191,10 +191,6 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev)
191191
dev->hs_hcnt, dev->hs_lcnt);
192192
}
193193

194-
ret = i2c_dw_set_sda_hold(dev);
195-
if (ret)
196-
return ret;
197-
198194
dev_dbg(dev->dev, "Bus speed: %s\n", i2c_freq_mode_string(t->bus_freq_hz));
199195
return 0;
200196
}
@@ -353,9 +349,8 @@ static int i2c_dw_status(struct dw_i2c_dev *dev)
353349
* Initiate and continue master read/write transaction with polling
354350
* based transfer routine afterward write messages into the Tx buffer.
355351
*/
356-
static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, int num_msgs)
352+
static int amd_i2c_dw_xfer_quirk(struct dw_i2c_dev *dev, struct i2c_msg *msgs, int num_msgs)
357353
{
358-
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
359354
int msg_wrt_idx, msg_itr_lmt, buf_len, data_idx;
360355
int cmd = 0, status;
361356
u8 *tx_buf;
@@ -752,9 +747,8 @@ static void i2c_dw_process_transfer(struct dw_i2c_dev *dev, unsigned int stat)
752747
* Interrupt service routine. This gets called whenever an I2C master interrupt
753748
* occurs.
754749
*/
755-
static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id)
750+
irqreturn_t i2c_dw_isr_master(struct dw_i2c_dev *dev)
756751
{
757-
struct dw_i2c_dev *dev = dev_id;
758752
unsigned int stat, enabled;
759753

760754
regmap_read(dev->map, DW_IC_ENABLE, &enabled);
@@ -815,9 +809,8 @@ static int i2c_dw_wait_transfer(struct dw_i2c_dev *dev)
815809
* Prepare controller for a transaction and call i2c_dw_xfer_msg.
816810
*/
817811
static int
818-
i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
812+
i2c_dw_xfer_common(struct dw_i2c_dev *dev, struct i2c_msg msgs[], int num)
819813
{
820-
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
821814
int ret;
822815

823816
dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num);
@@ -908,19 +901,15 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
908901
return ret;
909902
}
910903

911-
static const struct i2c_algorithm i2c_dw_algo = {
912-
.xfer = i2c_dw_xfer,
913-
.functionality = i2c_dw_func,
914-
};
904+
int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
905+
{
906+
struct dw_i2c_dev *dev = i2c_get_adapdata(adap);
915907

916-
static const struct i2c_algorithm amd_i2c_dw_algo = {
917-
.xfer = amd_i2c_dw_xfer_quirk,
918-
.functionality = i2c_dw_func,
919-
};
908+
if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU)
909+
return amd_i2c_dw_xfer_quirk(dev, msgs, num);
920910

921-
static const struct i2c_adapter_quirks i2c_dw_quirks = {
922-
.flags = I2C_AQ_NO_ZERO_LEN,
923-
};
911+
return i2c_dw_xfer_common(dev, msgs, num);
912+
}
924913

925914
void i2c_dw_configure_master(struct dw_i2c_dev *dev)
926915
{
@@ -1005,27 +994,17 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev)
1005994

1006995
int i2c_dw_probe_master(struct dw_i2c_dev *dev)
1007996
{
1008-
struct i2c_adapter *adap = &dev->adapter;
1009-
unsigned long irq_flags;
1010997
unsigned int ic_con;
1011998
int ret;
1012999

10131000
init_completion(&dev->cmd_complete);
10141001

10151002
dev->init = i2c_dw_init_master;
10161003

1017-
ret = i2c_dw_init_regmap(dev);
1018-
if (ret)
1019-
return ret;
1020-
10211004
ret = i2c_dw_set_timings_master(dev);
10221005
if (ret)
10231006
return ret;
10241007

1025-
ret = i2c_dw_set_fifo_size(dev);
1026-
if (ret)
1027-
return ret;
1028-
10291008
/* Lock the bus for accessing DW_IC_CON */
10301009
ret = i2c_dw_acquire_lock(dev);
10311010
if (ret)
@@ -1045,61 +1024,7 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev)
10451024
if (ic_con & DW_IC_CON_BUS_CLEAR_CTRL)
10461025
dev->master_cfg |= DW_IC_CON_BUS_CLEAR_CTRL;
10471026

1048-
ret = dev->init(dev);
1049-
if (ret)
1050-
return ret;
1051-
1052-
if (!adap->name[0])
1053-
scnprintf(adap->name, sizeof(adap->name),
1054-
"Synopsys DesignWare I2C adapter");
1055-
adap->retries = 3;
1056-
if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU)
1057-
adap->algo = &amd_i2c_dw_algo;
1058-
else
1059-
adap->algo = &i2c_dw_algo;
1060-
adap->quirks = &i2c_dw_quirks;
1061-
adap->dev.parent = dev->dev;
1062-
i2c_set_adapdata(adap, dev);
1063-
1064-
if (dev->flags & ACCESS_NO_IRQ_SUSPEND) {
1065-
irq_flags = IRQF_NO_SUSPEND;
1066-
} else {
1067-
irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND;
1068-
}
1069-
1070-
ret = i2c_dw_acquire_lock(dev);
1071-
if (ret)
1072-
return ret;
1073-
1074-
__i2c_dw_write_intr_mask(dev, 0);
1075-
i2c_dw_release_lock(dev);
1076-
1077-
if (!(dev->flags & ACCESS_POLLING)) {
1078-
ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr,
1079-
irq_flags, dev_name(dev->dev), dev);
1080-
if (ret)
1081-
return dev_err_probe(dev->dev, ret,
1082-
"failure requesting irq %i: %d\n",
1083-
dev->irq, ret);
1084-
}
1085-
1086-
ret = i2c_dw_init_recovery_info(dev);
1087-
if (ret)
1088-
return ret;
1089-
1090-
/*
1091-
* Increment PM usage count during adapter registration in order to
1092-
* avoid possible spurious runtime suspend when adapter device is
1093-
* registered to the device core and immediate resume in case bus has
1094-
* registered I2C slaves that do I2C transfers in their probe.
1095-
*/
1096-
pm_runtime_get_noresume(dev->dev);
1097-
ret = i2c_add_numbered_adapter(adap);
1098-
if (ret)
1099-
dev_err(dev->dev, "failure adding adapter: %d\n", ret);
1100-
pm_runtime_put_noidle(dev->dev);
1101-
1102-
return ret;
1027+
return i2c_dw_init_recovery_info(dev);
11031028
}
11041029

11051030
MODULE_DESCRIPTION("Synopsys DesignWare I2C bus master adapter");

0 commit comments

Comments
 (0)