diff options
Diffstat (limited to 'drivers/i2c')
182 files changed, 17593 insertions, 7751 deletions
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig index 438905e2a1d0..c232054fddd6 100644 --- a/drivers/i2c/Kconfig +++ b/drivers/i2c/Kconfig @@ -40,14 +40,6 @@ config I2C_BOARDINFO bool default y -config I2C_COMPAT - bool "Enable compatibility bits for old user-space" - default y - help - Say Y here if you intend to run lm-sensors 3.1.1 or older, or any - other user-space package which expects i2c adapters to be class - devices. If you don't know, say Y. - config I2C_CHARDEV tristate "I2C device interface" help @@ -71,6 +63,15 @@ config I2C_MUX source "drivers/i2c/muxes/Kconfig" +config I2C_ATR + tristate "I2C Address Translator (ATR) support" if COMPILE_TEST + help + Enable support for I2C Address Translator (ATR) chips. + + An ATR allows accessing multiple I2C busses from a single + physical bus via address translation instead of bus selection as + i2c-muxes do. + config I2C_HELPER_AUTO bool "Autoselect pertinent helper modules" default y @@ -126,7 +127,7 @@ config I2C_SLAVE_EEPROM Documentation/i2c/slave-eeprom-backend.rst for further details. config I2C_SLAVE_TESTUNIT - tristate "I2C eeprom testunit driver" + tristate "I2C testunit driver" help This backend can be used to trigger test cases for I2C bus masters which require a remote device with certain capabilities, e.g. diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index c1d493dc9bac..d27de18de46f 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -5,14 +5,16 @@ obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o obj-$(CONFIG_I2C) += i2c-core.o -i2c-core-objs := i2c-core-base.o i2c-core-smbus.o +i2c-core-y := i2c-core-base.o i2c-core-smbus.o i2c-core-$(CONFIG_ACPI) += i2c-core-acpi.o -i2c-core-$(CONFIG_I2C_SLAVE) += i2c-core-slave.o -i2c-core-$(CONFIG_OF) += i2c-core-of.o +i2c-core-$(CONFIG_I2C_SLAVE) += i2c-core-slave.o +i2c-core-$(CONFIG_OF) += i2c-core-of.o +i2c-core-$(CONFIG_OF_DYNAMIC) += i2c-core-of-prober.o obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o obj-$(CONFIG_I2C_MUX) += i2c-mux.o +obj-$(CONFIG_I2C_ATR) += i2c-atr.o obj-y += algos/ busses/ muxes/ obj-$(CONFIG_I2C_STUB) += i2c-stub.o obj-$(CONFIG_I2C_SLAVE_EEPROM) += i2c-slave-eeprom.o diff --git a/drivers/i2c/algos/i2c-algo-bit.c b/drivers/i2c/algos/i2c-algo-bit.c index fc90293afcbf..6544d27e4419 100644 --- a/drivers/i2c/algos/i2c-algo-bit.c +++ b/drivers/i2c/algos/i2c-algo-bit.c @@ -184,8 +184,9 @@ static int i2c_outb(struct i2c_adapter *i2c_adap, unsigned char c) /* read ack: SDA should be pulled down by slave, or it may * NAK (usually to report problems with the data we wrote). + * Always report ACK if SDA is write-only. */ - ack = !getsda(adap); /* ack: sda is pulled low -> success */ + ack = !adap->getsda || !getsda(adap); /* ack: sda is pulled low -> success */ bit_dbg(2, &i2c_adap->dev, "i2c_outb: 0x%02x %s\n", (int)c, ack ? "A" : "NA"); @@ -238,71 +239,55 @@ static int test_bus(struct i2c_adapter *i2c_adap) return -ENODEV; } + if (adap->getsda == NULL) + pr_info("%s: SDA is write-only, testing not possible\n", name); if (adap->getscl == NULL) - pr_info("%s: Testing SDA only, SCL is not readable\n", name); + pr_info("%s: SCL is write-only, testing not possible\n", name); - sda = getsda(adap); - scl = (adap->getscl == NULL) ? 1 : getscl(adap); + sda = adap->getsda ? getsda(adap) : 1; + scl = adap->getscl ? getscl(adap) : 1; if (!scl || !sda) { - printk(KERN_WARNING - "%s: bus seems to be busy (scl=%d, sda=%d)\n", - name, scl, sda); + pr_warn("%s: bus seems to be busy (scl=%d, sda=%d)\n", name, scl, sda); goto bailout; } sdalo(adap); - sda = getsda(adap); - scl = (adap->getscl == NULL) ? 1 : getscl(adap); - if (sda) { - printk(KERN_WARNING "%s: SDA stuck high!\n", name); + if (adap->getsda && getsda(adap)) { + pr_warn("%s: SDA stuck high!\n", name); goto bailout; } - if (!scl) { - printk(KERN_WARNING - "%s: SCL unexpected low while pulling SDA low!\n", - name); + if (adap->getscl && !getscl(adap)) { + pr_warn("%s: SCL unexpected low while pulling SDA low!\n", name); goto bailout; } sdahi(adap); - sda = getsda(adap); - scl = (adap->getscl == NULL) ? 1 : getscl(adap); - if (!sda) { - printk(KERN_WARNING "%s: SDA stuck low!\n", name); + if (adap->getsda && !getsda(adap)) { + pr_warn("%s: SDA stuck low!\n", name); goto bailout; } - if (!scl) { - printk(KERN_WARNING - "%s: SCL unexpected low while pulling SDA high!\n", - name); + if (adap->getscl && !getscl(adap)) { + pr_warn("%s: SCL unexpected low while pulling SDA high!\n", name); goto bailout; } scllo(adap); - sda = getsda(adap); - scl = (adap->getscl == NULL) ? 0 : getscl(adap); - if (scl) { - printk(KERN_WARNING "%s: SCL stuck high!\n", name); + if (adap->getscl && getscl(adap)) { + pr_warn("%s: SCL stuck high!\n", name); goto bailout; } - if (!sda) { - printk(KERN_WARNING - "%s: SDA unexpected low while pulling SCL low!\n", - name); + if (adap->getsda && !getsda(adap)) { + pr_warn("%s: SDA unexpected low while pulling SCL low!\n", name); goto bailout; } sclhi(adap); - sda = getsda(adap); - scl = (adap->getscl == NULL) ? 1 : getscl(adap); - if (!scl) { - printk(KERN_WARNING "%s: SCL stuck low!\n", name); + if (adap->getscl && !getscl(adap)) { + pr_warn("%s: SCL stuck low!\n", name); goto bailout; } - if (!sda) { - printk(KERN_WARNING - "%s: SDA unexpected low while pulling SCL high!\n", - name); + if (adap->getsda && !getsda(adap)) { + pr_warn("%s: SDA unexpected low while pulling SCL high!\n", name); goto bailout; } @@ -420,6 +405,10 @@ static int readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msg) unsigned char *temp = msg->buf; int count = msg->len; const unsigned flags = msg->flags; + struct i2c_algo_bit_data *adap = i2c_adap->algo_data; + + if (!adap->getsda) + return -EOPNOTSUPP; while (count > 0) { inval = i2c_inb(i2c_adap); @@ -630,8 +619,8 @@ static u32 bit_func(struct i2c_adapter *adap) /* -----exported algorithm data: ------------------------------------- */ const struct i2c_algorithm i2c_bit_algo = { - .master_xfer = bit_xfer, - .master_xfer_atomic = bit_xfer_atomic, + .xfer = bit_xfer, + .xfer_atomic = bit_xfer_atomic, .functionality = bit_func, }; EXPORT_SYMBOL(i2c_bit_algo); @@ -670,11 +659,15 @@ static int __i2c_bit_add_bus(struct i2c_adapter *adap, if (ret < 0) return ret; - /* Complain if SCL can't be read */ - if (bit_adap->getscl == NULL) { + if (bit_adap->getsda == NULL) + dev_warn(&adap->dev, "Not I2C compliant: can't read SDA\n"); + + if (bit_adap->getscl == NULL) dev_warn(&adap->dev, "Not I2C compliant: can't read SCL\n"); + + if (bit_adap->getsda == NULL || bit_adap->getscl == NULL) dev_warn(&adap->dev, "Bus may be unreliable\n"); - } + return 0; } diff --git a/drivers/i2c/algos/i2c-algo-pca.c b/drivers/i2c/algos/i2c-algo-pca.c index 384af88e58ad..ee86df4cff4b 100644 --- a/drivers/i2c/algos/i2c-algo-pca.c +++ b/drivers/i2c/algos/i2c-algo-pca.c @@ -30,7 +30,7 @@ static int i2c_debug; #define pca_clock(adap) adap->i2c_clock #define pca_set_con(adap, val) pca_outw(adap, I2C_PCA_CON, val) #define pca_get_con(adap) pca_inw(adap, I2C_PCA_CON) -#define pca_wait(adap) adap->wait_for_completion(adap->data) +#define pca_wait(adap) adap->wait_for_completion_cb(adap->data) static void pca_reset(struct i2c_algo_pca_data *adap) { @@ -361,8 +361,8 @@ static u32 pca_func(struct i2c_adapter *adap) } static const struct i2c_algorithm pca_algo = { - .master_xfer = pca_xfer, - .functionality = pca_func, + .xfer = pca_xfer, + .functionality = pca_func, }; static unsigned int pca_probe_chip(struct i2c_adapter *adap) diff --git a/drivers/i2c/algos/i2c-algo-pcf.c b/drivers/i2c/algos/i2c-algo-pcf.c index 7a01f2687b4c..a87ecea7f510 100644 --- a/drivers/i2c/algos/i2c-algo-pcf.c +++ b/drivers/i2c/algos/i2c-algo-pcf.c @@ -19,20 +19,12 @@ #include <linux/errno.h> #include <linux/i2c.h> #include <linux/i2c-algo-pcf.h> +#include <linux/string_choices.h> #include "i2c-algo-pcf.h" -#define DEB2(x) if (i2c_debug >= 2) x -#define DEB3(x) if (i2c_debug >= 3) x /* print several statistical values */ -#define DEBPROTO(x) if (i2c_debug >= 9) x; - /* debug the protocol by showing transferred bits */ #define DEF_TIMEOUT 16 -/* - * module parameters: - */ -static int i2c_debug; - /* setting states on the bus with the right timing: */ #define set_pcf(adap, ctl, val) adap->setpcf(adap->data, ctl, val) @@ -46,27 +38,21 @@ static int i2c_debug; static void i2c_start(struct i2c_algo_pcf_data *adap) { - DEBPROTO(printk(KERN_DEBUG "S ")); set_pcf(adap, 1, I2C_PCF_START); } static void i2c_repstart(struct i2c_algo_pcf_data *adap) { - DEBPROTO(printk(" Sr ")); set_pcf(adap, 1, I2C_PCF_REPSTART); } static void i2c_stop(struct i2c_algo_pcf_data *adap) { - DEBPROTO(printk("P\n")); set_pcf(adap, 1, I2C_PCF_STOP); } static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status) { - DEB2(printk(KERN_INFO - "i2c-algo-pcf.o: lost arbitration (CSR 0x%02x)\n", - *status)); /* * Cleanup from LAB -- reset and enable ESO. * This resets the PCF8584; since we've lost the bus, no @@ -87,9 +73,6 @@ static void handle_lab(struct i2c_algo_pcf_data *adap, const int *status) if (adap->lab_mdelay) mdelay(adap->lab_mdelay); - DEB2(printk(KERN_INFO - "i2c-algo-pcf.o: reset LAB condition (CSR 0x%02x)\n", - get_pcf(adap, 1))); } static int wait_for_bb(struct i2c_algo_pcf_data *adap) @@ -146,56 +129,48 @@ static int wait_for_pin(struct i2c_algo_pcf_data *adap, int *status) * * vdovikin: added detect code for PCF8584 */ -static int pcf_init_8584 (struct i2c_algo_pcf_data *adap) +static int pcf_init_8584(struct i2c_algo_pcf_data *adap) { unsigned char temp; - DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: PCF state 0x%02x\n", - get_pcf(adap, 1))); - /* S1=0x80: S0 selected, serial interface off */ set_pcf(adap, 1, I2C_PCF_PIN); /* * check to see S1 now used as R/W ctrl - * PCF8584 does that when ESO is zero */ - if (((temp = get_pcf(adap, 1)) & 0x7f) != (0)) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S0 (0x%02x).\n", temp)); + temp = get_pcf(adap, 1); + if ((temp & 0x7f) != 0) return -ENXIO; /* definitely not PCF8584 */ - } /* load own address in S0, effective address is (own << 1) */ i2c_outb(adap, get_own(adap)); /* check it's really written */ - if ((temp = i2c_inb(adap)) != get_own(adap)) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S0 (0x%02x).\n", temp)); + temp = i2c_inb(adap); + if (temp != get_own(adap)) return -ENXIO; - } /* S1=0xA0, next byte in S2 */ set_pcf(adap, 1, I2C_PCF_PIN | I2C_PCF_ES1); /* check to see S2 now selected */ - if (((temp = get_pcf(adap, 1)) & 0x7f) != I2C_PCF_ES1) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S2 (0x%02x).\n", temp)); + temp = get_pcf(adap, 1); + if ((temp & 0x7f) != I2C_PCF_ES1) return -ENXIO; - } /* load clock register S2 */ i2c_outb(adap, get_clock(adap)); /* check it's really written, the only 5 lowest bits does matter */ - if (((temp = i2c_inb(adap)) & 0x1f) != get_clock(adap)) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't set S2 (0x%02x).\n", temp)); + temp = i2c_inb(adap); + if ((temp & 0x1f) != get_clock(adap)) return -ENXIO; - } /* Enable serial interface, idle, S0 selected */ set_pcf(adap, 1, I2C_PCF_IDLE); /* check to see PCF is really idled and we can access status register */ - if ((temp = get_pcf(adap, 1)) != (I2C_PCF_PIN | I2C_PCF_BB)) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: PCF detection failed -- can't select S1` (0x%02x).\n", temp)); + temp = get_pcf(adap, 1); + if (temp != (I2C_PCF_PIN | I2C_PCF_BB)) return -ENXIO; - } printk(KERN_DEBUG "i2c-algo-pcf.o: detected and initialized PCF8584.\n"); @@ -208,9 +183,7 @@ static int pcf_sendbytes(struct i2c_adapter *i2c_adap, const char *buf, struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; int wrcount, status, timeout; - for (wrcount=0; wrcount<count; ++wrcount) { - DEB2(dev_dbg(&i2c_adap->dev, "i2c_write: writing %2.2X\n", - buf[wrcount] & 0xff)); + for (wrcount = 0; wrcount < count; ++wrcount) { i2c_outb(adap, buf[wrcount]); timeout = wait_for_pin(adap, &status); if (timeout) { @@ -245,7 +218,8 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, /* increment number of bytes to read by one -- read dummy byte */ for (i = 0; i <= count; i++) { - if ((wfp = wait_for_pin(adap, &status))) { + wfp = wait_for_pin(adap, &status); + if (wfp) { if (wfp == -EINTR) return -EINTR; /* arbitration lost */ @@ -279,7 +253,7 @@ static int pcf_readbytes(struct i2c_adapter *i2c_adap, char *buf, } -static int pcf_doAddress(struct i2c_algo_pcf_data *adap, +static void pcf_send_address(struct i2c_algo_pcf_data *adap, struct i2c_msg *msg) { unsigned char addr = i2c_8bit_addr_from_msg(msg); @@ -287,8 +261,6 @@ static int pcf_doAddress(struct i2c_algo_pcf_data *adap, if (msg->flags & I2C_M_REV_DIR_ADDR) addr ^= 1; i2c_outb(adap, addr); - - return 0; } static int pcf_xfer(struct i2c_adapter *i2c_adap, @@ -298,7 +270,7 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, struct i2c_algo_pcf_data *adap = i2c_adap->algo_data; struct i2c_msg *pmsg; int i; - int ret=0, timeout, status; + int timeout, status; if (adap->xfer_begin) adap->xfer_begin(adap->data); @@ -306,20 +278,15 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, /* Check for bus busy */ timeout = wait_for_bb(adap); if (timeout) { - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: " - "Timeout waiting for BB in pcf_xfer\n");) i = -EIO; goto out; } - for (i = 0;ret >= 0 && i < num; i++) { - pmsg = &msgs[i]; - - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: Doing %s %d bytes to 0x%02x - %d of %d messages\n", - pmsg->flags & I2C_M_RD ? "read" : "write", - pmsg->len, pmsg->addr, i + 1, num);) + for (i = 0; i < num; i++) { + int ret; - ret = pcf_doAddress(adap, pmsg); + pmsg = &msgs[i]; + pcf_send_address(adap, pmsg); /* Send START */ if (i == 0) @@ -334,8 +301,6 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, goto out; } i2c_stop(adap); - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: Timeout waiting " - "for PIN(1) in pcf_xfer\n");) i = -EREMOTEIO; goto out; } @@ -343,35 +308,21 @@ static int pcf_xfer(struct i2c_adapter *i2c_adap, /* Check LRB (last rcvd bit - slave ack) */ if (status & I2C_PCF_LRB) { i2c_stop(adap); - DEB2(printk(KERN_ERR "i2c-algo-pcf.o: No LRB(1) in pcf_xfer\n");) i = -EREMOTEIO; goto out; } - DEB3(printk(KERN_DEBUG "i2c-algo-pcf.o: Msg %d, addr=0x%x, flags=0x%x, len=%d\n", - i, msgs[i].addr, msgs[i].flags, msgs[i].len);) if (pmsg->flags & I2C_M_RD) { ret = pcf_readbytes(i2c_adap, pmsg->buf, pmsg->len, (i + 1 == num)); - - if (ret != pmsg->len) { - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: " - "only read %d bytes.\n",ret)); - } else { - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: read %d bytes.\n",ret)); - } } else { ret = pcf_sendbytes(i2c_adap, pmsg->buf, pmsg->len, (i + 1 == num)); - - if (ret != pmsg->len) { - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: fail: " - "only wrote %d bytes.\n",ret)); - } else { - DEB2(printk(KERN_DEBUG "i2c-algo-pcf.o: wrote %d bytes.\n",ret)); - } } + + if (ret < 0) + goto out; } out: @@ -388,8 +339,8 @@ static u32 pcf_func(struct i2c_adapter *adap) /* exported algorithm data: */ static const struct i2c_algorithm pcf_algo = { - .master_xfer = pcf_xfer, - .functionality = pcf_func, + .xfer = pcf_xfer, + .functionality = pcf_func, }; /* @@ -400,12 +351,11 @@ int i2c_pcf_add_bus(struct i2c_adapter *adap) struct i2c_algo_pcf_data *pcf_adap = adap->algo_data; int rval; - DEB2(dev_dbg(&adap->dev, "hw routines registered.\n")); - /* register new adapter to i2c module... */ adap->algo = &pcf_algo; - if ((rval = pcf_init_8584(pcf_adap))) + rval = pcf_init_8584(pcf_adap); + if (rval) return rval; rval = i2c_add_adapter(adap); @@ -417,7 +367,3 @@ EXPORT_SYMBOL(i2c_pcf_add_bus); MODULE_AUTHOR("Hans Berglund <hb@spacetec.no>"); MODULE_DESCRIPTION("I2C-Bus PCF8584 algorithm"); MODULE_LICENSE("GPL"); - -module_param(i2c_debug, int, S_IRUGO | S_IWUSR); -MODULE_PARM_DESC(i2c_debug, - "debug level - 0 off; 1 normal; 2,3 more verbose; 9 pcf-protocol"); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index a7bfddf08fa7..cea87fcb4a1a 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -18,7 +18,7 @@ config I2C_CCGX_UCSI config I2C_ALI1535 tristate "ALI 1535" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the SMB Host controller on Acer Labs Inc. (ALI) M1535 South Bridges. The SMB @@ -30,7 +30,7 @@ config I2C_ALI1535 config I2C_ALI1563 tristate "ALI 1563" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the SMB Host controller on Acer Labs Inc. (ALI) M1563 South Bridges. The SMB @@ -42,7 +42,7 @@ config I2C_ALI1563 config I2C_ALI15X3 tristate "ALI 15x3" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces. @@ -52,7 +52,7 @@ config I2C_ALI15X3 config I2C_AMD756 tristate "AMD 756/766/768/8111 and nVidia nForce" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the AMD 756/766/768 mainboard I2C interfaces. The driver also includes @@ -62,22 +62,9 @@ config I2C_AMD756 This driver can also be built as a module. If so, the module will be called i2c-amd756. -config I2C_AMD756_S4882 - tristate "SMBus multiplexing on the Tyan S4882" - depends on I2C_AMD756 && X86 - help - Enabling this option will add specific SMBus support for the Tyan - S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed - over 8 different channels, where the various memory module EEPROMs - and temperature sensors live. Saying yes here will give you access - to these in addition to the trunk. - - This driver can also be built as a module. If so, the module - will be called i2c-amd756-s4882. - config I2C_AMD8111 tristate "AMD 8111" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the second (SMBus 2.0) AMD 8111 mainboard I2C interface. @@ -95,6 +82,23 @@ config I2C_AMD_MP2 This driver can also be built as modules. If so, the modules will be called i2c-amd-mp2-pci and i2c-amd-mp2-plat. +config I2C_AMD_ASF + tristate "AMD ASF I2C Controller Support" + depends on I2C_PIIX4 + select I2C_SLAVE + help + This option enables support for the AMD ASF (Alert Standard Format) + I2C controller. The AMD ASF controller is an SMBus controller with + built-in ASF functionality, allowing it to issue generic SMBus + packets and communicate with the DASH controller using MCTP over + ASF. + + If you have an AMD system with ASF support and want to enable this + functionality, say Y or M here. If unsure, say N. + + To compile this driver as a module, choose M here: the module will + be called i2c_amd_asf_plat. + config I2C_HIX5HD2 tristate "Hix5hd2 high-speed I2C driver" depends on ARCH_HISI || ARCH_HIX5HD2 || COMPILE_TEST @@ -107,7 +111,7 @@ config I2C_HIX5HD2 config I2C_I801 tristate "Intel 82801 (ICH/PCH)" - depends on PCI + depends on PCI && HAS_IOPORT select P2SB if X86 select CHECK_SIGNATURE if X86 && DMI select I2C_SMBUS @@ -157,14 +161,27 @@ config I2C_I801 Emmitsburg (PCH) Alder Lake (PCH) Raptor Lake (PCH) - Meteor Lake (SOC) + Meteor Lake (SOC and PCH) + Birch Stream (SOC) + Arrow Lake (SOC) + Panther Lake (SOC) + Wildcat Lake (SOC) + Diamond Rapids (SOC) This driver can also be built as a module. If so, the module will be called i2c-i801. +config I2C_I801_MUX + def_bool I2C_I801 + depends on DMI && I2C_MUX_GPIO + depends on !(I2C_I801=y && I2C_MUX=m) + help + Optional support for multiplexed SMBUS on certain systems with + more than 8 memory slots. + config I2C_ISCH tristate "Intel SCH SMBus 1.0" - depends on PCI + depends on PCI && HAS_IOPORT select LPC_SCH help Say Y here if you want to use SMBus controller on the Intel SCH @@ -185,7 +202,8 @@ config I2C_ISMT config I2C_PIIX4 tristate "Intel PIIX4 and compatible (ATI/AMD/Serverworks/Broadcom/SMSC)" - depends on PCI + depends on PCI && HAS_IOPORT + select I2C_SMBUS help If you say yes to this option, support will be included for the Intel PIIX4 family of mainboard I2C interfaces. Specifically, the following @@ -231,7 +249,7 @@ config I2C_CHT_WC config I2C_NFORCE2 tristate "Nvidia nForce2, nForce3 and nForce4" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the Nvidia nForce2, nForce3 and nForce4 families of mainboard I2C interfaces. @@ -239,19 +257,6 @@ config I2C_NFORCE2 This driver can also be built as a module. If so, the module will be called i2c-nforce2. -config I2C_NFORCE2_S4985 - tristate "SMBus multiplexing on the Tyan S4985" - depends on I2C_NFORCE2 && X86 - help - Enabling this option will add specific SMBus support for the Tyan - S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed - over 4 different channels, where the various memory module EEPROMs - live. Saying yes here will give you access to these in addition - to the trunk. - - This driver can also be built as a module. If so, the module - will be called i2c-nforce2-s4985. - config I2C_NVIDIA_GPU tristate "NVIDIA GPU I2C controller" depends on PCI @@ -264,7 +269,7 @@ config I2C_NVIDIA_GPU config I2C_SIS5595 tristate "SiS 5595" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the SiS5595 SMBus (a subset of I2C) interface. @@ -274,7 +279,7 @@ config I2C_SIS5595 config I2C_SIS630 tristate "SiS 630/730/964" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the SiS630, SiS730 and SiS964 SMBus (a subset of I2C) interface. @@ -284,7 +289,7 @@ config I2C_SIS630 config I2C_SIS96X tristate "SiS 96x" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the SiS 96x SMBus (a subset of I2C) interfaces. Specifically, the following @@ -302,7 +307,7 @@ config I2C_SIS96X config I2C_VIA tristate "VIA VT82C586B" - depends on PCI + depends on PCI && HAS_IOPORT select I2C_ALGOBIT help If you say yes to this option, support will be included for the VIA @@ -313,7 +318,7 @@ config I2C_VIA config I2C_VIAPRO tristate "VIA VT82C596/82C686/82xx and CX700/VX8xx/VX900" - depends on PCI + depends on PCI && HAS_IOPORT help If you say yes to this option, support will be included for the VIA VT82C596 and later SMBus interface. Specifically, the following @@ -335,6 +340,16 @@ config I2C_VIAPRO if ACPI +config I2C_ZHAOXIN + tristate "Zhaoxin I2C Interface" + depends on PCI || COMPILE_TEST + help + If you say yes to this option, support will be included for the + ZHAOXIN I2C interface + + This driver can also be built as a module. If so, the module + will be called i2c-zhaoxin. + comment "ACPI drivers" config I2C_SCMI @@ -401,7 +416,7 @@ config I2C_ASPEED config I2C_AT91 tristate "Atmel AT91 I2C Two-Wire interface (TWI)" - depends on ARCH_AT91 || COMPILE_TEST + depends on ARCH_MICROCHIP || COMPILE_TEST help This supports the use of the I2C interface on Atmel AT91 processors. @@ -418,7 +433,7 @@ config I2C_AT91 are facing this situation, use the i2c-gpio driver. config I2C_AT91_SLAVE_EXPERIMENTAL - tristate "Microchip AT91 I2C experimental slave mode" + bool "Microchip AT91 I2C experimental slave mode" depends on I2C_AT91 select I2C_SLAVE help @@ -427,7 +442,7 @@ config I2C_AT91_SLAVE_EXPERIMENTAL been tested in a heavy way, help wanted. There are known bugs: - It can hang, on a SAMA5D4, after several transfers. - - There are some mismtaches with a SAMA5D4 as slave and a SAMA5D2 as + - There are some mismatches with a SAMA5D4 as slave and a SAMA5D2 as master. config I2C_AU1550 @@ -490,7 +505,7 @@ config I2C_BRCMSTB tristate "BRCM Settop/DSL I2C controller" depends on ARCH_BCM2835 || ARCH_BCMBCA || ARCH_BRCMSTB || \ BMIPS_GENERIC || COMPILE_TEST - default y + default ARCH_BCM2835 || ARCH_BCMBCA || ARCH_BRCMSTB || BMIPS_GENERIC help If you say yes to this option, support will be included for the I2C interface on the Broadcom Settop/DSL SoCs. @@ -499,7 +514,7 @@ config I2C_BRCMSTB config I2C_CADENCE tristate "Cadence I2C Controller" - depends on ARCH_ZYNQ || ARM64 || XTENSA || COMPILE_TEST + depends on ARCH_ZYNQ || ARM64 || XTENSA || RISCV || COMPILE_TEST help Say yes here to select Cadence I2C Host Controller. This controller is e.g. used by Xilinx Zynq. @@ -514,6 +529,16 @@ config I2C_CBUS_GPIO This driver can also be built as a module. If so, the module will be called i2c-cbus-gpio. +config I2C_CGBC + tristate "Congatec I2C Controller" + depends on MFD_CGBC + help + This driver supports the 2 I2C interfaces on the Congatec Board + Controller. + + This driver can also be built as a module. If so, the module will + be called i2c-cgbc.ko. + config I2C_CPM tristate "Freescale CPM1 or CPM2 (MPC8xx/826x)" depends on CPM1 || CPM2 @@ -538,37 +563,56 @@ config I2C_DAVINCI For details please see http://www.ti.com/davinci config I2C_DESIGNWARE_CORE - tristate + tristate "Synopsys DesignWare I2C adapter" select REGMAP + help + This option enables support for the Synopsys DesignWare I2C adapter. + This driver includes support for the I2C host on the Synopsys + Designware I2C adapter. + + To compile the driver as a module, choose M here: the module will be + called i2c-designware-core. + +if I2C_DESIGNWARE_CORE config I2C_DESIGNWARE_SLAVE bool "Synopsys DesignWare Slave" - depends on I2C_DESIGNWARE_CORE select I2C_SLAVE help If you say yes to this option, support will be included for the Synopsys DesignWare I2C slave adapter. - This is not a standalone module, this module compiles together with - i2c-designware-core. - config I2C_DESIGNWARE_PLATFORM - tristate "Synopsys DesignWare Platform" + tristate "Synopsys DesignWare Platform driver" depends on (ACPI && COMMON_CLK) || !ACPI - select I2C_DESIGNWARE_CORE select MFD_SYSCON if MIPS_BAIKAL_T1 + default I2C_DESIGNWARE_CORE help If you say yes to this option, support will be included for the - Synopsys DesignWare I2C adapter. + Synopsys DesignWare I2C adapters on the platform bus. This driver can also be built as a module. If so, the module will be called i2c-designware-platform. +config I2C_DESIGNWARE_AMDISP + tristate "Synopsys DesignWare Platform for AMDISP" + depends on DRM_AMD_ISP || COMPILE_TEST + depends on I2C_DESIGNWARE_CORE + help + If you say yes to this option, support will be included for the + AMDISP Synopsys DesignWare I2C adapter. + + This driver can also be built as a module. If so, the module + will be called amd_isp_i2c_designware. + config I2C_DESIGNWARE_AMDPSP bool "AMD PSP I2C semaphore support" - depends on X86_MSR depends on ACPI + depends on CRYPTO_DEV_SP_PSP + depends on PCI depends on I2C_DESIGNWARE_PLATFORM + depends on (I2C_DESIGNWARE_PLATFORM=y && CRYPTO_DEV_CCP_DD=y) || \ + (I2C_DESIGNWARE_PLATFORM=m && CRYPTO_DEV_CCP_DD) help This driver enables managed host access to the selected I2C bus shared between AMD CPU and AMD PSP. @@ -589,17 +633,19 @@ config I2C_DESIGNWARE_BAYTRAIL a BayTrail system using the AXP288. config I2C_DESIGNWARE_PCI - tristate "Synopsys DesignWare PCI" + tristate "Synopsys DesignWare PCI driver" depends on PCI - select I2C_DESIGNWARE_CORE select I2C_CCGX_UCSI help If you say yes to this option, support will be included for the - Synopsys DesignWare I2C adapter. Only master mode is supported. + Synopsys DesignWare I2C adapters on the PCI bus. Only master mode is + supported. This driver can also be built as a module. If so, the module will be called i2c-designware-pci. +endif + config I2C_DIGICOLOR tristate "Conexant Digicolor I2C driver" depends on ARCH_DIGICOLOR || COMPILE_TEST @@ -659,6 +705,13 @@ config I2C_GPIO_FAULT_INJECTOR faults to an I2C bus, so another bus master can be stress-tested. This is for debugging. If unsure, say 'no'. +config I2C_GXP + tristate "GXP I2C Interface" + depends on ARCH_HPE_GXP || COMPILE_TEST + help + This enables support for GXP I2C interface. The I2C engines can be + either I2C master or I2C slaves. + config I2C_HIGHLANDER tristate "Highlander FPGA SMBus interface" depends on SH_HIGHLANDER || COMPILE_TEST @@ -703,18 +756,20 @@ config I2C_IMG config I2C_IMX tristate "IMX I2C interface" - depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE || COMPILE_TEST + depends on ARCH_MXC || ARCH_LAYERSCAPE || ARCH_S32 || COLDFIRE \ + || COMPILE_TEST select I2C_SLAVE help Say Y here if you want to use the IIC bus controller on - the Freescale i.MX/MXC, Layerscape or ColdFire processors. + the Freescale i.MX/MXC/S32G, Layerscape or ColdFire processors. - This driver can also be built as a module. If so, the module + This driver can also be built as a module. If so, the module will be called i2c-imx. config I2C_IMX_LPI2C tristate "IMX Low Power I2C interface" depends on ARCH_MXC || COMPILE_TEST + select I2C_SLAVE help Say Y here if you want to use the Low Power IIC bus controller on the Freescale i.MX processors. @@ -723,11 +778,11 @@ config I2C_IMX_LPI2C will be called i2c-imx-lpi2c. config I2C_IOP3XX - tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface" - depends on ARCH_IOP32X || ARCH_IXP4XX || COMPILE_TEST + tristate "Intel IXP4xx on-chip I2C interface" + depends on ARCH_IXP4XX || COMPILE_TEST help Say Y here if you want to use the IIC bus controller on - the Intel IOPx3xx I/O Processors or IXP4xx Network Processors. + the Intel IXP4xx Network Processors. This driver can also be built as a module. If so, the module will be called i2c-iop3xx. @@ -741,6 +796,35 @@ config I2C_JZ4780 If you don't know what to do here, say N. +config I2C_K1 + tristate "SpacemiT K1 I2C adapter" + depends on ARCH_SPACEMIT || COMPILE_TEST + depends on OF + help + This option enables support for the I2C interface on the SpacemiT K1 + platform. + + If you enable this configuration, the kernel will include support for + the I2C adapter specific to the SpacemiT K1 platform. This driver can + be used to manage I2C bus transactions, which are necessary for + interfacing with I2C peripherals such as sensors, EEPROMs, and other + devices. + + This driver can also be built as a module. If so, the + module will be called `i2c-k1`. + +config I2C_KEBA + tristate "KEBA I2C controller support" + depends on HAS_IOMEM + depends on KEBA_CP500 || COMPILE_TEST + select AUXILIARY_BUS + help + This driver supports the I2C controller found in KEBA system FPGA + devices. + + This driver can also be built as a module. If so, the module + will be called i2c-keba. + config I2C_KEMPLD tristate "Kontron COM I2C Controller" depends on MFD_KEMPLD @@ -761,9 +845,20 @@ config I2C_LPC2K This driver can also be built as a module. If so, the module will be called i2c-lpc2k. +config I2C_LS2X + tristate "Loongson LS2X I2C adapter" + depends on MACH_LOONGSON64 || COMPILE_TEST + help + If you say yes to this option, support will be included for the + I2C interface on the Loongson-2K SoCs and Loongson LS7A bridge + chip. + + This driver can also be built as a module. If so, the module + will be called i2c-ls2x. + config I2C_MLXBF tristate "Mellanox BlueField I2C controller" - depends on MELLANOX_PLATFORM && ARM64 + depends on (MELLANOX_PLATFORM && ARM64) || COMPILE_TEST depends on ACPI select I2C_SLAVE help @@ -786,7 +881,7 @@ config I2C_MESON config I2C_MICROCHIP_CORE tristate "Microchip FPGA I2C controller" - depends on SOC_MICROCHIP_POLARFIRE || COMPILE_TEST + depends on ARCH_MICROCHIP_POLARFIRE || COMPILE_TEST depends on OF help If you say yes to this option, support will be included for the @@ -817,7 +912,7 @@ config I2C_MT65XX config I2C_MT7621 tristate "MT7621/MT7628 I2C Controller" - depends on (RALINK && (SOC_MT7620 || SOC_MT7621)) || COMPILE_TEST + depends on (RALINK && (SOC_MT7620 || SOC_MT7621)) || ARCH_AIROHA || COMPILE_TEST help Say Y here to include support for I2C controller in the MediaTek MT7621/MT7628 SoCs. @@ -846,7 +941,7 @@ config I2C_MXS config I2C_NOMADIK tristate "ST-Ericsson Nomadik/Ux500 I2C Controller" - depends on ARM_AMBA + depends on ARM_AMBA || COMPILE_TEST help If you say yes to this option, support will be included for the I2C interface from ST-Ericsson's Nomadik and Ux500 architectures, @@ -874,7 +969,8 @@ config I2C_OCORES config I2C_OMAP tristate "OMAP I2C adapter" depends on ARCH_OMAP || ARCH_K3 || COMPILE_TEST - default y if MACH_OMAP_H3 || MACH_OMAP_OSK + default MACH_OMAP_OSK + select MULTIPLEXER help If you say yes to this option, support will be included for the I2C interface on the Texas Instruments OMAP1/2 family of processors. @@ -896,8 +992,8 @@ config I2C_PASEMI config I2C_APPLE tristate "Apple SMBus platform driver" + depends on !I2C_PASEMI depends on ARCH_APPLE || COMPILE_TEST - default ARCH_APPLE help Say Y here if you want to use the I2C controller present on Apple Silicon chips such as the M1. @@ -998,20 +1094,29 @@ config I2C_RK3X This driver can also be built as a module. If so, the module will be called i2c-rk3x. +config I2C_RTL9300 + tristate "Realtek RTL9300 I2C controller" + depends on MACH_REALTEK_RTL || COMPILE_TEST + help + Say Y here to include support for the I2C controller in Realtek + RTL9300 SoCs. + + This driver can also be built as a module. If so, the module will + be called i2c-rtl9300. + config I2C_RZV2M tristate "Renesas RZ/V2M adapter" depends on ARCH_RENESAS || COMPILE_TEST help If you say yes to this option, support will be included for the - Renesas RZ/V2M I2C interface. + Renesas RZ/V2M I2C interface. This driver can also be built as a module. If so, the module will be called i2c-rzv2m. config I2C_S3C2410 tristate "S3C/Exynos I2C Driver" - depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || \ - ARCH_S5PV210 || COMPILE_TEST + depends on ARCH_EXYNOS || ARCH_S3C64XX || ARCH_S5PV210 || COMPILE_TEST help Say Y here to include support for I2C controller in the Samsung SoCs (S3C, S5Pv210, Exynos). @@ -1213,7 +1318,7 @@ config I2C_RCAR depends on ARCH_RENESAS || COMPILE_TEST select I2C_SLAVE select I2C_SMBUS - select RESET_CONTROLLER if ARCH_RCAR_GEN3 + select RESET_CONTROLLER if ARCH_RCAR_GEN3 || ARCH_RCAR_GEN4 help If you say yes to this option, support will be included for the R-Car I2C controller. @@ -1243,6 +1348,38 @@ config I2C_DLN2 This driver can also be built as a module. If so, the module will be called i2c-dln2. +config I2C_LJCA + tristate "I2C functionality of Intel La Jolla Cove Adapter" + depends on USB_LJCA + default USB_LJCA + help + If you say yes to this option, I2C functionality support of Intel + La Jolla Cove Adapter (LJCA) will be included. + + This driver can also be built as a module. If so, the module + will be called i2c-ljca. + +config I2C_NCT6694 + tristate "Nuvoton NCT6694 I2C adapter support" + depends on MFD_NCT6694 + help + If you say yes to this option, support will be included for Nuvoton + NCT6694, a USB to I2C interface. + + This driver can also be built as a module. If so, the module will + be called i2c-nct6694. + +config I2C_USBIO + tristate "Intel USBIO I2C Adapter support" + depends on USB_USBIO + default USB_USBIO + help + Select this option to enable I2C driver for the INTEL + USBIO driver stack. + + This driver can also be built as a module. If so, the module + will be called i2c_usbio. + config I2C_CP2615 tristate "Silicon Labs CP2615 USB sound card and I2C adapter" depends on USB @@ -1338,7 +1475,7 @@ config I2C_ACORN config I2C_ELEKTOR tristate "Elektor ISA card" - depends on ISA && HAS_IOPORT_MAP && BROKEN_ON_SMP + depends on ISA && HAS_IOPORT_MAP select I2C_ALGOPCF help This supports the PCF8584 ISA bus I2C adapter. Say Y if you own @@ -1363,10 +1500,11 @@ config I2C_ICY config I2C_MLXCPLD tristate "Mellanox I2C driver" - depends on X86_64 || COMPILE_TEST + depends on X86_64 || (ARM64 && ACPI) || COMPILE_TEST + depends on HAS_IOPORT help This exposes the Mellanox platform I2C busses to the linux I2C layer - for X86 based systems. + for X86 and ARM64/ACPI based systems. Controller is implemented as CPLD logic. This driver can also be built as a module. If so, the module will be @@ -1414,7 +1552,7 @@ config I2C_XGENE_SLIMPRO config SCx200_ACB tristate "Geode ACCESS.bus support" - depends on X86_32 && PCI + depends on X86_32 && PCI && HAS_IOPORT help Enable the use of the ACCESS.bus controllers on the Geode SCx200 and SC1100 processors and the CS5535 and CS5536 Geode companion devices. diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index e73cdb1d2b5a..fb985769f5ff 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -14,14 +14,12 @@ obj-$(CONFIG_I2C_ALI1535) += i2c-ali1535.o obj-$(CONFIG_I2C_ALI1563) += i2c-ali1563.o obj-$(CONFIG_I2C_ALI15X3) += i2c-ali15x3.o obj-$(CONFIG_I2C_AMD756) += i2c-amd756.o -obj-$(CONFIG_I2C_AMD756_S4882) += i2c-amd756-s4882.o obj-$(CONFIG_I2C_AMD8111) += i2c-amd8111.o obj-$(CONFIG_I2C_CHT_WC) += i2c-cht-wc.o obj-$(CONFIG_I2C_I801) += i2c-i801.o obj-$(CONFIG_I2C_ISCH) += i2c-isch.o obj-$(CONFIG_I2C_ISMT) += i2c-ismt.o obj-$(CONFIG_I2C_NFORCE2) += i2c-nforce2.o -obj-$(CONFIG_I2C_NFORCE2_S4985) += i2c-nforce2-s4985.o obj-$(CONFIG_I2C_NVIDIA_GPU) += i2c-nvidia-gpu.o obj-$(CONFIG_I2C_PIIX4) += i2c-piix4.o obj-$(CONFIG_I2C_SIS5595) += i2c-sis5595.o @@ -29,6 +27,7 @@ obj-$(CONFIG_I2C_SIS630) += i2c-sis630.o obj-$(CONFIG_I2C_SIS96X) += i2c-sis96x.o obj-$(CONFIG_I2C_VIA) += i2c-via.o obj-$(CONFIG_I2C_VIAPRO) += i2c-viapro.o +obj-$(CONFIG_I2C_ZHAOXIN) += i2c-viai2c-zhaoxin.o i2c-viai2c-common.o # Mac SMBus host controller drivers obj-$(CONFIG_I2C_HYDRA) += i2c-hydra.o @@ -37,18 +36,18 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o # Embedded system I2C/SMBus host controller drivers obj-$(CONFIG_I2C_ALTERA) += i2c-altera.o obj-$(CONFIG_I2C_AMD_MP2) += i2c-amd-mp2-pci.o i2c-amd-mp2-plat.o +obj-$(CONFIG_I2C_AMD_ASF) += i2c-amd-asf-plat.o obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o obj-$(CONFIG_I2C_AT91) += i2c-at91.o -i2c-at91-objs := i2c-at91-core.o i2c-at91-master.o -ifeq ($(CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL),y) - i2c-at91-objs += i2c-at91-slave.o -endif +i2c-at91-y := i2c-at91-core.o i2c-at91-master.o +i2c-at91-$(CONFIG_I2C_AT91_SLAVE_EXPERIMENTAL) += i2c-at91-slave.o obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o +obj-$(CONFIG_I2C_CGBC) += i2c-cgbc.o obj-$(CONFIG_I2C_CPM) += i2c-cpm.o obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o @@ -59,6 +58,7 @@ obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o i2c-designware-platform-y := i2c-designware-platdrv.o i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_AMDPSP) += i2c-designware-amdpsp.o i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o +obj-$(CONFIG_I2C_DESIGNWARE_AMDISP) += i2c-designware-amdisp.o obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o i2c-designware-pci-y := i2c-designware-pcidrv.o obj-$(CONFIG_I2C_DIGICOLOR) += i2c-digicolor.o @@ -75,8 +75,11 @@ obj-$(CONFIG_I2C_IMX) += i2c-imx.o obj-$(CONFIG_I2C_IMX_LPI2C) += i2c-imx-lpi2c.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o +obj-$(CONFIG_I2C_K1) += i2c-k1.o +obj-$(CONFIG_I2C_KEBA) += i2c-keba.o obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o obj-$(CONFIG_I2C_LPC2K) += i2c-lpc2k.o +obj-$(CONFIG_I2C_LS2X) += i2c-ls2x.o obj-$(CONFIG_I2C_MESON) += i2c-meson.o obj-$(CONFIG_I2C_MICROCHIP_CORE) += i2c-microchip-corei2c.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o @@ -89,10 +92,8 @@ obj-$(CONFIG_I2C_NPCM) += i2c-npcm7xx.o obj-$(CONFIG_I2C_OCORES) += i2c-ocores.o obj-$(CONFIG_I2C_OMAP) += i2c-omap.o obj-$(CONFIG_I2C_OWL) += i2c-owl.o -i2c-pasemi-objs := i2c-pasemi-core.o i2c-pasemi-pci.o -obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.o -i2c-apple-objs := i2c-pasemi-core.o i2c-pasemi-platform.o -obj-$(CONFIG_I2C_APPLE) += i2c-apple.o +obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi-core.o i2c-pasemi-pci.o +obj-$(CONFIG_I2C_APPLE) += i2c-pasemi-core.o i2c-pasemi-platform.o obj-$(CONFIG_I2C_PCA_PLATFORM) += i2c-pca-platform.o obj-$(CONFIG_I2C_PNX) += i2c-pnx.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o @@ -102,6 +103,7 @@ obj-$(CONFIG_I2C_QCOM_GENI) += i2c-qcom-geni.o obj-$(CONFIG_I2C_QUP) += i2c-qup.o obj-$(CONFIG_I2C_RIIC) += i2c-riic.o obj-$(CONFIG_I2C_RK3X) += i2c-rk3x.o +obj-$(CONFIG_I2C_RTL9300) += i2c-rtl9300.o obj-$(CONFIG_I2C_RZV2M) += i2c-rzv2m.o obj-$(CONFIG_I2C_S3C2410) += i2c-s3c2410.o obj-$(CONFIG_I2C_SH7760) += i2c-sh7760.o @@ -110,8 +112,8 @@ obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o obj-$(CONFIG_I2C_SPRD) += i2c-sprd.o obj-$(CONFIG_I2C_ST) += i2c-st.o obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o -i2c-stm32f7-drv-objs := i2c-stm32f7.o i2c-stm32.o obj-$(CONFIG_I2C_STM32F7) += i2c-stm32f7-drv.o +i2c-stm32f7-drv-y := i2c-stm32f7.o i2c-stm32.o obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o obj-$(CONFIG_I2C_SYNQUACER) += i2c-synquacer.o obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o @@ -119,18 +121,22 @@ obj-$(CONFIG_I2C_TEGRA_BPMP) += i2c-tegra-bpmp.o obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o -obj-$(CONFIG_I2C_WMT) += i2c-wmt.o -i2c-octeon-objs := i2c-octeon-core.o i2c-octeon-platdrv.o +obj-$(CONFIG_I2C_WMT) += i2c-viai2c-wmt.o i2c-viai2c-common.o obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o -i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o +i2c-octeon-y := i2c-octeon-core.o i2c-octeon-platdrv.o obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o +i2c-thunderx-y := i2c-octeon-core.o i2c-thunderx-pcidrv.o obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o +obj-$(CONFIG_I2C_GXP) += i2c-gxp.o # External I2C/SMBus adapter drivers obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o obj-$(CONFIG_I2C_DLN2) += i2c-dln2.o +obj-$(CONFIG_I2C_LJCA) += i2c-ljca.o +obj-$(CONFIG_I2C_NCT6694) += i2c-nct6694.o +obj-$(CONFIG_I2C_USBIO) += i2c-usbio.o obj-$(CONFIG_I2C_CP2615) += i2c-cp2615.o obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o obj-$(CONFIG_I2C_PCI1XXXX) += i2c-mchp-pci1xxxx.o diff --git a/drivers/i2c/busses/i2c-ali1535.c b/drivers/i2c/busses/i2c-ali1535.c index ee83c4581bce..1eac35838040 100644 --- a/drivers/i2c/busses/i2c-ali1535.c +++ b/drivers/i2c/busses/i2c-ali1535.c @@ -285,10 +285,8 @@ static int ali1535_transaction(struct i2c_adapter *adap) && (timeout++ < MAX_TIMEOUT)); /* If the SMBus is still busy, we give up */ - if (timeout > MAX_TIMEOUT) { + if (timeout > MAX_TIMEOUT) result = -ETIMEDOUT; - dev_err(&adap->dev, "SMBus Timeout!\n"); - } if (temp & ALI1535_STS_FAIL) { result = -EIO; @@ -313,10 +311,8 @@ static int ali1535_transaction(struct i2c_adapter *adap) } /* check to see if the "command complete" indication is set */ - if (!(temp & ALI1535_STS_DONE)) { + if (!(temp & ALI1535_STS_DONE)) result = -ETIMEDOUT; - dev_err(&adap->dev, "Error: command never completed\n"); - } dev_dbg(&adap->dev, "Transaction (post): STS=%02x, TYP=%02x, " "CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", @@ -477,19 +473,20 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter ali1535_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; static const struct pci_device_id ali1535_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) }, - { }, + { } }; - MODULE_DEVICE_TABLE(pci, ali1535_ids); static int ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id) { + int ret; + if (ali1535_setup(dev)) { dev_warn(&dev->dev, "ALI1535 not detected, module not inserted.\n"); @@ -501,7 +498,15 @@ static int ali1535_probe(struct pci_dev *dev, const struct pci_device_id *id) snprintf(ali1535_adapter.name, sizeof(ali1535_adapter.name), "SMBus ALI1535 adapter at %04x", ali1535_offset); - return i2c_add_adapter(&ali1535_adapter); + ret = i2c_add_adapter(&ali1535_adapter); + if (ret) + goto release_region; + + return 0; + +release_region: + release_region(ali1535_smba, ALI1535_SMB_IOSIZE); + return ret; } static void ali1535_remove(struct pci_dev *dev) diff --git a/drivers/i2c/busses/i2c-ali1563.c b/drivers/i2c/busses/i2c-ali1563.c index 55a9e93fbfeb..ee4fd66dedb0 100644 --- a/drivers/i2c/busses/i2c-ali1563.c +++ b/drivers/i2c/busses/i2c-ali1563.c @@ -99,7 +99,6 @@ static int ali1563_transaction(struct i2c_adapter *a, int size) return 0; if (!timeout) { - dev_err(&a->dev, "Timeout - Trying to KILL transaction!\n"); /* Issue 'kill' to host controller */ outb_p(HST_CNTL2_KILL, SMB_HST_CNTL2); data = inb_p(SMB_HST_STS); @@ -390,7 +389,7 @@ static const struct i2c_algorithm ali1563_algorithm = { static struct i2c_adapter ali1563_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &ali1563_algorithm, }; @@ -439,4 +438,5 @@ static struct pci_driver ali1563_pci_driver = { module_pci_driver(ali1563_pci_driver); +MODULE_DESCRIPTION("i2c driver for the ALi 1563 Southbridge"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c index cc58feacd082..418d11266671 100644 --- a/drivers/i2c/busses/i2c-ali15x3.c +++ b/drivers/i2c/busses/i2c-ali15x3.c @@ -39,7 +39,7 @@ We make sure that the SMB is enabled. We leave the ACPI alone. This driver controls the SMB Host only. - The SMB Slave controller on the M15X3 is not enabled. + The SMB Target controller on the M15X3 is not enabled. This driver does not use interrupts. */ @@ -165,14 +165,15 @@ static int ali15x3_setup(struct pci_dev *ALI15X3_dev) } if(force_addr) { + int ret; + dev_info(&ALI15X3_dev->dev, "forcing ISA address 0x%04X\n", ali15x3_smba); - if (PCIBIOS_SUCCESSFUL != pci_write_config_word(ALI15X3_dev, - SMBBA, - ali15x3_smba)) + ret = pci_write_config_word(ALI15X3_dev, SMBBA, ali15x3_smba); + if (ret != PCIBIOS_SUCCESSFUL) goto error; - if (PCIBIOS_SUCCESSFUL != pci_read_config_word(ALI15X3_dev, - SMBBA, &a)) + ret = pci_read_config_word(ALI15X3_dev, SMBBA, &a); + if (ret != PCIBIOS_SUCCESSFUL) goto error; if ((a & ~(ALI15X3_SMB_IOSIZE - 1)) != ali15x3_smba) { /* make sure it works */ @@ -293,10 +294,8 @@ static int ali15x3_transaction(struct i2c_adapter *adap) && (timeout++ < MAX_TIMEOUT)); /* If the SMBus is still busy, we give up */ - if (timeout > MAX_TIMEOUT) { + if (timeout > MAX_TIMEOUT) result = -ETIMEDOUT; - dev_err(&adap->dev, "SMBus Timeout!\n"); - } if (temp & ALI15X3_STS_TERM) { result = -EIO; @@ -460,7 +459,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter ali15x3_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; @@ -473,6 +472,8 @@ MODULE_DEVICE_TABLE (pci, ali15x3_ids); static int ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id) { + int ret; + if (ali15x3_setup(dev)) { dev_err(&dev->dev, "ALI15X3 not detected, module not inserted.\n"); @@ -484,7 +485,15 @@ static int ali15x3_probe(struct pci_dev *dev, const struct pci_device_id *id) snprintf(ali15x3_adapter.name, sizeof(ali15x3_adapter.name), "SMBus ALI15X3 adapter at %04x", ali15x3_smba); - return i2c_add_adapter(&ali15x3_adapter); + ret = i2c_add_adapter(&ali15x3_adapter); + if (ret) + goto release_region; + + return 0; + +release_region: + release_region(ali15x3_smba, ALI15X3_SMB_IOSIZE); + return ret; } static void ali15x3_remove(struct pci_dev *dev) diff --git a/drivers/i2c/busses/i2c-altera.c b/drivers/i2c/busses/i2c-altera.c index 50e7f3f670b6..2da73173ce24 100644 --- a/drivers/i2c/busses/i2c-altera.c +++ b/drivers/i2c/busses/i2c-altera.c @@ -168,7 +168,7 @@ static void altr_i2c_init(struct altr_i2c_dev *idev) /* SDA Hold Time, 300ns */ writel(3 * clk_mhz / 10, idev->base + ALTR_I2C_SDA_HOLD); - /* Mask all master interrupt bits */ + /* Mask all interrupt bits */ altr_i2c_int_enable(idev, ALTR_I2C_ALL_IRQ, false); } @@ -376,7 +376,7 @@ static u32 altr_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm altr_i2c_algo = { - .master_xfer = altr_i2c_xfer, + .xfer = altr_i2c_xfer, .functionality = altr_i2c_func, }; @@ -465,14 +465,12 @@ static int altr_i2c_probe(struct platform_device *pdev) return 0; } -static int altr_i2c_remove(struct platform_device *pdev) +static void altr_i2c_remove(struct platform_device *pdev) { struct altr_i2c_dev *idev = platform_get_drvdata(pdev); clk_disable_unprepare(idev->i2c_clk); i2c_del_adapter(&idev->adapter); - - return 0; } /* Match table for of_platform binding */ diff --git a/drivers/i2c/busses/i2c-amd-asf-plat.c b/drivers/i2c/busses/i2c-amd-asf-plat.c new file mode 100644 index 000000000000..ca45f0f23321 --- /dev/null +++ b/drivers/i2c/busses/i2c-amd-asf-plat.c @@ -0,0 +1,370 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD Alert Standard Format Platform Driver + * + * Copyright (c) 2024, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> + * Sanket Goswami <Sanket.Goswami@amd.com> + */ + +#include <linux/bitops.h> +#include <linux/device.h> +#include <linux/devm-helpers.h> +#include <linux/errno.h> +#include <linux/gfp_types.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/sprintf.h> + +#include "i2c-piix4.h" + +/* ASF register bits */ +#define ASF_SLV_LISTN 0 +#define ASF_SLV_INTR 1 +#define ASF_SLV_RST 4 +#define ASF_PEC_SP 5 +#define ASF_DATA_EN 7 +#define ASF_MSTR_EN 16 +#define ASF_CLK_EN 17 + +/* ASF address offsets */ +#define ASFINDEX (0x07 + piix4_smba) +#define ASFLISADDR (0x09 + piix4_smba) +#define ASFSTA (0x0A + piix4_smba) +#define ASFSLVSTA (0x0D + piix4_smba) +#define ASFDATARWPTR (0x11 + piix4_smba) +#define ASFSETDATARDPTR (0x12 + piix4_smba) +#define ASFDATABNKSEL (0x13 + piix4_smba) +#define ASFSLVEN (0x15 + piix4_smba) + +#define ASF_BLOCK_MAX_BYTES 72 +#define ASF_ERROR_STATUS GENMASK(3, 1) + +struct amd_asf_dev { + struct i2c_adapter adap; + void __iomem *eoi_base; + struct i2c_client *target; + struct delayed_work work_buf; + struct sb800_mmio_cfg mmio_cfg; + struct resource *port_addr; +}; + +static void amd_asf_process_target(struct work_struct *work) +{ + struct amd_asf_dev *dev = container_of(work, struct amd_asf_dev, work_buf.work); + unsigned short piix4_smba = dev->port_addr->start; + u8 data[ASF_BLOCK_MAX_BYTES]; + u8 bank, reg, cmd; + u8 len = 0, idx, val; + + /* Read target status register */ + reg = inb_p(ASFSLVSTA); + + /* Check if no error bits are set in target status register */ + if (reg & ASF_ERROR_STATUS) { + /* Set bank as full */ + cmd = 1; + reg |= GENMASK(3, 2); + outb_p(reg, ASFDATABNKSEL); + } else { + /* Read data bank */ + reg = inb_p(ASFDATABNKSEL); + bank = (reg & BIT(3)) ? 1 : 0; + + /* Set read data bank */ + if (bank) { + reg |= BIT(4); + reg &= ~BIT(3); + } else { + reg &= ~BIT(4); + reg &= ~BIT(2); + } + + /* Read command register */ + outb_p(reg, ASFDATABNKSEL); + cmd = inb_p(ASFINDEX); + len = inb_p(ASFDATARWPTR); + for (idx = 0; idx < len; idx++) + data[idx] = inb_p(ASFINDEX); + + /* Clear data bank status */ + if (bank) { + reg |= BIT(3); + outb_p(reg, ASFDATABNKSEL); + } else { + reg |= BIT(2); + outb_p(reg, ASFDATABNKSEL); + } + } + + outb_p(0, ASFSETDATARDPTR); + if (cmd & BIT(0)) + return; + + /* + * Although i2c_slave_event() returns an appropriate error code, we + * don't check it here because we're operating in the workqueue context. + */ + i2c_slave_event(dev->target, I2C_SLAVE_WRITE_REQUESTED, &val); + for (idx = 0; idx < len; idx++) { + val = data[idx]; + i2c_slave_event(dev->target, I2C_SLAVE_WRITE_RECEIVED, &val); + } + i2c_slave_event(dev->target, I2C_SLAVE_STOP, &val); +} + +static void amd_asf_update_ioport_target(unsigned short piix4_smba, u8 bit, + unsigned long offset, bool set) +{ + unsigned long reg; + + reg = inb_p(offset); + __assign_bit(bit, ®, set); + outb_p(reg, offset); +} + +static void amd_asf_update_mmio_target(struct amd_asf_dev *dev, u8 bit, bool set) +{ + unsigned long reg; + + reg = ioread32(dev->mmio_cfg.addr); + __assign_bit(bit, ®, set); + iowrite32(reg, dev->mmio_cfg.addr); +} + +static void amd_asf_setup_target(struct amd_asf_dev *dev) +{ + unsigned short piix4_smba = dev->port_addr->start; + + /* Reset both host and target before setting up */ + outb_p(0, SMBHSTSTS); + outb_p(0, ASFSLVSTA); + outb_p(0, ASFSTA); + + /* Update target address */ + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_LISTN, ASFLISADDR, true); + /* Enable target and set the clock */ + amd_asf_update_mmio_target(dev, ASF_MSTR_EN, false); + amd_asf_update_mmio_target(dev, ASF_CLK_EN, true); + /* Enable target interrupt */ + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, ASFSLVEN, true); + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, false); + /* Enable PEC and PEC append */ + amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, SMBHSTCNT, true); + amd_asf_update_ioport_target(piix4_smba, ASF_PEC_SP, SMBHSTCNT, true); +} + +static int amd_asf_access(struct i2c_adapter *adap, u16 addr, u8 command, u8 *data) +{ + struct amd_asf_dev *dev = i2c_get_adapdata(adap); + unsigned short piix4_smba = dev->port_addr->start; + u8 i, len; + + outb_p((addr << 1), SMBHSTADD); + outb_p(command, SMBHSTCMD); + len = data[0]; + if (len == 0 || len > ASF_BLOCK_MAX_BYTES) + return -EINVAL; + + outb_p(len, SMBHSTDAT0); + /* Reset SMBBLKDAT */ + inb_p(SMBHSTCNT); + for (i = 1; i <= len; i++) + outb_p(data[i], SMBBLKDAT); + + outb_p(PIIX4_BLOCK_DATA, SMBHSTCNT); + /* Enable PEC and PEC append */ + amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, SMBHSTCNT, true); + amd_asf_update_ioport_target(piix4_smba, ASF_PEC_SP, SMBHSTCNT, true); + + return piix4_transaction(adap, piix4_smba); +} + +static int amd_asf_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct amd_asf_dev *dev = i2c_get_adapdata(adap); + unsigned short piix4_smba = dev->port_addr->start; + u8 asf_data[ASF_BLOCK_MAX_BYTES]; + struct i2c_msg *dev_msgs = msgs; + u8 prev_port; + int ret; + + if (msgs->flags & I2C_M_RD) { + dev_err(&adap->dev, "ASF: Read not supported\n"); + return -EOPNOTSUPP; + } + + /* Exclude the receive header and PEC */ + if (msgs->len > ASF_BLOCK_MAX_BYTES - 3) { + dev_warn(&adap->dev, "ASF: max message length exceeded\n"); + return -EOPNOTSUPP; + } + + asf_data[0] = dev_msgs->len; + memcpy(asf_data + 1, dev_msgs[0].buf, dev_msgs->len); + + ret = piix4_sb800_region_request(&adap->dev, &dev->mmio_cfg); + if (ret) + return ret; + + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, true); + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_LISTN, ASFLISADDR, false); + /* Clear ASF target status */ + outb_p(0, ASFSLVSTA); + + /* Enable ASF SMBus controller function */ + amd_asf_update_mmio_target(dev, ASF_MSTR_EN, true); + prev_port = piix4_sb800_port_sel(0, &dev->mmio_cfg); + ret = amd_asf_access(adap, msgs->addr, msgs[0].buf[0], asf_data); + piix4_sb800_port_sel(prev_port, &dev->mmio_cfg); + amd_asf_setup_target(dev); + piix4_sb800_region_release(&adap->dev, &dev->mmio_cfg); + return ret; +} + +static int amd_asf_reg_target(struct i2c_client *target) +{ + struct amd_asf_dev *dev = i2c_get_adapdata(target->adapter); + unsigned short piix4_smba = dev->port_addr->start; + int ret; + u8 reg; + + if (dev->target) + return -EBUSY; + + ret = piix4_sb800_region_request(&target->dev, &dev->mmio_cfg); + if (ret) + return ret; + + reg = (target->addr << 1) | I2C_M_RD; + outb_p(reg, ASFLISADDR); + + amd_asf_setup_target(dev); + dev->target = target; + amd_asf_update_ioport_target(piix4_smba, ASF_DATA_EN, ASFDATABNKSEL, false); + piix4_sb800_region_release(&target->dev, &dev->mmio_cfg); + + return 0; +} + +static int amd_asf_unreg_target(struct i2c_client *target) +{ + struct amd_asf_dev *dev = i2c_get_adapdata(target->adapter); + unsigned short piix4_smba = dev->port_addr->start; + + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, ASFSLVEN, false); + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_RST, ASFSLVEN, true); + dev->target = NULL; + + return 0; +} + +static u32 amd_asf_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_SMBUS_WRITE_BLOCK_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | + I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_PEC | I2C_FUNC_SLAVE; +} + +static const struct i2c_algorithm amd_asf_smbus_algorithm = { + .xfer = amd_asf_xfer, + .reg_target = amd_asf_reg_target, + .unreg_target = amd_asf_unreg_target, + .functionality = amd_asf_func, +}; + +static irqreturn_t amd_asf_irq_handler(int irq, void *ptr) +{ + struct amd_asf_dev *dev = ptr; + unsigned short piix4_smba = dev->port_addr->start; + u8 target_int = inb_p(ASFSTA); + + if (target_int & BIT(6)) { + /* Target Interrupt */ + outb_p(target_int | BIT(6), ASFSTA); + schedule_delayed_work(&dev->work_buf, HZ); + } else { + /* Controller Interrupt */ + amd_asf_update_ioport_target(piix4_smba, ASF_SLV_INTR, SMBHSTSTS, true); + } + + iowrite32(irq, dev->eoi_base); + return IRQ_HANDLED; +} + +static int amd_asf_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct amd_asf_dev *asf_dev; + struct resource *eoi_addr; + int ret, irq; + + asf_dev = devm_kzalloc(dev, sizeof(*asf_dev), GFP_KERNEL); + if (!asf_dev) + return dev_err_probe(dev, -ENOMEM, "Failed to allocate memory\n"); + + asf_dev->mmio_cfg.use_mmio = true; + asf_dev->port_addr = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!asf_dev->port_addr) + return dev_err_probe(dev, -EINVAL, "missing IO resources\n"); + + /* + * The resource obtained via ACPI might not belong to the ASF device address space. Instead, + * it could be within other IP blocks of the ASIC, which are crucial for generating + * subsequent interrupts. Therefore, we avoid using devm_platform_ioremap_resource() and + * use platform_get_resource() and devm_ioremap() separately to prevent any address space + * conflicts. + */ + eoi_addr = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!eoi_addr) + return dev_err_probe(dev, -EINVAL, "missing MEM resources\n"); + + asf_dev->eoi_base = devm_ioremap(dev, eoi_addr->start, resource_size(eoi_addr)); + if (!asf_dev->eoi_base) + return dev_err_probe(dev, -EBUSY, "failed mapping IO region\n"); + + ret = devm_delayed_work_autocancel(dev, &asf_dev->work_buf, amd_asf_process_target); + if (ret) + return dev_err_probe(dev, ret, "failed to create work queue\n"); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return dev_err_probe(dev, irq, "missing IRQ resources\n"); + + ret = devm_request_irq(dev, irq, amd_asf_irq_handler, IRQF_SHARED, "amd_asf", asf_dev); + if (ret) + return dev_err_probe(dev, ret, "Unable to request irq: %d for use\n", irq); + + asf_dev->adap.owner = THIS_MODULE; + asf_dev->adap.algo = &amd_asf_smbus_algorithm; + asf_dev->adap.dev.parent = dev; + + i2c_set_adapdata(&asf_dev->adap, asf_dev); + snprintf(asf_dev->adap.name, sizeof(asf_dev->adap.name), "AMD ASF adapter"); + + return devm_i2c_add_adapter(dev, &asf_dev->adap); +} + +static const struct acpi_device_id amd_asf_acpi_ids[] = { + { "AMDI001A" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, amd_asf_acpi_ids); + +static struct platform_driver amd_asf_driver = { + .driver = { + .name = "i2c-amd-asf", + .acpi_match_table = amd_asf_acpi_ids, + }, + .probe = amd_asf_probe, +}; +module_platform_driver(amd_asf_driver); + +MODULE_IMPORT_NS("PIIX4_SMBUS"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("AMD Alert Standard Format Driver"); diff --git a/drivers/i2c/busses/i2c-amd-mp2-pci.c b/drivers/i2c/busses/i2c-amd-mp2-pci.c index 143165300949..60edbabc2986 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-pci.c +++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c @@ -327,13 +327,11 @@ static int amd_mp2_pci_init(struct amd_mp2_dev *privdata, amd_mp2_irq_isr, irq_flag, dev_name(&pci_dev->dev), privdata); if (rc) { pci_err(pci_dev, "Failure requesting irq %i: %d\n", privdata->dev_irq, rc); - goto free_irq_vectors; + goto err_dma_mask; } return rc; -free_irq_vectors: - free_irq(privdata->dev_irq, privdata); err_dma_mask: pci_clear_master(pci_dev); err_pci_enable: @@ -376,7 +374,6 @@ static void amd_mp2_pci_remove(struct pci_dev *pci_dev) pm_runtime_forbid(&pci_dev->dev); pm_runtime_get_noresume(&pci_dev->dev); - free_irq(privdata->dev_irq, privdata); pci_clear_master(pci_dev); amd_mp2_clear_reg(privdata); @@ -461,13 +458,16 @@ struct amd_mp2_dev *amd_mp2_find_device(void) { struct device *dev; struct pci_dev *pci_dev; + struct amd_mp2_dev *mp2_dev; dev = driver_find_next_device(&amd_mp2_pci_driver.driver, NULL); if (!dev) return NULL; pci_dev = to_pci_dev(dev); - return (struct amd_mp2_dev *)pci_get_drvdata(pci_dev); + mp2_dev = (struct amd_mp2_dev *)pci_get_drvdata(pci_dev); + put_device(dev); + return mp2_dev; } EXPORT_SYMBOL_GPL(amd_mp2_find_device); diff --git a/drivers/i2c/busses/i2c-amd-mp2-plat.c b/drivers/i2c/busses/i2c-amd-mp2-plat.c index 423fe0c8a471..188e24cc4d35 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-plat.c +++ b/drivers/i2c/busses/i2c-amd-mp2-plat.c @@ -97,17 +97,17 @@ static void i2c_amd_cmd_completion(struct amd_i2c_common *i2c_common) static int i2c_amd_check_cmd_completion(struct amd_i2c_dev *i2c_dev) { struct amd_i2c_common *i2c_common = &i2c_dev->common; - unsigned long timeout; + unsigned long time_left; - timeout = wait_for_completion_timeout(&i2c_dev->cmd_complete, - i2c_dev->adap.timeout); + time_left = wait_for_completion_timeout(&i2c_dev->cmd_complete, + i2c_dev->adap.timeout); if ((i2c_common->reqcmd == i2c_read || i2c_common->reqcmd == i2c_write) && i2c_common->msg->len > 32) i2c_amd_dma_unmap(i2c_common); - if (timeout == 0) { + if (time_left == 0) { amd_mp2_rw_timeout(i2c_common); return -ETIMEDOUT; } @@ -179,7 +179,7 @@ static u32 i2c_amd_func(struct i2c_adapter *a) } static const struct i2c_algorithm i2c_amd_algorithm = { - .master_xfer = i2c_amd_xfer, + .xfer = i2c_amd_xfer, .functionality = i2c_amd_func, }; @@ -322,7 +322,7 @@ static int i2c_amd_probe(struct platform_device *pdev) return ret; } -static int i2c_amd_remove(struct platform_device *pdev) +static void i2c_amd_remove(struct platform_device *pdev) { struct amd_i2c_dev *i2c_dev = platform_get_drvdata(pdev); struct amd_i2c_common *i2c_common = &i2c_dev->common; @@ -336,12 +336,11 @@ static int i2c_amd_remove(struct platform_device *pdev) i2c_unlock_bus(&i2c_dev->adap, I2C_LOCK_ROOT_ADAPTER); i2c_del_adapter(&i2c_dev->adap); - return 0; } static const struct acpi_device_id i2c_amd_acpi_match[] = { { "AMDI0011" }, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, i2c_amd_acpi_match); diff --git a/drivers/i2c/busses/i2c-amd-mp2.h b/drivers/i2c/busses/i2c-amd-mp2.h index 018a42de8b1e..9b7e9494dd12 100644 --- a/drivers/i2c/busses/i2c-amd-mp2.h +++ b/drivers/i2c/busses/i2c-amd-mp2.h @@ -207,7 +207,6 @@ static inline void amd_mp2_pm_runtime_get(struct amd_mp2_dev *mp2_dev) static inline void amd_mp2_pm_runtime_put(struct amd_mp2_dev *mp2_dev) { - pm_runtime_mark_last_busy(&mp2_dev->pci_dev->dev); pm_runtime_put_autosuspend(&mp2_dev->pci_dev->dev); } diff --git a/drivers/i2c/busses/i2c-amd756-s4882.c b/drivers/i2c/busses/i2c-amd756-s4882.c deleted file mode 100644 index 063274388a75..000000000000 --- a/drivers/i2c/busses/i2c-amd756-s4882.c +++ /dev/null @@ -1,245 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard - * - * Copyright (C) 2004, 2008 Jean Delvare <jdelvare@suse.de> - */ - -/* - * We select the channels by sending commands to the Philips - * PCA9556 chip at I2C address 0x18. The main adapter is used for - * the non-multiplexed part of the bus, and 4 virtual adapters - * are defined for the multiplexed addresses: 0x50-0x53 (memory - * module EEPROM) located on channels 1-4, and 0x4c (LM63) - * located on multiplexed channels 0 and 5-7. We define one - * virtual adapter per CPU, which corresponds to two multiplexed - * channels: - * CPU0: virtual adapter 1, channels 1 and 0 - * CPU1: virtual adapter 2, channels 2 and 5 - * CPU2: virtual adapter 3, channels 3 and 6 - * CPU3: virtual adapter 4, channels 4 and 7 - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/i2c.h> -#include <linux/mutex.h> - -extern struct i2c_adapter amd756_smbus; - -static struct i2c_adapter *s4882_adapter; -static struct i2c_algorithm *s4882_algo; - -/* Wrapper access functions for multiplexed SMBus */ -static DEFINE_MUTEX(amd756_lock); - -static s32 amd756_access_virt0(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - int error; - - /* We exclude the multiplexed addresses */ - if (addr == 0x4c || (addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30 - || addr == 0x18) - return -ENXIO; - - mutex_lock(&amd756_lock); - - error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write, - command, size, data); - - mutex_unlock(&amd756_lock); - - return error; -} - -/* We remember the last used channels combination so as to only switch - channels when it is really needed. This greatly reduces the SMBus - overhead, but also assumes that nobody will be writing to the PCA9556 - in our back. */ -static u8 last_channels; - -static inline s32 amd756_access_channel(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data, - u8 channels) -{ - int error; - - /* We exclude the non-multiplexed addresses */ - if (addr != 0x4c && (addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30) - return -ENXIO; - - mutex_lock(&amd756_lock); - - if (last_channels != channels) { - union i2c_smbus_data mplxdata; - mplxdata.byte = channels; - - error = amd756_smbus.algo->smbus_xfer(adap, 0x18, 0, - I2C_SMBUS_WRITE, 0x01, - I2C_SMBUS_BYTE_DATA, - &mplxdata); - if (error) - goto UNLOCK; - last_channels = channels; - } - error = amd756_smbus.algo->smbus_xfer(adap, addr, flags, read_write, - command, size, data); - -UNLOCK: - mutex_unlock(&amd756_lock); - return error; -} - -static s32 amd756_access_virt1(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU0: channels 1 and 0 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x03); -} - -static s32 amd756_access_virt2(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU1: channels 2 and 5 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x24); -} - -static s32 amd756_access_virt3(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU2: channels 3 and 6 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x48); -} - -static s32 amd756_access_virt4(struct i2c_adapter * adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data * data) -{ - /* CPU3: channels 4 and 7 enabled */ - return amd756_access_channel(adap, addr, flags, read_write, command, - size, data, 0x90); -} - -static int __init amd756_s4882_init(void) -{ - int i, error; - union i2c_smbus_data ioconfig; - - if (!amd756_smbus.dev.parent) - return -ENODEV; - - /* Configure the PCA9556 multiplexer */ - ioconfig.byte = 0x00; /* All I/O to output mode */ - error = i2c_smbus_xfer(&amd756_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03, - I2C_SMBUS_BYTE_DATA, &ioconfig); - if (error) { - dev_err(&amd756_smbus.dev, "PCA9556 configuration failed\n"); - error = -EIO; - goto ERROR0; - } - - /* Unregister physical bus */ - i2c_del_adapter(&amd756_smbus); - - printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4882\n"); - /* Define the 5 virtual adapters and algorithms structures */ - if (!(s4882_adapter = kcalloc(5, sizeof(struct i2c_adapter), - GFP_KERNEL))) { - error = -ENOMEM; - goto ERROR1; - } - if (!(s4882_algo = kcalloc(5, sizeof(struct i2c_algorithm), - GFP_KERNEL))) { - error = -ENOMEM; - goto ERROR2; - } - - /* Fill in the new structures */ - s4882_algo[0] = *(amd756_smbus.algo); - s4882_algo[0].smbus_xfer = amd756_access_virt0; - s4882_adapter[0] = amd756_smbus; - s4882_adapter[0].algo = s4882_algo; - s4882_adapter[0].dev.parent = amd756_smbus.dev.parent; - for (i = 1; i < 5; i++) { - s4882_algo[i] = *(amd756_smbus.algo); - s4882_adapter[i] = amd756_smbus; - snprintf(s4882_adapter[i].name, sizeof(s4882_adapter[i].name), - "SMBus 8111 adapter (CPU%d)", i-1); - s4882_adapter[i].algo = s4882_algo+i; - s4882_adapter[i].dev.parent = amd756_smbus.dev.parent; - } - s4882_algo[1].smbus_xfer = amd756_access_virt1; - s4882_algo[2].smbus_xfer = amd756_access_virt2; - s4882_algo[3].smbus_xfer = amd756_access_virt3; - s4882_algo[4].smbus_xfer = amd756_access_virt4; - - /* Register virtual adapters */ - for (i = 0; i < 5; i++) { - error = i2c_add_adapter(s4882_adapter+i); - if (error) { - printk(KERN_ERR "i2c-amd756-s4882: " - "Virtual adapter %d registration " - "failed, module not inserted\n", i); - for (i--; i >= 0; i--) - i2c_del_adapter(s4882_adapter+i); - goto ERROR3; - } - } - - return 0; - -ERROR3: - kfree(s4882_algo); - s4882_algo = NULL; -ERROR2: - kfree(s4882_adapter); - s4882_adapter = NULL; -ERROR1: - /* Restore physical bus */ - i2c_add_adapter(&amd756_smbus); -ERROR0: - return error; -} - -static void __exit amd756_s4882_exit(void) -{ - if (s4882_adapter) { - int i; - - for (i = 0; i < 5; i++) - i2c_del_adapter(s4882_adapter+i); - kfree(s4882_adapter); - s4882_adapter = NULL; - } - kfree(s4882_algo); - s4882_algo = NULL; - - /* Restore physical bus */ - if (i2c_add_adapter(&amd756_smbus)) - printk(KERN_ERR "i2c-amd756-s4882: " - "Physical bus restoration failed\n"); -} - -MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); -MODULE_DESCRIPTION("S4882 SMBus multiplexing"); -MODULE_LICENSE("GPL"); - -module_init(amd756_s4882_init); -module_exit(amd756_s4882_exit); diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index ef1307a258e9..3621c02f1cba 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -211,7 +211,7 @@ static s32 amd756_access(struct i2c_adapter * adap, u16 addr, SMB_HOST_ADDRESS); outb_p(command, SMB_HOST_COMMAND); if (read_write == I2C_SMBUS_WRITE) - outw_p(data->word, SMB_HOST_DATA); /* TODO: endian???? */ + outw_p(data->word, SMB_HOST_DATA); size = AMD756_WORD_DATA; break; case I2C_SMBUS_BLOCK_DATA: @@ -256,7 +256,7 @@ static s32 amd756_access(struct i2c_adapter * adap, u16 addr, data->byte = inw_p(SMB_HOST_DATA); break; case AMD756_WORD_DATA: - data->word = inw_p(SMB_HOST_DATA); /* TODO: endian???? */ + data->word = inw_p(SMB_HOST_DATA); break; case AMD756_BLOCK_DATA: data->block[0] = inw_p(SMB_HOST_DATA) & 0x3f; @@ -283,9 +283,9 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = amd756_func, }; -struct i2c_adapter amd756_smbus = { +static struct i2c_adapter amd756_smbus = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; @@ -398,5 +398,3 @@ module_pci_driver(amd756_driver); MODULE_AUTHOR("Merlin Hughes <merlin@merlin.org>"); MODULE_DESCRIPTION("AMD756/766/768/8111 and nVidia nForce SMBus driver"); MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(amd756_smbus); diff --git a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c index 1ed7e945bb6d..42a9b1221065 100644 --- a/drivers/i2c/busses/i2c-amd8111.c +++ b/drivers/i2c/busses/i2c-amd8111.c @@ -449,7 +449,7 @@ static int amd8111_probe(struct pci_dev *dev, const struct pci_device_id *id) smbus->adapter.owner = THIS_MODULE; snprintf(smbus->adapter.name, sizeof(smbus->adapter.name), "SMBus2 AMD8111 adapter at %04x", smbus->base); - smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + smbus->adapter.class = I2C_CLASS_HWMON; smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; diff --git a/drivers/i2c/busses/i2c-aspeed.c b/drivers/i2c/busses/i2c-aspeed.c index c64c381b69b7..a26b74c71206 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -170,6 +170,13 @@ struct aspeed_i2c_bus { static int aspeed_i2c_reset(struct aspeed_i2c_bus *bus); +/* precondition: bus.lock has been acquired. */ +static void aspeed_i2c_do_stop(struct aspeed_i2c_bus *bus) +{ + bus->master_state = ASPEED_I2C_MASTER_STOP; + writel(ASPEED_I2CD_M_STOP_CMD, bus->base + ASPEED_I2C_CMD_REG); +} + static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus) { unsigned long time_left, flags; @@ -187,7 +194,7 @@ static int aspeed_i2c_recover_bus(struct aspeed_i2c_bus *bus) command); reinit_completion(&bus->cmd_complete); - writel(ASPEED_I2CD_M_STOP_CMD, bus->base + ASPEED_I2C_CMD_REG); + aspeed_i2c_do_stop(bus); spin_unlock_irqrestore(&bus->lock, flags); time_left = wait_for_completion_timeout( @@ -249,18 +256,46 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) if (!slave) return 0; - command = readl(bus->base + ASPEED_I2C_CMD_REG); + /* + * Handle stop conditions early, prior to SLAVE_MATCH. Some masters may drive + * transfers with low enough latency between the nak/stop phase of the current + * command and the start/address phase of the following command that the + * interrupts are coalesced by the time we process them. + */ + if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) { + irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP; + bus->slave_state = ASPEED_I2C_SLAVE_STOP; + } + + if (irq_status & ASPEED_I2CD_INTR_TX_NAK && + bus->slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED) { + irq_handled |= ASPEED_I2CD_INTR_TX_NAK; + bus->slave_state = ASPEED_I2C_SLAVE_STOP; + } - /* Slave was requested, restart state machine. */ + /* Propagate any stop conditions to the slave implementation. */ + if (bus->slave_state == ASPEED_I2C_SLAVE_STOP) { + i2c_slave_event(slave, I2C_SLAVE_STOP, &value); + bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE; + } + + /* + * Now that we've dealt with any potentially coalesced stop conditions, + * address any start conditions. + */ if (irq_status & ASPEED_I2CD_INTR_SLAVE_MATCH) { irq_handled |= ASPEED_I2CD_INTR_SLAVE_MATCH; bus->slave_state = ASPEED_I2C_SLAVE_START; } - /* Slave is not currently active, irq was for someone else. */ + /* + * If the slave has been stopped and not started then slave interrupt + * handling is complete. + */ if (bus->slave_state == ASPEED_I2C_SLAVE_INACTIVE) return irq_handled; + command = readl(bus->base + ASPEED_I2C_CMD_REG); dev_dbg(bus->dev, "slave irq status 0x%08x, cmd 0x%08x\n", irq_status, command); @@ -279,17 +314,6 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) irq_handled |= ASPEED_I2CD_INTR_RX_DONE; } - /* Slave was asked to stop. */ - if (irq_status & ASPEED_I2CD_INTR_NORMAL_STOP) { - irq_handled |= ASPEED_I2CD_INTR_NORMAL_STOP; - bus->slave_state = ASPEED_I2C_SLAVE_STOP; - } - if (irq_status & ASPEED_I2CD_INTR_TX_NAK && - bus->slave_state == ASPEED_I2C_SLAVE_READ_PROCESSED) { - irq_handled |= ASPEED_I2CD_INTR_TX_NAK; - bus->slave_state = ASPEED_I2C_SLAVE_STOP; - } - switch (bus->slave_state) { case ASPEED_I2C_SLAVE_READ_REQUESTED: if (unlikely(irq_status & ASPEED_I2CD_INTR_TX_ACK)) @@ -324,8 +348,7 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value); break; case ASPEED_I2C_SLAVE_STOP: - i2c_slave_event(slave, I2C_SLAVE_STOP, &value); - bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE; + /* Stop event handling is done early. Unreachable. */ break; case ASPEED_I2C_SLAVE_START: /* Slave was just started. Waiting for the next event. */; @@ -375,13 +398,6 @@ static void aspeed_i2c_do_start(struct aspeed_i2c_bus *bus) } /* precondition: bus.lock has been acquired. */ -static void aspeed_i2c_do_stop(struct aspeed_i2c_bus *bus) -{ - bus->master_state = ASPEED_I2C_MASTER_STOP; - writel(ASPEED_I2CD_M_STOP_CMD, bus->base + ASPEED_I2C_CMD_REG); -} - -/* precondition: bus.lock has been acquired. */ static void aspeed_i2c_next_msg_or_stop(struct aspeed_i2c_bus *bus) { if (bus->msgs_index + 1 < bus->msgs_count) { @@ -429,6 +445,7 @@ static u32 aspeed_i2c_master_irq(struct aspeed_i2c_bus *bus, u32 irq_status) irq_status); irq_handled |= (irq_status & ASPEED_I2CD_INTR_MASTER_ERRORS); if (bus->master_state != ASPEED_I2C_MASTER_INACTIVE) { + irq_handled = irq_status; bus->cmd_err = ret; bus->master_state = ASPEED_I2C_MASTER_INACTIVE; goto out_complete; @@ -698,13 +715,16 @@ static int aspeed_i2c_master_xfer(struct i2c_adapter *adap, if (time_left == 0) { /* - * If timed out and bus is still busy in a multi master - * environment, attempt recovery at here. + * In a multi-master setup, if a timeout occurs, attempt + * recovery. But if the bus is idle, we still need to reset the + * i2c controller to clear the remaining interrupts. */ if (bus->multi_master && (readl(bus->base + ASPEED_I2C_CMD_REG) & ASPEED_I2CD_BUS_BUSY_STS)) aspeed_i2c_recover_bus(bus); + else + aspeed_i2c_reset(bus); /* * If timed out and the state is still pending, drop the pending @@ -746,6 +766,8 @@ static void __aspeed_i2c_reg_slave(struct aspeed_i2c_bus *bus, u16 slave_addr) func_ctrl_reg_val = readl(bus->base + ASPEED_I2C_FUN_CTRL_REG); func_ctrl_reg_val |= ASPEED_I2CD_SLAVE_EN; writel(func_ctrl_reg_val, bus->base + ASPEED_I2C_FUN_CTRL_REG); + + bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE; } static int aspeed_i2c_reg_slave(struct i2c_client *client) @@ -762,7 +784,6 @@ static int aspeed_i2c_reg_slave(struct i2c_client *client) __aspeed_i2c_reg_slave(bus, client->addr); bus->slave = client; - bus->slave_state = ASPEED_I2C_SLAVE_INACTIVE; spin_unlock_irqrestore(&bus->lock, flags); return 0; @@ -793,11 +814,11 @@ static int aspeed_i2c_unreg_slave(struct i2c_client *client) #endif /* CONFIG_I2C_SLAVE */ static const struct i2c_algorithm aspeed_i2c_algo = { - .master_xfer = aspeed_i2c_master_xfer, - .functionality = aspeed_i2c_functionality, + .xfer = aspeed_i2c_master_xfer, + .functionality = aspeed_i2c_functionality, #if IS_ENABLED(CONFIG_I2C_SLAVE) - .reg_slave = aspeed_i2c_reg_slave, - .unreg_slave = aspeed_i2c_unreg_slave, + .reg_slave = aspeed_i2c_reg_slave, + .unreg_slave = aspeed_i2c_unreg_slave, #endif /* CONFIG_I2C_SLAVE */ }; @@ -970,7 +991,7 @@ static const struct of_device_id aspeed_i2c_bus_of_table[] = { .compatible = "aspeed,ast2600-i2c-bus", .data = aspeed_i2c_25xx_get_clk_reg_val, }, - { }, + { } }; MODULE_DEVICE_TABLE(of, aspeed_i2c_bus_of_table); @@ -979,15 +1000,13 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) const struct of_device_id *match; struct aspeed_i2c_bus *bus; struct clk *parent_clk; - struct resource *res; int irq, ret; bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL); if (!bus) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - bus->base = devm_ioremap_resource(&pdev->dev, res); + bus->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(bus->base)) return PTR_ERR(bus->base); @@ -1063,7 +1082,7 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) return 0; } -static int aspeed_i2c_remove_bus(struct platform_device *pdev) +static void aspeed_i2c_remove_bus(struct platform_device *pdev) { struct aspeed_i2c_bus *bus = platform_get_drvdata(pdev); unsigned long flags; @@ -1079,8 +1098,6 @@ static int aspeed_i2c_remove_bus(struct platform_device *pdev) reset_control_assert(bus->rst); i2c_del_adapter(&bus->adap); - - return 0; } static struct platform_driver aspeed_i2c_bus_driver = { diff --git a/drivers/i2c/busses/i2c-at91-core.c b/drivers/i2c/busses/i2c-at91-core.c index 2df9df585131..b64adef778d4 100644 --- a/drivers/i2c/busses/i2c-at91-core.c +++ b/drivers/i2c/busses/i2c-at91-core.c @@ -19,7 +19,6 @@ #include <linux/io.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/pinctrl/consumer.h> @@ -207,31 +206,25 @@ static int at91_twi_probe(struct platform_device *pdev) dev->dev = &pdev->dev; - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) - return -ENODEV; + dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &mem); + if (IS_ERR(dev->base)) + return PTR_ERR(dev->base); phy_addr = mem->start; dev->pdata = at91_twi_get_driver_data(pdev); if (!dev->pdata) return -ENODEV; - dev->base = devm_ioremap_resource(&pdev->dev, mem); - if (IS_ERR(dev->base)) - return PTR_ERR(dev->base); - dev->irq = platform_get_irq(pdev, 0); if (dev->irq < 0) return dev->irq; platform_set_drvdata(pdev, dev); - dev->clk = devm_clk_get(dev->dev, NULL); - if (IS_ERR(dev->clk)) { - dev_err(dev->dev, "no clock defined\n"); - return -ENODEV; - } - clk_prepare_enable(dev->clk); + dev->clk = devm_clk_get_enabled(dev->dev, NULL); + if (IS_ERR(dev->clk)) + return dev_err_probe(dev->dev, PTR_ERR(dev->clk), + "failed to enable clock\n"); snprintf(dev->adapter.name, sizeof(dev->adapter.name), "AT91"); i2c_set_adapdata(&dev->adapter, dev); @@ -260,8 +253,6 @@ static int at91_twi_probe(struct platform_device *pdev) rc = i2c_add_numbered_adapter(&dev->adapter); if (rc) { - clk_disable_unprepare(dev->clk); - pm_runtime_disable(dev->dev); pm_runtime_set_suspended(dev->dev); @@ -273,17 +264,14 @@ static int at91_twi_probe(struct platform_device *pdev) return 0; } -static int at91_twi_remove(struct platform_device *pdev) +static void at91_twi_remove(struct platform_device *pdev) { struct at91_twi_dev *dev = platform_get_drvdata(pdev); i2c_del_adapter(&dev->adapter); - clk_disable_unprepare(dev->clk); pm_runtime_disable(dev->dev); pm_runtime_set_suspended(dev->dev); - - return 0; } static int __maybe_unused at91_twi_runtime_suspend(struct device *dev) @@ -325,7 +313,6 @@ static int __maybe_unused at91_twi_resume_noirq(struct device *dev) return ret; } - pm_runtime_mark_last_busy(dev); pm_request_autosuspend(dev); at91_init_twi_bus(twi_dev); diff --git a/drivers/i2c/busses/i2c-at91-master.c b/drivers/i2c/busses/i2c-at91-master.c index c0c35785a0dc..894cedbca99f 100644 --- a/drivers/i2c/busses/i2c-at91-master.c +++ b/drivers/i2c/busses/i2c-at91-master.c @@ -23,10 +23,10 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/string_choices.h> #include "i2c-at91.h" @@ -524,7 +524,7 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) */ dev_dbg(dev->dev, "transfer: %s %zu bytes.\n", - (dev->msg->flags & I2C_M_RD) ? "read" : "write", dev->buf_len); + str_read_write(dev->msg->flags & I2C_M_RD), dev->buf_len); reinit_completion(&dev->cmd_complete); dev->transfer_status = 0; @@ -592,7 +592,6 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev) dev->adapter.timeout); if (time_left == 0) { dev->transfer_status |= at91_twi_read(dev, AT91_TWI_SR); - dev_err(dev->dev, "controller timed out\n"); at91_init_twi_bus(dev); ret = -ETIMEDOUT; goto error; @@ -718,7 +717,6 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) ret = (ret < 0) ? ret : num; out: - pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); return ret; @@ -740,8 +738,8 @@ static u32 at91_twi_func(struct i2c_adapter *adapter) } static const struct i2c_algorithm at91_twi_algorithm = { - .master_xfer = at91_twi_xfer, - .functionality = at91_twi_func, + .xfer = at91_twi_xfer, + .functionality = at91_twi_func, }; static int at91_twi_configure_dma(struct at91_twi_dev *dev, u32 phy_addr) @@ -832,7 +830,11 @@ static int at91_init_twi_recovery_gpio(struct platform_device *pdev, struct i2c_bus_recovery_info *rinfo = &dev->rinfo; rinfo->pinctrl = devm_pinctrl_get(&pdev->dev); - if (!rinfo->pinctrl || IS_ERR(rinfo->pinctrl)) { + if (!rinfo->pinctrl) { + dev_info(dev->dev, "pinctrl unavailable, bus recovery not supported\n"); + return 0; + } + if (IS_ERR(rinfo->pinctrl)) { dev_info(dev->dev, "can't get pinctrl, bus recovery not supported\n"); return PTR_ERR(rinfo->pinctrl); } diff --git a/drivers/i2c/busses/i2c-at91-slave.c b/drivers/i2c/busses/i2c-at91-slave.c index d6eeea5166c0..131a67d9d4a6 100644 --- a/drivers/i2c/busses/i2c-at91-slave.c +++ b/drivers/i2c/busses/i2c-at91-slave.c @@ -106,8 +106,7 @@ static int at91_unreg_slave(struct i2c_client *slave) static u32 at91_twi_func(struct i2c_adapter *adapter) { - return I2C_FUNC_SLAVE | I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL - | I2C_FUNC_SMBUS_READ_BLOCK_DATA; + return I2C_FUNC_SLAVE; } static const struct i2c_algorithm at91_twi_algorithm_slave = { diff --git a/drivers/i2c/busses/i2c-au1550.c b/drivers/i2c/busses/i2c-au1550.c index 99bd24d0e6a5..b78b38ddac46 100644 --- a/drivers/i2c/busses/i2c-au1550.c +++ b/drivers/i2c/busses/i2c-au1550.c @@ -81,11 +81,10 @@ static int wait_ack(struct i2c_au1550_data *adap) return 0; } -static int wait_master_done(struct i2c_au1550_data *adap) +static int wait_controller_done(struct i2c_au1550_data *adap) { int i; - /* Wait for Master Done. */ for (i = 0; i < 2 * adap->xfer_timeout; i++) { if ((RD(adap, PSC_SMBEVNT) & PSC_SMBEVNT_MD) != 0) return 0; @@ -120,12 +119,12 @@ do_address(struct i2c_au1550_data *adap, unsigned int addr, int rd, int q) if (q) addr |= PSC_SMBTXRX_STP; - /* Put byte into fifo, start up master. */ + /* Put byte into fifo, start up controller */ WR(adap, PSC_SMBTXRX, addr); WR(adap, PSC_SMBPCR, PSC_SMBPCR_MS); if (wait_ack(adap)) return -EIO; - return (q) ? wait_master_done(adap) : 0; + return (q) ? wait_controller_done(adap) : 0; } static int wait_for_rx_byte(struct i2c_au1550_data *adap, unsigned char *out) @@ -175,7 +174,7 @@ static int i2c_read(struct i2c_au1550_data *adap, unsigned char *buf, /* The last byte has to indicate transfer done. */ WR(adap, PSC_SMBTXRX, PSC_SMBTXRX_STP); - if (wait_master_done(adap)) + if (wait_controller_done(adap)) return -EIO; buf[i] = (unsigned char)(RD(adap, PSC_SMBTXRX) & 0xff); @@ -204,7 +203,7 @@ static int i2c_write(struct i2c_au1550_data *adap, unsigned char *buf, data = buf[i]; data |= PSC_SMBTXRX_STP; WR(adap, PSC_SMBTXRX, data); - if (wait_master_done(adap)) + if (wait_controller_done(adap)) return -EIO; return 0; } @@ -246,8 +245,8 @@ static u32 au1550_func(struct i2c_adapter *adap) } static const struct i2c_algorithm au1550_algo = { - .master_xfer = au1550_xfer, - .functionality = au1550_func, + .xfer = au1550_xfer, + .functionality = au1550_func, }; static void i2c_au1550_setup(struct i2c_au1550_data *priv) @@ -302,7 +301,6 @@ static int i2c_au1550_probe(struct platform_device *pdev) { struct i2c_au1550_data *priv; - struct resource *r; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(struct i2c_au1550_data), @@ -310,8 +308,7 @@ i2c_au1550_probe(struct platform_device *pdev) if (!priv) return -ENOMEM; - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->psc_base = devm_ioremap_resource(&pdev->dev, r); + priv->psc_base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(priv->psc_base)) return PTR_ERR(priv->psc_base); @@ -336,16 +333,14 @@ i2c_au1550_probe(struct platform_device *pdev) return 0; } -static int i2c_au1550_remove(struct platform_device *pdev) +static void i2c_au1550_remove(struct platform_device *pdev) { struct i2c_au1550_data *priv = platform_get_drvdata(pdev); i2c_del_adapter(&priv->adap); i2c_au1550_disable(priv); - return 0; } -#ifdef CONFIG_PM static int i2c_au1550_suspend(struct device *dev) { struct i2c_au1550_data *priv = dev_get_drvdata(dev); @@ -364,21 +359,13 @@ static int i2c_au1550_resume(struct device *dev) return 0; } -static const struct dev_pm_ops i2c_au1550_pmops = { - .suspend = i2c_au1550_suspend, - .resume = i2c_au1550_resume, -}; - -#define AU1XPSC_SMBUS_PMOPS (&i2c_au1550_pmops) - -#else -#define AU1XPSC_SMBUS_PMOPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(i2c_au1550_pmops, + i2c_au1550_suspend, i2c_au1550_resume); static struct platform_driver au1xpsc_smbus_driver = { .driver = { .name = "au1xpsc_smbus", - .pm = AU1XPSC_SMBUS_PMOPS, + .pm = pm_sleep_ptr(&i2c_au1550_pmops), }, .probe = i2c_au1550_probe, .remove = i2c_au1550_remove, diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c index c1c74ce08407..0555eeb6903a 100644 --- a/drivers/i2c/busses/i2c-axxia.c +++ b/drivers/i2c/busses/i2c-axxia.c @@ -131,6 +131,8 @@ * @i2c_clk: clock reference for i2c input clock * @bus_clk_rate: current i2c bus clock rate * @last: a flag indicating is this is last message in transfer + * @slave: associated &i2c_client + * @irq: platform device IRQ number */ struct axxia_i2c_dev { void __iomem *base; @@ -165,7 +167,7 @@ static void i2c_int_enable(struct axxia_i2c_dev *idev, u32 mask) writel(int_en | mask, idev->base + MST_INT_ENABLE); } -/** +/* * ns_to_clk - Convert time (ns) to clock cycles for the given clock frequency. */ static u32 ns_to_clk(u64 ns, u32 clk_mhz) @@ -253,17 +255,12 @@ static int i2c_m_rd(const struct i2c_msg *msg) return (msg->flags & I2C_M_RD) != 0; } -static int i2c_m_ten(const struct i2c_msg *msg) -{ - return (msg->flags & I2C_M_TEN) != 0; -} - static int i2c_m_recv_len(const struct i2c_msg *msg) { return (msg->flags & I2C_M_RECV_LEN) != 0; } -/** +/* * axxia_i2c_empty_rx_fifo - Fetch data from RX FIFO and update SMBus block * transfer length if this is the first byte of such a transfer. */ @@ -295,7 +292,7 @@ static int axxia_i2c_empty_rx_fifo(struct axxia_i2c_dev *idev) return 0; } -/** +/* * axxia_i2c_fill_tx_fifo - Fill TX FIFO from current message buffer. * @return: Number of bytes left to transfer. */ @@ -437,20 +434,10 @@ static void axxia_i2c_set_addr(struct axxia_i2c_dev *idev, struct i2c_msg *msg) { u32 addr_1, addr_2; - if (i2c_m_ten(msg)) { - /* 10-bit address - * addr_1: 5'b11110 | addr[9:8] | (R/nW) - * addr_2: addr[7:0] - */ - addr_1 = 0xF0 | ((msg->addr >> 7) & 0x06); - if (i2c_m_rd(msg)) - addr_1 |= 1; /* Set the R/nW bit of the address */ - addr_2 = msg->addr & 0xFF; + if (msg->flags & I2C_M_TEN) { + addr_1 = i2c_10bit_addr_hi_from_msg(msg); + addr_2 = i2c_10bit_addr_lo_from_msg(msg); } else { - /* 7-bit address - * addr_1: addr[6:0] | (R/nW) - * addr_2: dont care - */ addr_1 = i2c_8bit_addr_from_msg(msg); addr_2 = 0; } @@ -719,7 +706,7 @@ static int axxia_i2c_unreg_slave(struct i2c_client *slave) } static const struct i2c_algorithm axxia_i2c_algo = { - .master_xfer = axxia_i2c_xfer, + .xfer = axxia_i2c_xfer, .functionality = axxia_i2c_func, .reg_slave = axxia_i2c_reg_slave, .unreg_slave = axxia_i2c_unreg_slave, @@ -804,14 +791,12 @@ error_disable_clk: return ret; } -static int axxia_i2c_remove(struct platform_device *pdev) +static void axxia_i2c_remove(struct platform_device *pdev) { struct axxia_i2c_dev *idev = platform_get_drvdata(pdev); clk_disable_unprepare(idev->i2c_clk); i2c_del_adapter(&idev->adapter); - - return 0; } /* Match table for of_platform binding */ diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 85d8a6b04885..e418a4f23f15 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -7,7 +7,7 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -224,22 +224,18 @@ static void slave_rx_tasklet_fn(unsigned long); | BIT(IS_S_TX_UNDERRUN_SHIFT) | BIT(IS_S_RX_FIFO_FULL_SHIFT)\ | BIT(IS_S_RX_THLD_SHIFT)) -static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave); -static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave); -static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c, - bool enable); - static inline u32 iproc_i2c_rd_reg(struct bcm_iproc_i2c_dev *iproc_i2c, u32 offset) { u32 val; + unsigned long flags; if (iproc_i2c->idm_base) { - spin_lock(&iproc_i2c->idm_lock); + spin_lock_irqsave(&iproc_i2c->idm_lock, flags); writel(iproc_i2c->ape_addr_mask, iproc_i2c->idm_base + IDM_CTRL_DIRECT_OFFSET); val = readl(iproc_i2c->base + offset); - spin_unlock(&iproc_i2c->idm_lock); + spin_unlock_irqrestore(&iproc_i2c->idm_lock, flags); } else { val = readl(iproc_i2c->base + offset); } @@ -250,19 +246,21 @@ static inline u32 iproc_i2c_rd_reg(struct bcm_iproc_i2c_dev *iproc_i2c, static inline void iproc_i2c_wr_reg(struct bcm_iproc_i2c_dev *iproc_i2c, u32 offset, u32 val) { + unsigned long flags; + if (iproc_i2c->idm_base) { - spin_lock(&iproc_i2c->idm_lock); + spin_lock_irqsave(&iproc_i2c->idm_lock, flags); writel(iproc_i2c->ape_addr_mask, iproc_i2c->idm_base + IDM_CTRL_DIRECT_OFFSET); writel(val, iproc_i2c->base + offset); - spin_unlock(&iproc_i2c->idm_lock); + spin_unlock_irqrestore(&iproc_i2c->idm_lock, flags); } else { writel(val, iproc_i2c->base + offset); } } -static void bcm_iproc_i2c_slave_init( - struct bcm_iproc_i2c_dev *iproc_i2c, bool need_reset) +static void bcm_iproc_i2c_slave_init(struct bcm_iproc_i2c_dev *iproc_i2c, + bool need_reset) { u32 val; @@ -273,8 +271,8 @@ static void bcm_iproc_i2c_slave_init( val |= BIT(CFG_RESET_SHIFT); iproc_i2c_wr_reg(iproc_i2c, CFG_OFFSET, val); - /* wait 100 usec per spec */ - udelay(100); + /* wait approximately 100 usec as per spec */ + usleep_range(100, 200); /* bring controller out of reset */ val &= ~(BIT(CFG_RESET_SHIFT)); @@ -313,26 +311,57 @@ static void bcm_iproc_i2c_slave_init( iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); } -static void bcm_iproc_i2c_check_slave_status( - struct bcm_iproc_i2c_dev *iproc_i2c) +static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c, + bool enable) { u32 val; - val = iproc_i2c_rd_reg(iproc_i2c, S_CMD_OFFSET); - /* status is valid only when START_BUSY is cleared after it was set */ - if (val & BIT(S_CMD_START_BUSY_SHIFT)) - return; + val = iproc_i2c_rd_reg(iproc_i2c, CFG_OFFSET); + if (enable) + val |= BIT(CFG_EN_SHIFT); + else + val &= ~BIT(CFG_EN_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, CFG_OFFSET, val); +} + +static bool bcm_iproc_i2c_check_slave_status + (struct bcm_iproc_i2c_dev *iproc_i2c, u32 status) +{ + u32 val; + bool recover = false; - val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK; - if (val == S_CMD_STATUS_TIMEOUT || val == S_CMD_STATUS_MASTER_ABORT) { - dev_err(iproc_i2c->device, (val == S_CMD_STATUS_TIMEOUT) ? - "slave random stretch time timeout\n" : - "Master aborted read transaction\n"); + /* check slave transmit status only if slave is transmitting */ + if (!iproc_i2c->slave_rx_only) { + val = iproc_i2c_rd_reg(iproc_i2c, S_CMD_OFFSET); + /* status is valid only when START_BUSY is cleared */ + if (!(val & BIT(S_CMD_START_BUSY_SHIFT))) { + val = (val >> S_CMD_STATUS_SHIFT) & S_CMD_STATUS_MASK; + if (val == S_CMD_STATUS_TIMEOUT || + val == S_CMD_STATUS_MASTER_ABORT) { + dev_warn(iproc_i2c->device, + (val == S_CMD_STATUS_TIMEOUT) ? + "slave random stretch time timeout\n" : + "Master aborted read transaction\n"); + recover = true; + } + } + } + + /* RX_EVENT is not valid when START_BUSY is set */ + if ((status & BIT(IS_S_RX_EVENT_SHIFT)) && + (status & BIT(IS_S_START_BUSY_SHIFT))) { + dev_warn(iproc_i2c->device, "Slave aborted read transaction\n"); + recover = true; + } + + if (recover) { /* re-initialize i2c for recovery */ bcm_iproc_i2c_enable_disable(iproc_i2c, false); bcm_iproc_i2c_slave_init(iproc_i2c, true); bcm_iproc_i2c_enable_disable(iproc_i2c, true); } + + return recover; } static void bcm_iproc_i2c_slave_read(struct bcm_iproc_i2c_dev *iproc_i2c) @@ -417,49 +446,6 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, u32 val; u8 value; - /* - * Slave events in case of master-write, master-write-read and, - * master-read - * - * Master-write : only IS_S_RX_EVENT_SHIFT event - * Master-write-read: both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT - * events - * Master-read : both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT - * events or only IS_S_RD_EVENT_SHIFT - * - * iproc has a slave rx fifo size of 64 bytes. Rx fifo full interrupt - * (IS_S_RX_FIFO_FULL_SHIFT) will be generated when RX fifo becomes - * full. This can happen if Master issues write requests of more than - * 64 bytes. - */ - if (status & BIT(IS_S_RX_EVENT_SHIFT) || - status & BIT(IS_S_RD_EVENT_SHIFT) || - status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) { - /* disable slave interrupts */ - val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); - val &= ~iproc_i2c->slave_int_mask; - iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); - - if (status & BIT(IS_S_RD_EVENT_SHIFT)) - /* Master-write-read request */ - iproc_i2c->slave_rx_only = false; - else - /* Master-write request only */ - iproc_i2c->slave_rx_only = true; - - /* schedule tasklet to read data later */ - tasklet_schedule(&iproc_i2c->slave_rx_tasklet); - - /* - * clear only IS_S_RX_EVENT_SHIFT and - * IS_S_RX_FIFO_FULL_SHIFT interrupt. - */ - val = BIT(IS_S_RX_EVENT_SHIFT); - if (status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) - val |= BIT(IS_S_RX_FIFO_FULL_SHIFT); - iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, val); - } - if (status & BIT(IS_S_TX_UNDERRUN_SHIFT)) { iproc_i2c->tx_underrun++; if (iproc_i2c->tx_underrun == 1) @@ -490,8 +476,9 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, * less than PKT_LENGTH bytes were output on the SMBUS */ iproc_i2c->slave_int_mask &= ~BIT(IE_S_TX_UNDERRUN_SHIFT); - iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, - iproc_i2c->slave_int_mask); + val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); + val &= ~BIT(IE_S_TX_UNDERRUN_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); /* End of SMBUS for Master Read */ val = BIT(S_TX_WR_STATUS_SHIFT); @@ -512,9 +499,49 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, BIT(IS_S_START_BUSY_SHIFT)); } - /* check slave transmit status only if slave is transmitting */ - if (!iproc_i2c->slave_rx_only) - bcm_iproc_i2c_check_slave_status(iproc_i2c); + /* if the controller has been reset, immediately return from the ISR */ + if (bcm_iproc_i2c_check_slave_status(iproc_i2c, status)) + return true; + + /* + * Slave events in case of master-write, master-write-read and, + * master-read + * + * Master-write : only IS_S_RX_EVENT_SHIFT event + * Master-write-read: both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT + * events + * Master-read : both IS_S_RX_EVENT_SHIFT and IS_S_RD_EVENT_SHIFT + * events or only IS_S_RD_EVENT_SHIFT + * + * iproc has a slave rx fifo size of 64 bytes. Rx fifo full interrupt + * (IS_S_RX_FIFO_FULL_SHIFT) will be generated when RX fifo becomes + * full. This can happen if Master issues write requests of more than + * 64 bytes. + */ + if (status & BIT(IS_S_RX_EVENT_SHIFT) || + status & BIT(IS_S_RD_EVENT_SHIFT) || + status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) { + /* disable slave interrupts */ + val = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); + val &= ~iproc_i2c->slave_int_mask; + iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, val); + + if (status & BIT(IS_S_RD_EVENT_SHIFT)) + /* Master-write-read request */ + iproc_i2c->slave_rx_only = false; + else + /* Master-write request only */ + iproc_i2c->slave_rx_only = true; + + /* schedule tasklet to read data later */ + tasklet_schedule(&iproc_i2c->slave_rx_tasklet); + + /* clear IS_S_RX_FIFO_FULL_SHIFT interrupt */ + if (status & BIT(IS_S_RX_FIFO_FULL_SHIFT)) { + val = BIT(IS_S_RX_FIFO_FULL_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, val); + } + } return true; } @@ -522,7 +549,7 @@ static bool bcm_iproc_i2c_slave_isr(struct bcm_iproc_i2c_dev *iproc_i2c, static void bcm_iproc_i2c_read_valid_bytes(struct bcm_iproc_i2c_dev *iproc_i2c) { struct i2c_msg *msg = iproc_i2c->msg; - uint32_t val; + u32 val; /* Read valid data from RX FIFO */ while (iproc_i2c->rx_bytes < msg->len) { @@ -658,7 +685,7 @@ static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data) return IRQ_HANDLED; } -static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c) +static void bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c) { u32 val; @@ -668,8 +695,8 @@ static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c) val &= ~(BIT(CFG_EN_SHIFT)); iproc_i2c_wr_reg(iproc_i2c, CFG_OFFSET, val); - /* wait 100 usec per spec */ - udelay(100); + /* wait approximately 100 usec as per spec */ + usleep_range(100, 200); /* bring controller out of reset */ val &= ~(BIT(CFG_RESET_SHIFT)); @@ -686,21 +713,6 @@ static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c) /* clear all pending interrupts */ iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, 0xffffffff); - - return 0; -} - -static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c, - bool enable) -{ - u32 val; - - val = iproc_i2c_rd_reg(iproc_i2c, CFG_OFFSET); - if (enable) - val |= BIT(CFG_EN_SHIFT); - else - val &= ~BIT(CFG_EN_SHIFT); - iproc_i2c_wr_reg(iproc_i2c, CFG_OFFSET, val); } static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c, @@ -716,31 +728,31 @@ static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c, return 0; case M_CMD_STATUS_LOST_ARB: - dev_dbg(iproc_i2c->device, "lost bus arbitration\n"); + dev_err(iproc_i2c->device, "lost bus arbitration\n"); return -EAGAIN; case M_CMD_STATUS_NACK_ADDR: - dev_dbg(iproc_i2c->device, "NAK addr:0x%02x\n", msg->addr); + dev_err(iproc_i2c->device, "NAK addr:0x%02x\n", msg->addr); return -ENXIO; case M_CMD_STATUS_NACK_DATA: - dev_dbg(iproc_i2c->device, "NAK data\n"); + dev_err(iproc_i2c->device, "NAK data\n"); return -ENXIO; case M_CMD_STATUS_TIMEOUT: - dev_dbg(iproc_i2c->device, "bus timeout\n"); + dev_err(iproc_i2c->device, "bus timeout\n"); return -ETIMEDOUT; case M_CMD_STATUS_FIFO_UNDERRUN: - dev_dbg(iproc_i2c->device, "FIFO under-run\n"); + dev_err(iproc_i2c->device, "FIFO under-run\n"); return -ENXIO; case M_CMD_STATUS_RX_FIFO_FULL: - dev_dbg(iproc_i2c->device, "RX FIFO full\n"); + dev_err(iproc_i2c->device, "RX FIFO full\n"); return -ETIMEDOUT; default: - dev_dbg(iproc_i2c->device, "unknown error code=%d\n", val); + dev_err(iproc_i2c->device, "unknown error code=%d\n", val); /* re-initialize i2c for recovery */ bcm_iproc_i2c_enable_disable(iproc_i2c, false); @@ -791,8 +803,6 @@ static int bcm_iproc_i2c_xfer_wait(struct bcm_iproc_i2c_dev *iproc_i2c, } if (!time_left && !iproc_i2c->xfer_is_done) { - dev_err(iproc_i2c->device, "transaction timed out\n"); - /* flush both TX/RX FIFOs */ val = BIT(M_FIFO_RX_FLUSH_SHIFT) | BIT(M_FIFO_TX_FLUSH_SHIFT); iproc_i2c_wr_reg(iproc_i2c, M_FIFO_CTRL_OFFSET, val); @@ -817,7 +827,7 @@ static int bcm_iproc_i2c_xfer_wait(struct bcm_iproc_i2c_dev *iproc_i2c, * The i2c quirks are set to enforce this rule. */ static int bcm_iproc_i2c_xfer_internal(struct bcm_iproc_i2c_dev *iproc_i2c, - struct i2c_msg *msgs, bool process_call) + struct i2c_msg *msgs, bool process_call) { int i; u8 addr; @@ -826,8 +836,8 @@ static int bcm_iproc_i2c_xfer_internal(struct bcm_iproc_i2c_dev *iproc_i2c, struct i2c_msg *msg = &msgs[0]; /* check if bus is busy */ - if (!!(iproc_i2c_rd_reg(iproc_i2c, - M_CMD_OFFSET) & BIT(M_CMD_START_BUSY_SHIFT))) { + if (iproc_i2c_rd_reg(iproc_i2c, + M_CMD_OFFSET) & BIT(M_CMD_START_BUSY_SHIFT)) { dev_warn(iproc_i2c->device, "bus is busy\n"); return -EBUSY; } @@ -954,14 +964,14 @@ static int bcm_iproc_i2c_xfer(struct i2c_adapter *adapter, ret = bcm_iproc_i2c_xfer_internal(iproc_i2c, msgs, process_call); if (ret) { - dev_dbg(iproc_i2c->device, "xfer failed\n"); + dev_err(iproc_i2c->device, "xfer failed\n"); return ret; } return num; } -static uint32_t bcm_iproc_i2c_functionality(struct i2c_adapter *adap) +static u32 bcm_iproc_i2c_functionality(struct i2c_adapter *adap) { u32 val; @@ -973,8 +983,65 @@ static uint32_t bcm_iproc_i2c_functionality(struct i2c_adapter *adap) return val; } +static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave) +{ + struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(slave->adapter); + + if (iproc_i2c->slave) + return -EBUSY; + + if (slave->flags & I2C_CLIENT_TEN) + return -EAFNOSUPPORT; + + iproc_i2c->slave = slave; + + tasklet_init(&iproc_i2c->slave_rx_tasklet, slave_rx_tasklet_fn, + (unsigned long)iproc_i2c); + + bcm_iproc_i2c_slave_init(iproc_i2c, false); + + return 0; +} + +static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave) +{ + struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(slave->adapter); + u32 tmp; + + if (!iproc_i2c->slave) + return -EINVAL; + + disable_irq(iproc_i2c->irq); + + tasklet_kill(&iproc_i2c->slave_rx_tasklet); + + /* disable all slave interrupts */ + tmp = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); + tmp &= ~(IE_S_ALL_INTERRUPT_MASK << + IE_S_ALL_INTERRUPT_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, tmp); + + /* Erase the slave address programmed */ + tmp = iproc_i2c_rd_reg(iproc_i2c, S_CFG_SMBUS_ADDR_OFFSET); + tmp &= ~BIT(S_CFG_EN_NIC_SMB_ADDR3_SHIFT); + iproc_i2c_wr_reg(iproc_i2c, S_CFG_SMBUS_ADDR_OFFSET, tmp); + + /* flush TX/RX FIFOs */ + tmp = (BIT(S_FIFO_RX_FLUSH_SHIFT) | BIT(S_FIFO_TX_FLUSH_SHIFT)); + iproc_i2c_wr_reg(iproc_i2c, S_FIFO_CTRL_OFFSET, tmp); + + /* clear all pending slave interrupts */ + iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, ISR_MASK_SLAVE); + + iproc_i2c->slave = NULL; + + enable_irq(iproc_i2c->irq); + + return 0; +} + static struct i2c_algorithm bcm_iproc_algo = { - .master_xfer = bcm_iproc_i2c_xfer, + .xfer = bcm_iproc_i2c_xfer, .functionality = bcm_iproc_i2c_functionality, .reg_slave = bcm_iproc_i2c_reg_slave, .unreg_slave = bcm_iproc_i2c_unreg_slave, @@ -994,21 +1061,18 @@ static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c) "clock-frequency", &bus_speed); if (ret < 0) { dev_info(iproc_i2c->device, - "unable to interpret clock-frequency DT property\n"); + "unable to interpret clock-frequency DT property\n"); bus_speed = I2C_MAX_STANDARD_MODE_FREQ; } - if (bus_speed < I2C_MAX_STANDARD_MODE_FREQ) { - dev_err(iproc_i2c->device, "%d Hz bus speed not supported\n", - bus_speed); - dev_err(iproc_i2c->device, - "valid speeds are 100khz and 400khz\n"); - return -EINVAL; - } else if (bus_speed < I2C_MAX_FAST_MODE_FREQ) { + if (bus_speed < I2C_MAX_STANDARD_MODE_FREQ) + return dev_err_probe(iproc_i2c->device, -EINVAL, + "%d Hz not supported (out of 100-400 kHz range)\n", + bus_speed); + else if (bus_speed < I2C_MAX_FAST_MODE_FREQ) bus_speed = I2C_MAX_STANDARD_MODE_FREQ; - } else { + else bus_speed = I2C_MAX_FAST_MODE_FREQ; - } iproc_i2c->bus_speed = bus_speed; val = iproc_i2c_rd_reg(iproc_i2c, TIM_CFG_OFFSET); @@ -1023,10 +1087,9 @@ static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c) static int bcm_iproc_i2c_probe(struct platform_device *pdev) { - int irq, ret = 0; struct bcm_iproc_i2c_dev *iproc_i2c; struct i2c_adapter *adap; - struct resource *res; + int irq, ret; iproc_i2c = devm_kzalloc(&pdev->dev, sizeof(*iproc_i2c), GFP_KERNEL); @@ -1039,26 +1102,21 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev) (enum bcm_iproc_i2c_type)of_device_get_match_data(&pdev->dev); init_completion(&iproc_i2c->done); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - iproc_i2c->base = devm_ioremap_resource(iproc_i2c->device, res); + iproc_i2c->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(iproc_i2c->base)) return PTR_ERR(iproc_i2c->base); if (iproc_i2c->type == IPROC_I2C_NIC) { - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - iproc_i2c->idm_base = devm_ioremap_resource(iproc_i2c->device, - res); + iproc_i2c->idm_base = devm_platform_ioremap_resource(pdev, 1); if (IS_ERR(iproc_i2c->idm_base)) return PTR_ERR(iproc_i2c->idm_base); ret = of_property_read_u32(iproc_i2c->device->of_node, "brcm,ape-hsls-addr-mask", &iproc_i2c->ape_addr_mask); - if (ret < 0) { - dev_err(iproc_i2c->device, - "'brcm,ape-hsls-addr-mask' missing\n"); - return -EINVAL; - } + if (ret < 0) + return dev_err_probe(iproc_i2c->device, ret, + "'brcm,ape-hsls-addr-mask' missing\n"); spin_lock_init(&iproc_i2c->idm_lock); @@ -1067,9 +1125,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev) bcm_iproc_algo.unreg_slave = NULL; } - ret = bcm_iproc_i2c_init(iproc_i2c); - if (ret) - return ret; + bcm_iproc_i2c_init(iproc_i2c); ret = bcm_iproc_i2c_cfg_speed(iproc_i2c); if (ret) @@ -1080,11 +1136,9 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(iproc_i2c->device, irq, bcm_iproc_i2c_isr, 0, pdev->name, iproc_i2c); - if (ret < 0) { - dev_err(iproc_i2c->device, - "unable to request irq %i\n", irq); - return ret; - } + if (ret < 0) + return dev_err_probe(iproc_i2c->device, ret, + "unable to request irq %i\n", irq); iproc_i2c->irq = irq; } else { @@ -1096,9 +1150,8 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev) adap = &iproc_i2c->adapter; i2c_set_adapdata(adap, iproc_i2c); - snprintf(adap->name, sizeof(adap->name), - "Broadcom iProc (%s)", - of_node_full_name(iproc_i2c->device->of_node)); + snprintf(adap->name, sizeof(adap->name), "Broadcom iProc (%s)", + of_node_full_name(iproc_i2c->device->of_node)); adap->algo = &bcm_iproc_algo; adap->quirks = &bcm_iproc_i2c_quirks; adap->dev.parent = &pdev->dev; @@ -1107,7 +1160,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev) return i2c_add_adapter(adap); } -static int bcm_iproc_i2c_remove(struct platform_device *pdev) +static void bcm_iproc_i2c_remove(struct platform_device *pdev) { struct bcm_iproc_i2c_dev *iproc_i2c = platform_get_drvdata(pdev); @@ -1123,12 +1176,8 @@ static int bcm_iproc_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&iproc_i2c->adapter); bcm_iproc_i2c_enable_disable(iproc_i2c, false); - - return 0; } -#ifdef CONFIG_PM_SLEEP - static int bcm_iproc_i2c_suspend(struct device *dev) { struct bcm_iproc_i2c_dev *iproc_i2c = dev_get_drvdata(dev); @@ -1152,16 +1201,13 @@ static int bcm_iproc_i2c_suspend(struct device *dev) static int bcm_iproc_i2c_resume(struct device *dev) { struct bcm_iproc_i2c_dev *iproc_i2c = dev_get_drvdata(dev); - int ret; u32 val; /* * Power domain could have been shut off completely in system deep * sleep, so re-initialize the block here */ - ret = bcm_iproc_i2c_init(iproc_i2c); - if (ret) - return ret; + bcm_iproc_i2c_init(iproc_i2c); /* configure to the desired bus speed */ val = iproc_i2c_rd_reg(iproc_i2c, TIM_CFG_OFFSET); @@ -1179,68 +1225,6 @@ static const struct dev_pm_ops bcm_iproc_i2c_pm_ops = { .resume_early = &bcm_iproc_i2c_resume }; -#define BCM_IPROC_I2C_PM_OPS (&bcm_iproc_i2c_pm_ops) -#else -#define BCM_IPROC_I2C_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ - - -static int bcm_iproc_i2c_reg_slave(struct i2c_client *slave) -{ - struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(slave->adapter); - - if (iproc_i2c->slave) - return -EBUSY; - - if (slave->flags & I2C_CLIENT_TEN) - return -EAFNOSUPPORT; - - iproc_i2c->slave = slave; - - tasklet_init(&iproc_i2c->slave_rx_tasklet, slave_rx_tasklet_fn, - (unsigned long)iproc_i2c); - - bcm_iproc_i2c_slave_init(iproc_i2c, false); - return 0; -} - -static int bcm_iproc_i2c_unreg_slave(struct i2c_client *slave) -{ - u32 tmp; - struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(slave->adapter); - - if (!iproc_i2c->slave) - return -EINVAL; - - disable_irq(iproc_i2c->irq); - - tasklet_kill(&iproc_i2c->slave_rx_tasklet); - - /* disable all slave interrupts */ - tmp = iproc_i2c_rd_reg(iproc_i2c, IE_OFFSET); - tmp &= ~(IE_S_ALL_INTERRUPT_MASK << - IE_S_ALL_INTERRUPT_SHIFT); - iproc_i2c_wr_reg(iproc_i2c, IE_OFFSET, tmp); - - /* Erase the slave address programmed */ - tmp = iproc_i2c_rd_reg(iproc_i2c, S_CFG_SMBUS_ADDR_OFFSET); - tmp &= ~BIT(S_CFG_EN_NIC_SMB_ADDR3_SHIFT); - iproc_i2c_wr_reg(iproc_i2c, S_CFG_SMBUS_ADDR_OFFSET, tmp); - - /* flush TX/RX FIFOs */ - tmp = (BIT(S_FIFO_RX_FLUSH_SHIFT) | BIT(S_FIFO_TX_FLUSH_SHIFT)); - iproc_i2c_wr_reg(iproc_i2c, S_FIFO_CTRL_OFFSET, tmp); - - /* clear all pending slave interrupts */ - iproc_i2c_wr_reg(iproc_i2c, IS_OFFSET, ISR_MASK_SLAVE); - - iproc_i2c->slave = NULL; - - enable_irq(iproc_i2c->irq); - - return 0; -} - static const struct of_device_id bcm_iproc_i2c_of_match[] = { { .compatible = "brcm,iproc-i2c", @@ -1257,7 +1241,7 @@ static struct platform_driver bcm_iproc_i2c_driver = { .driver = { .name = "bcm-iproc-i2c", .of_match_table = bcm_iproc_i2c_of_match, - .pm = BCM_IPROC_I2C_PM_OPS, + .pm = pm_sleep_ptr(&bcm_iproc_i2c_pm_ops), }, .probe = bcm_iproc_i2c_probe, .remove = bcm_iproc_i2c_remove, diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c index f3e369f0fd40..9d8838bbd938 100644 --- a/drivers/i2c/busses/i2c-bcm-kona.c +++ b/drivers/i2c/busses/i2c-bcm-kona.c @@ -85,7 +85,7 @@ #define STD_EXT_CLK_FREQ 13000000UL #define HS_EXT_CLK_FREQ 104000000UL -#define MASTERCODE 0x08 /* Mastercodes are 0000_1xxxb */ +#define CONTROLLER_CODE 0x08 /* Controller codes are 0000_1xxxb */ #define I2C_TIMEOUT 100 /* msecs */ @@ -471,12 +471,12 @@ static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev, if (msg->flags & I2C_M_TEN) { /* First byte is 11110XX0 where XX is upper 2 bits */ - addr = 0xF0 | ((msg->addr & 0x300) >> 7); + addr = i2c_10bit_addr_hi_from_msg(msg) & ~I2C_M_RD; if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0) return -EREMOTEIO; /* Second byte is the remaining 8 bits */ - addr = msg->addr & 0xFF; + addr = i2c_10bit_addr_lo_from_msg(msg); if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0) return -EREMOTEIO; @@ -486,7 +486,7 @@ static int bcm_kona_i2c_do_addr(struct bcm_kona_i2c_dev *dev, return -EREMOTEIO; /* Then re-send the first byte with the read bit set */ - addr = 0xF0 | ((msg->addr & 0x300) >> 7) | 0x01; + addr = i2c_10bit_addr_hi_from_msg(msg); if (bcm_kona_i2c_write_byte(dev, addr, 0) < 0) return -EREMOTEIO; } @@ -544,8 +544,8 @@ static int bcm_kona_i2c_switch_to_hs(struct bcm_kona_i2c_dev *dev) { int rc; - /* Send mastercode at standard speed */ - rc = bcm_kona_i2c_write_byte(dev, MASTERCODE, 1); + /* Send controller code at standard speed */ + rc = bcm_kona_i2c_write_byte(dev, CONTROLLER_CODE, 1); if (rc < 0) { pr_err("High speed handshake failed\n"); return rc; @@ -587,7 +587,6 @@ static int bcm_kona_i2c_switch_to_std(struct bcm_kona_i2c_dev *dev) return rc; } -/* Master transfer function */ static int bcm_kona_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg msgs[], int num) { @@ -637,7 +636,7 @@ static int bcm_kona_i2c_xfer(struct i2c_adapter *adapter, } } - /* Send slave address */ + /* Send target address */ if (!(pmsg->flags & I2C_M_NOSTART)) { rc = bcm_kona_i2c_do_addr(dev, pmsg); if (rc < 0) { @@ -697,7 +696,7 @@ static uint32_t bcm_kona_i2c_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm bcm_algo = { - .master_xfer = bcm_kona_i2c_xfer, + .xfer = bcm_kona_i2c_xfer, .functionality = bcm_kona_i2c_functionality, }; @@ -722,7 +721,7 @@ static int bcm_kona_i2c_assign_bus_speed(struct bcm_kona_i2c_dev *dev) dev->std_cfg = &std_cfg_table[BCM_SPD_1MHZ]; break; case I2C_MAX_HIGH_SPEED_MODE_FREQ: - /* Send mastercode at 100k */ + /* Send controller code at 100k */ dev->std_cfg = &std_cfg_table[BCM_SPD_100K]; dev->hs_cfg = &hs_cfg_table[BCM_SPD_3P4MHZ]; break; @@ -859,13 +858,11 @@ probe_disable_clk: return rc; } -static int bcm_kona_i2c_remove(struct platform_device *pdev) +static void bcm_kona_i2c_remove(struct platform_device *pdev) { struct bcm_kona_i2c_dev *dev = platform_get_drvdata(pdev); i2c_del_adapter(&dev->adapter); - - return 0; } static const struct of_device_id bcm_kona_i2c_of_match[] = { diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index f72c6576d8a3..0d7e2654a534 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 /* - * BCM2835 master mode driver + * BCM2835 I2C controller driver */ #include <linux/clk.h> @@ -12,7 +12,7 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/slab.h> @@ -25,7 +25,7 @@ #define BCM2835_I2C_DEL 0x18 /* * 16-bit field for the number of SCL cycles to wait after rising SCL - * before deciding the slave is not responding. 0 disables the + * before deciding the target is not responding. 0 disables the * timeout detection. */ #define BCM2835_I2C_CLKT 0x1c @@ -137,12 +137,14 @@ static int clk_bcm2835_i2c_set_rate(struct clk_hw *hw, unsigned long rate, return 0; } -static long clk_bcm2835_i2c_round_rate(struct clk_hw *hw, unsigned long rate, - unsigned long *parent_rate) +static int clk_bcm2835_i2c_determine_rate(struct clk_hw *hw, + struct clk_rate_request *req) { - u32 divider = clk_bcm2835_i2c_calc_divider(rate, *parent_rate); + u32 divider = clk_bcm2835_i2c_calc_divider(req->rate, req->best_parent_rate); - return DIV_ROUND_UP(*parent_rate, divider); + req->rate = DIV_ROUND_UP(req->best_parent_rate, divider); + + return 0; } static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw, @@ -156,7 +158,7 @@ static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw, static const struct clk_ops clk_bcm2835_i2c_ops = { .set_rate = clk_bcm2835_i2c_set_rate, - .round_rate = clk_bcm2835_i2c_round_rate, + .determine_rate = clk_bcm2835_i2c_determine_rate, .recalc_rate = clk_bcm2835_i2c_recalc_rate, }; @@ -223,7 +225,7 @@ static void bcm2835_drain_rxfifo(struct bcm2835_i2c_dev *i2c_dev) /* * Repeated Start Condition (Sr) * The BCM2835 ARM Peripherals datasheet mentions a way to trigger a Sr when it - * talks about reading from a slave with 10 bit address. This is achieved by + * talks about reading from a target with 10 bit address. This is achieved by * issuing a write, poll the I2CS.TA flag and wait for it to be set, and then * issue a read. * A comment in https://github.com/raspberrypi/linux/issues/254 shows how the @@ -370,7 +372,6 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (!time_left) { bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, BCM2835_I2C_C_CLEAR); - dev_err(i2c_dev->dev, "i2c transfer timed out\n"); return -ETIMEDOUT; } @@ -391,8 +392,8 @@ static u32 bcm2835_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm bcm2835_i2c_algo = { - .master_xfer = bcm2835_i2c_xfer, - .functionality = bcm2835_i2c_func, + .xfer = bcm2835_i2c_xfer, + .functionality = bcm2835_i2c_func, }; /* @@ -407,7 +408,6 @@ static const struct i2c_adapter_quirks bcm2835_i2c_quirks = { static int bcm2835_i2c_probe(struct platform_device *pdev) { struct bcm2835_i2c_dev *i2c_dev; - struct resource *mem; int ret; struct i2c_adapter *adap; struct clk *mclk; @@ -420,8 +420,7 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) i2c_dev->dev = &pdev->dev; init_completion(&i2c_dev->completion); - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2c_dev->regs = devm_ioremap_resource(&pdev->dev, mem); + i2c_dev->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(i2c_dev->regs)) return PTR_ERR(i2c_dev->regs); @@ -432,10 +431,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) i2c_dev->bus_clk = bcm2835_i2c_register_div(&pdev->dev, mclk, i2c_dev); - if (IS_ERR(i2c_dev->bus_clk)) { - dev_err(&pdev->dev, "Could not register clock\n"); - return PTR_ERR(i2c_dev->bus_clk); - } + if (IS_ERR(i2c_dev->bus_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2c_dev->bus_clk), + "Could not register clock\n"); ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", &bus_clk_rate); @@ -446,10 +444,9 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) } ret = clk_set_rate_exclusive(i2c_dev->bus_clk, bus_clk_rate); - if (ret < 0) { - dev_err(&pdev->dev, "Could not set clock frequency\n"); - return ret; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, + "Could not set clock frequency\n"); ret = clk_prepare_enable(i2c_dev->bus_clk); if (ret) { @@ -505,7 +502,7 @@ err_put_exclusive_rate: return ret; } -static int bcm2835_i2c_remove(struct platform_device *pdev) +static void bcm2835_i2c_remove(struct platform_device *pdev) { struct bcm2835_i2c_dev *i2c_dev = platform_get_drvdata(pdev); @@ -514,8 +511,6 @@ static int bcm2835_i2c_remove(struct platform_device *pdev) free_irq(i2c_dev->irq, i2c_dev); i2c_del_adapter(&i2c_dev->adapter); - - return 0; } static const struct of_device_id bcm2835_i2c_of_match[] = { diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c index 69383be47905..5fa30e8926c5 100644 --- a/drivers/i2c/busses/i2c-brcmstb.c +++ b/drivers/i2c/busses/i2c-brcmstb.c @@ -67,7 +67,7 @@ /* BSC block register map structure to cache fields to be written */ struct bsc_regs { - u32 chip_address; /* slave address */ + u32 chip_address; /* target address */ u32 data_in[N_DATA_REGS]; /* tx data buffer*/ u32 cnt_reg; /* rx/tx data length */ u32 ctl_reg; /* control register */ @@ -160,6 +160,7 @@ struct brcmstb_i2c_dev { struct completion done; u32 clk_freq_hz; int data_regsz; + bool atomic; }; /* register accessors for both be and le cpu arch */ @@ -240,7 +241,7 @@ static int brcmstb_i2c_wait_for_completion(struct brcmstb_i2c_dev *dev) int ret = 0; unsigned long timeout = msecs_to_jiffies(I2C_TIMEOUT); - if (dev->irq >= 0) { + if (dev->irq >= 0 && !dev->atomic) { if (!wait_for_completion_timeout(&dev->done, timeout)) ret = -ETIMEDOUT; } else { @@ -287,7 +288,7 @@ static int brcmstb_send_i2c_cmd(struct brcmstb_i2c_dev *dev, return rc; /* only if we are in interrupt mode */ - if (dev->irq >= 0) + if (dev->irq >= 0 && !dev->atomic) reinit_completion(&dev->done); /* enable BSC CTL interrupt line */ @@ -319,7 +320,7 @@ cmd_out: return rc; } -/* Actual data transfer through the BSC master */ +/* Actual data transfer through the BSC controller */ static int brcmstb_i2c_xfer_bsc_data(struct brcmstb_i2c_dev *dev, u8 *buf, unsigned int len, struct i2c_msg *pmsg) @@ -413,23 +414,22 @@ static int brcmstb_i2c_do_addr(struct brcmstb_i2c_dev *dev, if (msg->flags & I2C_M_TEN) { /* First byte is 11110XX0 where XX is upper 2 bits */ - addr = 0xF0 | ((msg->addr & 0x300) >> 7); + addr = i2c_10bit_addr_hi_from_msg(msg) & ~I2C_M_RD; bsc_writel(dev, addr, chip_address); /* Second byte is the remaining 8 bits */ - addr = msg->addr & 0xFF; + addr = i2c_10bit_addr_lo_from_msg(msg); if (brcmstb_i2c_write_data_byte(dev, &addr, 0) < 0) return -EREMOTEIO; if (msg->flags & I2C_M_RD) { /* For read, send restart without stop condition */ - brcmstb_set_i2c_start_stop(dev, COND_RESTART - | COND_NOSTOP); + brcmstb_set_i2c_start_stop(dev, COND_RESTART | COND_NOSTOP); + /* Then re-send the first byte with the read bit set */ - addr = 0xF0 | ((msg->addr & 0x300) >> 7) | 0x01; + addr = i2c_10bit_addr_hi_from_msg(msg); if (brcmstb_i2c_write_data_byte(dev, &addr, 0) < 0) return -EREMOTEIO; - } } else { addr = i2c_8bit_addr_from_msg(msg); @@ -440,7 +440,6 @@ static int brcmstb_i2c_do_addr(struct brcmstb_i2c_dev *dev, return 0; } -/* Master transfer function */ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg msgs[], int num) { @@ -472,7 +471,7 @@ static int brcmstb_i2c_xfer(struct i2c_adapter *adapter, brcmstb_set_i2c_start_stop(dev, cond); - /* Send slave address */ + /* Send target address */ if (!(pmsg->flags & I2C_M_NOSTART)) { rc = brcmstb_i2c_do_addr(dev, pmsg); if (rc < 0) { @@ -520,6 +519,23 @@ out: } +static int brcmstb_i2c_xfer_atomic(struct i2c_adapter *adapter, + struct i2c_msg msgs[], int num) +{ + struct brcmstb_i2c_dev *dev = i2c_get_adapdata(adapter); + int ret; + + if (dev->irq >= 0) + disable_irq(dev->irq); + dev->atomic = true; + ret = brcmstb_i2c_xfer(adapter, msgs, num); + dev->atomic = false; + if (dev->irq >= 0) + enable_irq(dev->irq); + + return ret; +} + static u32 brcmstb_i2c_functionality(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR @@ -527,7 +543,8 @@ static u32 brcmstb_i2c_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm brcmstb_i2c_algo = { - .master_xfer = brcmstb_i2c_xfer, + .xfer = brcmstb_i2c_xfer, + .xfer_atomic = brcmstb_i2c_xfer_atomic, .functionality = brcmstb_i2c_functionality, }; @@ -575,12 +592,10 @@ static void brcmstb_i2c_set_bsc_reg_defaults(struct brcmstb_i2c_dev *dev) static int bcm2711_release_bsc(struct brcmstb_i2c_dev *dev) { struct platform_device *pdev = to_platform_device(dev->device); - struct resource *iomem; void __iomem *autoi2c; /* Map hardware registers */ - iomem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "auto-i2c"); - autoi2c = devm_ioremap_resource(&pdev->dev, iomem); + autoi2c = devm_platform_ioremap_resource_byname(pdev, "auto-i2c"); if (IS_ERR(autoi2c)) return PTR_ERR(autoi2c); @@ -596,11 +611,10 @@ static int bcm2711_release_bsc(struct brcmstb_i2c_dev *dev) static int brcmstb_i2c_probe(struct platform_device *pdev) { - int rc = 0; struct brcmstb_i2c_dev *dev; struct i2c_adapter *adap; - struct resource *iomem; const char *int_name; + int rc; /* Allocate memory for private data structure */ dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); @@ -616,18 +630,15 @@ static int brcmstb_i2c_probe(struct platform_device *pdev) init_completion(&dev->done); /* Map hardware registers */ - iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - dev->base = devm_ioremap_resource(dev->device, iomem); - if (IS_ERR(dev->base)) { - rc = -ENOMEM; - goto probe_errorout; - } + dev->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(dev->base)) + return PTR_ERR(dev->base); if (of_device_is_compatible(dev->device->of_node, "brcm,bcm2711-hdmi-i2c")) { rc = bcm2711_release_bsc(dev); if (rc) - goto probe_errorout; + return rc; } rc = of_property_read_string(dev->device->of_node, "interrupt-names", @@ -680,27 +691,22 @@ static int brcmstb_i2c_probe(struct platform_device *pdev) adap->dev.of_node = pdev->dev.of_node; rc = i2c_add_adapter(adap); if (rc) - goto probe_errorout; + return rc; dev_info(dev->device, "%s@%dhz registered in %s mode\n", int_name ? int_name : " ", dev->clk_freq_hz, (dev->irq >= 0) ? "interrupt" : "polling"); return 0; - -probe_errorout: - return rc; } -static int brcmstb_i2c_remove(struct platform_device *pdev) +static void brcmstb_i2c_remove(struct platform_device *pdev) { struct brcmstb_i2c_dev *dev = platform_get_drvdata(pdev); i2c_del_adapter(&dev->adapter); - return 0; } -#ifdef CONFIG_PM_SLEEP static int brcmstb_i2c_suspend(struct device *dev) { struct brcmstb_i2c_dev *i2c_dev = dev_get_drvdata(dev); @@ -718,10 +724,9 @@ static int brcmstb_i2c_resume(struct device *dev) return 0; } -#endif -static SIMPLE_DEV_PM_OPS(brcmstb_i2c_pm, brcmstb_i2c_suspend, - brcmstb_i2c_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(brcmstb_i2c_pm, brcmstb_i2c_suspend, + brcmstb_i2c_resume); static const struct of_device_id brcmstb_i2c_of_match[] = { {.compatible = "brcm,brcmstb-i2c"}, @@ -735,7 +740,7 @@ static struct platform_driver brcmstb_i2c_driver = { .driver = { .name = "brcmstb-i2c", .of_match_table = brcmstb_i2c_of_match, - .pm = &brcmstb_i2c_pm, + .pm = pm_sleep_ptr(&brcmstb_i2c_pm), }, .probe = brcmstb_i2c_probe, .remove = brcmstb_i2c_remove, diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index f58943cb1341..0fb728ade92e 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -16,6 +16,7 @@ #include <linux/of.h> #include <linux/pm_runtime.h> #include <linux/pinctrl/consumer.h> +#include <linux/reset.h> /* Register offsets for the I2C device. */ #define CDNS_I2C_CR_OFFSET 0x00 /* Control Register, RW */ @@ -114,12 +115,10 @@ /* timeout for pm runtime autosuspend */ #define CNDS_I2C_PM_TIMEOUT 1000 /* ms */ -#define CDNS_I2C_FIFO_DEPTH 16 -/* FIFO depth at which the DATA interrupt occurs */ -#define CDNS_I2C_DATA_INTR_DEPTH (CDNS_I2C_FIFO_DEPTH - 2) +#define CDNS_I2C_FIFO_DEPTH_DEFAULT 16 #define CDNS_I2C_MAX_TRANSFER_SIZE 255 /* Transfer size in multiples of data interrupt depth */ -#define CDNS_I2C_TRANSFER_SIZE (CDNS_I2C_MAX_TRANSFER_SIZE - 3) +#define CDNS_I2C_TRANSFER_SIZE(max) ((max) - 3) #define DRIVER_NAME "cdns-i2c" @@ -130,6 +129,7 @@ #define CDNS_I2C_BROKEN_HOLD_BIT BIT(0) #define CDNS_I2C_POLL_US 100000 +#define CDNS_I2C_POLL_US_ATOMIC 10 #define CDNS_I2C_TIMEOUT_US 500000 #define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset) @@ -175,18 +175,23 @@ enum cdns_i2c_slave_state { * @send_count: Number of bytes still expected to send * @recv_count: Number of bytes still expected to receive * @curr_recv_count: Number of bytes to be received in current transfer - * @irq: IRQ number * @input_clk: Input clock to I2C controller * @i2c_clk: Maximum I2C clock speed * @bus_hold_flag: Flag used in repeated start for clearing HOLD bit * @clk: Pointer to struct clk * @clk_rate_change_nb: Notifier block for clock rate changes + * @reset: Reset control for the device * @quirks: flag for broken hold bit usage in r1p10 * @ctrl_reg: Cached value of the control register. + * @rinfo: I2C GPIO recovery information * @ctrl_reg_diva_divb: value of fields DIV_A and DIV_B from CR register * @slave: Registered slave instance. * @dev_mode: I2C operating role(master/slave). * @slave_state: I2C Slave state(idle/read/write). + * @fifo_depth: The depth of the transfer FIFO + * @transfer_size: The maximum number of bytes in one transfer + * @atomic: Mode of transfer + * @err_status_atomic: Error status in atomic mode */ struct cdns_i2c { struct device *dev; @@ -200,12 +205,12 @@ struct cdns_i2c { unsigned int send_count; unsigned int recv_count; unsigned int curr_recv_count; - int irq; unsigned long input_clk; unsigned int i2c_clk; unsigned int bus_hold_flag; struct clk *clk; struct notifier_block clk_rate_change_nb; + struct reset_control *reset; u32 quirks; u32 ctrl_reg; struct i2c_bus_recovery_info rinfo; @@ -215,6 +220,10 @@ struct cdns_i2c { enum cdns_i2c_mode dev_mode; enum cdns_i2c_slave_state slave_state; #endif + u32 fifo_depth; + unsigned int transfer_size; + bool atomic; + int err_status_atomic; }; struct cdns_platform_data { @@ -225,6 +234,66 @@ struct cdns_platform_data { clk_rate_change_nb) /** + * cdns_i2c_init - Controller initialisation + * @id: Device private data structure + * + * Initialise the i2c controller. + * + */ +static void cdns_i2c_init(struct cdns_i2c *id) +{ + cdns_i2c_writereg(id->ctrl_reg, CDNS_I2C_CR_OFFSET); + /* + * Cadence I2C controller has a bug wherein it generates + * invalid read transaction after HW timeout in master receiver mode. + * HW timeout is not used by this driver and the interrupt is disabled. + * But the feature itself cannot be disabled. Hence maximum value + * is written to this register to reduce the chances of error. + */ + cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET); +} + +/** + * cdns_i2c_runtime_suspend - Runtime suspend method for the driver + * @dev: Address of the platform_device structure + * + * Put the driver into low power mode. + * + * Return: 0 always + */ +static int cdns_i2c_runtime_suspend(struct device *dev) +{ + struct cdns_i2c *xi2c = dev_get_drvdata(dev); + + clk_disable(xi2c->clk); + + return 0; +} + +/** + * cdns_i2c_runtime_resume - Runtime resume + * @dev: Address of the platform_device structure + * + * Runtime resume callback. + * + * Return: 0 on success and error value on error + */ +static int cdns_i2c_runtime_resume(struct device *dev) +{ + struct cdns_i2c *xi2c = dev_get_drvdata(dev); + int ret; + + ret = clk_enable(xi2c->clk); + if (ret) { + dev_err(dev, "Cannot enable clock.\n"); + return ret; + } + cdns_i2c_init(xi2c); + + return 0; +} + +/** * cdns_i2c_clear_bus_hold - Clear bus hold bit * @id: Pointer to driver data struct * @@ -240,7 +309,7 @@ static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id) static inline bool cdns_is_holdquirk(struct cdns_i2c *id, bool hold_wrkaround) { return (hold_wrkaround && - (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)); + (id->curr_recv_count == id->fifo_depth + 1)); } #if IS_ENABLED(CONFIG_I2C_SLAVE) @@ -435,7 +504,7 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr) * if RX data left is less than or equal to * FIFO DEPTH unless repeated start is selected */ - if (id->recv_count <= CDNS_I2C_FIFO_DEPTH && + if (id->recv_count <= id->fifo_depth && !id->bus_hold_flag) cdns_i2c_clear_bus_hold(id); @@ -460,22 +529,22 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr) if (cdns_is_holdquirk(id, updatetx)) { /* wait while fifo is full */ while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) != - (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH)) + (id->curr_recv_count - id->fifo_depth)) ; /* * Check number of bytes to be received against maximum * transfer size and update register accordingly. */ - if (((int)(id->recv_count) - CDNS_I2C_FIFO_DEPTH) > - CDNS_I2C_TRANSFER_SIZE) { - cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE, + if (((int)(id->recv_count) - id->fifo_depth) > + id->transfer_size) { + cdns_i2c_writereg(id->transfer_size, CDNS_I2C_XFER_SIZE_OFFSET); - id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE + - CDNS_I2C_FIFO_DEPTH; + id->curr_recv_count = id->transfer_size + + id->fifo_depth; } else { cdns_i2c_writereg(id->recv_count - - CDNS_I2C_FIFO_DEPTH, + id->fifo_depth, CDNS_I2C_XFER_SIZE_OFFSET); id->curr_recv_count = id->recv_count; } @@ -498,7 +567,7 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr) * space available in FIFO and fill with that many bytes. */ if (id->send_count) { - avail_bytes = CDNS_I2C_FIFO_DEPTH - + avail_bytes = id->fifo_depth - cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); if (id->send_count > avail_bytes) bytes_to_send = avail_bytes; @@ -557,6 +626,89 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr) return cdns_i2c_master_isr(ptr); } +static bool cdns_i2c_error_check(struct cdns_i2c *id) +{ + unsigned int isr_status; + + id->err_status = 0; + + isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET); + cdns_i2c_writereg(isr_status & CDNS_I2C_IXR_ERR_INTR_MASK, CDNS_I2C_ISR_OFFSET); + + id->err_status = isr_status & CDNS_I2C_IXR_ERR_INTR_MASK; + + return !!id->err_status; +} + +static void cdns_i2c_mrecv_atomic(struct cdns_i2c *id) +{ + while (id->recv_count > 0) { + bool updatetx; + + /* + * Check if transfer size register needs to be updated again for a + * large data receive operation. + */ + updatetx = id->recv_count > id->curr_recv_count; + + while (id->curr_recv_count > 0) { + if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_RXDV) { + *id->p_recv_buf = cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET); + id->p_recv_buf++; + id->recv_count--; + id->curr_recv_count--; + + /* + * Clear the hold bit that was set for FIFO control, + * if the remaining RX data is less than or equal to + * the FIFO depth, unless a repeated start is selected. + */ + if (id->recv_count <= id->fifo_depth && !id->bus_hold_flag) + cdns_i2c_clear_bus_hold(id); + } + if (cdns_i2c_error_check(id)) + return; + if (cdns_is_holdquirk(id, updatetx)) + break; + } + + /* + * The controller sends NACK to the slave/target when transfer size + * register reaches zero without considering the HOLD bit. + * This workaround is implemented for large data transfers to + * maintain transfer size non-zero while performing a large + * receive operation. + */ + if (cdns_is_holdquirk(id, updatetx)) { + /* wait while fifo is full */ + while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) != + (id->curr_recv_count - id->fifo_depth)) + ; + + /* + * Check number of bytes to be received against maximum + * transfer size and update register accordingly. + */ + if ((id->recv_count - id->fifo_depth) > + id->transfer_size) { + cdns_i2c_writereg(id->transfer_size, + CDNS_I2C_XFER_SIZE_OFFSET); + id->curr_recv_count = id->transfer_size + + id->fifo_depth; + } else { + cdns_i2c_writereg(id->recv_count - + id->fifo_depth, + CDNS_I2C_XFER_SIZE_OFFSET); + id->curr_recv_count = id->recv_count; + } + } + } + + /* Clear hold (if not repeated start) */ + if (!id->recv_count && !id->bus_hold_flag) + cdns_i2c_clear_bus_hold(id); +} + /** * cdns_i2c_mrecv - Prepare and start a master receive operation * @id: pointer to the i2c device structure @@ -592,7 +744,7 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id) * Check for the message size against FIFO depth and set the * 'hold bus' bit if it is greater than FIFO depth. */ - if (id->recv_count > CDNS_I2C_FIFO_DEPTH) + if (id->recv_count > id->fifo_depth) ctrl_reg |= CDNS_I2C_CR_HOLD; cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET); @@ -607,19 +759,17 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id) * receive if it is less than transfer size and transfer size if * it is more. Enable the interrupts. */ - if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) { - cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE, + if (id->recv_count > id->transfer_size) { + cdns_i2c_writereg(id->transfer_size, CDNS_I2C_XFER_SIZE_OFFSET); - id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE; + id->curr_recv_count = id->transfer_size; } else { cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET); } /* Determine hold_clear based on number of bytes to receive and hold flag */ - if (!id->bus_hold_flag && - ((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) && - (id->recv_count <= CDNS_I2C_FIFO_DEPTH)) { - if (cdns_i2c_readreg(CDNS_I2C_CR_OFFSET) & CDNS_I2C_CR_HOLD) { + if (!id->bus_hold_flag && id->recv_count <= id->fifo_depth) { + if (ctrl_reg & CDNS_I2C_CR_HOLD) { hold_clear = true; if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT) irq_save = true; @@ -630,7 +780,8 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id) addr &= CDNS_I2C_ADDR_MASK; if (hold_clear) { - ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET) & ~CDNS_I2C_CR_HOLD; + ctrl_reg &= ~CDNS_I2C_CR_HOLD; + ctrl_reg &= ~CDNS_I2C_CR_CLR_FIFO; /* * In case of Xilinx Zynq SOC, clear the HOLD bit before transfer size * register reaches '0'. This is an IP bug which causes transfer size @@ -652,7 +803,34 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id) cdns_i2c_writereg(addr, CDNS_I2C_ADDR_OFFSET); } - cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET); + if (!id->atomic) + cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET); + else + cdns_i2c_mrecv_atomic(id); +} + +static void cdns_i2c_msend_rem_atomic(struct cdns_i2c *id) +{ + while (id->send_count) { + unsigned int avail_bytes; + unsigned int bytes_to_send; + + avail_bytes = id->fifo_depth - cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); + if (id->send_count > avail_bytes) + bytes_to_send = avail_bytes; + else + bytes_to_send = id->send_count; + + while (bytes_to_send--) { + cdns_i2c_writereg((*id->p_send_buf++), CDNS_I2C_DATA_OFFSET); + id->send_count--; + } + if (cdns_i2c_error_check(id)) + return; + } + + if (!id->send_count && !id->bus_hold_flag) + cdns_i2c_clear_bus_hold(id); } /** @@ -679,7 +857,7 @@ static void cdns_i2c_msend(struct cdns_i2c *id) * Check for the message size against FIFO depth and set the * 'hold bus' bit if it is greater than FIFO depth. */ - if (id->send_count > CDNS_I2C_FIFO_DEPTH) + if (id->send_count > id->fifo_depth) ctrl_reg |= CDNS_I2C_CR_HOLD; cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET); @@ -692,7 +870,7 @@ static void cdns_i2c_msend(struct cdns_i2c *id) * against the space available, and fill the FIFO accordingly. * Enable the interrupts. */ - avail_bytes = CDNS_I2C_FIFO_DEPTH - + avail_bytes = id->fifo_depth - cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); if (id->send_count > avail_bytes) @@ -715,7 +893,10 @@ static void cdns_i2c_msend(struct cdns_i2c *id) cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK, CDNS_I2C_ADDR_OFFSET); - cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET); + if (!id->atomic) + cdns_i2c_writereg(CDNS_I2C_ENABLED_INTR_MASK, CDNS_I2C_IER_OFFSET); + else if (id->send_count > 0) + cdns_i2c_msend_rem_atomic(id); } /** @@ -755,7 +936,8 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, id->p_msg = msg; id->err_status = 0; - reinit_completion(&id->xfer_done); + if (!id->atomic) + reinit_completion(&id->xfer_done); /* Check for the TEN Bit mode on each msg */ reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); @@ -777,18 +959,33 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, /* Minimal time to execute this message */ msg_timeout = msecs_to_jiffies((1000 * msg->len * BITS_PER_BYTE) / id->i2c_clk); - /* Plus some wiggle room */ - msg_timeout += msecs_to_jiffies(500); + + /* + * Plus some wiggle room. + * For non-atomic contexts, 500 ms is added to the timeout. + * For atomic contexts, 2000 ms is added because transfers happen in polled + * mode, requiring more time to account for the polling overhead. + */ + if (!id->atomic) + msg_timeout += msecs_to_jiffies(500); + else + msg_timeout += msecs_to_jiffies(2000); if (msg_timeout < adap->timeout) msg_timeout = adap->timeout; - /* Wait for the signal of completion */ - time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout); + if (!id->atomic) { + /* Wait for the signal of completion */ + time_left = wait_for_completion_timeout(&id->xfer_done, msg_timeout); + } else { + /* 0 is success, -ETIMEDOUT is error */ + time_left = !readl_poll_timeout_atomic(id->membase + CDNS_I2C_ISR_OFFSET, + reg, (reg & CDNS_I2C_IXR_COMP), + CDNS_I2C_POLL_US_ATOMIC, msg_timeout); + } + if (time_left == 0) { cdns_i2c_master_reset(adap); - dev_err(id->adap.dev.parent, - "timeout waiting on completion\n"); return -ETIMEDOUT; } @@ -805,56 +1002,31 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, return 0; } -/** - * cdns_i2c_master_xfer - The main i2c transfer function - * @adap: pointer to the i2c adapter driver instance - * @msgs: pointer to the i2c message structure - * @num: the number of messages to transfer - * - * Initiates the send/recv activity based on the transfer message received. - * - * Return: number of msgs processed on success, negative error otherwise - */ -static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num) +static int cdns_i2c_master_common_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, + int num) { int ret, count; u32 reg; struct cdns_i2c *id = adap->algo_data; bool hold_quirk; -#if IS_ENABLED(CONFIG_I2C_SLAVE) - bool change_role = false; -#endif - - ret = pm_runtime_resume_and_get(id->dev); - if (ret < 0) - return ret; - -#if IS_ENABLED(CONFIG_I2C_SLAVE) - /* Check i2c operating mode and switch if possible */ - if (id->dev_mode == CDNS_I2C_MODE_SLAVE) { - if (id->slave_state != CDNS_I2C_SLAVE_STATE_IDLE) - return -EAGAIN; - - /* Set mode to master */ - cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id); - - /* Mark flag to change role once xfer is completed */ - change_role = true; - } -#endif /* Check if the bus is free */ - - ret = readl_relaxed_poll_timeout(id->membase + CDNS_I2C_SR_OFFSET, - reg, - !(reg & CDNS_I2C_SR_BA), - CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US); + if (!id->atomic) + ret = readl_relaxed_poll_timeout(id->membase + CDNS_I2C_SR_OFFSET, + reg, + !(reg & CDNS_I2C_SR_BA), + CDNS_I2C_POLL_US, CDNS_I2C_TIMEOUT_US); + else + ret = readl_poll_timeout_atomic(id->membase + CDNS_I2C_SR_OFFSET, + reg, + !(reg & CDNS_I2C_SR_BA), + CDNS_I2C_POLL_US_ATOMIC, CDNS_I2C_TIMEOUT_US); if (ret) { ret = -EAGAIN; if (id->adap.bus_recovery_info) i2c_recover_bus(adap); - goto out; + return ret; } hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT); @@ -874,8 +1046,7 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, if (msgs[count].flags & I2C_M_RD) { dev_warn(adap->dev.parent, "Can't do repeated start after a receive message\n"); - ret = -EOPNOTSUPP; - goto out; + return -EOPNOTSUPP; } } id->bus_hold_flag = 1; @@ -893,37 +1064,110 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, ret = cdns_i2c_process_msg(id, msgs, adap); if (ret) - goto out; + return ret; /* Report the other error interrupts to application */ - if (id->err_status) { + if (id->err_status || id->err_status_atomic) { cdns_i2c_master_reset(adap); - if (id->err_status & CDNS_I2C_IXR_NACK) { - ret = -ENXIO; - goto out; - } - ret = -EIO; - goto out; + if (id->err_status & CDNS_I2C_IXR_NACK) + return -ENXIO; + + return -EIO; } } + return 0; +} - ret = num; +/** + * cdns_i2c_master_xfer - The main i2c transfer function + * @adap: pointer to the i2c adapter driver instance + * @msgs: pointer to the i2c message structure + * @num: the number of messages to transfer + * + * Initiates the send/recv activity based on the transfer message received. + * + * Return: number of msgs processed on success, negative error otherwise + */ +static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + int ret; + struct cdns_i2c *id = adap->algo_data; +#if IS_ENABLED(CONFIG_I2C_SLAVE) + bool change_role = false; +#endif -out: + ret = pm_runtime_resume_and_get(id->dev); + if (ret < 0) + return ret; + +#if IS_ENABLED(CONFIG_I2C_SLAVE) + /* Check i2c operating mode and switch if possible */ + if (id->dev_mode == CDNS_I2C_MODE_SLAVE) { + if (id->slave_state != CDNS_I2C_SLAVE_STATE_IDLE) { + ret = -EAGAIN; + goto out; + } + + /* Set mode to master */ + cdns_i2c_set_mode(CDNS_I2C_MODE_MASTER, id); + + /* Mark flag to change role once xfer is completed */ + change_role = true; + } +#endif + ret = cdns_i2c_master_common_xfer(adap, msgs, num); + if (!ret) + ret = num; #if IS_ENABLED(CONFIG_I2C_SLAVE) +out: /* Switch i2c mode to slave */ if (change_role) cdns_i2c_set_mode(CDNS_I2C_MODE_SLAVE, id); #endif - pm_runtime_mark_last_busy(id->dev); pm_runtime_put_autosuspend(id->dev); return ret; } /** + * cdns_i2c_master_xfer_atomic - The i2c transfer function in atomic mode + * @adap: pointer to the i2c adapter driver instance + * @msgs: pointer to the i2c message structure + * @num: the number of messages to transfer + * + * Return: number of msgs processed on success, negative error otherwise + */ +static int cdns_i2c_master_xfer_atomic(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + int ret; + struct cdns_i2c *id = adap->algo_data; + + ret = cdns_i2c_runtime_resume(id->dev); + if (ret) + return ret; + + if (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT) { + dev_warn(id->adap.dev.parent, + "Atomic xfer not supported for version 1.0\n"); + return 0; + } + + id->atomic = true; + ret = cdns_i2c_master_common_xfer(adap, msgs, num); + if (!ret) + ret = num; + + id->atomic = false; + cdns_i2c_runtime_suspend(id->dev); + + return ret; +} + +/** * cdns_i2c_func - Returns the supported features of the I2C driver * @adap: pointer to the i2c adapter structure * @@ -986,11 +1230,12 @@ static int cdns_unreg_slave(struct i2c_client *slave) #endif static const struct i2c_algorithm cdns_i2c_algo = { - .master_xfer = cdns_i2c_master_xfer, - .functionality = cdns_i2c_func, + .xfer = cdns_i2c_master_xfer, + .xfer_atomic = cdns_i2c_master_xfer_atomic, + .functionality = cdns_i2c_func, #if IS_ENABLED(CONFIG_I2C_SLAVE) - .reg_slave = cdns_reg_slave, - .unreg_slave = cdns_unreg_slave, + .reg_slave = cdns_reg_slave, + .unreg_slave = cdns_unreg_slave, #endif }; @@ -1036,8 +1281,7 @@ static int cdns_i2c_calc_divs(unsigned long *f, unsigned long input_clk, if (actual_fscl > fscl) continue; - current_error = ((actual_fscl > fscl) ? (actual_fscl - fscl) : - (fscl - actual_fscl)); + current_error = fscl - actual_fscl; if (last_error > current_error) { calc_div_a = div_a; @@ -1156,67 +1400,40 @@ static int cdns_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long } } -/** - * cdns_i2c_runtime_suspend - Runtime suspend method for the driver - * @dev: Address of the platform_device structure - * - * Put the driver into low power mode. - * - * Return: 0 always - */ -static int __maybe_unused cdns_i2c_runtime_suspend(struct device *dev) +static int __maybe_unused cdns_i2c_suspend(struct device *dev) { struct cdns_i2c *xi2c = dev_get_drvdata(dev); - clk_disable(xi2c->clk); + i2c_mark_adapter_suspended(&xi2c->adap); + + if (!pm_runtime_status_suspended(dev)) + return cdns_i2c_runtime_suspend(dev); return 0; } -/** - * cdns_i2c_init - Controller initialisation - * @id: Device private data structure - * - * Initialise the i2c controller. - * - */ -static void cdns_i2c_init(struct cdns_i2c *id) -{ - cdns_i2c_writereg(id->ctrl_reg, CDNS_I2C_CR_OFFSET); - /* - * Cadence I2C controller has a bug wherein it generates - * invalid read transaction after HW timeout in master receiver mode. - * HW timeout is not used by this driver and the interrupt is disabled. - * But the feature itself cannot be disabled. Hence maximum value - * is written to this register to reduce the chances of error. - */ - cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET); -} - -/** - * cdns_i2c_runtime_resume - Runtime resume - * @dev: Address of the platform_device structure - * - * Runtime resume callback. - * - * Return: 0 on success and error value on error - */ -static int __maybe_unused cdns_i2c_runtime_resume(struct device *dev) +static int __maybe_unused cdns_i2c_resume(struct device *dev) { struct cdns_i2c *xi2c = dev_get_drvdata(dev); - int ret; + int err; - ret = clk_enable(xi2c->clk); - if (ret) { - dev_err(dev, "Cannot enable clock.\n"); - return ret; + err = cdns_i2c_runtime_resume(dev); + if (err) + return err; + + if (pm_runtime_status_suspended(dev)) { + err = cdns_i2c_runtime_suspend(dev); + if (err) + return err; } - cdns_i2c_init(xi2c); + + i2c_mark_adapter_resumed(&xi2c->adap); return 0; } static const struct dev_pm_ops cdns_i2c_dev_pm_ops = { + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(cdns_i2c_suspend, cdns_i2c_resume) SET_RUNTIME_PM_OPS(cdns_i2c_runtime_suspend, cdns_i2c_runtime_resume, NULL) }; @@ -1233,6 +1450,37 @@ static const struct of_device_id cdns_i2c_of_match[] = { MODULE_DEVICE_TABLE(of, cdns_i2c_of_match); /** + * cdns_i2c_detect_transfer_size - Detect the maximum transfer size supported + * @id: Device private data structure + * + * Detect the maximum transfer size that is supported by this instance of the + * Cadence I2C controller. + */ +static void cdns_i2c_detect_transfer_size(struct cdns_i2c *id) +{ + u32 val; + + /* + * Writing to the transfer size register is only possible if these two bits + * are set in the control register. + */ + cdns_i2c_writereg(CDNS_I2C_CR_MS | CDNS_I2C_CR_RW, CDNS_I2C_CR_OFFSET); + + /* + * The number of writable bits of the transfer size register can be between + * 4 and 8. This is a controlled through a synthesis parameter of the IP + * core and can vary from instance to instance. The unused MSBs always read + * back as 0. Writing 0xff and then reading the value back will report the + * maximum supported transfer size. + */ + cdns_i2c_writereg(CDNS_I2C_MAX_TRANSFER_SIZE, CDNS_I2C_XFER_SIZE_OFFSET); + val = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET); + id->transfer_size = CDNS_I2C_TRANSFER_SIZE(val); + cdns_i2c_writereg(0, CDNS_I2C_XFER_SIZE_OFFSET); + cdns_i2c_writereg(0, CDNS_I2C_CR_OFFSET); +} + +/** * cdns_i2c_probe - Platform registration call * @pdev: Handle to the platform device structure * @@ -1246,7 +1494,7 @@ static int cdns_i2c_probe(struct platform_device *pdev) { struct resource *r_mem; struct cdns_i2c *id; - int ret; + int ret, irq; const struct of_device_id *match; id = devm_kzalloc(&pdev->dev, sizeof(*id), GFP_KERNEL); @@ -1277,10 +1525,9 @@ static int cdns_i2c_probe(struct platform_device *pdev) if (IS_ERR(id->membase)) return PTR_ERR(id->membase); - ret = platform_get_irq(pdev, 0); - if (ret < 0) - return ret; - id->irq = ret; + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; id->adap.owner = THIS_MODULE; id->adap.dev.of_node = pdev->dev.of_node; @@ -1293,14 +1540,20 @@ static int cdns_i2c_probe(struct platform_device *pdev) snprintf(id->adap.name, sizeof(id->adap.name), "Cadence I2C at %08lx", (unsigned long)r_mem->start); - id->clk = devm_clk_get(&pdev->dev, NULL); + id->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(id->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(id->clk), "input clock not found.\n"); - ret = clk_prepare_enable(id->clk); + id->reset = devm_reset_control_get_optional_shared(&pdev->dev, NULL); + if (IS_ERR(id->reset)) + return dev_err_probe(&pdev->dev, PTR_ERR(id->reset), + "Failed to request reset.\n"); + + ret = reset_control_deassert(id->reset); if (ret) - dev_err(&pdev->dev, "Unable to enable clock.\n"); + return dev_err_probe(&pdev->dev, ret, + "Failed to de-assert reset.\n"); pm_runtime_set_autosuspend_delay(id->dev, CNDS_I2C_PM_TIMEOUT); pm_runtime_use_autosuspend(id->dev); @@ -1324,35 +1577,40 @@ static int cdns_i2c_probe(struct platform_device *pdev) #endif id->ctrl_reg = CDNS_I2C_CR_ACK_EN | CDNS_I2C_CR_NEA | CDNS_I2C_CR_MS; + id->fifo_depth = CDNS_I2C_FIFO_DEPTH_DEFAULT; + of_property_read_u32(pdev->dev.of_node, "fifo-depth", &id->fifo_depth); + + cdns_i2c_detect_transfer_size(id); + ret = cdns_i2c_setclk(id->input_clk, id); if (ret) { dev_err(&pdev->dev, "invalid SCL clock: %u Hz\n", id->i2c_clk); ret = -EINVAL; - goto err_clk_dis; + goto err_clk_notifier_unregister; } - ret = devm_request_irq(&pdev->dev, id->irq, cdns_i2c_isr, 0, + ret = devm_request_irq(&pdev->dev, irq, cdns_i2c_isr, 0, DRIVER_NAME, id); if (ret) { - dev_err(&pdev->dev, "cannot get irq %d\n", id->irq); - goto err_clk_dis; + dev_err(&pdev->dev, "cannot get irq %d\n", irq); + goto err_clk_notifier_unregister; } cdns_i2c_init(id); ret = i2c_add_adapter(&id->adap); if (ret < 0) - goto err_clk_dis; + goto err_clk_notifier_unregister; dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n", - id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq); + id->i2c_clk / 1000, (unsigned long)r_mem->start, irq); return 0; -err_clk_dis: +err_clk_notifier_unregister: clk_notifier_unregister(id->clk, &id->clk_rate_change_nb); - clk_disable_unprepare(id->clk); pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); + reset_control_assert(id->reset); return ret; } @@ -1364,7 +1622,7 @@ err_clk_dis: * * Return: 0 always */ -static int cdns_i2c_remove(struct platform_device *pdev) +static void cdns_i2c_remove(struct platform_device *pdev) { struct cdns_i2c *id = platform_get_drvdata(pdev); @@ -1374,9 +1632,7 @@ static int cdns_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&id->adap); clk_notifier_unregister(id->clk, &id->clk_rate_change_nb); - clk_disable_unprepare(id->clk); - - return 0; + reset_control_assert(id->reset); } static struct platform_driver cdns_i2c_drv = { diff --git a/drivers/i2c/busses/i2c-cbus-gpio.c b/drivers/i2c/busses/i2c-cbus-gpio.c index d97c61eec95c..8065c7e4462e 100644 --- a/drivers/i2c/busses/i2c-cbus-gpio.c +++ b/drivers/i2c/busses/i2c-cbus-gpio.c @@ -200,13 +200,11 @@ static const struct i2c_algorithm cbus_i2c_algo = { .functionality = cbus_i2c_func, }; -static int cbus_i2c_remove(struct platform_device *pdev) +static void cbus_i2c_remove(struct platform_device *pdev) { struct i2c_adapter *adapter = platform_get_drvdata(pdev); i2c_del_adapter(adapter); - - return 0; } static int cbus_i2c_probe(struct platform_device *pdev) @@ -266,7 +264,7 @@ MODULE_DEVICE_TABLE(of, i2c_cbus_dt_ids); static struct platform_driver cbus_i2c_driver = { .probe = cbus_i2c_probe, - .remove = cbus_i2c_remove, + .remove = cbus_i2c_remove, .driver = { .name = "i2c-cbus-gpio", .of_match_table = of_match_ptr(i2c_cbus_dt_ids), diff --git a/drivers/i2c/busses/i2c-ccgx-ucsi.c b/drivers/i2c/busses/i2c-ccgx-ucsi.c index 092dc92dea9f..d97233862a6c 100644 --- a/drivers/i2c/busses/i2c-ccgx-ucsi.c +++ b/drivers/i2c/busses/i2c-ccgx-ucsi.c @@ -27,4 +27,5 @@ struct i2c_client *i2c_new_ccgx_ucsi(struct i2c_adapter *adapter, int irq, } EXPORT_SYMBOL_GPL(i2c_new_ccgx_ucsi); +MODULE_DESCRIPTION("Instantiate UCSI device for Cypress CCGx Type-C controller"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-cgbc.c b/drivers/i2c/busses/i2c-cgbc.c new file mode 100644 index 000000000000..25a74fa51aa0 --- /dev/null +++ b/drivers/i2c/busses/i2c-cgbc.c @@ -0,0 +1,406 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Congatec Board Controller I2C busses driver + * + * Copyright (C) 2024 Bootlin + * Author: Thomas Richard <thomas.richard@bootlin.com> + */ + +#include <linux/i2c.h> +#include <linux/iopoll.h> +#include <linux/mfd/cgbc.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#define CGBC_I2C_PRIMARY_BUS_ID 0 +#define CGBC_I2C_PM_BUS_ID 4 + +#define CGBC_I2C_CMD_START 0x40 +#define CGBC_I2C_CMD_STAT 0x48 +#define CGBC_I2C_CMD_DATA 0x50 +#define CGBC_I2C_CMD_SPEED 0x58 + +#define CGBC_I2C_STAT_IDL 0x00 +#define CGBC_I2C_STAT_DAT 0x01 +#define CGBC_I2C_STAT_BUSY 0x02 + +#define CGBC_I2C_START 0x80 +#define CGBC_I2C_STOP 0x40 + +#define CGBC_I2C_LAST_ACK 0x80 /* send ACK on last read byte */ + +/* + * Reference code defines 1kHz as min freq and 6.1MHz as max freq. + * But in practice, the board controller limits the frequency to 1MHz, and the + * 1kHz is not functional (minimal working freq is 50kHz). + * So use these values as limits. + */ +#define CGBC_I2C_FREQ_MIN_HZ 50000 /* 50 kHz */ +#define CGBC_I2C_FREQ_MAX_HZ 1000000 /* 1 MHz */ + +#define CGBC_I2C_FREQ_UNIT_1KHZ 0x40 +#define CGBC_I2C_FREQ_UNIT_10KHZ 0x80 +#define CGBC_I2C_FREQ_UNIT_100KHZ 0xC0 + +#define CGBC_I2C_FREQ_UNIT_MASK 0xC0 +#define CGBC_I2C_FREQ_VALUE_MASK 0x3F + +#define CGBC_I2C_READ_MAX_LEN 31 +#define CGBC_I2C_WRITE_MAX_LEN 32 + +#define CGBC_I2C_CMD_HEADER_SIZE 4 +#define CGBC_I2C_CMD_SIZE (CGBC_I2C_CMD_HEADER_SIZE + CGBC_I2C_WRITE_MAX_LEN) + +enum cgbc_i2c_state { + CGBC_I2C_STATE_DONE = 0, + CGBC_I2C_STATE_INIT, + CGBC_I2C_STATE_START, + CGBC_I2C_STATE_READ, + CGBC_I2C_STATE_WRITE, + CGBC_I2C_STATE_ERROR, +}; + +struct i2c_algo_cgbc_data { + u8 bus_id; + unsigned long read_maxtime_us; +}; + +struct cgbc_i2c_data { + struct device *dev; + struct cgbc_device_data *cgbc; + struct i2c_adapter adap; + struct i2c_msg *msg; + int nmsgs; + int pos; + enum cgbc_i2c_state state; +}; + +struct cgbc_i2c_transfer { + u8 bus_id; + bool start; + bool stop; + bool last_ack; + u8 read; + u8 write; + u8 addr; + u8 data[CGBC_I2C_WRITE_MAX_LEN]; +}; + +static u8 cgbc_i2c_freq_to_reg(unsigned int bus_frequency) +{ + u8 reg; + + if (bus_frequency <= 10000) + reg = CGBC_I2C_FREQ_UNIT_1KHZ | (bus_frequency / 1000); + else if (bus_frequency <= 100000) + reg = CGBC_I2C_FREQ_UNIT_10KHZ | (bus_frequency / 10000); + else + reg = CGBC_I2C_FREQ_UNIT_100KHZ | (bus_frequency / 100000); + + return reg; +} + +static unsigned int cgbc_i2c_reg_to_freq(u8 reg) +{ + unsigned int freq = reg & CGBC_I2C_FREQ_VALUE_MASK; + u8 unit = reg & CGBC_I2C_FREQ_UNIT_MASK; + + if (unit == CGBC_I2C_FREQ_UNIT_100KHZ) + return freq * 100000; + else if (unit == CGBC_I2C_FREQ_UNIT_10KHZ) + return freq * 10000; + else + return freq * 1000; +} + +static int cgbc_i2c_get_status(struct i2c_adapter *adap) +{ + struct i2c_algo_cgbc_data *algo_data = adap->algo_data; + struct cgbc_i2c_data *i2c = i2c_get_adapdata(adap); + struct cgbc_device_data *cgbc = i2c->cgbc; + u8 cmd = CGBC_I2C_CMD_STAT | algo_data->bus_id; + u8 status; + int ret; + + ret = cgbc_command(cgbc, &cmd, sizeof(cmd), NULL, 0, &status); + if (ret) + return ret; + + return status; +} + +static int cgbc_i2c_set_frequency(struct i2c_adapter *adap, + unsigned int bus_frequency) +{ + struct i2c_algo_cgbc_data *algo_data = adap->algo_data; + struct cgbc_i2c_data *i2c = i2c_get_adapdata(adap); + struct cgbc_device_data *cgbc = i2c->cgbc; + u8 cmd[2], data; + int ret; + + if (bus_frequency > CGBC_I2C_FREQ_MAX_HZ || + bus_frequency < CGBC_I2C_FREQ_MIN_HZ) { + dev_info(i2c->dev, "invalid frequency %u, using default\n", bus_frequency); + bus_frequency = I2C_MAX_STANDARD_MODE_FREQ; + } + + cmd[0] = CGBC_I2C_CMD_SPEED | algo_data->bus_id; + cmd[1] = cgbc_i2c_freq_to_reg(bus_frequency); + + ret = cgbc_command(cgbc, &cmd, sizeof(cmd), &data, 1, NULL); + if (ret) + return dev_err_probe(i2c->dev, ret, + "Failed to initialize I2C bus %s", + adap->name); + + cmd[1] = 0x00; + + ret = cgbc_command(cgbc, &cmd, sizeof(cmd), &data, 1, NULL); + if (ret) + return dev_err_probe(i2c->dev, ret, + "Failed to get I2C bus frequency"); + + bus_frequency = cgbc_i2c_reg_to_freq(data); + + dev_dbg(i2c->dev, "%s is running at %d Hz\n", adap->name, bus_frequency); + + /* + * The read_maxtime_us variable represents the maximum time to wait + * for data during a read operation. The maximum amount of data that + * can be read by a command is CGBC_I2C_READ_MAX_LEN. + * Therefore, calculate the max time to properly size the timeout. + */ + algo_data->read_maxtime_us = (BITS_PER_BYTE + 1) * CGBC_I2C_READ_MAX_LEN + * USEC_PER_SEC / bus_frequency; + + return 0; +} + +static unsigned int cgbc_i2c_xfer_to_cmd(struct cgbc_i2c_transfer xfer, u8 *cmd) +{ + int i = 0; + + cmd[i++] = CGBC_I2C_CMD_START | xfer.bus_id; + + cmd[i] = (xfer.start) ? CGBC_I2C_START : 0x00; + if (xfer.stop) + cmd[i] |= CGBC_I2C_STOP; + cmd[i++] |= (xfer.start) ? xfer.write + 1 : xfer.write; + + cmd[i++] = (xfer.last_ack) ? (xfer.read | CGBC_I2C_LAST_ACK) : xfer.read; + + if (xfer.start) + cmd[i++] = xfer.addr; + + if (xfer.write > 0) + memcpy(&cmd[i], &xfer.data, xfer.write); + + return i + xfer.write; +} + +static int cgbc_i2c_xfer_msg(struct i2c_adapter *adap) +{ + struct i2c_algo_cgbc_data *algo_data = adap->algo_data; + struct cgbc_i2c_data *i2c = i2c_get_adapdata(adap); + struct cgbc_device_data *cgbc = i2c->cgbc; + struct i2c_msg *msg = i2c->msg; + u8 cmd[CGBC_I2C_CMD_SIZE]; + int ret, max_len, len, i; + unsigned int cmd_len; + u8 cmd_data; + + struct cgbc_i2c_transfer xfer = { + .bus_id = algo_data->bus_id, + .addr = i2c_8bit_addr_from_msg(msg), + }; + + if (i2c->state == CGBC_I2C_STATE_DONE) + return 0; + + ret = cgbc_i2c_get_status(adap); + + if (ret == CGBC_I2C_STAT_BUSY) + return -EBUSY; + else if (ret < 0) + goto err; + + if (i2c->state == CGBC_I2C_STATE_INIT || + (i2c->state == CGBC_I2C_STATE_WRITE && msg->flags & I2C_M_RD)) + xfer.start = true; + + i2c->state = (msg->flags & I2C_M_RD) ? CGBC_I2C_STATE_READ : CGBC_I2C_STATE_WRITE; + + max_len = (i2c->state == CGBC_I2C_STATE_READ) ? + CGBC_I2C_READ_MAX_LEN : CGBC_I2C_WRITE_MAX_LEN; + + if (msg->len - i2c->pos > max_len) { + len = max_len; + } else { + len = msg->len - i2c->pos; + + if (i2c->nmsgs == 1) + xfer.stop = true; + } + + if (i2c->state == CGBC_I2C_STATE_WRITE) { + xfer.write = len; + xfer.read = 0; + + for (i = 0; i < len; i++) + xfer.data[i] = msg->buf[i2c->pos + i]; + + cmd_len = cgbc_i2c_xfer_to_cmd(xfer, &cmd[0]); + + ret = cgbc_command(cgbc, &cmd, cmd_len, NULL, 0, NULL); + if (ret) + goto err; + } else if (i2c->state == CGBC_I2C_STATE_READ) { + xfer.write = 0; + xfer.read = len; + + if (i2c->nmsgs > 1 || msg->len - i2c->pos > max_len) + xfer.read |= CGBC_I2C_LAST_ACK; + + cmd_len = cgbc_i2c_xfer_to_cmd(xfer, &cmd[0]); + ret = cgbc_command(cgbc, &cmd, cmd_len, NULL, 0, NULL); + if (ret) + goto err; + + ret = read_poll_timeout(cgbc_i2c_get_status, ret, + ret != CGBC_I2C_STAT_BUSY, 0, + 2 * algo_data->read_maxtime_us, false, adap); + if (ret < 0) + goto err; + + cmd_data = CGBC_I2C_CMD_DATA | algo_data->bus_id; + ret = cgbc_command(cgbc, &cmd_data, sizeof(cmd_data), + msg->buf + i2c->pos, len, NULL); + if (ret) + goto err; + } + + if (len == (msg->len - i2c->pos)) { + i2c->msg++; + i2c->nmsgs--; + i2c->pos = 0; + } else { + i2c->pos += len; + } + + if (i2c->nmsgs == 0) + i2c->state = CGBC_I2C_STATE_DONE; + + return 0; + +err: + i2c->state = CGBC_I2C_STATE_ERROR; + return ret; +} + +static int cgbc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct cgbc_i2c_data *i2c = i2c_get_adapdata(adap); + unsigned long timeout = jiffies + HZ; + int ret; + + i2c->state = CGBC_I2C_STATE_INIT; + i2c->msg = msgs; + i2c->nmsgs = num; + i2c->pos = 0; + + while (time_before(jiffies, timeout)) { + ret = cgbc_i2c_xfer_msg(adap); + if (i2c->state == CGBC_I2C_STATE_DONE) + return num; + + if (i2c->state == CGBC_I2C_STATE_ERROR) + return ret; + + if (ret == 0) + timeout = jiffies + HZ; + } + + i2c->state = CGBC_I2C_STATE_ERROR; + return -ETIMEDOUT; +} + +static u32 cgbc_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~(I2C_FUNC_SMBUS_QUICK)); +} + +static const struct i2c_algorithm cgbc_i2c_algorithm = { + .xfer = cgbc_i2c_xfer, + .functionality = cgbc_i2c_func, +}; + +static struct i2c_algo_cgbc_data cgbc_i2c_algo_data[] = { + { .bus_id = CGBC_I2C_PRIMARY_BUS_ID }, + { .bus_id = CGBC_I2C_PM_BUS_ID }, +}; + +static const struct i2c_adapter cgbc_i2c_adapter[] = { + { + .owner = THIS_MODULE, + .name = "Congatec General Purpose I2C adapter", + .class = I2C_CLASS_DEPRECATED, + .algo = &cgbc_i2c_algorithm, + .algo_data = &cgbc_i2c_algo_data[0], + .nr = -1, + }, + { + .owner = THIS_MODULE, + .name = "Congatec Power Management I2C adapter", + .class = I2C_CLASS_DEPRECATED, + .algo = &cgbc_i2c_algorithm, + .algo_data = &cgbc_i2c_algo_data[1], + .nr = -1, + }, +}; + +static int cgbc_i2c_probe(struct platform_device *pdev) +{ + struct cgbc_device_data *cgbc = dev_get_drvdata(pdev->dev.parent); + struct cgbc_i2c_data *i2c; + int ret; + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + i2c->cgbc = cgbc; + i2c->dev = &pdev->dev; + i2c->adap = cgbc_i2c_adapter[pdev->id]; + i2c->adap.dev.parent = i2c->dev; + i2c_set_adapdata(&i2c->adap, i2c); + platform_set_drvdata(pdev, i2c); + + ret = cgbc_i2c_set_frequency(&i2c->adap, I2C_MAX_STANDARD_MODE_FREQ); + if (ret) + return ret; + + return i2c_add_numbered_adapter(&i2c->adap); +} + +static void cgbc_i2c_remove(struct platform_device *pdev) +{ + struct cgbc_i2c_data *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c->adap); +} + +static struct platform_driver cgbc_i2c_driver = { + .driver = { + .name = "cgbc-i2c", + }, + .probe = cgbc_i2c_probe, + .remove = cgbc_i2c_remove, +}; + +module_platform_driver(cgbc_i2c_driver); + +MODULE_DESCRIPTION("Congatec Board Controller I2C Driver"); +MODULE_AUTHOR("Thomas Richard <thomas.richard@bootlin.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:cgbc_i2c"); diff --git a/drivers/i2c/busses/i2c-cht-wc.c b/drivers/i2c/busses/i2c-cht-wc.c index 190abdc46dd3..606ac071cb80 100644 --- a/drivers/i2c/busses/i2c-cht-wc.c +++ b/drivers/i2c/busses/i2c-cht-wc.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Intel CHT Whiskey Cove PMIC I2C Master driver + * Intel CHT Whiskey Cove PMIC I2C controller driver * Copyright (C) 2017 Hans de Goede <hdegoede@redhat.com> * * Based on various non upstream patches to support the CHT Whiskey Cove PMIC: @@ -106,7 +106,7 @@ static irqreturn_t cht_wc_i2c_adap_thread_handler(int id, void *data) return IRQ_HANDLED; } -static u32 cht_wc_i2c_adap_master_func(struct i2c_adapter *adap) +static u32 cht_wc_i2c_adap_func(struct i2c_adapter *adap) { /* This i2c adapter only supports SMBUS byte transfers */ return I2C_FUNC_SMBUS_BYTE_DATA; @@ -168,7 +168,7 @@ static int cht_wc_i2c_adap_smbus_xfer(struct i2c_adapter *_adap, u16 addr, } static const struct i2c_algorithm cht_wc_i2c_adap_algo = { - .functionality = cht_wc_i2c_adap_master_func, + .functionality = cht_wc_i2c_adap_func, .smbus_xfer = cht_wc_i2c_adap_smbus_xfer, }; @@ -380,6 +380,49 @@ static struct i2c_board_info lenovo_yogabook1_board_info = { .platform_data = &bq2589x_pdata, }; +/********** Lenovo Yogabook YT3-X90F charger settings **********/ +static const char * const lenovo_yt3_bq25892_1_suppliers[] = { "cht_wcove_pwrsrc" }; + +/* + * bq25892 charger settings for the round li-ion cells in the hinge, + * this is the main / biggest battery. + */ +static const struct property_entry lenovo_yt3_bq25892_1_props[] = { + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", lenovo_yt3_bq25892_1_suppliers), + PROPERTY_ENTRY_STRING("linux,secondary-charger-name", "bq25890-charger-0"), + PROPERTY_ENTRY_U32("linux,iinlim-percentage", 60), + PROPERTY_ENTRY_U32("linux,pump-express-vbus-max", 12000000), + PROPERTY_ENTRY_BOOL("linux,skip-reset"), + /* + * The firmware sets everything to the defaults, leading to a low(ish) + * charge-current and battery-voltage of 2048mA resp 4.2V. Use the + * Android values instead of "linux,read-back-settings" to fix this. + */ + PROPERTY_ENTRY_U32("ti,charge-current", 3072000), + PROPERTY_ENTRY_U32("ti,battery-regulation-voltage", 4352000), + PROPERTY_ENTRY_U32("ti,termination-current", 128000), + PROPERTY_ENTRY_U32("ti,precharge-current", 128000), + PROPERTY_ENTRY_U32("ti,minimum-sys-voltage", 3700000), + PROPERTY_ENTRY_BOOL("ti,use-ilim-pin"), + /* Set 5V boost current-limit to 1.2A (MAX/POR values are 2.45A/1.4A) */ + PROPERTY_ENTRY_U32("ti,boost-voltage", 4998000), + PROPERTY_ENTRY_U32("ti,boost-max-current", 1200000), + { } +}; + +static const struct software_node lenovo_yt3_bq25892_1_node = { + .properties = lenovo_yt3_bq25892_1_props, +}; + +/* bq25892 charger for the round li-ion cells in the hinge */ +static struct i2c_board_info lenovo_yoga_tab3_board_info = { + .type = "bq25892", + .addr = 0x6b, + .dev_name = "bq25892_1", + .swnode = &lenovo_yt3_bq25892_1_node, + .platform_data = &bq2589x_pdata, +}; + static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) { struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent); @@ -424,7 +467,7 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) return ret; /* Alloc and register client IRQ */ - adap->irq_domain = irq_domain_add_linear(NULL, 1, &irq_domain_simple_ops, NULL); + adap->irq_domain = irq_domain_create_linear(NULL, 1, &irq_domain_simple_ops, NULL); if (!adap->irq_domain) return -ENOMEM; @@ -459,6 +502,9 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) case INTEL_CHT_WC_LENOVO_YOGABOOK1: board_info = &lenovo_yogabook1_board_info; break; + case INTEL_CHT_WC_LENOVO_YT3_X90: + board_info = &lenovo_yoga_tab3_board_info; + break; default: dev_warn(&pdev->dev, "Unknown model, not instantiating charger device\n"); break; @@ -483,15 +529,13 @@ remove_irq_domain: return ret; } -static int cht_wc_i2c_adap_i2c_remove(struct platform_device *pdev) +static void cht_wc_i2c_adap_i2c_remove(struct platform_device *pdev) { struct cht_wc_i2c_adap *adap = platform_get_drvdata(pdev); i2c_unregister_device(adap->client); i2c_del_adapter(&adap->adapter); irq_domain_remove(adap->irq_domain); - - return 0; } static const struct platform_device_id cht_wc_i2c_adap_id_table[] = { @@ -510,6 +554,6 @@ static struct platform_driver cht_wc_i2c_adap_driver = { }; module_platform_driver(cht_wc_i2c_adap_driver); -MODULE_DESCRIPTION("Intel CHT Whiskey Cove PMIC I2C Master driver"); +MODULE_DESCRIPTION("Intel CHT Whiskey Cove PMIC I2C controller driver"); MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-cp2615.c b/drivers/i2c/busses/i2c-cp2615.c index 3ded28632e4c..e7720ea4045e 100644 --- a/drivers/i2c/busses/i2c-cp2615.c +++ b/drivers/i2c/busses/i2c-cp2615.c @@ -60,11 +60,11 @@ enum cp2615_i2c_status { CP2615_CFG_LOCKED = -6, /* read_len or write_len out of range */ CP2615_INVALID_PARAM = -4, - /* I2C slave did not ACK in time */ + /* I2C target did not ACK in time */ CP2615_TIMEOUT, /* I2C bus busy */ CP2615_BUS_BUSY, - /* I2C bus error (ie. device NAK'd the request) */ + /* I2C bus error (ie. target NAK'd the request) */ CP2615_BUS_ERROR, CP2615_SUCCESS }; @@ -85,7 +85,7 @@ static int cp2615_init_iop_msg(struct cp2615_iop_msg *ret, enum cp2615_iop_msg_t if (!ret) return -EINVAL; - ret->preamble = 0x2A2A; + ret->preamble = htons(0x2A2AU); ret->length = htons(data_len + 6); ret->msg = htons(msg); if (data && data_len) @@ -211,7 +211,7 @@ out: } static int -cp2615_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +cp2615_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct usb_interface *usbif = adap->algo_data; int i = 0, ret = 0; @@ -250,8 +250,8 @@ cp2615_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm cp2615_i2c_algo = { - .master_xfer = cp2615_i2c_master_xfer, - .functionality = cp2615_i2c_func, + .xfer = cp2615_i2c_xfer, + .functionality = cp2615_i2c_func, }; /* @@ -298,7 +298,7 @@ cp2615_i2c_probe(struct usb_interface *usbif, const struct usb_device_id *id) if (!adap) return -ENOMEM; - strncpy(adap->name, usbdev->serial, sizeof(adap->name) - 1); + strscpy(adap->name, usbdev->serial, sizeof(adap->name)); adap->owner = THIS_MODULE; adap->dev.parent = &usbif->dev; adap->dev.of_node = usbif->dev.of_node; diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 24d584a1c9a7..260e1643c2cc 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -26,10 +26,10 @@ #include <linux/i2c.h> #include <linux/io.h> #include <linux/dma-mapping.h> +#include <linux/of.h> #include <linux/of_address.h> -#include <linux/of_device.h> #include <linux/of_irq.h> -#include <linux/of_platform.h> +#include <linux/platform_device.h> #include <sysdev/fsl_soc.h> #include <asm/cpm.h> @@ -402,7 +402,7 @@ static u32 cpm_i2c_func(struct i2c_adapter *adap) /* -----exported algorithm data: ------------------------------------- */ static const struct i2c_algorithm cpm_i2c_algo = { - .master_xfer = cpm_i2c_xfer, + .xfer = cpm_i2c_xfer, .functionality = cpm_i2c_func, }; @@ -570,7 +570,7 @@ static int cpm_i2c_setup(struct cpm_i2c *cpm) out_8(&cpm->i2c_reg->i2brg, brg); out_8(&cpm->i2c_reg->i2mod, 0x00); - out_8(&cpm->i2c_reg->i2com, I2COM_MASTER); /* Master mode */ + out_8(&cpm->i2c_reg->i2com, I2COM_MASTER); /* Disable interrupts. */ out_8(&cpm->i2c_reg->i2cmr, 0); @@ -658,7 +658,7 @@ static int cpm_i2c_probe(struct platform_device *ofdev) /* register new adapter to i2c module... */ data = of_get_property(ofdev->dev.of_node, "linux,i2c-index", &len); - cpm->adap.nr = (data && len == 4) ? be32_to_cpup(data) : -1; + cpm->adap.nr = (data && len == 4) ? *data : -1; result = i2c_add_numbered_adapter(&cpm->adap); if (result < 0) @@ -676,7 +676,7 @@ out_free: return result; } -static int cpm_i2c_remove(struct platform_device *ofdev) +static void cpm_i2c_remove(struct platform_device *ofdev) { struct cpm_i2c *cpm = platform_get_drvdata(ofdev); @@ -685,8 +685,6 @@ static int cpm_i2c_remove(struct platform_device *ofdev) cpm_i2c_shutdown(cpm); kfree(cpm); - - return 0; } static const struct of_device_id cpm_i2c_match[] = { diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c index 4e787dc709f9..208ce4f9e782 100644 --- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c +++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c @@ -235,8 +235,8 @@ static u32 ec_i2c_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm ec_i2c_algorithm = { - .master_xfer = ec_i2c_xfer, - .functionality = ec_i2c_functionality, + .xfer = ec_i2c_xfer, + .functionality = ec_i2c_functionality, }; static int ec_i2c_probe(struct platform_device *pdev) @@ -247,6 +247,9 @@ static int ec_i2c_probe(struct platform_device *pdev) u32 remote_bus; int err; + if (!ec) + return dev_err_probe(dev, -EPROBE_DEFER, "couldn't find parent EC device\n"); + if (!ec->cmd_xfer) { dev_err(dev, "Missing sendrecv\n"); return -EINVAL; @@ -283,22 +286,20 @@ static int ec_i2c_probe(struct platform_device *pdev) return err; } -static int ec_i2c_remove(struct platform_device *dev) +static void ec_i2c_remove(struct platform_device *dev) { struct ec_i2c_device *bus = platform_get_drvdata(dev); i2c_del_adapter(&bus->adap); - - return 0; } -static const struct of_device_id cros_ec_i2c_of_match[] = { +static const struct of_device_id cros_ec_i2c_of_match[] __maybe_unused = { { .compatible = "google,cros-ec-i2c-tunnel" }, {}, }; MODULE_DEVICE_TABLE(of, cros_ec_i2c_of_match); -static const struct acpi_device_id cros_ec_i2c_tunnel_acpi_id[] = { +static const struct acpi_device_id cros_ec_i2c_tunnel_acpi_id[] __maybe_unused = { { "GOOG0012", 0 }, { } }; diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index c836cf884185..a773ba082321 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -11,23 +11,23 @@ * * ---------------------------------------------------------------------------- */ -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/delay.h> -#include <linux/i2c.h> + #include <linux/clk.h> -#include <linux/errno.h> -#include <linux/sched.h> +#include <linux/cpufreq.h> +#include <linux/delay.h> #include <linux/err.h> +#include <linux/errno.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/platform_device.h> #include <linux/io.h> -#include <linux/slab.h> -#include <linux/cpufreq.h> -#include <linux/gpio/consumer.h> -#include <linux/of_device.h> -#include <linux/platform_data/i2c-davinci.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/property.h> +#include <linux/sched.h> +#include <linux/slab.h> /* ----- global defines ----------------------------------------------- */ @@ -117,6 +117,8 @@ /* timeout for pm runtime autosuspend */ #define DAVINCI_I2C_PM_TIMEOUT 1000 /* ms */ +#define DAVINCI_I2C_DEFAULT_BUS_FREQ 100 + struct davinci_i2c_dev { struct device *dev; void __iomem *base; @@ -132,13 +134,10 @@ struct davinci_i2c_dev { #ifdef CONFIG_CPU_FREQ struct notifier_block freq_transition; #endif - struct davinci_i2c_platform_data *pdata; -}; - -/* default platform data to use if not supplied in the platform_device */ -static struct davinci_i2c_platform_data davinci_i2c_platform_data_default = { - .bus_freq = 100, - .bus_delay = 0, + /* standard bus frequency (kHz) */ + unsigned int bus_freq; + /* Chip has a ICPFUNC register */ + bool has_pfunc; }; static inline void davinci_i2c_write_reg(struct davinci_i2c_dev *i2c_dev, @@ -168,14 +167,12 @@ static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev, static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev) { - struct davinci_i2c_platform_data *pdata = dev->pdata; u16 psc; u32 clk; u32 d; u32 clkh; u32 clkl; u32 input_clock = clk_get_rate(dev->clk); - struct device_node *of_node = dev->dev->of_node; /* NOTE: I2C Clock divider programming info * As per I2C specs the following formulas provide prescaler @@ -209,19 +206,19 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev) psc++; /* better to run under spec than over */ d = (psc >= 2) ? 5 : 7 - psc; - if (of_node && of_device_is_compatible(of_node, "ti,keystone-i2c")) + if (device_is_compatible(dev->dev, "ti,keystone-i2c")) d = 6; - clk = ((input_clock / (psc + 1)) / (pdata->bus_freq * 1000)); + clk = ((input_clock / (psc + 1)) / (dev->bus_freq * 1000)); /* Avoid driving the bus too fast because of rounding errors above */ - if (input_clock / (psc + 1) / clk > pdata->bus_freq * 1000) + if (input_clock / (psc + 1) / clk > dev->bus_freq * 1000) clk++; /* * According to I2C-BUS Spec 2.1, in FAST-MODE LOW period should be at * least 1.3uS, which is not the case with 50% duty cycle. Driving HIGH * to LOW ratio as 1 to 2 is more safe. */ - if (pdata->bus_freq > 100) + if (dev->bus_freq > 100) clkl = (clk << 1) / 3; else clkl = (clk >> 1); @@ -255,15 +252,13 @@ static void i2c_davinci_calc_clk_dividers(struct davinci_i2c_dev *dev) */ static int i2c_davinci_init(struct davinci_i2c_dev *dev) { - struct davinci_i2c_platform_data *pdata = dev->pdata; - /* put I2C into reset */ davinci_i2c_reset_ctrl(dev, 0); /* compute clock dividers */ i2c_davinci_calc_clk_dividers(dev); - /* Respond at reserved "SMBus Host" slave address" (and zero); + /* Respond at reserved "SMBus Host" target address" (and zero); * we seem to have no option to not respond... */ davinci_i2c_write_reg(dev, DAVINCI_I2C_OAR_REG, DAVINCI_I2C_OWN_ADDRESS); @@ -274,8 +269,7 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev) davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKL_REG)); dev_dbg(dev->dev, "CLKH = %d\n", davinci_i2c_read_reg(dev, DAVINCI_I2C_CLKH_REG)); - dev_dbg(dev->dev, "bus_freq = %dkHz, bus_delay = %d\n", - pdata->bus_freq, pdata->bus_delay); + dev_dbg(dev->dev, "bus_freq = %dkHz\n", dev->bus_freq); /* Take the I2C module out of reset: */ @@ -309,12 +303,6 @@ static void davinci_i2c_unprepare_recovery(struct i2c_adapter *adap) i2c_davinci_init(dev); } -static struct i2c_bus_recovery_info davinci_i2c_gpio_recovery_info = { - .recover_bus = i2c_generic_scl_recovery, - .prepare_recovery = davinci_i2c_prepare_recovery, - .unprepare_recovery = davinci_i2c_unprepare_recovery, -}; - static void davinci_i2c_set_scl(struct i2c_adapter *adap, int val) { struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); @@ -407,14 +395,13 @@ static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev) } /* - * Low level master read/write transaction. This function is called - * from i2c_davinci_xfer. + * Low level read/write transaction. This function is called from + * i2c_davinci_xfer. */ static int i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) { struct davinci_i2c_dev *dev = i2c_get_adapdata(adap); - struct davinci_i2c_platform_data *pdata = dev->pdata; u32 flag; u16 w; unsigned long time_left; @@ -424,11 +411,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) return -EADDRNOTAVAIL; } - /* Introduce a delay, required for some boards (e.g Davinci EVM) */ - if (pdata->bus_delay) - udelay(pdata->bus_delay); - - /* set the slave address */ + /* set the target address */ davinci_i2c_write_reg(dev, DAVINCI_I2C_SAR_REG, msg->addr); dev->buf = msg->buf; @@ -440,10 +423,9 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) reinit_completion(&dev->cmd_complete); dev->cmd_err = 0; - /* Take I2C out of reset and configure it as master */ + /* Take I2C out of reset and configure it as controller */ flag = DAVINCI_I2C_MDR_IRS | DAVINCI_I2C_MDR_MST; - /* if the slave address is ten bit address, enable XA bit */ if (msg->flags & I2C_M_TEN) flag |= DAVINCI_I2C_MDR_XA; if (!(msg->flags & I2C_M_RD)) @@ -489,7 +471,6 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop) time_left = wait_for_completion_timeout(&dev->cmd_complete, dev->adapter.timeout); if (!time_left) { - dev_err(dev->dev, "controller timed out\n"); i2c_recover_bus(adap); dev->buf_len = 0; return -ETIMEDOUT; @@ -562,7 +543,6 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ret = num; out: - pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); return ret; @@ -570,7 +550,8 @@ out: static u32 i2c_davinci_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | + I2C_FUNC_PROTOCOL_MANGLING; } static void terminate_read(struct davinci_i2c_dev *dev) @@ -688,7 +669,7 @@ static irqreturn_t i2c_davinci_isr(int this_irq, void *dev_id) break; case DAVINCI_I2C_IVR_AAS: - dev_dbg(dev->dev, "Address as slave interrupt\n"); + dev_dbg(dev->dev, "Address as target interrupt\n"); break; default: @@ -745,8 +726,8 @@ static inline void i2c_davinci_cpufreq_deregister(struct davinci_i2c_dev *dev) #endif static const struct i2c_algorithm i2c_davinci_algo = { - .master_xfer = i2c_davinci_xfer, - .functionality = i2c_davinci_func, + .xfer = i2c_davinci_xfer, + .functionality = i2c_davinci_func, }; static const struct of_device_id davinci_i2c_of_match[] = { @@ -760,50 +741,30 @@ static int davinci_i2c_probe(struct platform_device *pdev) { struct davinci_i2c_dev *dev; struct i2c_adapter *adap; - struct i2c_bus_recovery_info *rinfo; int r, irq; + u32 prop; irq = platform_get_irq(pdev, 0); - if (irq <= 0) { - if (!irq) - irq = -ENXIO; - return dev_err_probe(&pdev->dev, irq, "can't get irq resource\n"); - } + if (irq < 0) + return irq; - dev = devm_kzalloc(&pdev->dev, sizeof(struct davinci_i2c_dev), - GFP_KERNEL); - if (!dev) { - dev_err(&pdev->dev, "Memory allocation failed\n"); + dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) return -ENOMEM; - } init_completion(&dev->cmd_complete); dev->dev = &pdev->dev; dev->irq = irq; - dev->pdata = dev_get_platdata(&pdev->dev); platform_set_drvdata(pdev, dev); - if (!dev->pdata && pdev->dev.of_node) { - u32 prop; - - dev->pdata = devm_kzalloc(&pdev->dev, - sizeof(struct davinci_i2c_platform_data), GFP_KERNEL); - if (!dev->pdata) - return -ENOMEM; - - memcpy(dev->pdata, &davinci_i2c_platform_data_default, - sizeof(struct davinci_i2c_platform_data)); - if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency", - &prop)) - dev->pdata->bus_freq = prop / 1000; - - dev->pdata->has_pfunc = - of_property_read_bool(pdev->dev.of_node, - "ti,has-pfunc"); - } else if (!dev->pdata) { - dev->pdata = &davinci_i2c_platform_data_default; - } + r = device_property_read_u32(&pdev->dev, "clock-frequency", &prop); + if (r) + prop = DAVINCI_I2C_DEFAULT_BUS_FREQ; + + dev->bus_freq = prop / 1000; + + dev->has_pfunc = device_property_present(&pdev->dev, "ti,has-pfunc"); dev->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(dev->clk)) @@ -849,32 +810,16 @@ static int davinci_i2c_probe(struct platform_device *pdev) adap->algo = &i2c_davinci_algo; adap->dev.parent = &pdev->dev; adap->timeout = DAVINCI_I2C_TIMEOUT; - adap->dev.of_node = pdev->dev.of_node; + adap->dev.of_node = dev_of_node(&pdev->dev); - if (dev->pdata->has_pfunc) + if (dev->has_pfunc) adap->bus_recovery_info = &davinci_i2c_scl_recovery_info; - else if (dev->pdata->gpio_recovery) { - rinfo = &davinci_i2c_gpio_recovery_info; - adap->bus_recovery_info = rinfo; - rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", - GPIOD_OUT_HIGH_OPEN_DRAIN); - if (IS_ERR(rinfo->scl_gpiod)) { - r = PTR_ERR(rinfo->scl_gpiod); - goto err_unuse_clocks; - } - rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN); - if (IS_ERR(rinfo->sda_gpiod)) { - r = PTR_ERR(rinfo->sda_gpiod); - goto err_unuse_clocks; - } - } adap->nr = pdev->id; r = i2c_add_numbered_adapter(adap); if (r) goto err_unuse_clocks; - pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); return 0; @@ -888,7 +833,7 @@ err_pm: return r; } -static int davinci_i2c_remove(struct platform_device *pdev) +static void davinci_i2c_remove(struct platform_device *pdev) { struct davinci_i2c_dev *dev = platform_get_drvdata(pdev); int ret; @@ -897,20 +842,17 @@ static int davinci_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&dev->adapter); - ret = pm_runtime_resume_and_get(&pdev->dev); + ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) - return ret; - - davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0); + dev_err(&pdev->dev, "Failed to resume device\n"); + else + davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0); pm_runtime_dont_use_autosuspend(dev->dev); pm_runtime_put_sync(dev->dev); pm_runtime_disable(dev->dev); - - return 0; } -#ifdef CONFIG_PM static int davinci_i2c_suspend(struct device *dev) { struct davinci_i2c_dev *i2c_dev = dev_get_drvdata(dev); @@ -934,24 +876,23 @@ static int davinci_i2c_resume(struct device *dev) static const struct dev_pm_ops davinci_i2c_pm = { .suspend = davinci_i2c_suspend, .resume = davinci_i2c_resume, - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) }; -#define davinci_i2c_pm_ops (&davinci_i2c_pm) -#else -#define davinci_i2c_pm_ops NULL -#endif - -/* work with hotplug and coldplug */ -MODULE_ALIAS("platform:i2c_davinci"); +static const struct platform_device_id davinci_i2c_driver_ids[] = { + { .name = "i2c_davinci", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(platform, davinci_i2c_driver_ids); static struct platform_driver davinci_i2c_driver = { .probe = davinci_i2c_probe, .remove = davinci_i2c_remove, + .id_table = davinci_i2c_driver_ids, .driver = { .name = "i2c_davinci", - .pm = davinci_i2c_pm_ops, + .pm = pm_sleep_ptr(&davinci_i2c_pm), .of_match_table = davinci_i2c_of_match, }, }; diff --git a/drivers/i2c/busses/i2c-designware-amdisp.c b/drivers/i2c/busses/i2c-designware-amdisp.c new file mode 100644 index 000000000000..450793d5f839 --- /dev/null +++ b/drivers/i2c/busses/i2c-designware-amdisp.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Based on Synopsys DesignWare I2C adapter driver. + * + * Copyright (C) 2025 Advanced Micro Devices, Inc. + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/soc/amd/isp4_misc.h> + +#include "i2c-designware-core.h" + +#define DRV_NAME "amd_isp_i2c_designware" +#define AMD_ISP_I2C_INPUT_CLK 100 /* Mhz */ + +static void amd_isp_dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *i2c_dev) +{ + pm_runtime_disable(i2c_dev->dev); + + if (i2c_dev->shared_with_punit) + pm_runtime_put_noidle(i2c_dev->dev); +} + +static inline u32 amd_isp_dw_i2c_get_clk_rate(struct dw_i2c_dev *i2c_dev) +{ + return AMD_ISP_I2C_INPUT_CLK * 1000; +} + +static int amd_isp_dw_i2c_plat_probe(struct platform_device *pdev) +{ + struct dw_i2c_dev *isp_i2c_dev; + struct i2c_adapter *adap; + int ret; + + isp_i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*isp_i2c_dev), GFP_KERNEL); + if (!isp_i2c_dev) + return -ENOMEM; + isp_i2c_dev->dev = &pdev->dev; + + pdev->dev.init_name = DRV_NAME; + + /* + * Use the polling mode to send/receive the data, because + * no IRQ connection from ISP I2C + */ + isp_i2c_dev->flags |= ACCESS_POLLING; + platform_set_drvdata(pdev, isp_i2c_dev); + + isp_i2c_dev->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(isp_i2c_dev->base)) + return dev_err_probe(&pdev->dev, PTR_ERR(isp_i2c_dev->base), + "failed to get IOMEM resource\n"); + + isp_i2c_dev->get_clk_rate_khz = amd_isp_dw_i2c_get_clk_rate; + ret = i2c_dw_fw_parse_and_configure(isp_i2c_dev); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed to parse i2c dw fwnode and configure\n"); + + i2c_dw_configure(isp_i2c_dev); + + adap = &isp_i2c_dev->adapter; + adap->owner = THIS_MODULE; + scnprintf(adap->name, sizeof(adap->name), AMDISP_I2C_ADAP_NAME); + ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev)); + adap->dev.of_node = pdev->dev.of_node; + /* use dynamically allocated adapter id */ + adap->nr = -1; + + if (isp_i2c_dev->flags & ACCESS_NO_IRQ_SUSPEND) + dev_pm_set_driver_flags(&pdev->dev, + DPM_FLAG_SMART_PREPARE); + else + dev_pm_set_driver_flags(&pdev->dev, + DPM_FLAG_SMART_PREPARE | + DPM_FLAG_SMART_SUSPEND); + + device_enable_async_suspend(&pdev->dev); + + if (isp_i2c_dev->shared_with_punit) + pm_runtime_get_noresume(&pdev->dev); + + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + + ret = i2c_dw_probe(isp_i2c_dev); + if (ret) { + dev_err_probe(&pdev->dev, ret, "i2c_dw_probe failed\n"); + goto error_release_rpm; + } + + pm_runtime_put_sync(&pdev->dev); + + return 0; + +error_release_rpm: + amd_isp_dw_i2c_plat_pm_cleanup(isp_i2c_dev); + pm_runtime_put_sync(&pdev->dev); + return ret; +} + +static void amd_isp_dw_i2c_plat_remove(struct platform_device *pdev) +{ + struct dw_i2c_dev *isp_i2c_dev = platform_get_drvdata(pdev); + + pm_runtime_get_sync(&pdev->dev); + + i2c_del_adapter(&isp_i2c_dev->adapter); + + i2c_dw_disable(isp_i2c_dev); + + pm_runtime_put_sync(&pdev->dev); + amd_isp_dw_i2c_plat_pm_cleanup(isp_i2c_dev); +} + +static int amd_isp_dw_i2c_plat_prepare(struct device *dev) +{ + /* + * If the ACPI companion device object is present for this device, it + * may be accessed during suspend and resume of other devices via I2C + * operation regions, so tell the PM core and middle layers to avoid + * skipping system suspend/resume callbacks for it in that case. + */ + return !has_acpi_companion(dev); +} + +static int amd_isp_dw_i2c_plat_runtime_suspend(struct device *dev) +{ + struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); + + if (i_dev->shared_with_punit) + return 0; + + i2c_dw_disable(i_dev); + i2c_dw_prepare_clk(i_dev, false); + + return 0; +} + +static int amd_isp_dw_i2c_plat_suspend(struct device *dev) +{ + struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); + int ret; + + if (!i_dev) + return -ENODEV; + + ret = amd_isp_dw_i2c_plat_runtime_suspend(dev); + if (!ret) + i2c_mark_adapter_suspended(&i_dev->adapter); + + return ret; +} + +static int amd_isp_dw_i2c_plat_runtime_resume(struct device *dev) +{ + struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); + + if (!i_dev) + return -ENODEV; + + if (!i_dev->shared_with_punit) + i2c_dw_prepare_clk(i_dev, true); + if (i_dev->init) + i_dev->init(i_dev); + + return 0; +} + +static int amd_isp_dw_i2c_plat_resume(struct device *dev) +{ + struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); + + amd_isp_dw_i2c_plat_runtime_resume(dev); + i2c_mark_adapter_resumed(&i_dev->adapter); + + return 0; +} + +static const struct dev_pm_ops amd_isp_dw_i2c_dev_pm_ops = { + .prepare = pm_sleep_ptr(amd_isp_dw_i2c_plat_prepare), + LATE_SYSTEM_SLEEP_PM_OPS(amd_isp_dw_i2c_plat_suspend, amd_isp_dw_i2c_plat_resume) + RUNTIME_PM_OPS(amd_isp_dw_i2c_plat_runtime_suspend, amd_isp_dw_i2c_plat_runtime_resume, NULL) +}; + +/* Work with hotplug and coldplug */ +MODULE_ALIAS("platform:amd_isp_i2c_designware"); + +static struct platform_driver amd_isp_dw_i2c_driver = { + .probe = amd_isp_dw_i2c_plat_probe, + .remove = amd_isp_dw_i2c_plat_remove, + .driver = { + .name = DRV_NAME, + .pm = pm_ptr(&amd_isp_dw_i2c_dev_pm_ops), + }, +}; +module_platform_driver(amd_isp_dw_i2c_driver); + +MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter in AMD ISP"); +MODULE_IMPORT_NS("I2C_DW"); +MODULE_IMPORT_NS("I2C_DW_COMMON"); +MODULE_AUTHOR("Venkata Narendra Kumar Gutta <vengutta@amd.com>"); +MODULE_AUTHOR("Pratap Nirujogi <pratap.nirujogi@amd.com>"); +MODULE_AUTHOR("Bin Du <bin.du@amd.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-designware-amdpsp.c b/drivers/i2c/busses/i2c-designware-amdpsp.c index 8f36167bce62..404571ad61a8 100644 --- a/drivers/i2c/busses/i2c-designware-amdpsp.c +++ b/drivers/i2c/busses/i2c-designware-amdpsp.c @@ -1,41 +1,21 @@ // SPDX-License-Identifier: GPL-2.0 -#include <linux/bitfield.h> -#include <linux/bits.h> #include <linux/i2c.h> -#include <linux/io-64-nonatomic-lo-hi.h> -#include <linux/psp-sev.h> -#include <linux/types.h> +#include <linux/pci.h> +#include <linux/psp-platform-access.h> +#include <linux/psp.h> #include <linux/workqueue.h> -#include <asm/msr.h> - #include "i2c-designware-core.h" -#define MSR_AMD_PSP_ADDR 0xc00110a2 -#define PSP_MBOX_OFFSET 0x10570 -#define PSP_CMD_TIMEOUT_US (500 * USEC_PER_MSEC) - #define PSP_I2C_RESERVATION_TIME_MS 100 -#define PSP_I2C_REQ_BUS_CMD 0x64 #define PSP_I2C_REQ_RETRY_CNT 400 #define PSP_I2C_REQ_RETRY_DELAY_US (25 * USEC_PER_MSEC) #define PSP_I2C_REQ_STS_OK 0x0 #define PSP_I2C_REQ_STS_BUS_BUSY 0x1 #define PSP_I2C_REQ_STS_INV_PARAM 0x3 -#define PSP_MBOX_FIELDS_STS GENMASK(15, 0) -#define PSP_MBOX_FIELDS_CMD GENMASK(23, 16) -#define PSP_MBOX_FIELDS_RESERVED GENMASK(29, 24) -#define PSP_MBOX_FIELDS_RECOVERY BIT(30) -#define PSP_MBOX_FIELDS_READY BIT(31) - -struct psp_req_buffer_hdr { - u32 total_size; - u32 status; -}; - enum psp_i2c_req_type { PSP_I2C_REQ_ACQUIRE, PSP_I2C_REQ_RELEASE, @@ -47,118 +27,13 @@ struct psp_i2c_req { enum psp_i2c_req_type type; }; -struct psp_mbox { - u32 cmd_fields; - u64 i2c_req_addr; -} __packed; - static DEFINE_MUTEX(psp_i2c_access_mutex); static unsigned long psp_i2c_sem_acquired; -static void __iomem *mbox_iomem; static u32 psp_i2c_access_count; static bool psp_i2c_mbox_fail; static struct device *psp_i2c_dev; -/* - * Implementation of PSP-x86 i2c-arbitration mailbox introduced for AMD Cezanne - * family of SoCs. - */ - -static int psp_get_mbox_addr(unsigned long *mbox_addr) -{ - unsigned long long psp_mmio; - - if (rdmsrl_safe(MSR_AMD_PSP_ADDR, &psp_mmio)) - return -EIO; - - *mbox_addr = (unsigned long)(psp_mmio + PSP_MBOX_OFFSET); - - return 0; -} - -static int psp_mbox_probe(void) -{ - unsigned long mbox_addr; - int ret; - - ret = psp_get_mbox_addr(&mbox_addr); - if (ret) - return ret; - - mbox_iomem = ioremap(mbox_addr, sizeof(struct psp_mbox)); - if (!mbox_iomem) - return -ENOMEM; - - return 0; -} - -/* Recovery field should be equal 0 to start sending commands */ -static int psp_check_mbox_recovery(struct psp_mbox __iomem *mbox) -{ - u32 tmp; - - tmp = readl(&mbox->cmd_fields); - - return FIELD_GET(PSP_MBOX_FIELDS_RECOVERY, tmp); -} - -static int psp_wait_cmd(struct psp_mbox __iomem *mbox) -{ - u32 tmp, expected; - - /* Expect mbox_cmd to be cleared and ready bit to be set by PSP */ - expected = FIELD_PREP(PSP_MBOX_FIELDS_READY, 1); - - /* - * Check for readiness of PSP mailbox in a tight loop in order to - * process further as soon as command was consumed. - */ - return readl_poll_timeout(&mbox->cmd_fields, tmp, (tmp == expected), - 0, PSP_CMD_TIMEOUT_US); -} - -/* Status equal to 0 means that PSP succeed processing command */ -static u32 psp_check_mbox_sts(struct psp_mbox __iomem *mbox) -{ - u32 cmd_reg; - - cmd_reg = readl(&mbox->cmd_fields); - - return FIELD_GET(PSP_MBOX_FIELDS_STS, cmd_reg); -} - -static int psp_send_cmd(struct psp_i2c_req *req) -{ - struct psp_mbox __iomem *mbox = mbox_iomem; - phys_addr_t req_addr; - u32 cmd_reg; - - if (psp_check_mbox_recovery(mbox)) - return -EIO; - - if (psp_wait_cmd(mbox)) - return -EBUSY; - - /* - * Fill mailbox with address of command-response buffer, which will be - * used for sending i2c requests as well as reading status returned by - * PSP. Use physical address of buffer, since PSP will map this region. - */ - req_addr = __psp_pa((void *)req); - writeq(req_addr, &mbox->i2c_req_addr); - - /* Write command register to trigger processing */ - cmd_reg = FIELD_PREP(PSP_MBOX_FIELDS_CMD, PSP_I2C_REQ_BUS_CMD); - writel(cmd_reg, &mbox->cmd_fields); - - if (psp_wait_cmd(mbox)) - return -ETIMEDOUT; - - if (psp_check_mbox_sts(mbox)) - return -EIO; - - return 0; -} +static int (*_psp_send_i2c_req)(struct psp_i2c_req *req); /* Helper to verify status returned by PSP */ static int check_i2c_req_sts(struct psp_i2c_req *req) @@ -179,22 +54,36 @@ static int check_i2c_req_sts(struct psp_i2c_req *req) } } -static int psp_send_check_i2c_req(struct psp_i2c_req *req) +/* + * Errors in x86-PSP i2c-arbitration protocol may occur at two levels: + * 1. mailbox communication - PSP is not operational or some IO errors with + * basic communication had happened. + * 2. i2c-requests - PSP refuses to grant i2c arbitration to x86 for too long. + * + * In order to distinguish between these in error handling code all mailbox + * communication errors on the first level (from CCP symbols) will be passed + * up and if -EIO is returned the second level will be checked. + */ +static int psp_send_i2c_req_cezanne(struct psp_i2c_req *req) { - /* - * Errors in x86-PSP i2c-arbitration protocol may occur at two levels: - * 1. mailbox communication - PSP is not operational or some IO errors - * with basic communication had happened; - * 2. i2c-requests - PSP refuses to grant i2c arbitration to x86 for too - * long. - * In order to distinguish between these two in error handling code, all - * errors on the first level (returned by psp_send_cmd) are shadowed by - * -EIO. - */ - if (psp_send_cmd(req)) - return -EIO; + int ret; - return check_i2c_req_sts(req); + ret = psp_send_platform_access_msg(PSP_I2C_REQ_BUS_CMD, (struct psp_request *)req); + if (ret == -EIO) + return check_i2c_req_sts(req); + + return ret; +} + +static int psp_send_i2c_req_doorbell(struct psp_i2c_req *req) +{ + int ret; + + ret = psp_ring_platform_doorbell(req->type, &req->hdr.status); + if (ret == -EIO) + return check_i2c_req_sts(req); + + return ret; } static int psp_send_i2c_req(enum psp_i2c_req_type i2c_req_type) @@ -208,11 +97,11 @@ static int psp_send_i2c_req(enum psp_i2c_req_type i2c_req_type) if (!req) return -ENOMEM; - req->hdr.total_size = sizeof(*req); + req->hdr.payload_size = sizeof(*req); req->type = i2c_req_type; start = jiffies; - ret = read_poll_timeout(psp_send_check_i2c_req, status, + ret = read_poll_timeout(_psp_send_i2c_req, status, (status != -EBUSY), PSP_I2C_REQ_RETRY_DELAY_US, PSP_I2C_REQ_RETRY_CNT * PSP_I2C_REQ_RETRY_DELAY_US, @@ -262,19 +151,16 @@ static void release_bus(void) static void psp_release_i2c_bus_deferred(struct work_struct *work) { - mutex_lock(&psp_i2c_access_mutex); + guard(mutex)(&psp_i2c_access_mutex); /* * If there is any pending transaction, cannot release the bus here. - * psp_release_i2c_bus will take care of this later. + * psp_release_i2c_bus() will take care of this later. */ if (psp_i2c_access_count) - goto cleanup; + return; release_bus(); - -cleanup: - mutex_unlock(&psp_i2c_access_mutex); } static DECLARE_DELAYED_WORK(release_queue, psp_release_i2c_bus_deferred); @@ -282,11 +168,11 @@ static int psp_acquire_i2c_bus(void) { int status; - mutex_lock(&psp_i2c_access_mutex); + guard(mutex)(&psp_i2c_access_mutex); /* Return early if mailbox malfunctioned */ if (psp_i2c_mbox_fail) - goto cleanup; + return 0; psp_i2c_access_count++; @@ -295,11 +181,11 @@ static int psp_acquire_i2c_bus(void) * reservation period. */ if (psp_i2c_sem_acquired) - goto cleanup; + return 0; status = psp_send_i2c_req(PSP_I2C_REQ_ACQUIRE); if (status) - goto cleanup; + return 0; psp_i2c_sem_acquired = jiffies; @@ -312,26 +198,24 @@ static int psp_acquire_i2c_bus(void) * communication with PSP. At any case i2c bus is granted to the caller, * thus always return success. */ -cleanup: - mutex_unlock(&psp_i2c_access_mutex); return 0; } static void psp_release_i2c_bus(void) { - mutex_lock(&psp_i2c_access_mutex); + guard(mutex)(&psp_i2c_access_mutex); - /* Return early if mailbox was malfunctional */ + /* Return early if mailbox was malfunctioned */ if (psp_i2c_mbox_fail) - goto cleanup; + return; /* - * If we are last owner of PSP semaphore, need to release aribtration + * If we are last owner of PSP semaphore, need to release arbitration * via mailbox. */ psp_i2c_access_count--; if (psp_i2c_access_count) - goto cleanup; + return; /* * Send a release command to PSP if the semaphore reservation timeout @@ -339,16 +223,13 @@ static void psp_release_i2c_bus(void) */ if (!delayed_work_pending(&release_queue)) release_bus(); - -cleanup: - mutex_unlock(&psp_i2c_access_mutex); } /* * Locking methods are based on the default implementation from - * drivers/i2c/i2c-core-base.c, but with psp acquire and release operations + * drivers/i2c/i2c-core-base.c, but with PSP acquire and release operations * added. With this in place we can ensure that i2c clients on the bus shared - * with psp are able to lock HW access to the bus for arbitrary number of + * with PSP are able to lock HW access to the bus for arbitrary number of * operations - that is e.g. write-wait-read. */ static void i2c_adapter_dw_psp_lock_bus(struct i2c_adapter *adapter, @@ -387,7 +268,10 @@ static const struct i2c_lock_operations i2c_dw_psp_lock_ops = { int i2c_dw_amdpsp_probe_lock_support(struct dw_i2c_dev *dev) { - int ret; + struct pci_dev *rdev; + + if (!IS_REACHABLE(CONFIG_CRYPTO_DEV_CCP_DD)) + return -ENODEV; if (!dev) return -ENODEV; @@ -399,11 +283,18 @@ int i2c_dw_amdpsp_probe_lock_support(struct dw_i2c_dev *dev) if (psp_i2c_dev) return -EEXIST; - psp_i2c_dev = dev->dev; + /* Cezanne uses platform mailbox, Mendocino and later use doorbell */ + rdev = pci_get_domain_bus_and_slot(0, 0, PCI_DEVFN(0, 0)); + if (rdev->device == 0x1630) + _psp_send_i2c_req = psp_send_i2c_req_cezanne; + else + _psp_send_i2c_req = psp_send_i2c_req_doorbell; + pci_dev_put(rdev); - ret = psp_mbox_probe(); - if (ret) - return ret; + if (psp_check_platform_access_status()) + return -EPROBE_DEFER; + + psp_i2c_dev = dev->dev; dev_info(psp_i2c_dev, "I2C bus managed by AMD PSP\n"); @@ -417,9 +308,3 @@ int i2c_dw_amdpsp_probe_lock_support(struct dw_i2c_dev *dev) return 0; } - -/* Unmap area used as a mailbox with PSP */ -void i2c_dw_amdpsp_remove_lock_support(struct dw_i2c_dev *dev) -{ - iounmap(mbox_iomem); -} diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index 581e02cc979a..5b1e8f74c4ac 100644 --- a/drivers/i2c/busses/i2c-designware-common.c +++ b/drivers/i2c/busses/i2c-designware-common.c @@ -8,6 +8,9 @@ * Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2009 Provigent Ltd. */ + +#define DEFAULT_SYMBOL_NAMESPACE "I2C_DW_COMMON" + #include <linux/acpi.h> #include <linux/clk.h> #include <linux/delay.h> @@ -20,7 +23,10 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/of.h> +#include <linux/pm.h> #include <linux/pm_runtime.h> +#include <linux/property.h> #include <linux/regmap.h> #include <linux/swab.h> #include <linux/types.h> @@ -28,7 +34,7 @@ #include "i2c-designware-core.h" -static char *abort_sources[] = { +static const char *const abort_sources[] = { [ABRT_7B_ADDR_NOACK] = "slave address not acknowledged (7bit mode)", [ABRT_10ADDR1_NOACK] = @@ -63,7 +69,7 @@ static int dw_reg_read(void *context, unsigned int reg, unsigned int *val) { struct dw_i2c_dev *dev = context; - *val = readl_relaxed(dev->base + reg); + *val = readl(dev->base + reg); return 0; } @@ -72,7 +78,7 @@ static int dw_reg_write(void *context, unsigned int reg, unsigned int val) { struct dw_i2c_dev *dev = context; - writel_relaxed(val, dev->base + reg); + writel(val, dev->base + reg); return 0; } @@ -81,7 +87,7 @@ static int dw_reg_read_swab(void *context, unsigned int reg, unsigned int *val) { struct dw_i2c_dev *dev = context; - *val = swab32(readl_relaxed(dev->base + reg)); + *val = swab32(readl(dev->base + reg)); return 0; } @@ -90,7 +96,7 @@ static int dw_reg_write_swab(void *context, unsigned int reg, unsigned int val) { struct dw_i2c_dev *dev = context; - writel_relaxed(swab32(val), dev->base + reg); + writel(swab32(val), dev->base + reg); return 0; } @@ -99,8 +105,8 @@ static int dw_reg_read_word(void *context, unsigned int reg, unsigned int *val) { struct dw_i2c_dev *dev = context; - *val = readw_relaxed(dev->base + reg) | - (readw_relaxed(dev->base + reg + 2) << 16); + *val = readw(dev->base + reg) | + (readw(dev->base + reg + 2) << 16); return 0; } @@ -109,8 +115,8 @@ static int dw_reg_write_word(void *context, unsigned int reg, unsigned int val) { struct dw_i2c_dev *dev = context; - writew_relaxed(val, dev->base + reg); - writew_relaxed(val >> 16, dev->base + reg + 2); + writew(val, dev->base + reg); + writew(val >> 16, dev->base + reg + 2); return 0; } @@ -122,6 +128,8 @@ static int dw_reg_write_word(void *context, unsigned int reg, unsigned int val) * Autodetects needed register access mode and creates the regmap with * corresponding read/write callbacks. This must be called before doing any * other register access. + * + * Return: 0 on success, or negative errno otherwise. */ int i2c_dw_init_regmap(struct dw_i2c_dev *dev) { @@ -169,7 +177,7 @@ int i2c_dw_init_regmap(struct dw_i2c_dev *dev) /* * Note we'll check the return value of the regmap IO accessors only * at the probe stage. The rest of the code won't do this because - * basically we have MMIO-based regmap so non of the read/write methods + * basically we have MMIO-based regmap, so none of the read/write methods * can fail. */ dev->map = devm_regmap_init(dev->dev, NULL, dev, &map_cfg); @@ -188,7 +196,7 @@ static const u32 supported_speeds[] = { I2C_MAX_STANDARD_MODE_FREQ, }; -int i2c_dw_validate_speed(struct dw_i2c_dev *dev) +static int i2c_dw_validate_speed(struct dw_i2c_dev *dev) { struct i2c_timings *t = &dev->timings; unsigned int i; @@ -208,7 +216,44 @@ int i2c_dw_validate_speed(struct dw_i2c_dev *dev) return -EINVAL; } -EXPORT_SYMBOL_GPL(i2c_dw_validate_speed); + +#ifdef CONFIG_OF + +#include <linux/platform_device.h> + +#define MSCC_ICPU_CFG_TWI_DELAY 0x0 +#define MSCC_ICPU_CFG_TWI_DELAY_ENABLE BIT(0) +#define MSCC_ICPU_CFG_TWI_SPIKE_FILTER 0x4 + +static int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev) +{ + writel((dev->sda_hold_time << 1) | MSCC_ICPU_CFG_TWI_DELAY_ENABLE, + dev->ext + MSCC_ICPU_CFG_TWI_DELAY); + + return 0; +} + +static void i2c_dw_of_configure(struct device *device) +{ + struct platform_device *pdev = to_platform_device(device); + struct dw_i2c_dev *dev = dev_get_drvdata(device); + + switch (dev->flags & MODEL_MASK) { + case MODEL_MSCC_OCELOT: + dev->ext = devm_platform_ioremap_resource(pdev, 1); + if (!IS_ERR(dev->ext)) + dev->set_sda_hold_time = mscc_twi_set_sda_hold_time; + break; + default: + break; + } +} + +#else /* CONFIG_OF */ + +static inline void i2c_dw_of_configure(struct device *device) { } + +#endif /* CONFIG_OF */ #ifdef CONFIG_ACPI @@ -255,7 +300,7 @@ static void i2c_dw_acpi_params(struct device *device, char method[], kfree(buf.pointer); } -int i2c_dw_acpi_configure(struct device *device) +static void i2c_dw_acpi_configure(struct device *device) { struct dw_i2c_dev *dev = dev_get_drvdata(device); struct i2c_timings *t = &dev->timings; @@ -285,10 +330,7 @@ int i2c_dw_acpi_configure(struct device *device) dev->sda_hold_time = fs_ht; break; } - - return 0; } -EXPORT_SYMBOL_GPL(i2c_dw_acpi_configure); static u32 i2c_dw_acpi_round_bus_speed(struct device *device) { @@ -297,7 +339,7 @@ static u32 i2c_dw_acpi_round_bus_speed(struct device *device) acpi_speed = i2c_acpi_find_bus_speed(device); /* - * Some DSTDs use a non standard speed, round down to the lowest + * Some DSDTs use a non standard speed, round down to the lowest * standard speed. */ for (i = 0; i < ARRAY_SIZE(supported_speeds); i++) { @@ -310,11 +352,13 @@ static u32 i2c_dw_acpi_round_bus_speed(struct device *device) #else /* CONFIG_ACPI */ +static inline void i2c_dw_acpi_configure(struct device *device) { } + static inline u32 i2c_dw_acpi_round_bus_speed(struct device *device) { return 0; } #endif /* CONFIG_ACPI */ -void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev) +static void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev) { u32 acpi_speed = i2c_dw_acpi_round_bus_speed(dev->dev); struct i2c_timings *t = &dev->timings; @@ -330,50 +374,75 @@ void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev) else t->bus_freq_hz = I2C_MAX_FAST_MODE_FREQ; } -EXPORT_SYMBOL_GPL(i2c_dw_adjust_bus_speed); -u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset) +int i2c_dw_fw_parse_and_configure(struct dw_i2c_dev *dev) { + struct i2c_timings *t = &dev->timings; + struct device *device = dev->dev; + struct fwnode_handle *fwnode = dev_fwnode(device); + + i2c_parse_fw_timings(device, t, false); + + if (device_property_read_u32(device, "snps,bus-capacitance-pf", &dev->bus_capacitance_pF)) + dev->bus_capacitance_pF = 100; + + dev->clk_freq_optimized = device_property_read_bool(device, "snps,clk-freq-optimized"); + + i2c_dw_adjust_bus_speed(dev); + + if (is_of_node(fwnode)) + i2c_dw_of_configure(device); + else if (is_acpi_node(fwnode)) + i2c_dw_acpi_configure(device); + + return i2c_dw_validate_speed(dev); +} +EXPORT_SYMBOL_GPL(i2c_dw_fw_parse_and_configure); + +static u32 i2c_dw_read_scl_reg(struct dw_i2c_dev *dev, u32 reg) +{ + u32 val; + int ret; + + ret = i2c_dw_acquire_lock(dev); + if (ret) + return 0; + + ret = regmap_read(dev->map, reg, &val); + i2c_dw_release_lock(dev); + + return ret ? 0 : val; +} + +u32 i2c_dw_scl_hcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, + u32 tSYMBOL, u32 tf, int offset) +{ + if (!ic_clk) + return i2c_dw_read_scl_reg(dev, reg); + /* - * DesignWare I2C core doesn't seem to have solid strategy to meet - * the tHD;STA timing spec. Configuring _HCNT based on tHIGH spec - * will result in violation of the tHD;STA spec. + * Conditional expression: + * + * IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf) + * + * This is just experimental rule; the tHD;STA period turned + * out to be proportinal to (_HCNT + 3). With this setting, + * we could meet both tHIGH and tHD;STA timing specs. + * + * If unsure, you'd better to take this alternative. + * + * The reason why we need to take into account "tf" here, + * is the same as described in i2c_dw_scl_lcnt(). */ - if (cond) - /* - * Conditional expression: - * - * IC_[FS]S_SCL_HCNT + (1+4+3) >= IC_CLK * tHIGH - * - * This is based on the DW manuals, and represents an ideal - * configuration. The resulting I2C bus speed will be - * faster than any of the others. - * - * If your hardware is free from tHD;STA issue, try this one. - */ - return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * tSYMBOL, MICRO) - - 8 + offset; - else - /* - * Conditional expression: - * - * IC_[FS]S_SCL_HCNT + 3 >= IC_CLK * (tHD;STA + tf) - * - * This is just experimental rule; the tHD;STA period turned - * out to be proportinal to (_HCNT + 3). With this setting, - * we could meet both tHIGH and tHD;STA timing specs. - * - * If unsure, you'd better to take this alternative. - * - * The reason why we need to take into account "tf" here, - * is the same as described in i2c_dw_scl_lcnt(). - */ - return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tSYMBOL + tf), MICRO) - - 3 + offset; + return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tSYMBOL + tf), MICRO) - 3 + offset; } -u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) +u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, + u32 tLOW, u32 tf, int offset) { + if (!ic_clk) + return i2c_dw_read_scl_reg(dev, reg); + /* * Conditional expression: * @@ -385,13 +454,12 @@ u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) * account the fall time of SCL signal (tf). Default tf value * should be 0.3 us, for safety. */ - return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tLOW + tf), MICRO) - - 1 + offset; + return DIV_ROUND_CLOSEST_ULL((u64)ic_clk * (tLOW + tf), MICRO) - 1 + offset; } int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev) { - u32 reg; + unsigned int reg; int ret; ret = i2c_dw_acquire_lock(dev); @@ -441,8 +509,41 @@ err_release_lock: void __i2c_dw_disable(struct dw_i2c_dev *dev) { + struct i2c_timings *t = &dev->timings; + unsigned int raw_intr_stats, ic_stats; + unsigned int enable; int timeout = 100; - u32 status; + bool abort_needed; + unsigned int status; + int ret; + + regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &raw_intr_stats); + regmap_read(dev->map, DW_IC_STATUS, &ic_stats); + regmap_read(dev->map, DW_IC_ENABLE, &enable); + + abort_needed = (raw_intr_stats & DW_IC_INTR_MST_ON_HOLD) || + (ic_stats & DW_IC_STATUS_MASTER_HOLD_TX_FIFO_EMPTY); + if (abort_needed) { + if (!(enable & DW_IC_ENABLE_ENABLE)) { + regmap_write(dev->map, DW_IC_ENABLE, DW_IC_ENABLE_ENABLE); + /* + * Wait 10 times the signaling period of the highest I2C + * transfer supported by the driver (for 400KHz this is + * 25us) to ensure the I2C ENABLE bit is already set + * as described in the DesignWare I2C databook. + */ + fsleep(DIV_ROUND_CLOSEST_ULL(10 * MICRO, t->bus_freq_hz)); + /* Set ENABLE bit before setting ABORT */ + enable |= DW_IC_ENABLE_ENABLE; + } + + regmap_write(dev->map, DW_IC_ENABLE, enable | DW_IC_ENABLE_ABORT); + ret = regmap_read_poll_timeout(dev->map, DW_IC_ENABLE, enable, + !(enable & DW_IC_ENABLE_ABORT), 10, + 100); + if (ret) + dev_err(dev->dev, "timeout while trying to abort current transfer\n"); + } do { __i2c_dw_disable_nowait(dev); @@ -456,7 +557,7 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev) /* * Wait 10 times the signaling period of the highest I2C - * transfer supported by the driver (for 400KHz this is + * transfer supported by the driver (for 400kHz this is * 25us) as described in the DesignWare I2C databook. */ usleep_range(25, 250); @@ -465,14 +566,16 @@ void __i2c_dw_disable(struct dw_i2c_dev *dev) dev_warn(dev->dev, "timeout in disabling adapter\n"); } -unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) +u32 i2c_dw_clk_rate(struct dw_i2c_dev *dev) { /* * Clock is not necessary if we got LCNT/HCNT values directly from * the platform code. */ - if (WARN_ON_ONCE(!dev->get_clk_rate_khz)) + if (!dev->get_clk_rate_khz) { + dev_dbg_once(dev->dev, "Callback get_clk_rate_khz() is not defined\n"); return 0; + } return dev->get_clk_rate_khz(dev); } @@ -527,7 +630,7 @@ void i2c_dw_release_lock(struct dw_i2c_dev *dev) */ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) { - u32 status; + unsigned int status; int ret; ret = regmap_read_poll_timeout(dev->map, DW_IC_STATUS, status, @@ -563,17 +666,26 @@ int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) if (abort_source & DW_IC_TX_ARB_LOST) return -EAGAIN; - else if (abort_source & DW_IC_TX_ABRT_GCALL_READ) + if (abort_source & DW_IC_TX_ABRT_GCALL_READ) return -EINVAL; /* wrong msgs[] data */ - else - return -EIO; + + return -EIO; } int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev) { - u32 param, tx_fifo_depth, rx_fifo_depth; + u32 tx_fifo_depth, rx_fifo_depth; + unsigned int param; int ret; + /* DW_IC_COMP_PARAM_1 not implement for IP issue */ + if ((dev->flags & MODEL_MASK) == MODEL_WANGXUN_SP) { + dev->tx_fifo_depth = TXGBE_TX_FIFO_DEPTH; + dev->rx_fifo_depth = TXGBE_RX_FIFO_DEPTH; + + return 0; + } + /* * Try to detect the FIFO depth if not set by interface driver, * the depth could be from 2 to 256 from HW spec. @@ -611,7 +723,7 @@ u32 i2c_dw_func(struct i2c_adapter *adap) void i2c_dw_disable(struct dw_i2c_dev *dev) { - u32 dummy; + unsigned int dummy; int ret; ret = i2c_dw_acquire_lock(dev); @@ -622,11 +734,89 @@ void i2c_dw_disable(struct dw_i2c_dev *dev) __i2c_dw_disable(dev); /* Disable all interrupts */ - regmap_write(dev->map, DW_IC_INTR_MASK, 0); + __i2c_dw_write_intr_mask(dev, 0); regmap_read(dev->map, DW_IC_CLR_INTR, &dummy); i2c_dw_release_lock(dev); } +EXPORT_SYMBOL_GPL(i2c_dw_disable); + +int i2c_dw_probe(struct dw_i2c_dev *dev) +{ + device_set_node(&dev->adapter.dev, dev_fwnode(dev->dev)); + + switch (dev->mode) { + case DW_IC_SLAVE: + return i2c_dw_probe_slave(dev); + case DW_IC_MASTER: + return i2c_dw_probe_master(dev); + default: + dev_err(dev->dev, "Wrong operation mode: %d\n", dev->mode); + return -EINVAL; + } +} +EXPORT_SYMBOL_GPL(i2c_dw_probe); + +static int i2c_dw_prepare(struct device *device) +{ + /* + * If the ACPI companion device object is present for this device, + * it may be accessed during suspend and resume of other devices via + * I2C operation regions, so tell the PM core and middle layers to + * avoid skipping system suspend/resume callbacks for it in that case. + */ + return !has_acpi_companion(device); +} + +static int i2c_dw_runtime_suspend(struct device *device) +{ + struct dw_i2c_dev *dev = dev_get_drvdata(device); + + if (dev->shared_with_punit) + return 0; + + i2c_dw_disable(dev); + i2c_dw_prepare_clk(dev, false); + + return 0; +} + +static int i2c_dw_suspend(struct device *device) +{ + struct dw_i2c_dev *dev = dev_get_drvdata(device); + + i2c_mark_adapter_suspended(&dev->adapter); + + return i2c_dw_runtime_suspend(device); +} + +static int i2c_dw_runtime_resume(struct device *device) +{ + struct dw_i2c_dev *dev = dev_get_drvdata(device); + + if (!dev->shared_with_punit) + i2c_dw_prepare_clk(dev, true); + + dev->init(dev); + + return 0; +} + +static int i2c_dw_resume(struct device *device) +{ + struct dw_i2c_dev *dev = dev_get_drvdata(device); + + i2c_dw_runtime_resume(device); + i2c_mark_adapter_resumed(&dev->adapter); + + return 0; +} + +EXPORT_GPL_DEV_PM_OPS(i2c_dw_dev_pm_ops) = { + .prepare = pm_sleep_ptr(i2c_dw_prepare), + LATE_SYSTEM_SLEEP_PM_OPS(i2c_dw_suspend, i2c_dw_resume) + RUNTIME_PM_OPS(i2c_dw_runtime_suspend, i2c_dw_runtime_resume, NULL) +}; MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter core"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 95ebc5eaa5d1..bb5ce0a382f9 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -10,11 +10,10 @@ */ #include <linux/bits.h> -#include <linux/compiler_types.h> #include <linux/completion.h> -#include <linux/dev_printk.h> #include <linux/errno.h> #include <linux/i2c.h> +#include <linux/pm.h> #include <linux/regmap.h> #include <linux/types.h> @@ -37,8 +36,10 @@ #define DW_IC_CON_STOP_DET_IFADDRESSED BIT(7) #define DW_IC_CON_TX_EMPTY_CTRL BIT(8) #define DW_IC_CON_RX_FIFO_FULL_HLD_CTRL BIT(9) +#define DW_IC_CON_BUS_CLEAR_CTRL BIT(11) #define DW_IC_DATA_CMD_DAT GENMASK(7, 0) +#define DW_IC_DATA_CMD_FIRST_DATA_BYTE BIT(11) /* * Registers offset @@ -77,6 +78,7 @@ #define DW_IC_TX_ABRT_SOURCE 0x80 #define DW_IC_ENABLE_STATUS 0x9c #define DW_IC_CLR_RESTART_DET 0xa8 +#define DW_IC_SMBUS_INTR_MASK 0xcc #define DW_IC_COMP_PARAM_1 0xf4 #define DW_IC_COMP_VERSION 0xf8 #define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A /* "111*" == v1.11* */ @@ -96,6 +98,7 @@ #define DW_IC_INTR_START_DET BIT(10) #define DW_IC_INTR_GEN_CALL BIT(11) #define DW_IC_INTR_RESTART_DET BIT(12) +#define DW_IC_INTR_MST_ON_HOLD BIT(13) #define DW_IC_INTR_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \ DW_IC_INTR_TX_ABRT | \ @@ -106,11 +109,15 @@ DW_IC_INTR_RX_UNDER | \ DW_IC_INTR_RD_REQ) +#define DW_IC_ENABLE_ENABLE BIT(0) +#define DW_IC_ENABLE_ABORT BIT(1) + #define DW_IC_STATUS_ACTIVITY BIT(0) #define DW_IC_STATUS_TFE BIT(2) #define DW_IC_STATUS_RFNE BIT(3) #define DW_IC_STATUS_MASTER_ACTIVITY BIT(5) #define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6) +#define DW_IC_STATUS_MASTER_HOLD_TX_FIFO_EMPTY BIT(7) #define DW_IC_SDA_HOLD_RX_SHIFT 16 #define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, 16) @@ -137,10 +144,10 @@ #define DW_IC_SLAVE 1 /* - * Hardware abort codes from the DW_IC_TX_ABRT_SOURCE register + * Hardware abort codes from the DW_IC_TX_ABRT_SOURCE register. * - * Only expected abort codes are listed here - * refer to the datasheet for the full list + * Only expected abort codes are listed here, + * refer to the datasheet for the full list. */ #define ABRT_7B_ADDR_NOACK 0 #define ABRT_10ADDR1_NOACK 1 @@ -195,7 +202,7 @@ struct reset_control; * @rst: optional reset for the controller * @slave: represent an I2C slave device * @get_clk_rate_khz: callback to retrieve IP specific bus speed - * @cmd_err: run time hadware error code + * @cmd_err: run time hardware error code * @msgs: points to an array of messages currently being transferred * @msgs_num: the number of elements in msgs * @msg_write_idx: the element index of the current tx message in the msgs array @@ -207,6 +214,7 @@ struct reset_control; * @msg_err: error status of the current transfer * @status: i2c master status, one of STATUS_* * @abort_source: copy of the TX_ABRT_SOURCE register + * @sw_mask: SW mask of DW_IC_INTR_MASK used in polling mode * @irq: interrupt number for the i2c master * @flags: platform specific flags like type of IO accessors or model * @adapter: i2c subsystem adapter node @@ -230,12 +238,15 @@ struct reset_control; * @release_lock: function to release a hardware lock on the bus * @semaphore_idx: Index of table with semaphore type attached to the bus. It's * -1 if there is no semaphore. - * @shared_with_punit: true if this bus is shared with the SoCs PUNIT - * @disable: function to disable the controller + * @shared_with_punit: true if this bus is shared with the SoC's PUNIT * @init: function to initialize the I2C hardware * @set_sda_hold_time: callback to retrieve IP specific SDA hold timing * @mode: operation mode - DW_IC_MASTER or DW_IC_SLAVE * @rinfo: I²C GPIO recovery information + * @bus_capacitance_pF: bus capacitance in picofarads + * @clk_freq_optimized: if this value is true, it means the hardware reduces + * its internal clock frequency by reducing the internal latency required + * to generate the high period and low period of SCL line. * * HCNT and LCNT parameters can be used if the platform knows more accurate * values than the one computed based only on the input clock frequency. @@ -264,7 +275,8 @@ struct dw_i2c_dev { u8 *rx_buf; int msg_err; unsigned int status; - u32 abort_source; + unsigned int abort_source; + unsigned int sw_mask; int irq; u32 flags; struct i2c_adapter adapter; @@ -288,20 +300,23 @@ struct dw_i2c_dev { void (*release_lock)(void); int semaphore_idx; bool shared_with_punit; - void (*disable)(struct dw_i2c_dev *dev); int (*init)(struct dw_i2c_dev *dev); int (*set_sda_hold_time)(struct dw_i2c_dev *dev); int mode; struct i2c_bus_recovery_info rinfo; + u32 bus_capacitance_pF; + bool clk_freq_optimized; }; #define ACCESS_INTR_MASK BIT(0) #define ACCESS_NO_IRQ_SUSPEND BIT(1) #define ARBITRATION_SEMAPHORE BIT(2) +#define ACCESS_POLLING BIT(3) #define MODEL_MSCC_OCELOT BIT(8) #define MODEL_BAIKAL_BT1 BIT(9) #define MODEL_AMD_NAVI_GPU BIT(10) +#define MODEL_WANGXUN_SP BIT(11) #define MODEL_MASK GENMASK(11, 8) /* @@ -311,16 +326,20 @@ struct dw_i2c_dev { #define AMD_UCSI_INTR_REG 0x474 #define AMD_UCSI_INTR_EN 0xd +#define TXGBE_TX_FIFO_DEPTH 4 +#define TXGBE_RX_FIFO_DEPTH 1 + struct i2c_dw_semaphore_callbacks { int (*probe)(struct dw_i2c_dev *dev); - void (*remove)(struct dw_i2c_dev *dev); }; int i2c_dw_init_regmap(struct dw_i2c_dev *dev); -u32 i2c_dw_scl_hcnt(u32 ic_clk, u32 tSYMBOL, u32 tf, int cond, int offset); -u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset); +u32 i2c_dw_scl_hcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, + u32 tSYMBOL, u32 tf, int offset); +u32 i2c_dw_scl_lcnt(struct dw_i2c_dev *dev, unsigned int reg, u32 ic_clk, + u32 tLOW, u32 tf, int offset); int i2c_dw_set_sda_hold(struct dw_i2c_dev *dev); -unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev); +u32 i2c_dw_clk_rate(struct dw_i2c_dev *dev); int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare); int i2c_dw_acquire_lock(struct dw_i2c_dev *dev); void i2c_dw_release_lock(struct dw_i2c_dev *dev); @@ -328,7 +347,8 @@ int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev); int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev); int i2c_dw_set_fifo_size(struct dw_i2c_dev *dev); u32 i2c_dw_func(struct i2c_adapter *adap); -void i2c_dw_disable(struct dw_i2c_dev *dev); + +extern const struct dev_pm_ops i2c_dw_dev_pm_ops; static inline void __i2c_dw_enable(struct dw_i2c_dev *dev) { @@ -342,7 +362,26 @@ static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev) dev->status &= ~STATUS_ACTIVE; } +static inline void __i2c_dw_write_intr_mask(struct dw_i2c_dev *dev, + unsigned int intr_mask) +{ + unsigned int val = dev->flags & ACCESS_POLLING ? 0 : intr_mask; + + regmap_write(dev->map, DW_IC_INTR_MASK, val); + dev->sw_mask = intr_mask; +} + +static inline void __i2c_dw_read_intr_mask(struct dw_i2c_dev *dev, + unsigned int *intr_mask) +{ + if (!(dev->flags & ACCESS_POLLING)) + regmap_read(dev->map, DW_IC_INTR_MASK, intr_mask); + else + *intr_mask = dev->sw_mask; +} + void __i2c_dw_disable(struct dw_i2c_dev *dev); +void i2c_dw_disable(struct dw_i2c_dev *dev); extern void i2c_dw_configure_master(struct dw_i2c_dev *dev); extern int i2c_dw_probe_master(struct dw_i2c_dev *dev); @@ -355,19 +394,6 @@ static inline void i2c_dw_configure_slave(struct dw_i2c_dev *dev) { } static inline int i2c_dw_probe_slave(struct dw_i2c_dev *dev) { return -EINVAL; } #endif -static inline int i2c_dw_probe(struct dw_i2c_dev *dev) -{ - switch (dev->mode) { - case DW_IC_SLAVE: - return i2c_dw_probe_slave(dev); - case DW_IC_MASTER: - return i2c_dw_probe_master(dev); - default: - dev_err(dev->dev, "Wrong operation mode: %d\n", dev->mode); - return -EINVAL; - } -} - static inline void i2c_dw_configure(struct dw_i2c_dev *dev) { if (i2c_detect_slave_mode(dev->dev)) @@ -376,20 +402,14 @@ static inline void i2c_dw_configure(struct dw_i2c_dev *dev) i2c_dw_configure_master(dev); } +int i2c_dw_probe(struct dw_i2c_dev *dev); + #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL) int i2c_dw_baytrail_probe_lock_support(struct dw_i2c_dev *dev); #endif #if IS_ENABLED(CONFIG_I2C_DESIGNWARE_AMDPSP) int i2c_dw_amdpsp_probe_lock_support(struct dw_i2c_dev *dev); -void i2c_dw_amdpsp_remove_lock_support(struct dw_i2c_dev *dev); #endif -int i2c_dw_validate_speed(struct dw_i2c_dev *dev); -void i2c_dw_adjust_bus_speed(struct dw_i2c_dev *dev); - -#if IS_ENABLED(CONFIG_ACPI) -int i2c_dw_acpi_configure(struct device *device); -#else -static inline int i2c_dw_acpi_configure(struct device *device) { return -ENODEV; } -#endif +int i2c_dw_fw_parse_and_configure(struct dw_i2c_dev *dev); diff --git a/drivers/i2c/busses/i2c-designware-master.c b/drivers/i2c/busses/i2c-designware-master.c index 45f569155bfe..45bfca05bb30 100644 --- a/drivers/i2c/busses/i2c-designware-master.c +++ b/drivers/i2c/busses/i2c-designware-master.c @@ -8,6 +8,9 @@ * Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2009 Provigent Ltd. */ + +#define DEFAULT_SYMBOL_NAMESPACE "I2C_DW" + #include <linux/delay.h> #include <linux/err.h> #include <linux/errno.h> @@ -17,6 +20,7 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> +#include <linux/pinctrl/consumer.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> #include <linux/reset.h> @@ -39,7 +43,7 @@ static void i2c_dw_configure_fifo_master(struct dw_i2c_dev *dev) static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) { - u32 comp_param1; + unsigned int comp_param1; u32 sda_falling_time, scl_falling_time; struct i2c_timings *t = &dev->timings; const char *fp_str = ""; @@ -63,13 +67,16 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) if (!dev->ss_hcnt || !dev->ss_lcnt) { ic_clk = i2c_dw_clk_rate(dev); dev->ss_hcnt = - i2c_dw_scl_hcnt(ic_clk, + i2c_dw_scl_hcnt(dev, + DW_IC_SS_SCL_HCNT, + ic_clk, 4000, /* tHD;STA = tHIGH = 4.0 us */ sda_falling_time, - 0, /* 0: DW default, 1: Ideal */ 0); /* No offset */ dev->ss_lcnt = - i2c_dw_scl_lcnt(ic_clk, + i2c_dw_scl_lcnt(dev, + DW_IC_SS_SCL_LCNT, + ic_clk, 4700, /* tLOW = 4.7 us */ scl_falling_time, 0); /* No offset */ @@ -93,13 +100,16 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) } else { ic_clk = i2c_dw_clk_rate(dev); dev->fs_hcnt = - i2c_dw_scl_hcnt(ic_clk, + i2c_dw_scl_hcnt(dev, + DW_IC_FS_SCL_HCNT, + ic_clk, 260, /* tHIGH = 260 ns */ sda_falling_time, - 0, /* DW default */ 0); /* No offset */ dev->fs_lcnt = - i2c_dw_scl_lcnt(ic_clk, + i2c_dw_scl_lcnt(dev, + DW_IC_FS_SCL_LCNT, + ic_clk, 500, /* tLOW = 500 ns */ scl_falling_time, 0); /* No offset */ @@ -113,13 +123,16 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) if (!dev->fs_hcnt || !dev->fs_lcnt) { ic_clk = i2c_dw_clk_rate(dev); dev->fs_hcnt = - i2c_dw_scl_hcnt(ic_clk, + i2c_dw_scl_hcnt(dev, + DW_IC_FS_SCL_HCNT, + ic_clk, 600, /* tHD;STA = tHIGH = 0.6 us */ sda_falling_time, - 0, /* 0: DW default, 1: Ideal */ 0); /* No offset */ dev->fs_lcnt = - i2c_dw_scl_lcnt(ic_clk, + i2c_dw_scl_lcnt(dev, + DW_IC_FS_SCL_LCNT, + ic_clk, 1300, /* tLOW = 1.3 us */ scl_falling_time, 0); /* No offset */ @@ -139,16 +152,38 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) dev->hs_hcnt = 0; dev->hs_lcnt = 0; } else if (!dev->hs_hcnt || !dev->hs_lcnt) { + u32 t_high, t_low; + + /* + * The legal values stated in the databook for bus + * capacitance are only 100pF and 400pF. + * If dev->bus_capacitance_pF is greater than or equals + * to 400, t_high and t_low are assumed to be + * appropriate values for 400pF, otherwise 100pF. + */ + if (dev->bus_capacitance_pF >= 400) { + /* assume bus capacitance is 400pF */ + t_high = dev->clk_freq_optimized ? 160 : 120; + t_low = 320; + } else { + /* assume bus capacitance is 100pF */ + t_high = 60; + t_low = dev->clk_freq_optimized ? 120 : 160; + } + ic_clk = i2c_dw_clk_rate(dev); dev->hs_hcnt = - i2c_dw_scl_hcnt(ic_clk, - 160, /* tHIGH = 160 ns */ + i2c_dw_scl_hcnt(dev, + DW_IC_HS_SCL_HCNT, + ic_clk, + t_high, sda_falling_time, - 0, /* DW default */ 0); /* No offset */ dev->hs_lcnt = - i2c_dw_scl_lcnt(ic_clk, - 320, /* tLOW = 320 ns */ + i2c_dw_scl_lcnt(dev, + DW_IC_HS_SCL_LCNT, + ic_clk, + t_low, scl_falling_time, 0); /* No offset */ } @@ -165,12 +200,14 @@ static int i2c_dw_set_timings_master(struct dw_i2c_dev *dev) } /** - * i2c_dw_init_master() - Initialize the designware I2C master hardware + * i2c_dw_init_master() - Initialize the DesignWare I2C master hardware * @dev: device private data * * This functions configures and enables the I2C master. * This function is called during I2C init function, and in case of timeout at * run time. + * + * Return: 0 on success, or negative errno otherwise. */ static int i2c_dw_init_master(struct dw_i2c_dev *dev) { @@ -183,6 +220,13 @@ static int i2c_dw_init_master(struct dw_i2c_dev *dev) /* Disable the adapter */ __i2c_dw_disable(dev); + /* + * Mask SMBus interrupts to block storms from broken + * firmware that leaves IC_SMBUS=1; the handler never + * services them. + */ + regmap_write(dev->map, DW_IC_SMBUS_INTR_MASK, 0); + /* Write standard speed timing parameters */ regmap_write(dev->map, DW_IC_SS_SCL_HCNT, dev->ss_hcnt); regmap_write(dev->map, DW_IC_SS_SCL_LCNT, dev->ss_lcnt); @@ -211,7 +255,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) { struct i2c_msg *msgs = dev->msgs; u32 ic_con = 0, ic_tar = 0; - u32 dummy; + unsigned int dummy; /* Disable the adapter */ __i2c_dw_disable(dev); @@ -239,7 +283,7 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) msgs[dev->msg_write_idx].addr | ic_tar); /* Enforce disabled interrupts (due to HW issues) */ - regmap_write(dev->map, DW_IC_INTR_MASK, 0); + __i2c_dw_write_intr_mask(dev, 0); /* Enable the adapter */ __i2c_dw_enable(dev); @@ -249,7 +293,35 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) /* Clear and enable interrupts */ regmap_read(dev->map, DW_IC_CLR_INTR, &dummy); - regmap_write(dev->map, DW_IC_INTR_MASK, DW_IC_INTR_MASTER_MASK); + __i2c_dw_write_intr_mask(dev, DW_IC_INTR_MASTER_MASK); +} + +/* + * This function waits for the controller to be idle before disabling I2C + * When the controller is not in the IDLE state, the MST_ACTIVITY bit + * (IC_STATUS[5]) is set. + * + * Values: + * 0x1 (ACTIVE): Controller not idle + * 0x0 (IDLE): Controller is idle + * + * The function is called after completing the current transfer. + * + * Returns: + * False when the controller is in the IDLE state. + * True when the controller is in the ACTIVE state. + */ +static bool i2c_dw_is_controller_active(struct dw_i2c_dev *dev) +{ + u32 status; + + regmap_read(dev->map, DW_IC_STATUS, &status); + if (!(status & DW_IC_STATUS_MASTER_ACTIVITY)) + return false; + + return regmap_read_poll_timeout(dev->map, DW_IC_STATUS, status, + !(status & DW_IC_STATUS_MASTER_ACTIVITY), + 1100, 20000) != 0; } static int i2c_dw_check_stopbit(struct dw_i2c_dev *dev) @@ -287,7 +359,7 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, int msg_wrt_idx, msg_itr_lmt, buf_len, data_idx; int cmd = 0, status; u8 *tx_buf; - u32 val; + unsigned int val; /* * In order to enable the interrupt for UCSI i.e. AMD NAVI GPU card, @@ -298,8 +370,8 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, dev->msgs = msgs; dev->msgs_num = num_msgs; + dev->msg_write_idx = 0; i2c_dw_xfer_init(dev); - regmap_write(dev->map, DW_IC_INTR_MASK, 0); /* Initiate messages read/write transaction */ for (msg_wrt_idx = 0; msg_wrt_idx < num_msgs; msg_wrt_idx++) { @@ -311,7 +383,7 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, /* * Initiate the i2c read/write transaction of buffer length, * and poll for bus busy status. For the last message transfer, - * update the command with stopbit enable. + * update the command with stop bit enable. */ for (msg_itr_lmt = buf_len; msg_itr_lmt > 0; msg_itr_lmt--) { if (msg_wrt_idx == num_msgs - 1 && msg_itr_lmt == 1) @@ -356,7 +428,7 @@ static int amd_i2c_dw_xfer_quirk(struct i2c_adapter *adap, struct i2c_msg *msgs, /* * Initiate (and continue) low level master read/write transaction. - * This function is only called from i2c_dw_isr, and pumping i2c_msg + * This function is only called from i2c_dw_isr(), and pumping i2c_msg * messages into the tx buffer. Even if the size of i2c_msg data is * longer than the size of the tx buffer, it handles everything. */ @@ -394,7 +466,8 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) buf = msgs[dev->msg_write_idx].buf; buf_len = msgs[dev->msg_write_idx].len; - /* If both IC_EMPTYFIFO_HOLD_MASTER_EN and + /* + * If both IC_EMPTYFIFO_HOLD_MASTER_EN and * IC_RESTART_EN are set, we must manually * set restart bit between messages. */ @@ -456,10 +529,16 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) /* * Because we don't know the buffer length in the - * I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop - * the transaction here. + * I2C_FUNC_SMBUS_BLOCK_DATA case, we can't stop the + * transaction here. Also disable the TX_EMPTY IRQ + * while waiting for the data length byte to avoid the + * bogus interrupts flood. */ - if (buf_len > 0 || flags & I2C_M_RECV_LEN) { + if (flags & I2C_M_RECV_LEN) { + dev->status |= STATUS_WRITE_IN_PROGRESS; + intr_mask &= ~DW_IC_INTR_TX_EMPTY; + break; + } else if (buf_len > 0) { /* more bytes to be written */ dev->status |= STATUS_WRITE_IN_PROGRESS; break; @@ -477,7 +556,7 @@ i2c_dw_xfer_msg(struct dw_i2c_dev *dev) if (dev->msg_err) intr_mask = 0; - regmap_write(dev->map, DW_IC_INTR_MASK, intr_mask); + __i2c_dw_write_intr_mask(dev, intr_mask); } static u8 @@ -485,6 +564,7 @@ i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len) { struct i2c_msg *msgs = dev->msgs; u32 flags = msgs[dev->msg_read_idx].flags; + unsigned int intr_mask; /* * Adjust the buffer length and mask the flag @@ -495,6 +575,14 @@ i2c_dw_recv_len(struct dw_i2c_dev *dev, u8 len) msgs[dev->msg_read_idx].len = len; msgs[dev->msg_read_idx].flags &= ~I2C_M_RECV_LEN; + /* + * Received buffer length, re-enable TX_EMPTY interrupt + * to resume the SMBUS transaction. + */ + __i2c_dw_read_intr_mask(dev, &intr_mask); + intr_mask |= DW_IC_INTR_TX_EMPTY; + __i2c_dw_write_intr_mask(dev, intr_mask); + return len; } @@ -505,7 +593,8 @@ i2c_dw_read(struct dw_i2c_dev *dev) unsigned int rx_valid; for (; dev->msg_read_idx < dev->msgs_num; dev->msg_read_idx++) { - u32 len, tmp; + unsigned int tmp; + u32 len; u8 *buf; if (!(msgs[dev->msg_read_idx].flags & I2C_M_RD)) @@ -525,9 +614,21 @@ i2c_dw_read(struct dw_i2c_dev *dev) u32 flags = msgs[dev->msg_read_idx].flags; regmap_read(dev->map, DW_IC_DATA_CMD, &tmp); + tmp &= DW_IC_DATA_CMD_DAT; /* Ensure length byte is a valid value */ - if (flags & I2C_M_RECV_LEN && - (tmp & DW_IC_DATA_CMD_DAT) <= I2C_SMBUS_BLOCK_MAX && tmp > 0) { + if (flags & I2C_M_RECV_LEN) { + /* + * if IC_EMPTYFIFO_HOLD_MASTER_EN is set, which cannot be + * detected from the registers, the controller can be + * disabled if the STOP bit is set. But it is only set + * after receiving block data response length in + * I2C_FUNC_SMBUS_BLOCK_DATA case. That needs to read + * another byte with STOP bit set when the block data + * response length is invalid to complete the transaction. + */ + if (!tmp || tmp > I2C_SMBUS_BLOCK_MAX) + tmp = 1; + len = i2c_dw_recv_len(dev, tmp); } *buf++ = tmp; @@ -544,116 +645,9 @@ i2c_dw_read(struct dw_i2c_dev *dev) } } -/* - * Prepare controller for a transaction and call i2c_dw_xfer_msg. - */ -static int -i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) -{ - struct dw_i2c_dev *dev = i2c_get_adapdata(adap); - int ret; - - dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); - - pm_runtime_get_sync(dev->dev); - - /* - * Initiate I2C message transfer when AMD NAVI GPU card is enabled, - * As it is polling based transfer mechanism, which does not support - * interrupt based functionalities of existing DesignWare driver. - */ - if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU) { - ret = amd_i2c_dw_xfer_quirk(adap, msgs, num); - goto done_nolock; - } - - reinit_completion(&dev->cmd_complete); - dev->msgs = msgs; - dev->msgs_num = num; - dev->cmd_err = 0; - dev->msg_write_idx = 0; - dev->msg_read_idx = 0; - dev->msg_err = 0; - dev->status = 0; - dev->abort_source = 0; - dev->rx_outstanding = 0; - - ret = i2c_dw_acquire_lock(dev); - if (ret) - goto done_nolock; - - ret = i2c_dw_wait_bus_not_busy(dev); - if (ret < 0) - goto done; - - /* Start the transfers */ - i2c_dw_xfer_init(dev); - - /* Wait for tx to complete */ - if (!wait_for_completion_timeout(&dev->cmd_complete, adap->timeout)) { - dev_err(dev->dev, "controller timed out\n"); - /* i2c_dw_init implicitly disables the adapter */ - i2c_recover_bus(&dev->adapter); - i2c_dw_init_master(dev); - ret = -ETIMEDOUT; - goto done; - } - - /* - * We must disable the adapter before returning and signaling the end - * of the current transfer. Otherwise the hardware might continue - * generating interrupts which in turn causes a race condition with - * the following transfer. Needs some more investigation if the - * additional interrupts are a hardware bug or this driver doesn't - * handle them correctly yet. - */ - __i2c_dw_disable_nowait(dev); - - if (dev->msg_err) { - ret = dev->msg_err; - goto done; - } - - /* No error */ - if (likely(!dev->cmd_err && !dev->status)) { - ret = num; - goto done; - } - - /* We have an error */ - if (dev->cmd_err == DW_IC_ERR_TX_ABRT) { - ret = i2c_dw_handle_tx_abort(dev); - goto done; - } - - if (dev->status) - dev_err(dev->dev, - "transfer terminated early - interrupt latency too high?\n"); - - ret = -EIO; - -done: - i2c_dw_release_lock(dev); - -done_nolock: - pm_runtime_mark_last_busy(dev->dev); - pm_runtime_put_autosuspend(dev->dev); - - return ret; -} - -static const struct i2c_algorithm i2c_dw_algo = { - .master_xfer = i2c_dw_xfer, - .functionality = i2c_dw_func, -}; - -static const struct i2c_adapter_quirks i2c_dw_quirks = { - .flags = I2C_AQ_NO_ZERO_LEN, -}; - static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) { - u32 stat, dummy; + unsigned int stat, dummy; /* * The IC_INTR_STAT register just indicates "enabled" interrupts. @@ -667,7 +661,12 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) * * The raw version might be useful for debugging purposes. */ - regmap_read(dev->map, DW_IC_INTR_STAT, &stat); + if (!(dev->flags & ACCESS_POLLING)) { + regmap_read(dev->map, DW_IC_INTR_STAT, &stat); + } else { + regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat); + stat &= dev->sw_mask; + } /* * Do not use the IC_CLR_INTR register to clear interrupts, or @@ -707,6 +706,45 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) return stat; } +static void i2c_dw_process_transfer(struct dw_i2c_dev *dev, unsigned int stat) +{ + if (stat & DW_IC_INTR_TX_ABRT) { + dev->cmd_err |= DW_IC_ERR_TX_ABRT; + dev->status &= ~STATUS_MASK; + dev->rx_outstanding = 0; + + /* + * Anytime TX_ABRT is set, the contents of the tx/rx + * buffers are flushed. Make sure to skip them. + */ + __i2c_dw_write_intr_mask(dev, 0); + goto tx_aborted; + } + + if (stat & DW_IC_INTR_RX_FULL) + i2c_dw_read(dev); + + if (stat & DW_IC_INTR_TX_EMPTY) + i2c_dw_xfer_msg(dev); + + /* + * No need to modify or disable the interrupt mask here. + * i2c_dw_xfer_msg() will take care of it according to + * the current transmit status. + */ + +tx_aborted: + if (((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err) && + (dev->rx_outstanding == 0)) + complete(&dev->cmd_complete); + else if (unlikely(dev->flags & ACCESS_INTR_MASK)) { + /* Workaround to trigger pending interrupt */ + __i2c_dw_read_intr_mask(dev, &stat); + __i2c_dw_write_intr_mask(dev, 0); + __i2c_dw_write_intr_mask(dev, stat); + } +} + /* * Interrupt service routine. This gets called whenever an I2C master interrupt * occurs. @@ -714,7 +752,7 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) { struct dw_i2c_dev *dev = dev_id; - u32 stat, enabled; + unsigned int stat, enabled; regmap_read(dev->map, DW_IC_ENABLE, &enabled); regmap_read(dev->map, DW_IC_RAW_INTR_STAT, &stat); @@ -734,49 +772,156 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) * interrupt really came from this HW (E.g. firmware has left * the HW active). */ - regmap_write(dev->map, DW_IC_INTR_MASK, 0); + __i2c_dw_write_intr_mask(dev, 0); return IRQ_HANDLED; } - if (stat & DW_IC_INTR_TX_ABRT) { - dev->cmd_err |= DW_IC_ERR_TX_ABRT; - dev->status &= ~STATUS_MASK; - dev->rx_outstanding = 0; + i2c_dw_process_transfer(dev, stat); - /* - * Anytime TX_ABRT is set, the contents of the tx/rx - * buffers are flushed. Make sure to skip them. - */ - regmap_write(dev->map, DW_IC_INTR_MASK, 0); - goto tx_aborted; + return IRQ_HANDLED; +} + +static int i2c_dw_wait_transfer(struct dw_i2c_dev *dev) +{ + unsigned long timeout = dev->adapter.timeout; + unsigned int stat; + int ret; + + if (!(dev->flags & ACCESS_POLLING)) { + ret = wait_for_completion_timeout(&dev->cmd_complete, timeout); + } else { + timeout += jiffies; + do { + ret = try_wait_for_completion(&dev->cmd_complete); + if (ret) + break; + + stat = i2c_dw_read_clear_intrbits(dev); + if (stat) + i2c_dw_process_transfer(dev, stat); + else + /* Try save some power */ + usleep_range(3, 25); + } while (time_before(jiffies, timeout)); } - if (stat & DW_IC_INTR_RX_FULL) - i2c_dw_read(dev); + return ret ? 0 : -ETIMEDOUT; +} - if (stat & DW_IC_INTR_TX_EMPTY) - i2c_dw_xfer_msg(dev); +/* + * Prepare controller for a transaction and call i2c_dw_xfer_msg. + */ +static int +i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct dw_i2c_dev *dev = i2c_get_adapdata(adap); + int ret; + + dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); + + pm_runtime_get_sync(dev->dev); + + switch (dev->flags & MODEL_MASK) { + case MODEL_AMD_NAVI_GPU: + ret = amd_i2c_dw_xfer_quirk(adap, msgs, num); + goto done_nolock; + default: + break; + } + + reinit_completion(&dev->cmd_complete); + dev->msgs = msgs; + dev->msgs_num = num; + dev->cmd_err = 0; + dev->msg_write_idx = 0; + dev->msg_read_idx = 0; + dev->msg_err = 0; + dev->status = 0; + dev->abort_source = 0; + dev->rx_outstanding = 0; + + ret = i2c_dw_acquire_lock(dev); + if (ret) + goto done_nolock; + + ret = i2c_dw_wait_bus_not_busy(dev); + if (ret < 0) + goto done; + + /* Start the transfers */ + i2c_dw_xfer_init(dev); + + /* Wait for tx to complete */ + ret = i2c_dw_wait_transfer(dev); + if (ret) { + dev_err(dev->dev, "controller timed out\n"); + /* i2c_dw_init_master() implicitly disables the adapter */ + i2c_recover_bus(&dev->adapter); + i2c_dw_init_master(dev); + goto done; + } /* - * No need to modify or disable the interrupt mask here. - * i2c_dw_xfer_msg() will take care of it according to - * the current transmit status. + * This happens rarely (~1:500) and is hard to reproduce. Debug trace + * showed that IC_STATUS had value of 0x23 when STOP_DET occurred, + * if disable IC_ENABLE.ENABLE immediately that can result in + * IC_RAW_INTR_STAT.MASTER_ON_HOLD holding SCL low. Check if + * controller is still ACTIVE before disabling I2C. */ + if (i2c_dw_is_controller_active(dev)) + dev_err(dev->dev, "controller active\n"); -tx_aborted: - if (((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err) && - (dev->rx_outstanding == 0)) - complete(&dev->cmd_complete); - else if (unlikely(dev->flags & ACCESS_INTR_MASK)) { - /* Workaround to trigger pending interrupt */ - regmap_read(dev->map, DW_IC_INTR_MASK, &stat); - regmap_write(dev->map, DW_IC_INTR_MASK, 0); - regmap_write(dev->map, DW_IC_INTR_MASK, stat); + /* + * We must disable the adapter before returning and signaling the end + * of the current transfer. Otherwise the hardware might continue + * generating interrupts which in turn causes a race condition with + * the following transfer. Needs some more investigation if the + * additional interrupts are a hardware bug or this driver doesn't + * handle them correctly yet. + */ + __i2c_dw_disable_nowait(dev); + + if (dev->msg_err) { + ret = dev->msg_err; + goto done; } - return IRQ_HANDLED; + /* No error */ + if (likely(!dev->cmd_err && !dev->status)) { + ret = num; + goto done; + } + + /* We have an error */ + if (dev->cmd_err == DW_IC_ERR_TX_ABRT) { + ret = i2c_dw_handle_tx_abort(dev); + goto done; + } + + if (dev->status) + dev_err(dev->dev, + "transfer terminated early - interrupt latency too high?\n"); + + ret = -EIO; + +done: + i2c_dw_release_lock(dev); + +done_nolock: + pm_runtime_put_autosuspend(dev->dev); + + return ret; } +static const struct i2c_algorithm i2c_dw_algo = { + .xfer = i2c_dw_xfer, + .functionality = i2c_dw_func, +}; + +static const struct i2c_adapter_quirks i2c_dw_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN, +}; + void i2c_dw_configure_master(struct dw_i2c_dev *dev) { struct i2c_timings *t = &dev->timings; @@ -836,41 +981,38 @@ static int i2c_dw_init_recovery_info(struct dw_i2c_dev *dev) return PTR_ERR(gpio); rinfo->sda_gpiod = gpio; + rinfo->pinctrl = devm_pinctrl_get(dev->dev); + if (IS_ERR(rinfo->pinctrl)) { + if (PTR_ERR(rinfo->pinctrl) == -EPROBE_DEFER) + return PTR_ERR(rinfo->pinctrl); + + rinfo->pinctrl = NULL; + dev_err(dev->dev, "getting pinctrl info failed: bus recovery might not work\n"); + } else if (!rinfo->pinctrl) { + dev_dbg(dev->dev, "pinctrl is disabled, bus recovery might not work\n"); + } + rinfo->recover_bus = i2c_generic_scl_recovery; rinfo->prepare_recovery = i2c_dw_prepare_recovery; rinfo->unprepare_recovery = i2c_dw_unprepare_recovery; adap->bus_recovery_info = rinfo; - dev_info(dev->dev, "running with gpio recovery mode! scl%s", + dev_info(dev->dev, "running with GPIO recovery mode! scl%s", rinfo->sda_gpiod ? ",sda" : ""); return 0; } -static int amd_i2c_adap_quirk(struct dw_i2c_dev *dev) -{ - struct i2c_adapter *adap = &dev->adapter; - int ret; - - pm_runtime_get_noresume(dev->dev); - ret = i2c_add_numbered_adapter(adap); - if (ret) - dev_err(dev->dev, "Failed to add adapter: %d\n", ret); - pm_runtime_put_noidle(dev->dev); - - return ret; -} - int i2c_dw_probe_master(struct dw_i2c_dev *dev) { struct i2c_adapter *adap = &dev->adapter; unsigned long irq_flags; + unsigned int ic_con; int ret; init_completion(&dev->cmd_complete); dev->init = i2c_dw_init_master; - dev->disable = i2c_dw_disable; ret = i2c_dw_init_regmap(dev); if (ret) @@ -884,21 +1026,38 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) if (ret) return ret; + /* Lock the bus for accessing DW_IC_CON */ + ret = i2c_dw_acquire_lock(dev); + if (ret) + return ret; + + /* + * On AMD platforms BIOS advertises the bus clear feature + * and enables the SCL/SDA stuck low. SMU FW does the + * bus recovery process. Driver should not ignore this BIOS + * advertisement of bus clear feature. + */ + ret = regmap_read(dev->map, DW_IC_CON, &ic_con); + i2c_dw_release_lock(dev); + if (ret) + return ret; + + if (ic_con & DW_IC_CON_BUS_CLEAR_CTRL) + dev->master_cfg |= DW_IC_CON_BUS_CLEAR_CTRL; + ret = dev->init(dev); if (ret) return ret; - snprintf(adap->name, sizeof(adap->name), - "Synopsys DesignWare I2C adapter"); + if (!adap->name[0]) + scnprintf(adap->name, sizeof(adap->name), + "Synopsys DesignWare I2C adapter"); adap->retries = 3; adap->algo = &i2c_dw_algo; adap->quirks = &i2c_dw_quirks; adap->dev.parent = dev->dev; i2c_set_adapdata(adap, dev); - if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU) - return amd_i2c_adap_quirk(dev); - if (dev->flags & ACCESS_NO_IRQ_SUSPEND) { irq_flags = IRQF_NO_SUSPEND; } else { @@ -909,15 +1068,16 @@ int i2c_dw_probe_master(struct dw_i2c_dev *dev) if (ret) return ret; - regmap_write(dev->map, DW_IC_INTR_MASK, 0); + __i2c_dw_write_intr_mask(dev, 0); i2c_dw_release_lock(dev); - ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, irq_flags, - dev_name(dev->dev), dev); - if (ret) { - dev_err(dev->dev, "failure requesting irq %i: %d\n", - dev->irq, ret); - return ret; + if (!(dev->flags & ACCESS_POLLING)) { + ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr, + irq_flags, dev_name(dev->dev), dev); + if (ret) + return dev_err_probe(dev->dev, ret, + "failure requesting irq %i: %d\n", + dev->irq, ret); } ret = i2c_dw_init_recovery_info(dev); @@ -942,3 +1102,4 @@ EXPORT_SYMBOL_GPL(i2c_dw_probe_master); MODULE_DESCRIPTION("Synopsys DesignWare I2C bus master adapter"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("I2C_DW_COMMON"); diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c index 782fe1ef3ca1..f21f9877c040 100644 --- a/drivers/i2c/busses/i2c-designware-pcidrv.c +++ b/drivers/i2c/busses/i2c-designware-pcidrv.c @@ -9,7 +9,6 @@ * Copyright (C) 2009 Provigent Ltd. * Copyright (C) 2011, 2015, 2016 Intel Corporation. */ -#include <linux/acpi.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/errno.h> @@ -19,7 +18,9 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> +#include <linux/pm.h> #include <linux/pm_runtime.h> +#include <linux/power_supply.h> #include <linux/sched.h> #include <linux/slab.h> @@ -50,7 +51,7 @@ struct dw_scl_sda_cfg { u16 fs_hcnt; u16 ss_lcnt; u16 fs_lcnt; - u32 sda_hold; + u32 sda_hold_time; }; struct dw_pci_controller { @@ -75,7 +76,7 @@ static struct dw_scl_sda_cfg byt_config = { .fs_hcnt = 0x55, .ss_lcnt = 0x200, .fs_lcnt = 0x99, - .sda_hold = 0x6, + .sda_hold_time = 0x6, }; /* Haswell HCNT/LCNT/SDA hold time */ @@ -84,14 +85,14 @@ static struct dw_scl_sda_cfg hsw_config = { .fs_hcnt = 0x48, .ss_lcnt = 0x01fb, .fs_lcnt = 0xa0, - .sda_hold = 0x9, + .sda_hold_time = 0x9, }; /* NAVI-AMD HCNT/LCNT/SDA hold time */ static struct dw_scl_sda_cfg navi_amd_config = { .ss_hcnt = 0x1ae, .ss_lcnt = 0x23a, - .sda_hold = 0x9, + .sda_hold_time = 0x9, }; static u32 mfld_get_clk_rate_khz(struct dw_i2c_dev *dev) @@ -101,7 +102,7 @@ static u32 mfld_get_clk_rate_khz(struct dw_i2c_dev *dev) static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c) { - struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev); + struct dw_i2c_dev *dev = pci_get_drvdata(pdev); switch (pdev->device) { case 0x0817: @@ -151,9 +152,9 @@ static u32 navi_amd_get_clk_rate_khz(struct dw_i2c_dev *dev) static int navi_amd_setup(struct pci_dev *pdev, struct dw_pci_controller *c) { - struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev); + struct dw_i2c_dev *dev = pci_get_drvdata(pdev); - dev->flags |= MODEL_AMD_NAVI_GPU; + dev->flags |= MODEL_AMD_NAVI_GPU | ACCESS_POLLING; dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ; return 0; } @@ -193,77 +194,43 @@ static struct dw_pci_controller dw_pci_controllers[] = { }, }; -static int __maybe_unused i2c_dw_pci_runtime_suspend(struct device *dev) -{ - struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - - i_dev->disable(i_dev); - return 0; -} - -static int __maybe_unused i2c_dw_pci_suspend(struct device *dev) -{ - struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - - i2c_mark_adapter_suspended(&i_dev->adapter); - - return i2c_dw_pci_runtime_suspend(dev); -} - -static int __maybe_unused i2c_dw_pci_runtime_resume(struct device *dev) -{ - struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - - return i_dev->init(i_dev); -} - -static int __maybe_unused i2c_dw_pci_resume(struct device *dev) -{ - struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - int ret; - - ret = i2c_dw_pci_runtime_resume(dev); - - i2c_mark_adapter_resumed(&i_dev->adapter); - - return ret; -} +static const struct property_entry dgpu_properties[] = { + /* USB-C doesn't power the system */ + PROPERTY_ENTRY_U8("scope", POWER_SUPPLY_SCOPE_DEVICE), + {} +}; -static const struct dev_pm_ops i2c_dw_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(i2c_dw_pci_suspend, i2c_dw_pci_resume) - SET_RUNTIME_PM_OPS(i2c_dw_pci_runtime_suspend, i2c_dw_pci_runtime_resume, NULL) +static const struct software_node dgpu_node = { + .properties = dgpu_properties, }; static int i2c_dw_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct device *device = &pdev->dev; struct dw_i2c_dev *dev; struct i2c_adapter *adap; int r; struct dw_pci_controller *controller; struct dw_scl_sda_cfg *cfg; - struct i2c_timings *t; if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) - return dev_err_probe(&pdev->dev, -EINVAL, - "Invalid driver data %ld\n", + return dev_err_probe(device, -EINVAL, "Invalid driver data %ld\n", id->driver_data); controller = &dw_pci_controllers[id->driver_data]; r = pcim_enable_device(pdev); if (r) - return dev_err_probe(&pdev->dev, r, - "Failed to enable I2C PCI device\n"); + return dev_err_probe(device, r, "Failed to enable I2C PCI device\n"); pci_set_master(pdev); r = pcim_iomap_regions(pdev, 1 << 0, pci_name(pdev)); if (r) - return dev_err_probe(&pdev->dev, r, - "I/O memory remapping failed\n"); + return dev_err_probe(device, r, "I/O memory remapping failed\n"); - dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); + dev = devm_kzalloc(device, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -273,33 +240,21 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, dev->get_clk_rate_khz = controller->get_clk_rate_khz; dev->base = pcim_iomap_table(pdev)[0]; - dev->dev = &pdev->dev; + dev->dev = device; dev->irq = pci_irq_vector(pdev, 0); dev->flags |= controller->flags; - t = &dev->timings; - i2c_parse_fw_timings(&pdev->dev, t, false); - pci_set_drvdata(pdev, dev); if (controller->setup) { r = controller->setup(pdev, controller); - if (r) { - pci_free_irq_vectors(pdev); + if (r) return r; - } } - i2c_dw_adjust_bus_speed(dev); - - if (has_acpi_companion(&pdev->dev)) - i2c_dw_acpi_configure(&pdev->dev); - - r = i2c_dw_validate_speed(dev); - if (r) { - pci_free_irq_vectors(pdev); + r = i2c_dw_fw_parse_and_configure(dev); + if (r) return r; - } i2c_dw_configure(dev); @@ -309,32 +264,31 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, dev->fs_hcnt = cfg->fs_hcnt; dev->ss_lcnt = cfg->ss_lcnt; dev->fs_lcnt = cfg->fs_lcnt; - dev->sda_hold_time = cfg->sda_hold; + dev->sda_hold_time = cfg->sda_hold_time; } adap = &dev->adapter; adap->owner = THIS_MODULE; adap->class = 0; - ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev)); adap->nr = controller->bus_num; r = i2c_dw_probe(dev); - if (r) { - pci_free_irq_vectors(pdev); + if (r) return r; - } if ((dev->flags & MODEL_MASK) == MODEL_AMD_NAVI_GPU) { - dev->slave = i2c_new_ccgx_ucsi(&dev->adapter, dev->irq, NULL); - if (IS_ERR(dev->slave)) - return dev_err_probe(dev->dev, PTR_ERR(dev->slave), + dev->slave = i2c_new_ccgx_ucsi(&dev->adapter, dev->irq, &dgpu_node); + if (IS_ERR(dev->slave)) { + i2c_del_adapter(&dev->adapter); + return dev_err_probe(device, PTR_ERR(dev->slave), "register UCSI failed\n"); + } } - pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_put_autosuspend(&pdev->dev); - pm_runtime_allow(&pdev->dev); + pm_runtime_set_autosuspend_delay(device, 1000); + pm_runtime_use_autosuspend(device); + pm_runtime_put_autosuspend(device); + pm_runtime_allow(device); return 0; } @@ -342,17 +296,17 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, static void i2c_dw_pci_remove(struct pci_dev *pdev) { struct dw_i2c_dev *dev = pci_get_drvdata(pdev); + struct device *device = &pdev->dev; + + i2c_dw_disable(dev); - dev->disable(dev); - pm_runtime_forbid(&pdev->dev); - pm_runtime_get_noresume(&pdev->dev); + pm_runtime_forbid(device); + pm_runtime_get_noresume(device); i2c_del_adapter(&dev->adapter); - devm_free_irq(&pdev->dev, dev->irq, dev); - pci_free_irq_vectors(pdev); } -static const struct pci_device_id i2_designware_pci_ids[] = { +static const struct pci_device_id i2c_designware_pci_ids[] = { /* Medfield */ { PCI_VDEVICE(INTEL, 0x0817), medfield }, { PCI_VDEVICE(INTEL, 0x0818), medfield }, @@ -398,23 +352,23 @@ static const struct pci_device_id i2_designware_pci_ids[] = { { PCI_VDEVICE(ATI, 0x73c4), navi_amd }, { PCI_VDEVICE(ATI, 0x7444), navi_amd }, { PCI_VDEVICE(ATI, 0x7464), navi_amd }, - { 0,} + {} }; -MODULE_DEVICE_TABLE(pci, i2_designware_pci_ids); +MODULE_DEVICE_TABLE(pci, i2c_designware_pci_ids); static struct pci_driver dw_i2c_driver = { .name = DRIVER_NAME, - .id_table = i2_designware_pci_ids, .probe = i2c_dw_pci_probe, .remove = i2c_dw_pci_remove, .driver = { - .pm = &i2c_dw_pm_ops, + .pm = pm_ptr(&i2c_dw_dev_pm_ops), }, + .id_table = i2c_designware_pci_ids, }; module_pci_driver(dw_i2c_driver); -/* Work with hotplug and coldplug */ -MODULE_ALIAS("i2c_designware-pci"); MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); MODULE_DESCRIPTION("Synopsys DesignWare PCI I2C bus adapter"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("I2C_DW"); +MODULE_IMPORT_NS("I2C_DW_COMMON"); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 74182db03a88..7be99656a67d 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -8,7 +8,6 @@ * Copyright (C) 2007 MontaVista Software Inc. * Copyright (C) 2009 Provigent Ltd. */ -#include <linux/acpi.h> #include <linux/clk-provider.h> #include <linux/clk.h> #include <linux/delay.h> @@ -21,7 +20,6 @@ #include <linux/kernel.h> #include <linux/mfd/syscon.h> #include <linux/module.h> -#include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/pm_runtime.h> @@ -30,38 +28,15 @@ #include <linux/reset.h> #include <linux/sched.h> #include <linux/slab.h> -#include <linux/suspend.h> #include <linux/units.h> #include "i2c-designware-core.h" static u32 i2c_dw_get_clk_rate_khz(struct dw_i2c_dev *dev) { - return clk_get_rate(dev->clk) / KILO; + return clk_get_rate(dev->clk) / HZ_PER_KHZ; } -#ifdef CONFIG_ACPI -static const struct acpi_device_id dw_i2c_acpi_match[] = { - { "INT33C2", 0 }, - { "INT33C3", 0 }, - { "INT3432", 0 }, - { "INT3433", 0 }, - { "80860F41", ACCESS_NO_IRQ_SUSPEND }, - { "808622C1", ACCESS_NO_IRQ_SUSPEND }, - { "AMD0010", ACCESS_INTR_MASK }, - { "AMDI0010", ACCESS_INTR_MASK }, - { "AMDI0019", ACCESS_INTR_MASK | ARBITRATION_SEMAPHORE }, - { "AMDI0510", 0 }, - { "APMC0D0F", 0 }, - { "HISI02A1", 0 }, - { "HISI02A2", 0 }, - { "HISI02A3", 0 }, - { "HYGO0010", ACCESS_INTR_MASK }, - { } -}; -MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match); -#endif - #ifdef CONFIG_OF #define BT1_I2C_CTL 0x100 #define BT1_I2C_CTL_ADDR_MASK GENMASK(7, 0) @@ -97,10 +72,10 @@ static int bt1_i2c_write(void *context, unsigned int reg, unsigned int val) return ret; return regmap_write(dev->sysmap, BT1_I2C_CTL, - BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK)); + BT1_I2C_CTL_GO | BT1_I2C_CTL_WR | (reg & BT1_I2C_CTL_ADDR_MASK)); } -static struct regmap_config bt1_i2c_cfg = { +static const struct regmap_config bt1_i2c_cfg = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, @@ -119,54 +94,21 @@ static int bt1_i2c_request_regs(struct dw_i2c_dev *dev) dev->map = devm_regmap_init(dev->dev, NULL, dev, &bt1_i2c_cfg); return PTR_ERR_OR_ZERO(dev->map); } - -#define MSCC_ICPU_CFG_TWI_DELAY 0x0 -#define MSCC_ICPU_CFG_TWI_DELAY_ENABLE BIT(0) -#define MSCC_ICPU_CFG_TWI_SPIKE_FILTER 0x4 - -static int mscc_twi_set_sda_hold_time(struct dw_i2c_dev *dev) -{ - writel((dev->sda_hold_time << 1) | MSCC_ICPU_CFG_TWI_DELAY_ENABLE, - dev->ext + MSCC_ICPU_CFG_TWI_DELAY); - - return 0; -} - -static int dw_i2c_of_configure(struct platform_device *pdev) -{ - struct dw_i2c_dev *dev = platform_get_drvdata(pdev); - - switch (dev->flags & MODEL_MASK) { - case MODEL_MSCC_OCELOT: - dev->ext = devm_platform_ioremap_resource(pdev, 1); - if (!IS_ERR(dev->ext)) - dev->set_sda_hold_time = mscc_twi_set_sda_hold_time; - break; - default: - break; - } - - return 0; -} - -static const struct of_device_id dw_i2c_of_match[] = { - { .compatible = "snps,designware-i2c", }, - { .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT }, - { .compatible = "baikal,bt1-sys-i2c", .data = (void *)MODEL_BAIKAL_BT1 }, - {}, -}; -MODULE_DEVICE_TABLE(of, dw_i2c_of_match); #else static int bt1_i2c_request_regs(struct dw_i2c_dev *dev) { return -ENODEV; } +#endif -static inline int dw_i2c_of_configure(struct platform_device *pdev) +static int dw_i2c_get_parent_regmap(struct dw_i2c_dev *dev) { - return -ENODEV; + dev->map = dev_get_regmap(dev->dev->parent, NULL); + if (!dev->map) + return -ENODEV; + + return 0; } -#endif static void dw_i2c_plat_pm_cleanup(struct dw_i2c_dev *dev) { @@ -181,10 +123,16 @@ static int dw_i2c_plat_request_regs(struct dw_i2c_dev *dev) struct platform_device *pdev = to_platform_device(dev->dev); int ret; + if (device_is_compatible(dev->dev, "intel,xe-i2c")) + return dw_i2c_get_parent_regmap(dev); + switch (dev->flags & MODEL_MASK) { case MODEL_BAIKAL_BT1: ret = bt1_i2c_request_regs(dev); break; + case MODEL_WANGXUN_SP: + ret = dw_i2c_get_parent_regmap(dev); + break; default: dev->base = devm_platform_ioremap_resource(pdev, 0); ret = PTR_ERR_OR_ZERO(dev->base); @@ -214,7 +162,6 @@ static const struct i2c_dw_semaphore_callbacks i2c_dw_semaphore_cb_table[] = { #ifdef CONFIG_I2C_DESIGNWARE_AMDPSP { .probe = i2c_dw_amdpsp_probe_lock_support, - .remove = i2c_dw_amdpsp_remove_lock_support, }, #endif {} @@ -226,11 +173,9 @@ static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) int i = 0; int ret; - ptr = i2c_dw_semaphore_cb_table; - dev->semaphore_idx = -1; - while (ptr->probe) { + for (ptr = i2c_dw_semaphore_cb_table; ptr->probe; ptr++) { ret = ptr->probe(dev); if (ret) { /* @@ -242,7 +187,6 @@ static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) return ret; i++; - ptr++; continue; } @@ -253,76 +197,64 @@ static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) return 0; } -static void i2c_dw_remove_lock_support(struct dw_i2c_dev *dev) -{ - if (dev->semaphore_idx < 0) - return; - - if (i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove) - i2c_dw_semaphore_cb_table[dev->semaphore_idx].remove(dev); -} - static int dw_i2c_plat_probe(struct platform_device *pdev) { + u32 flags = (uintptr_t)device_get_match_data(&pdev->dev); + struct device *device = &pdev->dev; struct i2c_adapter *adap; struct dw_i2c_dev *dev; - struct i2c_timings *t; int irq, ret; - irq = platform_get_irq(pdev, 0); - if (irq < 0) + irq = platform_get_irq_optional(pdev, 0); + if (irq == -ENXIO) + flags |= ACCESS_POLLING; + else if (irq < 0) return irq; - dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL); + dev = devm_kzalloc(device, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; - dev->flags = (uintptr_t)device_get_match_data(&pdev->dev); - dev->dev = &pdev->dev; + if (device_property_present(device, "wx,i2c-snps-model")) + flags = MODEL_WANGXUN_SP | ACCESS_POLLING; + + dev->dev = device; dev->irq = irq; + dev->flags = flags; platform_set_drvdata(pdev, dev); ret = dw_i2c_plat_request_regs(dev); if (ret) return ret; - dev->rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); + dev->rst = devm_reset_control_get_optional_exclusive(device, NULL); if (IS_ERR(dev->rst)) - return PTR_ERR(dev->rst); + return dev_err_probe(device, PTR_ERR(dev->rst), "failed to acquire reset\n"); reset_control_deassert(dev->rst); - t = &dev->timings; - i2c_parse_fw_timings(&pdev->dev, t, false); - - i2c_dw_adjust_bus_speed(dev); - - if (pdev->dev.of_node) - dw_i2c_of_configure(pdev); - - if (has_acpi_companion(&pdev->dev)) - i2c_dw_acpi_configure(&pdev->dev); - - ret = i2c_dw_validate_speed(dev); + ret = i2c_dw_fw_parse_and_configure(dev); if (ret) goto exit_reset; ret = i2c_dw_probe_lock_support(dev); - if (ret) + if (ret) { + dev_err_probe(device, ret, "failed to probe lock support\n"); goto exit_reset; + } i2c_dw_configure(dev); /* Optional interface clock */ - dev->pclk = devm_clk_get_optional(&pdev->dev, "pclk"); + dev->pclk = devm_clk_get_optional(device, "pclk"); if (IS_ERR(dev->pclk)) { - ret = PTR_ERR(dev->pclk); + ret = dev_err_probe(device, PTR_ERR(dev->pclk), "failed to acquire pclk\n"); goto exit_reset; } - dev->clk = devm_clk_get_optional(&pdev->dev, NULL); + dev->clk = devm_clk_get_optional(device, NULL); if (IS_ERR(dev->clk)) { - ret = PTR_ERR(dev->clk); + ret = dev_err_probe(device, PTR_ERR(dev->clk), "failed to acquire clock\n"); goto exit_reset; } @@ -331,6 +263,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) goto exit_reset; if (dev->clk) { + struct i2c_timings *t = &dev->timings; u64 clk_khz; dev->get_clk_rate_khz = i2c_dw_get_clk_rate_khz; @@ -344,33 +277,27 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) adap = &dev->adapter; adap->owner = THIS_MODULE; adap->class = dmi_check_system(dw_i2c_hwmon_class_dmi) ? - I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED; - ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev)); - adap->dev.of_node = pdev->dev.of_node; + I2C_CLASS_HWMON : I2C_CLASS_DEPRECATED; adap->nr = -1; - if (dev->flags & ACCESS_NO_IRQ_SUSPEND) { - dev_pm_set_driver_flags(&pdev->dev, - DPM_FLAG_SMART_PREPARE); - } else { - dev_pm_set_driver_flags(&pdev->dev, - DPM_FLAG_SMART_PREPARE | - DPM_FLAG_SMART_SUSPEND); - } + if (dev->flags & ACCESS_NO_IRQ_SUSPEND) + dev_pm_set_driver_flags(device, DPM_FLAG_SMART_PREPARE); + else + dev_pm_set_driver_flags(device, DPM_FLAG_SMART_PREPARE | DPM_FLAG_SMART_SUSPEND); - device_enable_async_suspend(&pdev->dev); + device_enable_async_suspend(device); /* The code below assumes runtime PM to be disabled. */ - WARN_ON(pm_runtime_enabled(&pdev->dev)); + WARN_ON(pm_runtime_enabled(device)); - pm_runtime_set_autosuspend_delay(&pdev->dev, 1000); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_set_active(&pdev->dev); + pm_runtime_set_autosuspend_delay(device, 1000); + pm_runtime_use_autosuspend(device); + pm_runtime_set_active(device); if (dev->shared_with_punit) - pm_runtime_get_noresume(&pdev->dev); + pm_runtime_get_noresume(device); - pm_runtime_enable(&pdev->dev); + pm_runtime_enable(device); ret = i2c_dw_probe(dev); if (ret) @@ -380,115 +307,79 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) exit_probe: dw_i2c_plat_pm_cleanup(dev); + i2c_dw_prepare_clk(dev, false); exit_reset: reset_control_assert(dev->rst); return ret; } -static int dw_i2c_plat_remove(struct platform_device *pdev) +static void dw_i2c_plat_remove(struct platform_device *pdev) { struct dw_i2c_dev *dev = platform_get_drvdata(pdev); + struct device *device = &pdev->dev; - pm_runtime_get_sync(&pdev->dev); + pm_runtime_get_sync(device); i2c_del_adapter(&dev->adapter); - dev->disable(dev); + i2c_dw_disable(dev); - pm_runtime_dont_use_autosuspend(&pdev->dev); - pm_runtime_put_sync(&pdev->dev); + pm_runtime_dont_use_autosuspend(device); + pm_runtime_put_noidle(device); dw_i2c_plat_pm_cleanup(dev); - i2c_dw_remove_lock_support(dev); + i2c_dw_prepare_clk(dev, false); reset_control_assert(dev->rst); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int dw_i2c_plat_prepare(struct device *dev) -{ - /* - * If the ACPI companion device object is present for this device, it - * may be accessed during suspend and resume of other devices via I2C - * operation regions, so tell the PM core and middle layers to avoid - * skipping system suspend/resume callbacks for it in that case. - */ - return !has_acpi_companion(dev); -} -#else -#define dw_i2c_plat_prepare NULL -#endif - -#ifdef CONFIG_PM -static int dw_i2c_plat_runtime_suspend(struct device *dev) -{ - struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - - if (i_dev->shared_with_punit) - return 0; - - i_dev->disable(i_dev); - i2c_dw_prepare_clk(i_dev, false); - - return 0; -} - -static int __maybe_unused dw_i2c_plat_suspend(struct device *dev) -{ - struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - - i2c_mark_adapter_suspended(&i_dev->adapter); - - return dw_i2c_plat_runtime_suspend(dev); -} - -static int dw_i2c_plat_runtime_resume(struct device *dev) -{ - struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - - if (!i_dev->shared_with_punit) - i2c_dw_prepare_clk(i_dev, true); - - i_dev->init(i_dev); - - return 0; -} - -static int __maybe_unused dw_i2c_plat_resume(struct device *dev) -{ - struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - - dw_i2c_plat_runtime_resume(dev); - i2c_mark_adapter_resumed(&i_dev->adapter); - - return 0; } -static const struct dev_pm_ops dw_i2c_dev_pm_ops = { - .prepare = dw_i2c_plat_prepare, - SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume) - SET_RUNTIME_PM_OPS(dw_i2c_plat_runtime_suspend, dw_i2c_plat_runtime_resume, NULL) +static const struct of_device_id dw_i2c_of_match[] = { + { .compatible = "snps,designware-i2c", }, + { .compatible = "mscc,ocelot-i2c", .data = (void *)MODEL_MSCC_OCELOT }, + { .compatible = "baikal,bt1-sys-i2c", .data = (void *)MODEL_BAIKAL_BT1 }, + {} }; +MODULE_DEVICE_TABLE(of, dw_i2c_of_match); -#define DW_I2C_DEV_PMOPS (&dw_i2c_dev_pm_ops) -#else -#define DW_I2C_DEV_PMOPS NULL -#endif +static const struct acpi_device_id dw_i2c_acpi_match[] = { + { "80860F41", ACCESS_NO_IRQ_SUSPEND }, + { "808622C1", ACCESS_NO_IRQ_SUSPEND }, + { "AMD0010", ACCESS_INTR_MASK }, + { "AMDI0010", ACCESS_INTR_MASK }, + { "AMDI0019", ACCESS_INTR_MASK | ARBITRATION_SEMAPHORE }, + { "AMDI0510", 0 }, + { "APMC0D0F", 0 }, + { "FUJI200B", 0 }, + { "HISI02A1", 0 }, + { "HISI02A2", 0 }, + { "HISI02A3", 0 }, + { "HJMC3001", 0 }, + { "HYGO0010", ACCESS_INTR_MASK }, + { "INT33C2", 0 }, + { "INT33C3", 0 }, + { "INT3432", 0 }, + { "INT3433", 0 }, + { "INTC10EF", 0 }, + {} +}; +MODULE_DEVICE_TABLE(acpi, dw_i2c_acpi_match); -/* Work with hotplug and coldplug */ -MODULE_ALIAS("platform:i2c_designware"); +static const struct platform_device_id dw_i2c_platform_ids[] = { + { "i2c_designware" }, + {} +}; +MODULE_DEVICE_TABLE(platform, dw_i2c_platform_ids); static struct platform_driver dw_i2c_driver = { .probe = dw_i2c_plat_probe, .remove = dw_i2c_plat_remove, .driver = { .name = "i2c_designware", - .of_match_table = of_match_ptr(dw_i2c_of_match), - .acpi_match_table = ACPI_PTR(dw_i2c_acpi_match), - .pm = DW_I2C_DEV_PMOPS, + .of_match_table = dw_i2c_of_match, + .acpi_match_table = dw_i2c_acpi_match, + .pm = pm_ptr(&i2c_dw_dev_pm_ops), }, + .id_table = dw_i2c_platform_ids, }; static int __init dw_i2c_init_driver(void) @@ -506,3 +397,5 @@ module_exit(dw_i2c_exit_driver); MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); MODULE_DESCRIPTION("Synopsys DesignWare I2C bus adapter"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("I2C_DW"); +MODULE_IMPORT_NS("I2C_DW_COMMON"); diff --git a/drivers/i2c/busses/i2c-designware-slave.c b/drivers/i2c/busses/i2c-designware-slave.c index c6d2e4c2ac23..6eb16b7d75a6 100644 --- a/drivers/i2c/busses/i2c-designware-slave.c +++ b/drivers/i2c/busses/i2c-designware-slave.c @@ -6,6 +6,9 @@ * * Copyright (C) 2016 Synopsys Inc. */ + +#define DEFAULT_SYMBOL_NAMESPACE "I2C_DW" + #include <linux/delay.h> #include <linux/err.h> #include <linux/errno.h> @@ -30,12 +33,14 @@ static void i2c_dw_configure_fifo_slave(struct dw_i2c_dev *dev) } /** - * i2c_dw_init_slave() - Initialize the designware i2c slave hardware + * i2c_dw_init_slave() - Initialize the DesignWare i2c slave hardware * @dev: device private data * * This function configures and enables the I2C in slave mode. * This function is called during I2C init function, and in case of timeout at * run time. + * + * Return: 0 on success, or negative errno otherwise. */ static int i2c_dw_init_slave(struct dw_i2c_dev *dev) { @@ -88,17 +93,17 @@ static int i2c_dw_unreg_slave(struct i2c_client *slave) struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter); regmap_write(dev->map, DW_IC_INTR_MASK, 0); - dev->disable(dev); + i2c_dw_disable(dev); synchronize_irq(dev->irq); dev->slave = NULL; - pm_runtime_put(dev->dev); + pm_runtime_put_sync_suspend(dev->dev); return 0; } static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev) { - u32 stat, dummy; + unsigned int stat, dummy; /* * The IC_INTR_STAT register just indicates "enabled" interrupts. @@ -150,7 +155,7 @@ static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev) static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id) { struct dw_i2c_dev *dev = dev_id; - u32 raw_stat, stat, enabled, tmp; + unsigned int raw_stat, stat, enabled, tmp; u8 val = 0, slave_activity; regmap_read(dev->map, DW_IC_ENABLE, &enabled); @@ -176,6 +181,10 @@ static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id) do { regmap_read(dev->map, DW_IC_DATA_CMD, &tmp); + if (tmp & DW_IC_DATA_CMD_FIRST_DATA_BYTE) + i2c_slave_event(dev->slave, + I2C_SLAVE_WRITE_REQUESTED, + &val); val = tmp; i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED, &val); @@ -216,7 +225,7 @@ static const struct i2c_algorithm i2c_dw_algo = { void i2c_dw_configure_slave(struct dw_i2c_dev *dev) { - dev->functionality = I2C_FUNC_SLAVE | DW_IC_DEFAULT_FUNCTIONALITY; + dev->functionality = I2C_FUNC_SLAVE; dev->slave_cfg = DW_IC_CON_RX_FIFO_FULL_HLD_CTRL | DW_IC_CON_RESTART_EN | DW_IC_CON_STOP_DET_IFADDRESSED; @@ -231,7 +240,6 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev) int ret; dev->init = i2c_dw_init_slave; - dev->disable = i2c_dw_disable; ret = i2c_dw_init_regmap(dev); if (ret) @@ -258,11 +266,10 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev) ret = devm_request_irq(dev->dev, dev->irq, i2c_dw_isr_slave, IRQF_SHARED, dev_name(dev->dev), dev); - if (ret) { - dev_err(dev->dev, "failure requesting irq %i: %d\n", - dev->irq, ret); - return ret; - } + if (ret) + return dev_err_probe(dev->dev, ret, + "failure requesting IRQ %i: %d\n", + dev->irq, ret); ret = i2c_add_numbered_adapter(adap); if (ret) @@ -275,3 +282,4 @@ EXPORT_SYMBOL_GPL(i2c_dw_probe_slave); MODULE_AUTHOR("Luis Oliveira <lolivei@synopsys.com>"); MODULE_DESCRIPTION("Synopsys DesignWare I2C bus slave adapter"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS("I2C_DW_COMMON"); diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c index 50925d97fa42..38d7f31aee79 100644 --- a/drivers/i2c/busses/i2c-digicolor.c +++ b/drivers/i2c/busses/i2c-digicolor.c @@ -213,7 +213,7 @@ out: static int dc_i2c_xfer_msg(struct dc_i2c *i2c, struct i2c_msg *msg, int first, int last) { - unsigned long timeout = msecs_to_jiffies(TIMEOUT_MS); + unsigned long time_left = msecs_to_jiffies(TIMEOUT_MS); unsigned long flags; spin_lock_irqsave(&i2c->lock, flags); @@ -227,9 +227,9 @@ static int dc_i2c_xfer_msg(struct dc_i2c *i2c, struct i2c_msg *msg, int first, dc_i2c_start_msg(i2c, first); spin_unlock_irqrestore(&i2c->lock, flags); - timeout = wait_for_completion_timeout(&i2c->done, timeout); + time_left = wait_for_completion_timeout(&i2c->done, time_left); dc_i2c_set_irq(i2c, 0); - if (timeout == 0) { + if (time_left == 0) { i2c->state = STATE_IDLE; return -ETIMEDOUT; } @@ -281,8 +281,8 @@ static u32 dc_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm dc_i2c_algorithm = { - .master_xfer = dc_i2c_xfer, - .functionality = dc_i2c_func, + .xfer = dc_i2c_xfer, + .functionality = dc_i2c_func, }; static int dc_i2c_probe(struct platform_device *pdev) @@ -347,25 +347,23 @@ static int dc_i2c_probe(struct platform_device *pdev) return 0; } -static int dc_i2c_remove(struct platform_device *pdev) +static void dc_i2c_remove(struct platform_device *pdev) { struct dc_i2c *i2c = platform_get_drvdata(pdev); i2c_del_adapter(&i2c->adap); clk_disable_unprepare(i2c->clk); - - return 0; } static const struct of_device_id dc_i2c_match[] = { { .compatible = "cnxt,cx92755-i2c" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, dc_i2c_match); static struct platform_driver dc_i2c_driver = { .probe = dc_i2c_probe, - .remove = dc_i2c_remove, + .remove = dc_i2c_remove, .driver = { .name = "digicolor-i2c", .of_match_table = dc_i2c_match, @@ -374,5 +372,5 @@ static struct platform_driver dc_i2c_driver = { module_platform_driver(dc_i2c_driver); MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>"); -MODULE_DESCRIPTION("Conexant Digicolor I2C master driver"); +MODULE_DESCRIPTION("Conexant Digicolor I2C controller driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c index b48b7888936f..c02459405b26 100644 --- a/drivers/i2c/busses/i2c-diolan-u2c.c +++ b/drivers/i2c/busses/i2c-diolan-u2c.c @@ -414,7 +414,7 @@ static u32 diolan_usb_func(struct i2c_adapter *a) } static const struct i2c_algorithm diolan_usb_algorithm = { - .master_xfer = diolan_usb_xfer, + .xfer = diolan_usb_xfer, .functionality = diolan_usb_func, }; diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c index 2a2089db71a5..bde2ef098862 100644 --- a/drivers/i2c/busses/i2c-dln2.c +++ b/drivers/i2c/busses/i2c-dln2.c @@ -175,7 +175,7 @@ static u32 dln2_i2c_func(struct i2c_adapter *a) } static const struct i2c_algorithm dln2_i2c_usb_algorithm = { - .master_xfer = dln2_i2c_xfer, + .xfer = dln2_i2c_xfer, .functionality = dln2_i2c_func, }; @@ -218,10 +218,8 @@ static int dln2_i2c_probe(struct platform_device *pdev) /* initialize the i2c interface */ ret = dln2_i2c_enable(dln2, true); - if (ret < 0) { - dev_err(dev, "failed to initialize adapter: %d\n", ret); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "failed to initialize adapter\n"); /* and finally attach to i2c layer */ ret = i2c_add_adapter(&dln2->adapter); @@ -236,14 +234,12 @@ out_disable: return ret; } -static int dln2_i2c_remove(struct platform_device *pdev) +static void dln2_i2c_remove(struct platform_device *pdev) { struct dln2_i2c *dln2 = platform_get_drvdata(pdev); i2c_del_adapter(&dln2->adapter); dln2_i2c_enable(dln2, false); - - return 0; } static struct platform_driver dln2_i2c_driver = { @@ -255,6 +251,6 @@ static struct platform_driver dln2_i2c_driver = { module_platform_driver(dln2_i2c_driver); MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>"); -MODULE_DESCRIPTION("Driver for the Diolan DLN2 I2C master interface"); +MODULE_DESCRIPTION("Driver for the Diolan DLN2 I2C controller interface"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:dln2-i2c"); diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 4914bfbee2a9..27ea3c130a16 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -48,8 +48,6 @@ #define BUS_IDLE_TIMEOUT 20 #define PCH_I2CCTL_I2CMEN 0x0080 -#define TEN_BIT_ADDR_DEFAULT 0xF000 -#define TEN_BIT_ADDR_MASK 0xF0 #define PCH_START 0x0020 #define PCH_RESTART 0x0004 #define PCH_ESR_START 0x0001 @@ -58,7 +56,6 @@ #define PCH_ACK 0x0008 #define PCH_GETACK 0x0001 #define CLR_REG 0x0 -#define I2C_RD 0x1 #define I2CMCF_BIT 0x0080 #define I2CMIF_BIT 0x0002 #define I2CMAL_BIT 0x0010 @@ -76,8 +73,6 @@ #define I2CMBB_BIT 0x0020 #define BUFFER_MODE_MASK (I2CBMFI_BIT | I2CBMAL_BIT | I2CBMNA_BIT | \ I2CBMTO_BIT | I2CBMIS_BIT) -#define I2C_ADDR_MSK 0xFF -#define I2C_MSB_2B_MSK 0x300 #define FAST_MODE_CLK 400 #define FAST_MODE_EN 0x0001 #define SUB_ADDR_LEN_MAX 4 @@ -371,16 +366,12 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, struct i2c_algo_pch_data *adap = i2c_adap->algo_data; u8 *buf; u32 length; - u32 addr; - u32 addr_2_msb; - u32 addr_8_lsb; s32 wrcount; s32 rtn; void __iomem *p = adap->pch_base_address; length = msgs->len; buf = msgs->buf; - addr = msgs->addr; /* enable master tx */ pch_setbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE); @@ -394,8 +385,7 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, } if (msgs->flags & I2C_M_TEN) { - addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7) & 0x06; - iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); + iowrite32(i2c_10bit_addr_hi_from_msg(msgs), p + PCH_I2CDR); if (first) pch_i2c_start(adap); @@ -403,8 +393,7 @@ static s32 pch_i2c_writebytes(struct i2c_adapter *i2c_adap, if (rtn) return rtn; - addr_8_lsb = (addr & I2C_ADDR_MSK); - iowrite32(addr_8_lsb, p + PCH_I2CDR); + iowrite32(i2c_10bit_addr_lo_from_msg(msgs), p + PCH_I2CDR); } else { /* set 7 bit slave address and R/W bit as 0 */ iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR); @@ -490,15 +479,11 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, u8 *buf; u32 count; u32 length; - u32 addr; - u32 addr_2_msb; - u32 addr_8_lsb; void __iomem *p = adap->pch_base_address; s32 rtn; length = msgs->len; buf = msgs->buf; - addr = msgs->addr; /* enable master reception */ pch_clrbit(adap->pch_base_address, PCH_I2CCTL, I2C_TX_MODE); @@ -509,8 +494,7 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, } if (msgs->flags & I2C_M_TEN) { - addr_2_msb = ((addr & I2C_MSB_2B_MSK) >> 7); - iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); + iowrite32(i2c_10bit_addr_hi_from_msg(msgs) & ~I2C_M_RD, p + PCH_I2CDR); if (first) pch_i2c_start(adap); @@ -518,8 +502,7 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, if (rtn) return rtn; - addr_8_lsb = (addr & I2C_ADDR_MSK); - iowrite32(addr_8_lsb, p + PCH_I2CDR); + iowrite32(i2c_10bit_addr_lo_from_msg(msgs), p + PCH_I2CDR); pch_i2c_restart(adap); @@ -527,8 +510,7 @@ static s32 pch_i2c_readbytes(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, if (rtn) return rtn; - addr_2_msb |= I2C_RD; - iowrite32(addr_2_msb | TEN_BIT_ADDR_MASK, p + PCH_I2CDR); + iowrite32(i2c_10bit_addr_hi_from_msg(msgs), p + PCH_I2CDR); } else { /* 7 address bits + R/W bit */ iowrite32(i2c_8bit_addr_from_msg(msgs), p + PCH_I2CDR); @@ -708,7 +690,7 @@ static u32 pch_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm pch_algorithm = { - .master_xfer = pch_i2c_xfer, + .xfer = pch_i2c_xfer, .functionality = pch_i2c_func }; diff --git a/drivers/i2c/busses/i2c-elektor.c b/drivers/i2c/busses/i2c-elektor.c index b0f50dce9d0f..cfe8665cacd2 100644 --- a/drivers/i2c/busses/i2c-elektor.c +++ b/drivers/i2c/busses/i2c-elektor.c @@ -188,7 +188,7 @@ static struct i2c_algo_pcf_data pcf_isa_data = { static struct i2c_adapter pcf_isa_ops = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo_data = &pcf_isa_data, .name = "i2c-elektor", }; diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c index f2e537b137b2..ece019b3d066 100644 --- a/drivers/i2c/busses/i2c-emev2.c +++ b/drivers/i2c/busses/i2c-emev2.c @@ -16,7 +16,7 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/sched.h> @@ -67,7 +67,6 @@ struct em_i2c_device { void __iomem *base; struct i2c_adapter adap; struct completion msg_done; - struct clk *sclk; struct i2c_client *slave; int irq; }; @@ -352,15 +351,16 @@ static int em_i2c_unreg_slave(struct i2c_client *slave) } static const struct i2c_algorithm em_i2c_algo = { - .master_xfer = em_i2c_xfer, + .xfer = em_i2c_xfer, .functionality = em_i2c_func, - .reg_slave = em_i2c_reg_slave, - .unreg_slave = em_i2c_unreg_slave, + .reg_slave = em_i2c_reg_slave, + .unreg_slave = em_i2c_unreg_slave, }; static int em_i2c_probe(struct platform_device *pdev) { struct em_i2c_device *priv; + struct clk *sclk; int ret; priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); @@ -373,13 +373,9 @@ static int em_i2c_probe(struct platform_device *pdev) strscpy(priv->adap.name, "EMEV2 I2C", sizeof(priv->adap.name)); - priv->sclk = devm_clk_get(&pdev->dev, "sclk"); - if (IS_ERR(priv->sclk)) - return PTR_ERR(priv->sclk); - - ret = clk_prepare_enable(priv->sclk); - if (ret) - return ret; + sclk = devm_clk_get_enabled(&pdev->dev, "sclk"); + if (IS_ERR(sclk)) + return PTR_ERR(sclk); priv->adap.timeout = msecs_to_jiffies(100); priv->adap.retries = 5; @@ -397,36 +393,29 @@ static int em_i2c_probe(struct platform_device *pdev) ret = platform_get_irq(pdev, 0); if (ret < 0) - goto err_clk; + return ret; priv->irq = ret; + ret = devm_request_irq(&pdev->dev, priv->irq, em_i2c_irq_handler, 0, "em_i2c", priv); if (ret) - goto err_clk; + return ret; ret = i2c_add_adapter(&priv->adap); - if (ret) - goto err_clk; + return ret; dev_info(&pdev->dev, "Added i2c controller %d, irq %d\n", priv->adap.nr, priv->irq); return 0; - -err_clk: - clk_disable_unprepare(priv->sclk); - return ret; } -static int em_i2c_remove(struct platform_device *dev) +static void em_i2c_remove(struct platform_device *dev) { struct em_i2c_device *priv = platform_get_drvdata(dev); i2c_del_adapter(&priv->adap); - clk_disable_unprepare(priv->sclk); - - return 0; } static const struct of_device_id em_i2c_ids[] = { diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 4a6260d04db2..9c1c5f3c09f6 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -18,9 +18,7 @@ #include <linux/clk.h> #include <linux/slab.h> #include <linux/io.h> -#include <linux/of_address.h> -#include <linux/of_device.h> -#include <linux/of_irq.h> +#include <linux/of.h> #include <linux/spinlock.h> /* @@ -170,6 +168,7 @@ enum i2c_type_exynos { I2C_TYPE_EXYNOS5, I2C_TYPE_EXYNOS7, I2C_TYPE_EXYNOSAUTOV9, + I2C_TYPE_EXYNOS8895, }; struct exynos5_i2c { @@ -196,6 +195,11 @@ struct exynos5_i2c { */ int trans_done; + /* + * Called from atomic context, don't use interrupts. + */ + unsigned int atomic; + /* Controller operating frequency */ unsigned int op_clock; @@ -237,6 +241,11 @@ static const struct exynos_hsi2c_variant exynosautov9_hsi2c_data = { .hw = I2C_TYPE_EXYNOSAUTOV9, }; +static const struct exynos_hsi2c_variant exynos8895_hsi2c_data = { + .fifo_depth = 64, + .hw = I2C_TYPE_EXYNOS8895, +}; + static const struct of_device_id exynos5_i2c_match[] = { { .compatible = "samsung,exynos5-hsi2c", @@ -253,6 +262,9 @@ static const struct of_device_id exynos5_i2c_match[] = { }, { .compatible = "samsung,exynosautov9-hsi2c", .data = &exynosautov9_hsi2c_data + }, { + .compatible = "samsung,exynos8895-hsi2c", + .data = &exynos8895_hsi2c_data }, {}, }; MODULE_DEVICE_TABLE(of, exynos5_i2c_match); @@ -267,7 +279,7 @@ static void exynos5_i2c_clr_pend_irq(struct exynos5_i2c *i2c) * exynos5_i2c_set_timing: updates the registers with appropriate * timing values calculated * - * Timing values for operation are calculated against either 100kHz + * Timing values for operation are calculated against 100kHz, 400kHz * or 1MHz controller operating frequency. * * Returns 0 on success, -EINVAL if the cycle length cannot @@ -328,23 +340,67 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings) * clk_cycle := TSCLK_L + TSCLK_H * temp := (CLK_DIV + 1) * (clk_cycle + 2) * + * In case of HSI2C controllers in Exynos8895 + * FPCLK / FI2C = + * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + + * 2 * ((FLT_CYCLE + 3) - (FLT_CYCLE + 3) % (CLK_DIV + 1)) + * + * clk_cycle := TSCLK_L + TSCLK_H + * temp := (FPCLK / FI2C) - (FLT_CYCLE + 3) * 2 + * * Constraints: 4 <= temp, 0 <= CLK_DIV < 256, 2 <= clk_cycle <= 510 * + * To split SCL clock into low, high periods appropriately, one + * proportion factor for each I2C mode is used, which is calculated + * using this formula. + * ``` + * ((t_low_min + (scl_clock - t_low_min - t_high_min) / 2) / scl_clock) + * ``` + * where: + * t_low_min is the minimal value of low period of the SCL clock in us; + * t_high_min is the minimal value of high period of the SCL clock in us; + * scl_clock is converted from SCL clock frequency into us. + * + * Below are the proportion factors for these I2C modes: + * t_low_min, t_high_min, scl_clock, proportion + * Standard Mode: 4.7us, 4.0us, 10us, 0.535 + * Fast Mode: 1.3us, 0.6us, 2.5us, 0.64 + * Fast-Plus Mode: 0.5us, 0.26us, 1us, 0.62 + * */ t_ftl_cycle = (readl(i2c->regs + HSI2C_CONF) >> 16) & 0x7; - temp = clkin / op_clk - 8 - t_ftl_cycle; - if (i2c->variant->hw != I2C_TYPE_EXYNOS7) - temp -= t_ftl_cycle; + if (i2c->variant->hw == I2C_TYPE_EXYNOS8895) + temp = clkin / op_clk - (t_ftl_cycle + 3) * 2; + else if (i2c->variant->hw == I2C_TYPE_EXYNOS7) + temp = clkin / op_clk - 8 - t_ftl_cycle; + else + temp = clkin / op_clk - 8 - (t_ftl_cycle * 2); div = temp / 512; - clk_cycle = temp / (div + 1) - 2; + + if (i2c->variant->hw == I2C_TYPE_EXYNOS8895) + clk_cycle = (temp + ((t_ftl_cycle + 3) % (div + 1)) * 2) / + (div + 1) - 2; + else + clk_cycle = temp / (div + 1) - 2; if (temp < 4 || div >= 256 || clk_cycle < 2) { dev_err(i2c->dev, "%s clock set-up failed\n", hs_timings ? "HS" : "FS"); return -EINVAL; } - t_scl_l = clk_cycle / 2; - t_scl_h = clk_cycle / 2; + /* + * Scale clk_cycle to get t_scl_l using the proption factors for individual I2C modes. + */ + if (op_clk <= I2C_MAX_STANDARD_MODE_FREQ) + t_scl_l = clk_cycle * 535 / 1000; + else if (op_clk <= I2C_MAX_FAST_MODE_FREQ) + t_scl_l = clk_cycle * 64 / 100; + else + t_scl_l = clk_cycle * 62 / 100; + + if (t_scl_l > 0xFF) + t_scl_l = 0xFF; + t_scl_h = clk_cycle - t_scl_l; t_start_su = t_scl_l; t_start_hd = t_scl_l; t_stop_su = t_scl_l; @@ -460,6 +516,8 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) switch (i2c->variant->hw) { case I2C_TYPE_EXYNOSAUTOV9: fallthrough; + case I2C_TYPE_EXYNOS8895: + fallthrough; case I2C_TYPE_EXYNOS7: if (int_status & HSI2C_INT_TRANS_DONE) { i2c->trans_done = 1; @@ -713,10 +771,26 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) spin_unlock_irqrestore(&i2c->lock, flags); } +static bool exynos5_i2c_poll_irqs_timeout(struct exynos5_i2c *i2c, + unsigned long timeout) +{ + unsigned long time_left = jiffies + timeout; + + while (time_before(jiffies, time_left) && + !((i2c->trans_done && (i2c->msg->len == i2c->msg_ptr)) || + (i2c->state < 0))) { + while (readl(i2c->regs + HSI2C_INT_ENABLE) & + readl(i2c->regs + HSI2C_INT_STATUS)) + exynos5_i2c_irq(i2c->irq, i2c); + usleep_range(100, 200); + } + return time_before(jiffies, time_left); +} + static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c, struct i2c_msg *msgs, int stop) { - unsigned long timeout; + unsigned long time_left; int ret; i2c->msg = msgs; @@ -727,15 +801,20 @@ static int exynos5_i2c_xfer_msg(struct exynos5_i2c *i2c, exynos5_i2c_message_start(i2c, stop); - timeout = wait_for_completion_timeout(&i2c->msg_complete, - EXYNOS5_I2C_TIMEOUT); - if (timeout == 0) + if (!i2c->atomic) + time_left = wait_for_completion_timeout(&i2c->msg_complete, + EXYNOS5_I2C_TIMEOUT); + else + time_left = exynos5_i2c_poll_irqs_timeout(i2c, + EXYNOS5_I2C_TIMEOUT); + + if (time_left == 0) ret = -ETIMEDOUT; else ret = i2c->state; /* - * If this is the last message to be transfered (stop == 1) + * If this is the last message to be transferred (stop == 1) * Then check if the bus can be brought back to idle. */ if (ret == 0 && stop) @@ -779,14 +858,30 @@ err_pclk: return ret ?: num; } +static int exynos5_i2c_xfer_atomic(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct exynos5_i2c *i2c = adap->algo_data; + int ret; + + disable_irq(i2c->irq); + i2c->atomic = true; + ret = exynos5_i2c_xfer(adap, msgs, num); + i2c->atomic = false; + enable_irq(i2c->irq); + + return ret; +} + static u32 exynos5_i2c_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); } static const struct i2c_algorithm exynos5_i2c_algorithm = { - .master_xfer = exynos5_i2c_xfer, - .functionality = exynos5_i2c_func, + .xfer = exynos5_i2c_xfer, + .xfer_atomic = exynos5_i2c_xfer_atomic, + .functionality = exynos5_i2c_func, }; static int exynos5_i2c_probe(struct platform_device *pdev) @@ -882,7 +977,7 @@ static int exynos5_i2c_probe(struct platform_device *pdev) return ret; } -static int exynos5_i2c_remove(struct platform_device *pdev) +static void exynos5_i2c_remove(struct platform_device *pdev) { struct exynos5_i2c *i2c = platform_get_drvdata(pdev); @@ -890,11 +985,8 @@ static int exynos5_i2c_remove(struct platform_device *pdev) clk_unprepare(i2c->clk); clk_unprepare(i2c->pclk); - - return 0; } -#ifdef CONFIG_PM_SLEEP static int exynos5_i2c_suspend_noirq(struct device *dev) { struct exynos5_i2c *i2c = dev_get_drvdata(dev); @@ -936,11 +1028,10 @@ err_pclk: clk_disable_unprepare(i2c->pclk); return ret; } -#endif static const struct dev_pm_ops exynos5_i2c_dev_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos5_i2c_suspend_noirq, - exynos5_i2c_resume_noirq) + NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos5_i2c_suspend_noirq, + exynos5_i2c_resume_noirq) }; static struct platform_driver exynos5_i2c_driver = { @@ -948,7 +1039,7 @@ static struct platform_driver exynos5_i2c_driver = { .remove = exynos5_i2c_remove, .driver = { .name = "exynos5-hsi2c", - .pm = &exynos5_i2c_dev_pm_ops, + .pm = pm_sleep_ptr(&exynos5_i2c_dev_pm_ops), .of_match_table = exynos5_i2c_match, }, }; diff --git a/drivers/i2c/busses/i2c-fsi.c b/drivers/i2c/busses/i2c-fsi.c index 10332693edf0..ae016a9431da 100644 --- a/drivers/i2c/busses/i2c-fsi.c +++ b/drivers/i2c/busses/i2c-fsi.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0+ /* - * FSI-attached I2C master algorithm + * FSI-attached I2C controller algorithm * * Copyright 2018 IBM Corporation * @@ -145,7 +145,7 @@ /* choose timeout length from legacy driver; it's well tested */ #define I2C_ABORT_TIMEOUT msecs_to_jiffies(100) -struct fsi_i2c_master { +struct fsi_i2c_ctrl { struct fsi_device *fsi; u8 fifo_size; struct list_head ports; @@ -155,7 +155,7 @@ struct fsi_i2c_master { struct fsi_i2c_port { struct list_head list; struct i2c_adapter adapter; - struct fsi_i2c_master *master; + struct fsi_i2c_ctrl *ctrl; u16 port; u16 xfrd; }; @@ -183,7 +183,7 @@ static int fsi_i2c_write_reg(struct fsi_device *fsi, unsigned int reg, return fsi_device_write(fsi, reg, &data_be, sizeof(data_be)); } -static int fsi_i2c_dev_init(struct fsi_i2c_master *i2c) +static int fsi_i2c_dev_init(struct fsi_i2c_ctrl *i2c) { int rc; u32 mode = I2C_MODE_ENHANCED, extended_status, watermark; @@ -214,7 +214,7 @@ static int fsi_i2c_dev_init(struct fsi_i2c_master *i2c) static int fsi_i2c_set_port(struct fsi_i2c_port *port) { int rc; - struct fsi_device *fsi = port->master->fsi; + struct fsi_device *fsi = port->ctrl->fsi; u32 mode, dummy = 0; rc = fsi_i2c_read_reg(fsi, I2C_FSI_MODE, &mode); @@ -236,7 +236,7 @@ static int fsi_i2c_set_port(struct fsi_i2c_port *port) static int fsi_i2c_start(struct fsi_i2c_port *port, struct i2c_msg *msg, bool stop) { - struct fsi_i2c_master *i2c = port->master; + struct fsi_i2c_ctrl *i2c = port->ctrl; u32 cmd = I2C_CMD_WITH_START | I2C_CMD_WITH_ADDR; port->xfrd = 0; @@ -268,7 +268,7 @@ static int fsi_i2c_write_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg, { int write; int rc; - struct fsi_i2c_master *i2c = port->master; + struct fsi_i2c_ctrl *i2c = port->ctrl; int bytes_to_write = i2c->fifo_size - fifo_count; int bytes_remaining = msg->len - port->xfrd; @@ -294,7 +294,7 @@ static int fsi_i2c_read_fifo(struct fsi_i2c_port *port, struct i2c_msg *msg, { int read; int rc; - struct fsi_i2c_master *i2c = port->master; + struct fsi_i2c_ctrl *i2c = port->ctrl; int bytes_to_read; int xfr_remaining = msg->len - port->xfrd; u32 dummy; @@ -330,7 +330,7 @@ static int fsi_i2c_get_scl(struct i2c_adapter *adap) { u32 stat = 0; struct fsi_i2c_port *port = adap->algo_data; - struct fsi_i2c_master *i2c = port->master; + struct fsi_i2c_ctrl *i2c = port->ctrl; fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); @@ -341,7 +341,7 @@ static void fsi_i2c_set_scl(struct i2c_adapter *adap, int val) { u32 dummy = 0; struct fsi_i2c_port *port = adap->algo_data; - struct fsi_i2c_master *i2c = port->master; + struct fsi_i2c_ctrl *i2c = port->ctrl; if (val) fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SCL, &dummy); @@ -353,7 +353,7 @@ static int fsi_i2c_get_sda(struct i2c_adapter *adap) { u32 stat = 0; struct fsi_i2c_port *port = adap->algo_data; - struct fsi_i2c_master *i2c = port->master; + struct fsi_i2c_ctrl *i2c = port->ctrl; fsi_i2c_read_reg(i2c->fsi, I2C_FSI_STAT, &stat); @@ -364,7 +364,7 @@ static void fsi_i2c_set_sda(struct i2c_adapter *adap, int val) { u32 dummy = 0; struct fsi_i2c_port *port = adap->algo_data; - struct fsi_i2c_master *i2c = port->master; + struct fsi_i2c_ctrl *i2c = port->ctrl; if (val) fsi_i2c_write_reg(i2c->fsi, I2C_FSI_SET_SDA, &dummy); @@ -377,7 +377,7 @@ static void fsi_i2c_prepare_recovery(struct i2c_adapter *adap) int rc; u32 mode; struct fsi_i2c_port *port = adap->algo_data; - struct fsi_i2c_master *i2c = port->master; + struct fsi_i2c_ctrl *i2c = port->ctrl; rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode); if (rc) @@ -392,7 +392,7 @@ static void fsi_i2c_unprepare_recovery(struct i2c_adapter *adap) int rc; u32 mode; struct fsi_i2c_port *port = adap->algo_data; - struct fsi_i2c_master *i2c = port->master; + struct fsi_i2c_ctrl *i2c = port->ctrl; rc = fsi_i2c_read_reg(i2c->fsi, I2C_FSI_MODE, &mode); if (rc) @@ -402,7 +402,7 @@ static void fsi_i2c_unprepare_recovery(struct i2c_adapter *adap) fsi_i2c_write_reg(i2c->fsi, I2C_FSI_MODE, &mode); } -static int fsi_i2c_reset_bus(struct fsi_i2c_master *i2c, +static int fsi_i2c_reset_bus(struct fsi_i2c_ctrl *i2c, struct fsi_i2c_port *port) { int rc; @@ -435,7 +435,7 @@ static int fsi_i2c_reset_bus(struct fsi_i2c_master *i2c, return fsi_i2c_dev_init(i2c); } -static int fsi_i2c_reset_engine(struct fsi_i2c_master *i2c, u16 port) +static int fsi_i2c_reset_engine(struct fsi_i2c_ctrl *i2c, u16 port) { int rc; u32 mode, dummy = 0; @@ -478,7 +478,7 @@ static int fsi_i2c_abort(struct fsi_i2c_port *port, u32 status) unsigned long start; u32 cmd = I2C_CMD_WITH_STOP; u32 stat; - struct fsi_i2c_master *i2c = port->master; + struct fsi_i2c_ctrl *i2c = port->ctrl; struct fsi_device *fsi = i2c->fsi; rc = fsi_i2c_reset_engine(i2c, port->port); @@ -505,7 +505,7 @@ static int fsi_i2c_abort(struct fsi_i2c_port *port, u32 status) if (rc) return rc; - /* wait until we see command complete in the master */ + /* wait until we see command complete in the controller */ start = jiffies; do { @@ -579,7 +579,7 @@ static int fsi_i2c_wait(struct fsi_i2c_port *port, struct i2c_msg *msg, unsigned long start = jiffies; do { - rc = fsi_i2c_read_reg(port->master->fsi, I2C_FSI_STAT, + rc = fsi_i2c_read_reg(port->ctrl->fsi, I2C_FSI_STAT, &status); if (rc) return rc; @@ -609,10 +609,10 @@ static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int i, rc; unsigned long start_time; struct fsi_i2c_port *port = adap->algo_data; - struct fsi_i2c_master *master = port->master; + struct fsi_i2c_ctrl *ctrl = port->ctrl; struct i2c_msg *msg; - mutex_lock(&master->lock); + mutex_lock(&ctrl->lock); rc = fsi_i2c_set_port(port); if (rc) @@ -633,7 +633,7 @@ static int fsi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } unlock: - mutex_unlock(&master->lock); + mutex_unlock(&ctrl->lock); return rc ? : num; } @@ -654,7 +654,7 @@ static struct i2c_bus_recovery_info fsi_i2c_bus_recovery_info = { }; static const struct i2c_algorithm fsi_i2c_algorithm = { - .master_xfer = fsi_i2c_xfer, + .xfer = fsi_i2c_xfer, .functionality = fsi_i2c_functionality, }; @@ -676,7 +676,7 @@ static struct device_node *fsi_i2c_find_port_of_node(struct device_node *fsi, static int fsi_i2c_probe(struct device *dev) { - struct fsi_i2c_master *i2c; + struct fsi_i2c_ctrl *i2c; struct fsi_i2c_port *port; struct device_node *np; u32 port_no, ports, stat; @@ -699,7 +699,7 @@ static int fsi_i2c_probe(struct device *dev) return rc; ports = FIELD_GET(I2C_STAT_MAX_PORT, stat) + 1; - dev_dbg(dev, "I2C master has %d ports\n", ports); + dev_dbg(dev, "I2C controller has %d ports\n", ports); for (port_no = 0; port_no < ports; port_no++) { np = fsi_i2c_find_port_of_node(dev->of_node, port_no); @@ -712,7 +712,7 @@ static int fsi_i2c_probe(struct device *dev) break; } - port->master = i2c; + port->ctrl = i2c; port->port = port_no; port->adapter.owner = THIS_MODULE; @@ -742,7 +742,7 @@ static int fsi_i2c_probe(struct device *dev) static int fsi_i2c_remove(struct device *dev) { - struct fsi_i2c_master *i2c = dev_get_drvdata(dev); + struct fsi_i2c_ctrl *i2c = dev_get_drvdata(dev); struct fsi_i2c_port *port, *tmp; list_for_each_entry_safe(port, tmp, &i2c->ports, list) { @@ -772,5 +772,5 @@ static struct fsi_driver fsi_i2c_driver = { module_fsi_driver(fsi_i2c_driver); MODULE_AUTHOR("Eddie James <eajames@us.ibm.com>"); -MODULE_DESCRIPTION("FSI attached I2C master"); +MODULE_DESCRIPTION("FSI attached I2C controller"); MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-gpio.c b/drivers/i2c/busses/i2c-gpio.c index 0e4385a9bcf7..f4355b17bfbf 100644 --- a/drivers/i2c/busses/i2c-gpio.c +++ b/drivers/i2c/busses/i2c-gpio.c @@ -13,9 +13,9 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/module.h> -#include <linux/of.h> #include <linux/platform_data/i2c-gpio.h> #include <linux/platform_device.h> +#include <linux/property.h> #include <linux/slab.h> struct i2c_gpio_private_data { @@ -25,7 +25,6 @@ struct i2c_gpio_private_data { struct i2c_algo_bit_data bit_data; struct i2c_gpio_platform_data pdata; #ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR - struct dentry *debug_dir; /* these must be protected by bus lock */ struct completion scl_irq_completion; u64 scl_irq_data; @@ -72,7 +71,6 @@ static int i2c_gpio_getscl(void *data) } #ifdef CONFIG_I2C_GPIO_FAULT_INJECTOR -static struct dentry *i2c_gpio_debug_dir; #define setsda(bd, val) ((bd)->setsda((bd)->data, val)) #define setscl(bd, val) ((bd)->setscl((bd)->data, val)) @@ -218,8 +216,8 @@ static int fops_lose_arbitration_set(void *data, u64 duration) priv->scl_irq_data = duration; /* - * Interrupt on falling SCL. This ensures that the master under test has - * really started the transfer. Interrupt on falling SDA did only + * Interrupt on falling SCL. This ensures that the controller under test + * has really started the transfer. Interrupt on falling SDA did only * exercise 'bus busy' detection on some HW but not 'arbitration lost'. * Note that the interrupt latency may cause the first bits to be * transmitted correctly. @@ -247,8 +245,8 @@ static int fops_inject_panic_set(void *data, u64 duration) priv->scl_irq_data = duration; /* - * Interrupt on falling SCL. This ensures that the master under test has - * really started the transfer. + * Interrupt on falling SCL. This ensures that the controller under test + * has really started the transfer. */ return i2c_gpio_fi_act_on_scl_irq(priv, inject_panic_irq); } @@ -258,64 +256,48 @@ static void i2c_gpio_fault_injector_init(struct platform_device *pdev) { struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); - /* - * If there will be a debugfs-dir per i2c adapter somewhen, put the - * 'fault-injector' dir there. Until then, we have a global dir with - * all adapters as subdirs. - */ - if (!i2c_gpio_debug_dir) { - i2c_gpio_debug_dir = debugfs_create_dir("i2c-fault-injector", NULL); - if (!i2c_gpio_debug_dir) - return; - } - - priv->debug_dir = debugfs_create_dir(pdev->name, i2c_gpio_debug_dir); - if (!priv->debug_dir) - return; - init_completion(&priv->scl_irq_completion); - debugfs_create_file_unsafe("incomplete_address_phase", 0200, priv->debug_dir, + debugfs_create_file_unsafe("incomplete_address_phase", 0200, priv->adap.debugfs, priv, &fops_incomplete_addr_phase); - debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->debug_dir, + debugfs_create_file_unsafe("incomplete_write_byte", 0200, priv->adap.debugfs, priv, &fops_incomplete_write_byte); if (priv->bit_data.getscl) { - debugfs_create_file_unsafe("inject_panic", 0200, priv->debug_dir, + debugfs_create_file_unsafe("inject_panic", 0200, priv->adap.debugfs, priv, &fops_inject_panic); - debugfs_create_file_unsafe("lose_arbitration", 0200, priv->debug_dir, + debugfs_create_file_unsafe("lose_arbitration", 0200, priv->adap.debugfs, priv, &fops_lose_arbitration); } - debugfs_create_file_unsafe("scl", 0600, priv->debug_dir, priv, &fops_scl); - debugfs_create_file_unsafe("sda", 0600, priv->debug_dir, priv, &fops_sda); -} - -static void i2c_gpio_fault_injector_exit(struct platform_device *pdev) -{ - struct i2c_gpio_private_data *priv = platform_get_drvdata(pdev); - - debugfs_remove_recursive(priv->debug_dir); + debugfs_create_file_unsafe("scl", 0600, priv->adap.debugfs, priv, &fops_scl); + debugfs_create_file_unsafe("sda", 0600, priv->adap.debugfs, priv, &fops_sda); } #else static inline void i2c_gpio_fault_injector_init(struct platform_device *pdev) {} -static inline void i2c_gpio_fault_injector_exit(struct platform_device *pdev) {} #endif /* CONFIG_I2C_GPIO_FAULT_INJECTOR*/ -static void of_i2c_gpio_get_props(struct device_node *np, - struct i2c_gpio_platform_data *pdata) +/* Get i2c-gpio properties from DT or ACPI table */ +static void i2c_gpio_get_properties(struct device *dev, + struct i2c_gpio_platform_data *pdata) { u32 reg; - of_property_read_u32(np, "i2c-gpio,delay-us", &pdata->udelay); + device_property_read_u32(dev, "i2c-gpio,delay-us", &pdata->udelay); - if (!of_property_read_u32(np, "i2c-gpio,timeout-ms", ®)) + if (!device_property_read_u32(dev, "i2c-gpio,timeout-ms", ®)) pdata->timeout = msecs_to_jiffies(reg); pdata->sda_is_open_drain = - of_property_read_bool(np, "i2c-gpio,sda-open-drain"); + device_property_read_bool(dev, "i2c-gpio,sda-open-drain"); pdata->scl_is_open_drain = - of_property_read_bool(np, "i2c-gpio,scl-open-drain"); + device_property_read_bool(dev, "i2c-gpio,scl-open-drain"); pdata->scl_is_output_only = - of_property_read_bool(np, "i2c-gpio,scl-output-only"); + device_property_read_bool(dev, "i2c-gpio,scl-output-only"); + pdata->sda_is_output_only = + device_property_read_bool(dev, "i2c-gpio,sda-output-only"); + pdata->sda_has_no_pullup = + device_property_read_bool(dev, "i2c-gpio,sda-has-no-pullup"); + pdata->scl_has_no_pullup = + device_property_read_bool(dev, "i2c-gpio,scl-has-no-pullup"); } static struct gpio_desc *i2c_gpio_get_desc(struct device *dev, @@ -361,7 +343,7 @@ static int i2c_gpio_probe(struct platform_device *pdev) struct i2c_algo_bit_data *bit_data; struct i2c_adapter *adap; struct device *dev = &pdev->dev; - struct device_node *np = dev->of_node; + struct fwnode_handle *fwnode = dev_fwnode(dev); enum gpiod_flags gflags; int ret; @@ -373,8 +355,8 @@ static int i2c_gpio_probe(struct platform_device *pdev) bit_data = &priv->bit_data; pdata = &priv->pdata; - if (np) { - of_i2c_gpio_get_props(np, pdata); + if (fwnode) { + i2c_gpio_get_properties(dev, pdata); } else { /* * If all platform data settings are zero it is OK @@ -392,7 +374,7 @@ static int i2c_gpio_probe(struct platform_device *pdev) * handle them as we handle any other output. Else we enforce open * drain as this is required for an I2C bus. */ - if (pdata->sda_is_open_drain) + if (pdata->sda_is_open_drain || pdata->sda_has_no_pullup) gflags = GPIOD_OUT_HIGH; else gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; @@ -400,7 +382,7 @@ static int i2c_gpio_probe(struct platform_device *pdev) if (IS_ERR(priv->sda)) return PTR_ERR(priv->sda); - if (pdata->scl_is_open_drain) + if (pdata->scl_is_open_drain || pdata->scl_has_no_pullup) gflags = GPIOD_OUT_HIGH; else gflags = GPIOD_OUT_HIGH_OPEN_DRAIN; @@ -418,7 +400,8 @@ static int i2c_gpio_probe(struct platform_device *pdev) if (!pdata->scl_is_output_only) bit_data->getscl = i2c_gpio_getscl; - bit_data->getsda = i2c_gpio_getsda; + if (!pdata->sda_is_output_only) + bit_data->getsda = i2c_gpio_getsda; if (pdata->udelay) bit_data->udelay = pdata->udelay; @@ -435,15 +418,15 @@ static int i2c_gpio_probe(struct platform_device *pdev) bit_data->data = priv; adap->owner = THIS_MODULE; - if (np) + if (fwnode) strscpy(adap->name, dev_name(dev), sizeof(adap->name)); else snprintf(adap->name, sizeof(adap->name), "i2c-gpio%d", pdev->id); adap->algo_data = bit_data; - adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + adap->class = I2C_CLASS_HWMON; adap->dev.parent = dev; - adap->dev.of_node = np; + device_set_node(&adap->dev, fwnode); adap->nr = pdev->id; ret = i2c_bit_add_numbered_bus(adap); @@ -467,19 +450,15 @@ static int i2c_gpio_probe(struct platform_device *pdev) return 0; } -static int i2c_gpio_remove(struct platform_device *pdev) +static void i2c_gpio_remove(struct platform_device *pdev) { struct i2c_gpio_private_data *priv; struct i2c_adapter *adap; - i2c_gpio_fault_injector_exit(pdev); - priv = platform_get_drvdata(pdev); adap = &priv->adap; i2c_del_adapter(adap); - - return 0; } static const struct of_device_id i2c_gpio_dt_ids[] = { @@ -489,10 +468,17 @@ static const struct of_device_id i2c_gpio_dt_ids[] = { MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids); +static const struct acpi_device_id i2c_gpio_acpi_match[] = { + { "LOON0005" }, /* LoongArch */ + { } +}; +MODULE_DEVICE_TABLE(acpi, i2c_gpio_acpi_match); + static struct platform_driver i2c_gpio_driver = { .driver = { .name = "i2c-gpio", .of_match_table = i2c_gpio_dt_ids, + .acpi_match_table = i2c_gpio_acpi_match, }, .probe = i2c_gpio_probe, .remove = i2c_gpio_remove, diff --git a/drivers/i2c/busses/i2c-gxp.c b/drivers/i2c/busses/i2c-gxp.c new file mode 100644 index 000000000000..2d117e7e3cb6 --- /dev/null +++ b/drivers/i2c/busses/i2c-gxp.c @@ -0,0 +1,608 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Copyright (C) 2022 Hewlett-Packard Enterprise Development Company, L.P. */ + +#include <linux/err.h> +#include <linux/io.h> +#include <linux/i2c.h> +#include <linux/mod_devicetable.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> + +#define GXP_MAX_I2C_ENGINE 10 +static const char * const gxp_i2c_name[] = { + "gxp-i2c0", "gxp-i2c1", "gxp-i2c2", "gxp-i2c3", + "gxp-i2c4", "gxp-i2c5", "gxp-i2c6", "gxp-i2c7", + "gxp-i2c8", "gxp-i2c9" }; + +/* GXP I2C Global interrupt status/enable register*/ +#define GXP_I2CINTSTAT 0x00 +#define GXP_I2CINTEN 0x04 + +/* GXP I2C registers */ +#define GXP_I2CSTAT 0x00 +#define MASK_STOP_EVENT 0x20 +#define MASK_ACK 0x08 +#define MASK_RW 0x04 +#define GXP_I2CEVTERR 0x01 +#define MASK_SLAVE_CMD_EVENT 0x01 +#define MASK_SLAVE_DATA_EVENT 0x02 +#define MASK_MASTER_EVENT 0x10 +#define GXP_I2CSNPDAT 0x02 +#define GXP_I2CMCMD 0x04 +#define GXP_I2CSCMD 0x06 +#define GXP_I2CSNPAA 0x09 +#define GXP_I2CADVFEAT 0x0A +#define GXP_I2COWNADR 0x0B +#define GXP_I2CFREQDIV 0x0C +#define GXP_I2CFLTFAIR 0x0D +#define GXP_I2CTMOEDG 0x0E +#define GXP_I2CCYCTIM 0x0F + +/* I2CSCMD Bits */ +#define SNOOP_EVT_CLR 0x80 +#define SLAVE_EVT_CLR 0x40 +#define SNOOP_EVT_MASK 0x20 +#define SLAVE_EVT_MASK 0x10 +#define SLAVE_ACK_ENAB 0x08 +#define SLAVE_EVT_STALL 0x01 + +/* I2CMCMD Bits */ +#define MASTER_EVT_CLR 0x80 +#define MASTER_ACK_ENAB 0x08 +#define RW_CMD 0x04 +#define STOP_CMD 0x02 +#define START_CMD 0x01 + +/* I2CTMOEDG value */ +#define GXP_DATA_EDGE_RST_CTRL 0x0a /* 30ns */ + +/* I2CFLTFAIR Bits */ +#define FILTER_CNT 0x30 +#define FAIRNESS_CNT 0x02 + +enum { + GXP_I2C_IDLE = 0, + GXP_I2C_ADDR_PHASE, + GXP_I2C_RDATA_PHASE, + GXP_I2C_WDATA_PHASE, + GXP_I2C_ADDR_NACK, + GXP_I2C_DATA_NACK, + GXP_I2C_ERROR, + GXP_I2C_COMP +}; + +struct gxp_i2c_drvdata { + struct device *dev; + void __iomem *base; + struct i2c_timings t; + u32 engine; + int irq; + struct completion completion; + struct i2c_adapter adapter; + struct i2c_msg *curr_msg; + int msgs_remaining; + int msgs_num; + u8 *buf; + size_t buf_remaining; + unsigned char state; + struct i2c_client *slave; + unsigned char stopped; +}; + +static struct regmap *i2cg_map; + +static void gxp_i2c_start(struct gxp_i2c_drvdata *drvdata) +{ + u16 value; + + drvdata->buf = drvdata->curr_msg->buf; + drvdata->buf_remaining = drvdata->curr_msg->len; + + /* Note: Address in struct i2c_msg is 7 bits */ + value = drvdata->curr_msg->addr << 9; + + /* Read or Write */ + value |= drvdata->curr_msg->flags & I2C_M_RD ? RW_CMD | START_CMD : START_CMD; + + drvdata->state = GXP_I2C_ADDR_PHASE; + writew(value, drvdata->base + GXP_I2CMCMD); +} + +static int gxp_i2c_master_xfer(struct i2c_adapter *adapter, + struct i2c_msg *msgs, int num) +{ + int ret; + struct gxp_i2c_drvdata *drvdata = i2c_get_adapdata(adapter); + unsigned long time_left; + + drvdata->msgs_remaining = num; + drvdata->curr_msg = msgs; + drvdata->msgs_num = num; + reinit_completion(&drvdata->completion); + + gxp_i2c_start(drvdata); + + time_left = wait_for_completion_timeout(&drvdata->completion, + adapter->timeout); + ret = num - drvdata->msgs_remaining; + if (time_left == 0) + return -ETIMEDOUT; + + if (drvdata->state == GXP_I2C_ADDR_NACK) + return -ENXIO; + + if (drvdata->state == GXP_I2C_DATA_NACK) + return -EIO; + + return ret; +} + +static u32 gxp_i2c_func(struct i2c_adapter *adap) +{ + if (IS_ENABLED(CONFIG_I2C_SLAVE)) + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SLAVE; + + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +#if IS_ENABLED(CONFIG_I2C_SLAVE) +static int gxp_i2c_reg_slave(struct i2c_client *slave) +{ + struct gxp_i2c_drvdata *drvdata = i2c_get_adapdata(slave->adapter); + + if (drvdata->slave) + return -EBUSY; + + if (slave->flags & I2C_CLIENT_TEN) + return -EAFNOSUPPORT; + + drvdata->slave = slave; + + writeb(slave->addr << 1, drvdata->base + GXP_I2COWNADR); + writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK | SLAVE_ACK_ENAB | + SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD); + + return 0; +} + +static int gxp_i2c_unreg_slave(struct i2c_client *slave) +{ + struct gxp_i2c_drvdata *drvdata = i2c_get_adapdata(slave->adapter); + + WARN_ON(!drvdata->slave); + + writeb(0x00, drvdata->base + GXP_I2COWNADR); + writeb(SNOOP_EVT_CLR | SLAVE_EVT_CLR | SNOOP_EVT_MASK | + SLAVE_EVT_MASK, drvdata->base + GXP_I2CSCMD); + + drvdata->slave = NULL; + + return 0; +} +#endif + +static const struct i2c_algorithm gxp_i2c_algo = { + .xfer = gxp_i2c_master_xfer, + .functionality = gxp_i2c_func, +#if IS_ENABLED(CONFIG_I2C_SLAVE) + .reg_slave = gxp_i2c_reg_slave, + .unreg_slave = gxp_i2c_unreg_slave, +#endif +}; + +static void gxp_i2c_stop(struct gxp_i2c_drvdata *drvdata) +{ + /* Clear event and send stop */ + writeb(MASTER_EVT_CLR | STOP_CMD, drvdata->base + GXP_I2CMCMD); + + complete(&drvdata->completion); +} + +static void gxp_i2c_restart(struct gxp_i2c_drvdata *drvdata) +{ + u16 value; + + drvdata->buf = drvdata->curr_msg->buf; + drvdata->buf_remaining = drvdata->curr_msg->len; + + value = drvdata->curr_msg->addr << 9; + + if (drvdata->curr_msg->flags & I2C_M_RD) { + /* Read and clear master event */ + value |= MASTER_EVT_CLR | RW_CMD | START_CMD; + } else { + /* Write and clear master event */ + value |= MASTER_EVT_CLR | START_CMD; + } + + drvdata->state = GXP_I2C_ADDR_PHASE; + + writew(value, drvdata->base + GXP_I2CMCMD); +} + +static void gxp_i2c_chk_addr_ack(struct gxp_i2c_drvdata *drvdata) +{ + u16 value; + + value = readb(drvdata->base + GXP_I2CSTAT); + if (!(value & MASK_ACK)) { + /* Got no ack, stop */ + drvdata->state = GXP_I2C_ADDR_NACK; + gxp_i2c_stop(drvdata); + return; + } + + if (drvdata->curr_msg->flags & I2C_M_RD) { + /* Start to read data from slave */ + if (drvdata->buf_remaining == 0) { + /* No more data to read, stop */ + drvdata->msgs_remaining--; + drvdata->state = GXP_I2C_COMP; + gxp_i2c_stop(drvdata); + return; + } + drvdata->state = GXP_I2C_RDATA_PHASE; + + if (drvdata->buf_remaining == 1) { + /* The last data, do not ack */ + writeb(MASTER_EVT_CLR | RW_CMD, + drvdata->base + GXP_I2CMCMD); + } else { + /* Read data and ack it */ + writeb(MASTER_EVT_CLR | MASTER_ACK_ENAB | + RW_CMD, drvdata->base + GXP_I2CMCMD); + } + } else { + /* Start to write first data to slave */ + if (drvdata->buf_remaining == 0) { + /* No more data to write, stop */ + drvdata->msgs_remaining--; + drvdata->state = GXP_I2C_COMP; + gxp_i2c_stop(drvdata); + return; + } + value = *drvdata->buf; + value = value << 8; + /* Clear master event */ + value |= MASTER_EVT_CLR; + drvdata->buf++; + drvdata->buf_remaining--; + drvdata->state = GXP_I2C_WDATA_PHASE; + writew(value, drvdata->base + GXP_I2CMCMD); + } +} + +static void gxp_i2c_ack_data(struct gxp_i2c_drvdata *drvdata) +{ + u8 value; + + /* Store the data returned */ + value = readb(drvdata->base + GXP_I2CSNPDAT); + *drvdata->buf = value; + drvdata->buf++; + drvdata->buf_remaining--; + + if (drvdata->buf_remaining == 0) { + /* No more data, this message is completed. */ + drvdata->msgs_remaining--; + + if (drvdata->msgs_remaining == 0) { + /* No more messages, stop */ + drvdata->state = GXP_I2C_COMP; + gxp_i2c_stop(drvdata); + return; + } + /* Move to next message and start transfer */ + drvdata->curr_msg++; + gxp_i2c_restart(drvdata); + return; + } + + /* Ack the slave to make it send next byte */ + drvdata->state = GXP_I2C_RDATA_PHASE; + if (drvdata->buf_remaining == 1) { + /* The last data, do not ack */ + writeb(MASTER_EVT_CLR | RW_CMD, + drvdata->base + GXP_I2CMCMD); + } else { + /* Read data and ack it */ + writeb(MASTER_EVT_CLR | MASTER_ACK_ENAB | + RW_CMD, drvdata->base + GXP_I2CMCMD); + } +} + +static void gxp_i2c_chk_data_ack(struct gxp_i2c_drvdata *drvdata) +{ + u16 value; + + value = readb(drvdata->base + GXP_I2CSTAT); + if (!(value & MASK_ACK)) { + /* Received No ack, stop */ + drvdata->state = GXP_I2C_DATA_NACK; + gxp_i2c_stop(drvdata); + return; + } + + /* Got ack, check if there is more data to write */ + if (drvdata->buf_remaining == 0) { + /* No more data, this message is completed */ + drvdata->msgs_remaining--; + + if (drvdata->msgs_remaining == 0) { + /* No more messages, stop */ + drvdata->state = GXP_I2C_COMP; + gxp_i2c_stop(drvdata); + return; + } + /* Move to next message and start transfer */ + drvdata->curr_msg++; + gxp_i2c_restart(drvdata); + return; + } + + /* Write data to slave */ + value = *drvdata->buf; + value = value << 8; + + /* Clear master event */ + value |= MASTER_EVT_CLR; + drvdata->buf++; + drvdata->buf_remaining--; + drvdata->state = GXP_I2C_WDATA_PHASE; + writew(value, drvdata->base + GXP_I2CMCMD); +} + +static bool gxp_i2c_slave_irq_handler(struct gxp_i2c_drvdata *drvdata) +{ + u8 value; + u8 buf; + int ret; + + value = readb(drvdata->base + GXP_I2CEVTERR); + + /* Received start or stop event */ + if (value & MASK_SLAVE_CMD_EVENT) { + value = readb(drvdata->base + GXP_I2CSTAT); + /* Master sent stop */ + if (value & MASK_STOP_EVENT) { + if (drvdata->stopped == 0) + i2c_slave_event(drvdata->slave, I2C_SLAVE_STOP, &buf); + writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK | + SLAVE_ACK_ENAB | SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD); + drvdata->stopped = 1; + } else { + /* Master sent start and wants to read */ + drvdata->stopped = 0; + if (value & MASK_RW) { + i2c_slave_event(drvdata->slave, + I2C_SLAVE_READ_REQUESTED, &buf); + value = buf << 8 | (SLAVE_EVT_CLR | SNOOP_EVT_MASK | + SLAVE_EVT_STALL); + writew(value, drvdata->base + GXP_I2CSCMD); + } else { + /* Master wants to write to us */ + ret = i2c_slave_event(drvdata->slave, + I2C_SLAVE_WRITE_REQUESTED, &buf); + if (!ret) { + /* Ack next byte from master */ + writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK | + SLAVE_ACK_ENAB | SLAVE_EVT_STALL, + drvdata->base + GXP_I2CSCMD); + } else { + /* Nack next byte from master */ + writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK | + SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD); + } + } + } + } else if (value & MASK_SLAVE_DATA_EVENT) { + value = readb(drvdata->base + GXP_I2CSTAT); + /* Master wants to read */ + if (value & MASK_RW) { + /* Master wants another byte */ + if (value & MASK_ACK) { + i2c_slave_event(drvdata->slave, + I2C_SLAVE_READ_PROCESSED, &buf); + value = buf << 8 | (SLAVE_EVT_CLR | SNOOP_EVT_MASK | + SLAVE_EVT_STALL); + writew(value, drvdata->base + GXP_I2CSCMD); + } else { + /* No more bytes needed */ + writew(SLAVE_EVT_CLR | SNOOP_EVT_MASK | + SLAVE_ACK_ENAB | SLAVE_EVT_STALL, + drvdata->base + GXP_I2CSCMD); + } + } else { + /* Master wants to write to us */ + value = readb(drvdata->base + GXP_I2CSNPDAT); + buf = (uint8_t)value; + ret = i2c_slave_event(drvdata->slave, + I2C_SLAVE_WRITE_RECEIVED, &buf); + if (!ret) { + /* Ack next byte from master */ + writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK | + SLAVE_ACK_ENAB | SLAVE_EVT_STALL, + drvdata->base + GXP_I2CSCMD); + } else { + /* Nack next byte from master */ + writeb(SLAVE_EVT_CLR | SNOOP_EVT_MASK | + SLAVE_EVT_STALL, drvdata->base + GXP_I2CSCMD); + } + } + } else { + return false; + } + + return true; +} + +static irqreturn_t gxp_i2c_irq_handler(int irq, void *_drvdata) +{ + struct gxp_i2c_drvdata *drvdata = (struct gxp_i2c_drvdata *)_drvdata; + u32 value; + + /* Check if the interrupt is for the current engine */ + regmap_read(i2cg_map, GXP_I2CINTSTAT, &value); + if (!(value & BIT(drvdata->engine))) + return IRQ_NONE; + + value = readb(drvdata->base + GXP_I2CEVTERR); + + /* Error */ + if (value & ~(MASK_MASTER_EVENT | MASK_SLAVE_CMD_EVENT | + MASK_SLAVE_DATA_EVENT)) { + /* Clear all events */ + writeb(0x00, drvdata->base + GXP_I2CEVTERR); + drvdata->state = GXP_I2C_ERROR; + gxp_i2c_stop(drvdata); + return IRQ_HANDLED; + } + + if (IS_ENABLED(CONFIG_I2C_SLAVE)) { + /* Slave mode */ + if (value & (MASK_SLAVE_CMD_EVENT | MASK_SLAVE_DATA_EVENT)) { + if (gxp_i2c_slave_irq_handler(drvdata)) + return IRQ_HANDLED; + return IRQ_NONE; + } + } + + /* Master mode */ + switch (drvdata->state) { + case GXP_I2C_ADDR_PHASE: + gxp_i2c_chk_addr_ack(drvdata); + break; + + case GXP_I2C_RDATA_PHASE: + gxp_i2c_ack_data(drvdata); + break; + + case GXP_I2C_WDATA_PHASE: + gxp_i2c_chk_data_ack(drvdata); + break; + } + + return IRQ_HANDLED; +} + +static void gxp_i2c_init(struct gxp_i2c_drvdata *drvdata) +{ + drvdata->state = GXP_I2C_IDLE; + writeb(2000000 / drvdata->t.bus_freq_hz, + drvdata->base + GXP_I2CFREQDIV); + writeb(FILTER_CNT | FAIRNESS_CNT, + drvdata->base + GXP_I2CFLTFAIR); + writeb(GXP_DATA_EDGE_RST_CTRL, drvdata->base + GXP_I2CTMOEDG); + writeb(0x00, drvdata->base + GXP_I2CCYCTIM); + writeb(0x00, drvdata->base + GXP_I2CSNPAA); + writeb(0x00, drvdata->base + GXP_I2CADVFEAT); + writeb(SNOOP_EVT_CLR | SLAVE_EVT_CLR | SNOOP_EVT_MASK | + SLAVE_EVT_MASK, drvdata->base + GXP_I2CSCMD); + writeb(MASTER_EVT_CLR, drvdata->base + GXP_I2CMCMD); + writeb(0x00, drvdata->base + GXP_I2CEVTERR); + writeb(0x00, drvdata->base + GXP_I2COWNADR); +} + +static int gxp_i2c_probe(struct platform_device *pdev) +{ + struct gxp_i2c_drvdata *drvdata; + int rc; + struct i2c_adapter *adapter; + + if (!i2cg_map) { + i2cg_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, + "hpe,sysreg"); + if (IS_ERR(i2cg_map)) { + return dev_err_probe(&pdev->dev, PTR_ERR(i2cg_map), + "failed to map i2cg_handle\n"); + } + + /* Disable interrupt */ + regmap_update_bits(i2cg_map, GXP_I2CINTEN, 0x00000FFF, 0); + } + + drvdata = devm_kzalloc(&pdev->dev, sizeof(*drvdata), + GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + platform_set_drvdata(pdev, drvdata); + drvdata->dev = &pdev->dev; + init_completion(&drvdata->completion); + + drvdata->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(drvdata->base)) + return PTR_ERR(drvdata->base); + + /* Use physical memory address to determine which I2C engine this is. */ + drvdata->engine = ((size_t)drvdata->base & 0xf00) >> 8; + + if (drvdata->engine >= GXP_MAX_I2C_ENGINE) { + return dev_err_probe(&pdev->dev, -EINVAL, "i2c engine% is unsupported\n", + drvdata->engine); + } + + rc = platform_get_irq(pdev, 0); + if (rc < 0) + return rc; + + drvdata->irq = rc; + rc = devm_request_irq(&pdev->dev, drvdata->irq, gxp_i2c_irq_handler, + IRQF_SHARED, gxp_i2c_name[drvdata->engine], drvdata); + if (rc < 0) + return dev_err_probe(&pdev->dev, rc, "irq request failed\n"); + + i2c_parse_fw_timings(&pdev->dev, &drvdata->t, true); + + gxp_i2c_init(drvdata); + + /* Enable interrupt */ + regmap_update_bits(i2cg_map, GXP_I2CINTEN, BIT(drvdata->engine), + BIT(drvdata->engine)); + + adapter = &drvdata->adapter; + i2c_set_adapdata(adapter, drvdata); + + adapter->owner = THIS_MODULE; + strscpy(adapter->name, "HPE GXP I2C adapter", sizeof(adapter->name)); + adapter->algo = &gxp_i2c_algo; + adapter->dev.parent = &pdev->dev; + adapter->dev.of_node = pdev->dev.of_node; + + rc = i2c_add_adapter(adapter); + if (rc) + return dev_err_probe(&pdev->dev, rc, "i2c add adapter failed\n"); + + return 0; +} + +static void gxp_i2c_remove(struct platform_device *pdev) +{ + struct gxp_i2c_drvdata *drvdata = platform_get_drvdata(pdev); + + /* Disable interrupt */ + regmap_update_bits(i2cg_map, GXP_I2CINTEN, BIT(drvdata->engine), 0); + i2c_del_adapter(&drvdata->adapter); +} + +static const struct of_device_id gxp_i2c_of_match[] = { + { .compatible = "hpe,gxp-i2c" }, + {}, +}; +MODULE_DEVICE_TABLE(of, gxp_i2c_of_match); + +static struct platform_driver gxp_i2c_driver = { + .probe = gxp_i2c_probe, + .remove = gxp_i2c_remove, + .driver = { + .name = "gxp-i2c", + .of_match_table = gxp_i2c_of_match, + }, +}; +module_platform_driver(gxp_i2c_driver); + +MODULE_AUTHOR("Nick Hawkins <nick.hawkins@hpe.com>"); +MODULE_DESCRIPTION("HPE GXP I2C bus driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c index 4374a8677271..78c5845e0877 100644 --- a/drivers/i2c/busses/i2c-highlander.c +++ b/drivers/i2c/busses/i2c-highlander.c @@ -331,7 +331,7 @@ static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, /* Ensure we're in a sane state */ highlander_i2c_done(dev); - /* Set slave address */ + /* Set target address */ iowrite16((addr << 1) | read_write, dev->base + SMSMADR); highlander_i2c_command(dev, command, dev->buf_len); @@ -435,7 +435,7 @@ err: return ret; } -static int highlander_i2c_remove(struct platform_device *pdev) +static void highlander_i2c_remove(struct platform_device *pdev) { struct highlander_i2c_dev *dev = platform_get_drvdata(pdev); @@ -446,8 +446,6 @@ static int highlander_i2c_remove(struct platform_device *pdev) iounmap(dev->base); kfree(dev); - - return 0; } static struct platform_driver highlander_i2c_driver = { diff --git a/drivers/i2c/busses/i2c-hisi.c b/drivers/i2c/busses/i2c-hisi.c index 8c6c7075c765..4b735ad9e193 100644 --- a/drivers/i2c/busses/i2c-hisi.c +++ b/drivers/i2c/busses/i2c-hisi.c @@ -57,6 +57,8 @@ #define HISI_I2C_FS_SPK_LEN_CNT GENMASK(7, 0) #define HISI_I2C_HS_SPK_LEN 0x003c #define HISI_I2C_HS_SPK_LEN_CNT GENMASK(7, 0) +#define HISI_I2C_TX_INT_CLR 0x0040 +#define HISI_I2C_TX_AEMPTY_INT BIT(0) #define HISI_I2C_INT_MSTAT 0x0044 #define HISI_I2C_INT_CLR 0x0048 #define HISI_I2C_INT_MASK 0x004C @@ -124,6 +126,11 @@ static void hisi_i2c_clear_int(struct hisi_i2c_controller *ctlr, u32 mask) writel_relaxed(mask, ctlr->iobase + HISI_I2C_INT_CLR); } +static void hisi_i2c_clear_tx_int(struct hisi_i2c_controller *ctlr, u32 mask) +{ + writel_relaxed(mask, ctlr->iobase + HISI_I2C_TX_INT_CLR); +} + static void hisi_i2c_handle_errors(struct hisi_i2c_controller *ctlr) { u32 int_err = ctlr->xfer_err, reg; @@ -168,6 +175,7 @@ static int hisi_i2c_start_xfer(struct hisi_i2c_controller *ctlr) writel(reg, ctlr->iobase + HISI_I2C_FIFO_CTRL); hisi_i2c_clear_int(ctlr, HISI_I2C_INT_ALL); + hisi_i2c_clear_tx_int(ctlr, HISI_I2C_TX_AEMPTY_INT); hisi_i2c_enable_int(ctlr, HISI_I2C_INT_ALL); return 0; @@ -189,8 +197,8 @@ static void hisi_i2c_reset_xfer(struct hisi_i2c_controller *ctlr) * wait for the transfer done. The major transfer process is performed * in the IRQ handler. */ -static int hisi_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num) +static int hisi_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) { struct hisi_i2c_controller *ctlr = i2c_get_adapdata(adap); DECLARE_COMPLETION_ONSTACK(done); @@ -228,8 +236,8 @@ static u32 hisi_i2c_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm hisi_i2c_algo = { - .master_xfer = hisi_i2c_master_xfer, - .functionality = hisi_i2c_functionality, + .xfer = hisi_i2c_xfer, + .functionality = hisi_i2c_functionality, }; static int hisi_i2c_read_rx_fifo(struct hisi_i2c_controller *ctlr) @@ -266,7 +274,7 @@ static int hisi_i2c_read_rx_fifo(struct hisi_i2c_controller *ctlr) static void hisi_i2c_xfer_msg(struct hisi_i2c_controller *ctlr) { - int max_write = HISI_I2C_TX_FIFO_DEPTH; + int max_write = HISI_I2C_TX_FIFO_DEPTH - HISI_I2C_TX_F_AE_THRESH; bool need_restart = false, last_msg; struct i2c_msg *cur_msg; u32 cmd, fifo_state; @@ -316,6 +324,15 @@ static void hisi_i2c_xfer_msg(struct hisi_i2c_controller *ctlr) max_write == 0) break; } + + /* + * Disable the TX_EMPTY interrupt after finishing all the messages to + * avoid overwhelming the CPU. + */ + if (ctlr->msg_tx_idx == ctlr->msg_num) + hisi_i2c_disable_int(ctlr, HISI_I2C_INT_TX_EMPTY); + + hisi_i2c_clear_tx_int(ctlr, HISI_I2C_TX_AEMPTY_INT); } static irqreturn_t hisi_i2c_irq(int irq, void *context) @@ -323,6 +340,14 @@ static irqreturn_t hisi_i2c_irq(int irq, void *context) struct hisi_i2c_controller *ctlr = context; u32 int_stat; + /* + * Don't handle the interrupt if cltr->completion is NULL. We may + * reach here because the interrupt is spurious or the transfer is + * started by another port (e.g. firmware) rather than us. + */ + if (!ctlr->completion) + return IRQ_NONE; + int_stat = readl(ctlr->iobase + HISI_I2C_INT_MSTAT); hisi_i2c_clear_int(ctlr, int_stat); if (!(int_stat & HISI_I2C_INT_ALL)) @@ -341,9 +366,14 @@ static irqreturn_t hisi_i2c_irq(int irq, void *context) hisi_i2c_read_rx_fifo(ctlr); out: - if (int_stat & HISI_I2C_INT_TRANS_CPLT || ctlr->xfer_err) { + /* + * Only use TRANS_CPLT to indicate the completion. On error cases we'll + * get two interrupts, INT_ERR first then TRANS_CPLT. + */ + if (int_stat & HISI_I2C_INT_TRANS_CPLT) { hisi_i2c_disable_int(ctlr, HISI_I2C_INT_ALL); hisi_i2c_clear_int(ctlr, HISI_I2C_INT_ALL); + hisi_i2c_clear_tx_int(ctlr, HISI_I2C_TX_AEMPTY_INT); complete(ctlr->completion); } @@ -451,18 +481,14 @@ static int hisi_i2c_probe(struct platform_device *pdev) hisi_i2c_disable_int(ctlr, HISI_I2C_INT_ALL); ret = devm_request_irq(dev, ctlr->irq, hisi_i2c_irq, 0, "hisi-i2c", ctlr); - if (ret) { - dev_err(dev, "failed to request irq handler, ret = %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to request irq handler\n"); ctlr->clk = devm_clk_get_optional_enabled(&pdev->dev, NULL); if (IS_ERR_OR_NULL(ctlr->clk)) { ret = device_property_read_u64(dev, "clk_rate", &clk_rate_hz); - if (ret) { - dev_err(dev, "failed to get clock frequency, ret = %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "failed to get clock frequency\n"); } else { clk_rate_hz = clk_get_rate(ctlr->clk); } diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c index 0e34cbaca22d..95ab910b80c0 100644 --- a/drivers/i2c/busses/i2c-hix5hd2.c +++ b/drivers/i2c/busses/i2c-hix5hd2.c @@ -200,7 +200,7 @@ static void hix5hd2_read_handle(struct hix5hd2_i2c_priv *priv) /* the last byte don't need send ACK */ writel_relaxed(I2C_READ | I2C_NO_ACK, priv->regs + HIX5I2C_COM); } else if (priv->msg_len > 1) { - /* if i2c master receive data will send ACK */ + /* if i2c controller receive data will send ACK */ writel_relaxed(I2C_READ, priv->regs + HIX5I2C_COM); } else { hix5hd2_rw_handle_stop(priv); @@ -314,7 +314,7 @@ static void hix5hd2_i2c_message_start(struct hix5hd2_i2c_priv *priv, int stop) static int hix5hd2_i2c_xfer_msg(struct hix5hd2_i2c_priv *priv, struct i2c_msg *msgs, int stop) { - unsigned long timeout; + unsigned long time_left; int ret; priv->msg = msgs; @@ -327,9 +327,9 @@ static int hix5hd2_i2c_xfer_msg(struct hix5hd2_i2c_priv *priv, reinit_completion(&priv->msg_complete); hix5hd2_i2c_message_start(priv, stop); - timeout = wait_for_completion_timeout(&priv->msg_complete, - priv->adap.timeout); - if (timeout == 0) { + time_left = wait_for_completion_timeout(&priv->msg_complete, + priv->adap.timeout); + if (time_left == 0) { priv->state = HIX5I2C_STAT_RW_ERR; priv->err = -ETIMEDOUT; dev_warn(priv->dev, "%s timeout=%d\n", @@ -339,7 +339,7 @@ static int hix5hd2_i2c_xfer_msg(struct hix5hd2_i2c_priv *priv, ret = priv->state; /* - * If this is the last message to be transfered (stop == 1) + * If this is the last message to be transferred (stop == 1) * Then check if the bus can be brought back to idle. */ if (priv->state == HIX5I2C_STAT_RW_SUCCESS && stop) @@ -360,7 +360,11 @@ static int hix5hd2_i2c_xfer(struct i2c_adapter *adap, pm_runtime_get_sync(priv->dev); for (i = 0; i < num; i++, msgs++) { - stop = (i == num - 1); + if ((i == num - 1) || (msgs->flags & I2C_M_STOP)) + stop = 1; + else + stop = 0; + ret = hix5hd2_i2c_xfer_msg(priv, msgs, stop); if (ret < 0) goto out; @@ -369,7 +373,6 @@ static int hix5hd2_i2c_xfer(struct i2c_adapter *adap, ret = num; out: - pm_runtime_mark_last_busy(priv->dev); pm_runtime_put_autosuspend(priv->dev); return ret; } @@ -380,8 +383,8 @@ static u32 hix5hd2_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm hix5hd2_i2c_algorithm = { - .master_xfer = hix5hd2_i2c_xfer, - .functionality = hix5hd2_i2c_func, + .xfer = hix5hd2_i2c_xfer, + .functionality = hix5hd2_i2c_func, }; static int hix5hd2_i2c_probe(struct platform_device *pdev) @@ -416,12 +419,11 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev) if (irq < 0) return irq; - priv->clk = devm_clk_get(&pdev->dev, NULL); + priv->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { - dev_err(&pdev->dev, "cannot get clock\n"); + dev_err(&pdev->dev, "cannot enable clock\n"); return PTR_ERR(priv->clk); } - clk_prepare_enable(priv->clk); strscpy(priv->adap.name, "hix5hd2-i2c", sizeof(priv->adap.name)); priv->dev = &pdev->dev; @@ -442,7 +444,7 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev) IRQF_NO_SUSPEND, dev_name(&pdev->dev), priv); if (ret != 0) { dev_err(&pdev->dev, "cannot request HS-I2C IRQ %d\n", irq); - goto err_clk; + return ret; } pm_runtime_set_autosuspend_delay(priv->dev, MSEC_PER_SEC); @@ -459,24 +461,19 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev) err_runtime: pm_runtime_disable(priv->dev); pm_runtime_set_suspended(priv->dev); -err_clk: - clk_disable_unprepare(priv->clk); + return ret; } -static int hix5hd2_i2c_remove(struct platform_device *pdev) +static void hix5hd2_i2c_remove(struct platform_device *pdev) { struct hix5hd2_i2c_priv *priv = platform_get_drvdata(pdev); i2c_del_adapter(&priv->adap); pm_runtime_disable(priv->dev); pm_runtime_set_suspended(priv->dev); - clk_disable_unprepare(priv->clk); - - return 0; } -#ifdef CONFIG_PM static int hix5hd2_i2c_runtime_suspend(struct device *dev) { struct hix5hd2_i2c_priv *priv = dev_get_drvdata(dev); @@ -495,12 +492,11 @@ static int hix5hd2_i2c_runtime_resume(struct device *dev) return 0; } -#endif static const struct dev_pm_ops hix5hd2_i2c_pm_ops = { - SET_RUNTIME_PM_OPS(hix5hd2_i2c_runtime_suspend, - hix5hd2_i2c_runtime_resume, - NULL) + RUNTIME_PM_OPS(hix5hd2_i2c_runtime_suspend, + hix5hd2_i2c_runtime_resume, + NULL) }; static const struct of_device_id hix5hd2_i2c_match[] = { @@ -514,7 +510,7 @@ static struct platform_driver hix5hd2_i2c_driver = { .remove = hix5hd2_i2c_remove, .driver = { .name = "hix5hd2-i2c", - .pm = &hix5hd2_i2c_pm_ops, + .pm = pm_ptr(&hix5hd2_i2c_pm_ops), .of_match_table = hix5hd2_i2c_match, }, }; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 1fda1eaa6d6a..81e6e2d7ad3d 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -77,6 +77,14 @@ * Alder Lake-M (PCH) 0x54a3 32 hard yes yes yes * Raptor Lake-S (PCH) 0x7a23 32 hard yes yes yes * Meteor Lake-P (SOC) 0x7e22 32 hard yes yes yes + * Meteor Lake SoC-S (SOC) 0xae22 32 hard yes yes yes + * Meteor Lake PCH-S (PCH) 0x7f23 32 hard yes yes yes + * Birch Stream (SOC) 0x5796 32 hard yes yes yes + * Arrow Lake-H (SOC) 0x7722 32 hard yes yes yes + * Panther Lake-H (SOC) 0xe322 32 hard yes yes yes + * Panther Lake-P (SOC) 0xe422 32 hard yes yes yes + * Wildcat Lake-U (SOC) 0x4d22 32 hard yes yes yes + * Diamond Rapids (SOC) 0x5827 32 hard yes yes yes * * Features supported by this driver: * Software PEC no @@ -84,7 +92,7 @@ * Block buffer yes * Block process call transaction yes * I2C block read transaction yes (doesn't use the block buffer) - * Slave mode no + * Target mode no * SMBus Host Notify yes * Interrupt processing yes * @@ -102,6 +110,7 @@ #include <linux/ioport.h> #include <linux/init.h> #include <linux/i2c.h> +#include <linux/i2c-mux.h> #include <linux/i2c-smbus.h> #include <linux/acpi.h> #include <linux/io.h> @@ -116,7 +125,7 @@ #include <linux/pm_runtime.h> #include <linux/mutex.h> -#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI +#ifdef CONFIG_I2C_I801_MUX #include <linux/gpio/machine.h> #include <linux/platform_data/i2c-mux-gpio.h> #endif @@ -137,6 +146,7 @@ #define SMBNTFDADD(p) (20 + (p)->smba) /* ICH3 and later */ /* PCI Address Constants */ +#define SMBBAR_MMIO 0 #define SMBBAR 4 #define SMBHSTCFG 0x040 #define TCOBASE 0x050 @@ -202,6 +212,8 @@ #define STATUS_FLAGS (SMBHSTSTS_BYTE_DONE | SMBHSTSTS_INTR | \ STATUS_ERROR_FLAGS) +#define SMBUS_LEN_SENTINEL (I2C_SMBUS_BLOCK_MAX + 1) + /* Older devices have their ID defined in <linux/pci_ids.h> */ #define PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS 0x02a3 #define PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS 0x06a3 @@ -226,13 +238,18 @@ #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 #define PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS 0x43a3 #define PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS 0x4b23 +#define PCI_DEVICE_ID_INTEL_WILDCAT_LAKE_U_SMBUS 0x4d22 #define PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS 0x4da3 #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS 0x51a3 #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_M_SMBUS 0x54a3 +#define PCI_DEVICE_ID_INTEL_BIRCH_STREAM_SMBUS 0x5796 +#define PCI_DEVICE_ID_INTEL_DIAMOND_RAPIDS_SMBUS 0x5827 #define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4 +#define PCI_DEVICE_ID_INTEL_ARROW_LAKE_H_SMBUS 0x7722 #define PCI_DEVICE_ID_INTEL_RAPTOR_LAKE_S_SMBUS 0x7a23 #define PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS 0x7aa3 #define PCI_DEVICE_ID_INTEL_METEOR_LAKE_P_SMBUS 0x7e22 +#define PCI_DEVICE_ID_INTEL_METEOR_LAKE_PCH_S_SMBUS 0x7f23 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 #define PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS 0x8ca2 #define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22 @@ -250,19 +267,21 @@ #define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS 0xa2a3 #define PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS 0xa323 #define PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS 0xa3a3 +#define PCI_DEVICE_ID_INTEL_METEOR_LAKE_SOC_S_SMBUS 0xae22 +#define PCI_DEVICE_ID_INTEL_PANTHER_LAKE_H_SMBUS 0xe322 +#define PCI_DEVICE_ID_INTEL_PANTHER_LAKE_P_SMBUS 0xe422 struct i801_mux_config { char *gpio_chip; unsigned values[3]; int n_values; - unsigned classes[3]; unsigned gpios[2]; /* Relative to gpio_chip->base */ int n_gpios; }; struct i801_priv { struct i2c_adapter adapter; - unsigned long smba; + void __iomem *smba; unsigned char original_hstcfg; unsigned char original_hstcnt; unsigned char original_slvcmd; @@ -280,19 +299,18 @@ struct i801_priv { int len; u8 *data; -#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI - const struct i801_mux_config *mux_drvdata; +#ifdef CONFIG_I2C_I801_MUX struct platform_device *mux_pdev; struct gpiod_lookup_table *lookup; + struct notifier_block mux_notifier_block; #endif struct platform_device *tco_pdev; /* * If set to true the host controller registers are reserved for - * ACPI AML use. Protected by acpi_lock. + * ACPI AML use. */ bool acpi_reserved; - struct mutex acpi_lock; }; #define FEATURE_SMBUS_PEC BIT(0) @@ -324,13 +342,75 @@ MODULE_PARM_DESC(disable_features, "Disable selected driver features:\n" "\t\t 0x10 don't use interrupts\n" "\t\t 0x20 disable SMBus Host Notify "); +/* Wait for BUSY being cleared and either INTR or an error flag being set */ +static int i801_wait_intr(struct i801_priv *priv) +{ + unsigned long timeout = jiffies + priv->adapter.timeout; + int status, busy; + + do { + usleep_range(250, 500); + status = ioread8(SMBHSTSTS(priv)); + busy = status & SMBHSTSTS_HOST_BUSY; + status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR; + if (!busy && status) + return status & STATUS_ERROR_FLAGS; + } while (time_is_after_eq_jiffies(timeout)); + + return -ETIMEDOUT; +} + +/* Wait for either BYTE_DONE or an error flag being set */ +static int i801_wait_byte_done(struct i801_priv *priv) +{ + unsigned long timeout = jiffies + priv->adapter.timeout; + int status; + + do { + usleep_range(250, 500); + status = ioread8(SMBHSTSTS(priv)); + if (status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE)) + return status & STATUS_ERROR_FLAGS; + } while (time_is_after_eq_jiffies(timeout)); + + return -ETIMEDOUT; +} + +static int i801_get_block_len(struct i801_priv *priv) +{ + u8 len = ioread8(SMBHSTDAT0(priv)); + + if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) { + pci_err(priv->pci_dev, "Illegal SMBus block read size %u\n", len); + return -EPROTO; + } + + return len; +} + +static int i801_check_and_clear_pec_error(struct i801_priv *priv) +{ + u8 status; + + if (!(priv->features & FEATURE_SMBUS_PEC)) + return 0; + + status = ioread8(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; + if (status) { + iowrite8(status, SMBAUXSTS(priv)); + return -EBADMSG; + } + + return 0; +} + /* Make sure the SMBus host is ready to start transmitting. Return 0 if it is, -EBUSY if it is not. */ static int i801_check_pre(struct i801_priv *priv) { - int status; + int status, result; - status = inb_p(SMBHSTSTS(priv)); + status = ioread8(SMBHSTSTS(priv)); if (status & SMBHSTSTS_HOST_BUSY) { pci_err(priv->pci_dev, "SMBus is busy, can't use it!\n"); return -EBUSY; @@ -339,7 +419,7 @@ static int i801_check_pre(struct i801_priv *priv) status &= STATUS_FLAGS; if (status) { pci_dbg(priv->pci_dev, "Clearing status flags (%02x)\n", status); - outb_p(status, SMBHSTSTS(priv)); + iowrite8(status, SMBHSTSTS(priv)); } /* @@ -349,13 +429,9 @@ static int i801_check_pre(struct i801_priv *priv) * the hardware was already in this state when the driver * started. */ - if (priv->features & FEATURE_SMBUS_PEC) { - status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; - if (status) { - pci_dbg(priv->pci_dev, "Clearing aux status flags (%02x)\n", status); - outb_p(status, SMBAUXSTS(priv)); - } - } + result = i801_check_and_clear_pec_error(priv); + if (result) + pci_dbg(priv->pci_dev, "Clearing aux status flag CRCE\n"); return 0; } @@ -368,25 +444,20 @@ static int i801_check_post(struct i801_priv *priv, int status) * If the SMBus is still busy, we give up */ if (unlikely(status < 0)) { - dev_err(&priv->pci_dev->dev, "Transaction timeout\n"); /* try to stop the current command */ - dev_dbg(&priv->pci_dev->dev, "Terminating the current operation\n"); - outb_p(SMBHSTCNT_KILL, SMBHSTCNT(priv)); - usleep_range(1000, 2000); - outb_p(0, SMBHSTCNT(priv)); + iowrite8(SMBHSTCNT_KILL, SMBHSTCNT(priv)); + status = i801_wait_intr(priv); + iowrite8(0, SMBHSTCNT(priv)); /* Check if it worked */ - status = inb_p(SMBHSTSTS(priv)); - if ((status & SMBHSTSTS_HOST_BUSY) || - !(status & SMBHSTSTS_FAILED)) - dev_err(&priv->pci_dev->dev, - "Failed terminating the transaction\n"); + if (status < 0 || !(status & SMBHSTSTS_FAILED)) + pci_dbg(priv->pci_dev, "Failed terminating the transaction\n"); return -ETIMEDOUT; } if (status & SMBHSTSTS_FAILED) { result = -EIO; - dev_err(&priv->pci_dev->dev, "Transaction failed\n"); + pci_err(priv->pci_dev, "Transaction failed\n"); } if (status & SMBHSTSTS_DEV_ERR) { /* @@ -404,87 +475,45 @@ static int i801_check_post(struct i801_priv *priv, int status) * bit is harmless as long as it's cleared before * the next operation. */ - if ((priv->features & FEATURE_SMBUS_PEC) && - (inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE)) { - outb_p(SMBAUXSTS_CRCE, SMBAUXSTS(priv)); - result = -EBADMSG; - dev_dbg(&priv->pci_dev->dev, "PEC error\n"); + result = i801_check_and_clear_pec_error(priv); + if (result) { + pci_dbg(priv->pci_dev, "PEC error\n"); } else { result = -ENXIO; - dev_dbg(&priv->pci_dev->dev, "No response\n"); + pci_dbg(priv->pci_dev, "No response\n"); } } if (status & SMBHSTSTS_BUS_ERR) { result = -EAGAIN; - dev_dbg(&priv->pci_dev->dev, "Lost arbitration\n"); + pci_dbg(priv->pci_dev, "Lost arbitration\n"); } return result; } -/* Wait for BUSY being cleared and either INTR or an error flag being set */ -static int i801_wait_intr(struct i801_priv *priv) -{ - unsigned long timeout = jiffies + priv->adapter.timeout; - int status, busy; - - do { - usleep_range(250, 500); - status = inb_p(SMBHSTSTS(priv)); - busy = status & SMBHSTSTS_HOST_BUSY; - status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR; - if (!busy && status) - return status; - } while (time_is_after_eq_jiffies(timeout)); - - return -ETIMEDOUT; -} - -/* Wait for either BYTE_DONE or an error flag being set */ -static int i801_wait_byte_done(struct i801_priv *priv) -{ - unsigned long timeout = jiffies + priv->adapter.timeout; - int status; - - do { - usleep_range(250, 500); - status = inb_p(SMBHSTSTS(priv)); - if (status & (STATUS_ERROR_FLAGS | SMBHSTSTS_BYTE_DONE)) - return status & STATUS_ERROR_FLAGS; - } while (time_is_after_eq_jiffies(timeout)); - - return -ETIMEDOUT; -} - static int i801_transaction(struct i801_priv *priv, int xact) { - int status; unsigned long result; const struct i2c_adapter *adap = &priv->adapter; - status = i801_check_pre(priv); - if (status < 0) - return status; - if (priv->features & FEATURE_IRQ) { reinit_completion(&priv->done); - outb_p(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START, + iowrite8(xact | SMBHSTCNT_INTREN | SMBHSTCNT_START, SMBHSTCNT(priv)); result = wait_for_completion_timeout(&priv->done, adap->timeout); - return i801_check_post(priv, result ? priv->status : -ETIMEDOUT); + return result ? priv->status : -ETIMEDOUT; } - outb_p(xact | SMBHSTCNT_START, SMBHSTCNT(priv)); + iowrite8(xact | SMBHSTCNT_START, SMBHSTCNT(priv)); - status = i801_wait_intr(priv); - return i801_check_post(priv, status); + return i801_wait_intr(priv); } static int i801_block_transaction_by_block(struct i801_priv *priv, union i2c_smbus_data *data, char read_write, int command) { - int i, len, status, xact; + int len, status, xact; switch (command) { case I2C_SMBUS_BLOCK_PROC_CALL: @@ -498,76 +527,74 @@ static int i801_block_transaction_by_block(struct i801_priv *priv, } /* Set block buffer mode */ - outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv)); - - inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */ + iowrite8(ioread8(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv)); if (read_write == I2C_SMBUS_WRITE) { len = data->block[0]; - outb_p(len, SMBHSTDAT0(priv)); - for (i = 0; i < len; i++) - outb_p(data->block[i+1], SMBBLKDAT(priv)); + iowrite8(len, SMBHSTDAT0(priv)); + ioread8(SMBHSTCNT(priv)); /* reset the data buffer index */ + iowrite8_rep(SMBBLKDAT(priv), data->block + 1, len); } status = i801_transaction(priv, xact); if (status) - return status; + goto out; if (read_write == I2C_SMBUS_READ || command == I2C_SMBUS_BLOCK_PROC_CALL) { - len = inb_p(SMBHSTDAT0(priv)); - if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) - return -EPROTO; + len = i801_get_block_len(priv); + if (len < 0) { + status = len; + goto out; + } data->block[0] = len; - for (i = 0; i < len; i++) - data->block[i + 1] = inb_p(SMBBLKDAT(priv)); + ioread8(SMBHSTCNT(priv)); /* reset the data buffer index */ + ioread8_rep(SMBBLKDAT(priv), data->block + 1, len); } - return 0; +out: + iowrite8(ioread8(SMBAUXCTL(priv)) & ~SMBAUXCTL_E32B, SMBAUXCTL(priv)); + return status; } static void i801_isr_byte_done(struct i801_priv *priv) { if (priv->is_read) { - /* For SMBus block reads, length is received with first byte */ - if (((priv->cmd & 0x1c) == I801_BLOCK_DATA) && - (priv->count == 0)) { - priv->len = inb_p(SMBHSTDAT0(priv)); - if (priv->len < 1 || priv->len > I2C_SMBUS_BLOCK_MAX) { - dev_err(&priv->pci_dev->dev, - "Illegal SMBus block read size %d\n", - priv->len); + /* + * At transfer start i801_smbus_block_transaction() marks + * the block length as invalid. Check for this sentinel value + * and read the block length from SMBHSTDAT0. + */ + if (priv->len == SMBUS_LEN_SENTINEL) { + priv->len = i801_get_block_len(priv); + if (priv->len < 0) /* FIXME: Recover */ priv->len = I2C_SMBUS_BLOCK_MAX; - } + priv->data[-1] = priv->len; } /* Read next byte */ if (priv->count < priv->len) - priv->data[priv->count++] = inb(SMBBLKDAT(priv)); + priv->data[priv->count++] = ioread8(SMBBLKDAT(priv)); else - dev_dbg(&priv->pci_dev->dev, - "Discarding extra byte on block read\n"); + pci_dbg(priv->pci_dev, "Discarding extra byte on block read\n"); /* Set LAST_BYTE for last byte of read transaction */ if (priv->count == priv->len - 1) - outb_p(priv->cmd | SMBHSTCNT_LAST_BYTE, + iowrite8(priv->cmd | SMBHSTCNT_LAST_BYTE, SMBHSTCNT(priv)); } else if (priv->count < priv->len - 1) { /* Write next byte, except for IRQ after last byte */ - outb_p(priv->data[++priv->count], SMBBLKDAT(priv)); + iowrite8(priv->data[++priv->count], SMBBLKDAT(priv)); } - - /* Clear BYTE_DONE to continue with next byte */ - outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); } static irqreturn_t i801_host_notify_isr(struct i801_priv *priv) { unsigned short addr; - addr = inb_p(SMBNTFDADD(priv)) >> 1; + addr = ioread8(SMBNTFDADD(priv)) >> 1; /* * With the tested platforms, reading SMBNTFDDAT (22 + (p)->smba) @@ -577,7 +604,7 @@ static irqreturn_t i801_host_notify_isr(struct i801_priv *priv) i2c_handle_smbus_host_notify(&priv->adapter, addr); /* clear Host Notify bit and return */ - outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); + iowrite8(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); return IRQ_HANDLED; } @@ -590,7 +617,6 @@ static irqreturn_t i801_host_notify_isr(struct i801_priv *priv) * BUS_ERR - SMI# transaction collision * FAILED - transaction was canceled due to a KILL request * When any of these occur, update ->status and signal completion. - * ->status must be cleared before kicking off the next transaction. * * 2) For byte-by-byte (I2C read/write) transactions, one BYTE_DONE interrupt * occurs for each byte of a byte-by-byte to prepare the next byte. @@ -609,31 +635,26 @@ static irqreturn_t i801_isr(int irq, void *dev_id) return IRQ_NONE; if (priv->features & FEATURE_HOST_NOTIFY) { - status = inb_p(SMBSLVSTS(priv)); + status = ioread8(SMBSLVSTS(priv)); if (status & SMBSLVSTS_HST_NTFY_STS) return i801_host_notify_isr(priv); } - status = inb_p(SMBHSTSTS(priv)); - if (status & SMBHSTSTS_BYTE_DONE) + status = ioread8(SMBHSTSTS(priv)); + if ((status & (SMBHSTSTS_BYTE_DONE | STATUS_ERROR_FLAGS)) == SMBHSTSTS_BYTE_DONE) i801_isr_byte_done(priv); /* - * Clear remaining IRQ sources: Completion of last command, errors - * and the SMB_ALERT signal. SMB_ALERT status is set after signal - * assertion independently of the interrupt generation being blocked - * or not so clear it always when the status is set. - */ - status &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS | SMBHSTSTS_SMBALERT_STS; - if (status) - outb_p(status, SMBHSTSTS(priv)); - status &= ~SMBHSTSTS_SMBALERT_STS; /* SMB_ALERT not reported */ - /* - * Report transaction result. - * ->status must be cleared before the next transaction is started. + * Clear IRQ sources: SMB_ALERT status is set after signal assertion + * independently of the interrupt generation being blocked or not + * so clear it always when the status is set. */ + status &= STATUS_FLAGS | SMBHSTSTS_SMBALERT_STS; + iowrite8(status, SMBHSTSTS(priv)); + + status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR; if (status) { - priv->status = status; + priv->status = status & STATUS_ERROR_FLAGS; complete(&priv->done); } @@ -658,15 +679,11 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, if (command == I2C_SMBUS_BLOCK_PROC_CALL) return -EOPNOTSUPP; - status = i801_check_pre(priv); - if (status < 0) - return status; - len = data->block[0]; if (read_write == I2C_SMBUS_WRITE) { - outb_p(len, SMBHSTDAT0(priv)); - outb_p(data->block[1], SMBBLKDAT(priv)); + iowrite8(len, SMBHSTDAT0(priv)); + iowrite8(data->block[1], SMBBLKDAT(priv)); } if (command == I2C_SMBUS_I2C_BLOCK_DATA && @@ -685,252 +702,237 @@ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, priv->data = &data->block[1]; reinit_completion(&priv->done); - outb_p(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv)); + iowrite8(priv->cmd | SMBHSTCNT_START, SMBHSTCNT(priv)); result = wait_for_completion_timeout(&priv->done, adap->timeout); - return i801_check_post(priv, result ? priv->status : -ETIMEDOUT); + return result ? priv->status : -ETIMEDOUT; } - for (i = 1; i <= len; i++) { - if (i == len && read_write == I2C_SMBUS_READ) - smbcmd |= SMBHSTCNT_LAST_BYTE; - outb_p(smbcmd, SMBHSTCNT(priv)); - - if (i == 1) - outb_p(inb(SMBHSTCNT(priv)) | SMBHSTCNT_START, - SMBHSTCNT(priv)); + if (len == 1 && read_write == I2C_SMBUS_READ) + smbcmd |= SMBHSTCNT_LAST_BYTE; + iowrite8(smbcmd | SMBHSTCNT_START, SMBHSTCNT(priv)); + for (i = 1; i <= len; i++) { status = i801_wait_byte_done(priv); if (status) - goto exit; - - if (i == 1 && read_write == I2C_SMBUS_READ - && command != I2C_SMBUS_I2C_BLOCK_DATA) { - len = inb_p(SMBHSTDAT0(priv)); - if (len < 1 || len > I2C_SMBUS_BLOCK_MAX) { - dev_err(&priv->pci_dev->dev, - "Illegal SMBus block read size %d\n", - len); + return status; + + /* + * At transfer start i801_smbus_block_transaction() marks + * the block length as invalid. Check for this sentinel value + * and read the block length from SMBHSTDAT0. + */ + if (len == SMBUS_LEN_SENTINEL) { + len = i801_get_block_len(priv); + if (len < 0) { /* Recover */ - while (inb_p(SMBHSTSTS(priv)) & + while (ioread8(SMBHSTSTS(priv)) & SMBHSTSTS_HOST_BUSY) - outb_p(SMBHSTSTS_BYTE_DONE, + iowrite8(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); - outb_p(SMBHSTSTS_INTR, SMBHSTSTS(priv)); + iowrite8(SMBHSTSTS_INTR, SMBHSTSTS(priv)); return -EPROTO; } data->block[0] = len; } - /* Retrieve/store value in SMBBLKDAT */ - if (read_write == I2C_SMBUS_READ) - data->block[i] = inb_p(SMBBLKDAT(priv)); + if (read_write == I2C_SMBUS_READ) { + data->block[i] = ioread8(SMBBLKDAT(priv)); + if (i == len - 1) + iowrite8(smbcmd | SMBHSTCNT_LAST_BYTE, SMBHSTCNT(priv)); + } + if (read_write == I2C_SMBUS_WRITE && i+1 <= len) - outb_p(data->block[i+1], SMBBLKDAT(priv)); + iowrite8(data->block[i+1], SMBBLKDAT(priv)); /* signals SMBBLKDAT ready */ - outb_p(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); + iowrite8(SMBHSTSTS_BYTE_DONE, SMBHSTSTS(priv)); } - status = i801_wait_intr(priv); -exit: - return i801_check_post(priv, status); + return i801_wait_intr(priv); } -/* Block transaction function */ -static int i801_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data, - char read_write, int command) +static void i801_set_hstadd(struct i801_priv *priv, u8 addr, char read_write) { - int result = 0; - unsigned char hostc; - - if (read_write == I2C_SMBUS_READ && command == I2C_SMBUS_BLOCK_DATA) - data->block[0] = I2C_SMBUS_BLOCK_MAX; - else if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) - return -EPROTO; - - if (command == I2C_SMBUS_I2C_BLOCK_DATA) { - if (read_write == I2C_SMBUS_WRITE) { - /* set I2C_EN bit in configuration register */ - pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc); - pci_write_config_byte(priv->pci_dev, SMBHSTCFG, - hostc | SMBHSTCFG_I2C_EN); - } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) { - dev_err(&priv->pci_dev->dev, - "I2C block read is unsupported!\n"); - return -EOPNOTSUPP; - } - } - - /* Experience has shown that the block buffer can only be used for - SMBus (not I2C) block transactions, even though the datasheet - doesn't mention this limitation. */ - if ((priv->features & FEATURE_BLOCK_BUFFER) && - command != I2C_SMBUS_I2C_BLOCK_DATA) - result = i801_block_transaction_by_block(priv, data, - read_write, - command); - else - result = i801_block_transaction_byte_by_byte(priv, data, - read_write, - command); - - if (command == I2C_SMBUS_I2C_BLOCK_DATA - && read_write == I2C_SMBUS_WRITE) { - /* restore saved configuration register value */ - pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc); - } - return result; + iowrite8((addr << 1) | (read_write & 0x01), SMBHSTADD(priv)); } -/* Return negative errno on error. */ -static s32 i801_access(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, u8 command, - int size, union i2c_smbus_data *data) +/* Single value transaction function */ +static int i801_simple_transaction(struct i801_priv *priv, union i2c_smbus_data *data, + u8 addr, u8 hstcmd, char read_write, int command) { - int hwpec; - int block = 0; - int ret, xact; - struct i801_priv *priv = i2c_get_adapdata(adap); - - mutex_lock(&priv->acpi_lock); - if (priv->acpi_reserved) { - mutex_unlock(&priv->acpi_lock); - return -EBUSY; - } - - pm_runtime_get_sync(&priv->pci_dev->dev); + int xact, ret; - hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) - && size != I2C_SMBUS_QUICK - && size != I2C_SMBUS_I2C_BLOCK_DATA; - - switch (size) { + switch (command) { case I2C_SMBUS_QUICK: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD(priv)); + i801_set_hstadd(priv, addr, read_write); xact = I801_QUICK; break; case I2C_SMBUS_BYTE: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD(priv)); + i801_set_hstadd(priv, addr, read_write); if (read_write == I2C_SMBUS_WRITE) - outb_p(command, SMBHSTCMD(priv)); + iowrite8(hstcmd, SMBHSTCMD(priv)); xact = I801_BYTE; break; case I2C_SMBUS_BYTE_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD(priv)); - outb_p(command, SMBHSTCMD(priv)); + i801_set_hstadd(priv, addr, read_write); if (read_write == I2C_SMBUS_WRITE) - outb_p(data->byte, SMBHSTDAT0(priv)); + iowrite8(data->byte, SMBHSTDAT0(priv)); + iowrite8(hstcmd, SMBHSTCMD(priv)); xact = I801_BYTE_DATA; break; case I2C_SMBUS_WORD_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD(priv)); - outb_p(command, SMBHSTCMD(priv)); + i801_set_hstadd(priv, addr, read_write); if (read_write == I2C_SMBUS_WRITE) { - outb_p(data->word & 0xff, SMBHSTDAT0(priv)); - outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv)); + iowrite8(data->word & 0xff, SMBHSTDAT0(priv)); + iowrite8((data->word & 0xff00) >> 8, SMBHSTDAT1(priv)); } + iowrite8(hstcmd, SMBHSTCMD(priv)); xact = I801_WORD_DATA; break; case I2C_SMBUS_PROC_CALL: - outb_p((addr & 0x7f) << 1, SMBHSTADD(priv)); - outb_p(command, SMBHSTCMD(priv)); - outb_p(data->word & 0xff, SMBHSTDAT0(priv)); - outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv)); - xact = I801_PROC_CALL; + i801_set_hstadd(priv, addr, I2C_SMBUS_WRITE); + iowrite8(data->word & 0xff, SMBHSTDAT0(priv)); + iowrite8((data->word & 0xff00) >> 8, SMBHSTDAT1(priv)); + iowrite8(hstcmd, SMBHSTCMD(priv)); read_write = I2C_SMBUS_READ; + xact = I801_PROC_CALL; break; - case I2C_SMBUS_BLOCK_DATA: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD(priv)); - outb_p(command, SMBHSTCMD(priv)); - block = 1; - break; - case I2C_SMBUS_I2C_BLOCK_DATA: - /* - * NB: page 240 of ICH5 datasheet shows that the R/#W - * bit should be cleared here, even when reading. - * However if SPD Write Disable is set (Lynx Point and later), - * the read will fail if we don't set the R/#W bit. - */ - outb_p(((addr & 0x7f) << 1) | - ((priv->original_hstcfg & SMBHSTCFG_SPD_WD) ? - (read_write & 0x01) : 0), - SMBHSTADD(priv)); - if (read_write == I2C_SMBUS_READ) { - /* NB: page 240 of ICH5 datasheet also shows - * that DATA1 is the cmd field when reading */ - outb_p(command, SMBHSTDAT1(priv)); - } else - outb_p(command, SMBHSTCMD(priv)); - block = 1; + default: + pci_err(priv->pci_dev, "Unsupported transaction %d\n", command); + return -EOPNOTSUPP; + } + + ret = i801_transaction(priv, xact); + if (ret || read_write == I2C_SMBUS_WRITE) + return ret; + + switch (command) { + case I2C_SMBUS_BYTE: + case I2C_SMBUS_BYTE_DATA: + data->byte = ioread8(SMBHSTDAT0(priv)); break; - case I2C_SMBUS_BLOCK_PROC_CALL: - /* - * Bit 0 of the slave address register always indicate a write - * command. - */ - outb_p((addr & 0x7f) << 1, SMBHSTADD(priv)); - outb_p(command, SMBHSTCMD(priv)); - block = 1; + case I2C_SMBUS_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + data->word = ioread8(SMBHSTDAT0(priv)) + + (ioread8(SMBHSTDAT1(priv)) << 8); break; - default: - dev_err(&priv->pci_dev->dev, "Unsupported transaction %d\n", - size); - ret = -EOPNOTSUPP; - goto out; } - if (hwpec) /* enable/disable hardware PEC */ - outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv)); + return 0; +} + +static int i801_smbus_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data, + u8 addr, u8 hstcmd, char read_write, int command) +{ + if (read_write == I2C_SMBUS_READ && command == I2C_SMBUS_BLOCK_DATA) + /* Mark block length as invalid */ + data->block[0] = SMBUS_LEN_SENTINEL; + else if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) + return -EPROTO; + + if (command == I2C_SMBUS_BLOCK_PROC_CALL) + /* Needs to be flagged as write transaction */ + i801_set_hstadd(priv, addr, I2C_SMBUS_WRITE); else - outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC), - SMBAUXCTL(priv)); + i801_set_hstadd(priv, addr, read_write); + iowrite8(hstcmd, SMBHSTCMD(priv)); - if (block) - ret = i801_block_transaction(priv, data, read_write, size); + if (priv->features & FEATURE_BLOCK_BUFFER) + return i801_block_transaction_by_block(priv, data, read_write, command); else - ret = i801_transaction(priv, xact); + return i801_block_transaction_byte_by_byte(priv, data, read_write, command); +} - /* Some BIOSes don't like it when PEC is enabled at reboot or resume - time, so we forcibly disable it after every transaction. Turn off - E32B for the same reason. */ - if (hwpec || block) - outb_p(inb_p(SMBAUXCTL(priv)) & - ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); +static int i801_i2c_block_transaction(struct i801_priv *priv, union i2c_smbus_data *data, + u8 addr, u8 hstcmd, char read_write, int command) +{ + int result; + u8 hostc; - if (block) - goto out; + if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) + return -EPROTO; + /* + * NB: page 240 of ICH5 datasheet shows that the R/#W bit should be cleared here, + * even when reading. However if SPD Write Disable is set (Lynx Point and later), + * the read will fail if we don't set the R/#W bit. + */ + i801_set_hstadd(priv, addr, + priv->original_hstcfg & SMBHSTCFG_SPD_WD ? read_write : I2C_SMBUS_WRITE); + + /* NB: page 240 of ICH5 datasheet shows that DATA1 is the cmd field when reading */ + if (read_write == I2C_SMBUS_READ) + iowrite8(hstcmd, SMBHSTDAT1(priv)); + else + iowrite8(hstcmd, SMBHSTCMD(priv)); + + if (read_write == I2C_SMBUS_WRITE) { + /* set I2C_EN bit in configuration register */ + pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &hostc); + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc | SMBHSTCFG_I2C_EN); + } else if (!(priv->features & FEATURE_I2C_BLOCK_READ)) { + pci_err(priv->pci_dev, "I2C block read is unsupported!\n"); + return -EOPNOTSUPP; + } + + /* Block buffer isn't supported for I2C block transactions */ + result = i801_block_transaction_byte_by_byte(priv, data, read_write, command); + + /* restore saved configuration register value */ + if (read_write == I2C_SMBUS_WRITE) + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hostc); + + return result; +} + +/* Return negative errno on error. */ +static s32 i801_access(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) +{ + int hwpec, ret; + struct i801_priv *priv = i2c_get_adapdata(adap); + + if (priv->acpi_reserved) + return -EBUSY; + + pm_runtime_get_sync(&priv->pci_dev->dev); + + ret = i801_check_pre(priv); if (ret) goto out; - if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) - goto out; - switch (xact) { - case I801_BYTE: /* Result put in SMBHSTDAT0 */ - case I801_BYTE_DATA: - data->byte = inb_p(SMBHSTDAT0(priv)); - break; - case I801_WORD_DATA: - case I801_PROC_CALL: - data->word = inb_p(SMBHSTDAT0(priv)) + - (inb_p(SMBHSTDAT1(priv)) << 8); - break; - } + hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) + && size != I2C_SMBUS_QUICK + && size != I2C_SMBUS_I2C_BLOCK_DATA; + + if (hwpec) /* enable/disable hardware PEC */ + iowrite8(ioread8(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv)); + else + iowrite8(ioread8(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC), + SMBAUXCTL(priv)); + if (size == I2C_SMBUS_BLOCK_DATA || size == I2C_SMBUS_BLOCK_PROC_CALL) + ret = i801_smbus_block_transaction(priv, data, addr, command, read_write, size); + else if (size == I2C_SMBUS_I2C_BLOCK_DATA) + ret = i801_i2c_block_transaction(priv, data, addr, command, read_write, size); + else + ret = i801_simple_transaction(priv, data, addr, command, read_write, size); + + ret = i801_check_post(priv, ret); + + /* Some BIOSes don't like it when PEC is enabled at reboot or resume + * time, so we forcibly disable it after every transaction. + */ + if (hwpec) + iowrite8(ioread8(SMBAUXCTL(priv)) & ~SMBAUXCTL_CRC, SMBAUXCTL(priv)); out: /* * Unlock the SMBus device for use by BIOS/ACPI, * and clear status flags if not done already. */ - outb_p(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv)); + iowrite8(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv)); - pm_runtime_mark_last_busy(&priv->pci_dev->dev); pm_runtime_put_autosuspend(&priv->pci_dev->dev); - mutex_unlock(&priv->acpi_lock); return ret; } @@ -964,11 +966,11 @@ static void i801_enable_host_notify(struct i2c_adapter *adapter) * from the SMB_ALERT signal because the driver does not support * SMBus Alert. */ - outb_p(SMBSLVCMD_HST_NTFY_INTREN | SMBSLVCMD_SMBALERT_DISABLE | + iowrite8(SMBSLVCMD_HST_NTFY_INTREN | SMBSLVCMD_SMBALERT_DISABLE | priv->original_slvcmd, SMBSLVCMD(priv)); /* clear Host Notify bit to allow a new notification */ - outb_p(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); + iowrite8(SMBSLVSTS_HST_NTFY_STS, SMBSLVSTS(priv)); } static void i801_disable_host_notify(struct i801_priv *priv) @@ -976,7 +978,7 @@ static void i801_disable_host_notify(struct i801_priv *priv) if (!(priv->features & FEATURE_HOST_NOTIFY)) return; - outb_p(priv->original_slvcmd, SMBSLVCMD(priv)); + iowrite8(priv->original_slvcmd, SMBSLVCMD(priv)); } static const struct i2c_algorithm smbus_algorithm = { @@ -984,81 +986,88 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = i801_func, }; -#define FEATURES_ICH5 (FEATURE_BLOCK_PROC | FEATURE_I2C_BLOCK_READ | \ - FEATURE_IRQ | FEATURE_SMBUS_PEC | \ - FEATURE_BLOCK_BUFFER | FEATURE_HOST_NOTIFY) #define FEATURES_ICH4 (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER | \ FEATURE_HOST_NOTIFY) +#define FEATURES_ICH5 (FEATURES_ICH4 | FEATURE_BLOCK_PROC | \ + FEATURE_I2C_BLOCK_READ | FEATURE_IRQ) static const struct pci_device_id i801_ids[] = { - { PCI_DEVICE_DATA(INTEL, 82801AA_3, 0) }, - { PCI_DEVICE_DATA(INTEL, 82801AB_3, 0) }, - { PCI_DEVICE_DATA(INTEL, 82801BA_2, 0) }, - { PCI_DEVICE_DATA(INTEL, 82801CA_3, FEATURE_HOST_NOTIFY) }, - { PCI_DEVICE_DATA(INTEL, 82801DB_3, FEATURES_ICH4) }, - { PCI_DEVICE_DATA(INTEL, 82801EB_3, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, ESB_4, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, ICH6_16, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, ICH7_17, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, ESB2_17, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, ICH8_5, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, ICH9_6, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, EP80579_1, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, ICH10_4, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, ICH10_5, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, 5_3400_SERIES_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, COUGARPOINT_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS_IDF0, FEATURES_ICH5 | FEATURE_IDF) }, - { PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS_IDF1, FEATURES_ICH5 | FEATURE_IDF) }, - { PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS_IDF2, FEATURES_ICH5 | FEATURE_IDF) }, - { PCI_DEVICE_DATA(INTEL, DH89XXCC_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, PANTHERPOINT_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, LYNXPOINT_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, LYNXPOINT_LP_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, AVOTON_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS_MS0, FEATURES_ICH5 | FEATURE_IDF) }, - { PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS_MS1, FEATURES_ICH5 | FEATURE_IDF) }, - { PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS_MS2, FEATURES_ICH5 | FEATURE_IDF) }, - { PCI_DEVICE_DATA(INTEL, COLETOCREEK_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, GEMINILAKE_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, WILDCATPOINT_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, WILDCATPOINT_LP_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, BAYTRAIL_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, BRASWELL_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, SUNRISEPOINT_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, - { PCI_DEVICE_DATA(INTEL, SUNRISEPOINT_LP_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, - { PCI_DEVICE_DATA(INTEL, CDF_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, DNV_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, - { PCI_DEVICE_DATA(INTEL, EBG_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, BROXTON_SMBUS, FEATURES_ICH5) }, - { PCI_DEVICE_DATA(INTEL, LEWISBURG_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, - { PCI_DEVICE_DATA(INTEL, LEWISBURG_SSKU_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, - { PCI_DEVICE_DATA(INTEL, KABYLAKE_PCH_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, - { PCI_DEVICE_DATA(INTEL, CANNONLAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, CANNONLAKE_LP_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, ICELAKE_LP_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, ICELAKE_N_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, COMETLAKE_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, COMETLAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, COMETLAKE_V_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, - { PCI_DEVICE_DATA(INTEL, ELKHART_LAKE_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, TIGERLAKE_LP_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, TIGERLAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, JASPER_LAKE_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, ALDER_LAKE_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, ALDER_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, ALDER_LAKE_M_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, RAPTOR_LAKE_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, - { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, 82801AA_3, 0) }, + { PCI_DEVICE_DATA(INTEL, 82801AB_3, 0) }, + { PCI_DEVICE_DATA(INTEL, 82801BA_2, 0) }, + { PCI_DEVICE_DATA(INTEL, 82801CA_3, FEATURE_HOST_NOTIFY) }, + { PCI_DEVICE_DATA(INTEL, 82801DB_3, FEATURES_ICH4) }, + { PCI_DEVICE_DATA(INTEL, 82801EB_3, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ESB_4, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ICH6_16, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ICH7_17, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ESB2_17, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ICH8_5, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ICH9_6, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, EP80579_1, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ICH10_4, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ICH10_5, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, 5_3400_SERIES_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, COUGARPOINT_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS_IDF0, FEATURES_ICH5 | FEATURE_IDF) }, + { PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS_IDF1, FEATURES_ICH5 | FEATURE_IDF) }, + { PCI_DEVICE_DATA(INTEL, PATSBURG_SMBUS_IDF2, FEATURES_ICH5 | FEATURE_IDF) }, + { PCI_DEVICE_DATA(INTEL, DH89XXCC_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, PANTHERPOINT_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, LYNXPOINT_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, LYNXPOINT_LP_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, AVOTON_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS_MS0, FEATURES_ICH5 | FEATURE_IDF) }, + { PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS_MS1, FEATURES_ICH5 | FEATURE_IDF) }, + { PCI_DEVICE_DATA(INTEL, WELLSBURG_SMBUS_MS2, FEATURES_ICH5 | FEATURE_IDF) }, + { PCI_DEVICE_DATA(INTEL, COLETOCREEK_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, GEMINILAKE_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, WILDCATPOINT_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, WILDCATPOINT_LP_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, BAYTRAIL_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, BRASWELL_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, SUNRISEPOINT_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, + { PCI_DEVICE_DATA(INTEL, SUNRISEPOINT_LP_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, + { PCI_DEVICE_DATA(INTEL, CDF_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, DNV_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, + { PCI_DEVICE_DATA(INTEL, EBG_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, BROXTON_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, LEWISBURG_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, + { PCI_DEVICE_DATA(INTEL, LEWISBURG_SSKU_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, + { PCI_DEVICE_DATA(INTEL, KABYLAKE_PCH_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, + { PCI_DEVICE_DATA(INTEL, CANNONLAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, CANNONLAKE_LP_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, ICELAKE_LP_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, ICELAKE_N_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, COMETLAKE_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, COMETLAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, COMETLAKE_V_SMBUS, FEATURES_ICH5 | FEATURE_TCO_SPT) }, + { PCI_DEVICE_DATA(INTEL, ELKHART_LAKE_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, TIGERLAKE_LP_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, TIGERLAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, JASPER_LAKE_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, ALDER_LAKE_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, ALDER_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, ALDER_LAKE_M_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, RAPTOR_LAKE_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_SOC_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, METEOR_LAKE_PCH_S_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, BIRCH_STREAM_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, DIAMOND_RAPIDS_SMBUS, FEATURES_ICH5) }, + { PCI_DEVICE_DATA(INTEL, ARROW_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_H_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, PANTHER_LAKE_P_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, + { PCI_DEVICE_DATA(INTEL, WILDCAT_LAKE_U_SMBUS, FEATURES_ICH5 | FEATURE_TCO_CNL) }, { 0, } }; MODULE_DEVICE_TABLE(pci, i801_ids); #if defined CONFIG_X86 && defined CONFIG_DMI -static unsigned char apanel_addr; +static unsigned char apanel_addr __ro_after_init; /* Scan the system ROM for the signature "FJKEYINF" */ static __init const void __iomem *bios_signature(const void __iomem *bios) @@ -1129,7 +1138,7 @@ static void dmi_check_onboard_devices(const struct dmi_header *dm, void *adap) { int i, count; - if (dm->type != 10) + if (dm->type != DMI_ENTRY_ONBOARD_DEVICE) return; count = (dm->length - sizeof(struct dmi_header)) / 2; @@ -1153,129 +1162,10 @@ static void dmi_check_onboard_devices(const struct dmi_header *dm, void *adap) } } -/* NOTE: Keep this list in sync with drivers/platform/x86/dell-smo8800.c */ -static const char *const acpi_smo8800_ids[] = { - "SMO8800", - "SMO8801", - "SMO8810", - "SMO8811", - "SMO8820", - "SMO8821", - "SMO8830", - "SMO8831", -}; - -static acpi_status check_acpi_smo88xx_device(acpi_handle obj_handle, - u32 nesting_level, - void *context, - void **return_value) -{ - struct acpi_device_info *info; - acpi_status status; - char *hid; - int i; - - status = acpi_get_object_info(obj_handle, &info); - if (ACPI_FAILURE(status)) - return AE_OK; - - if (!(info->valid & ACPI_VALID_HID)) - goto smo88xx_not_found; - - hid = info->hardware_id.string; - if (!hid) - goto smo88xx_not_found; - - i = match_string(acpi_smo8800_ids, ARRAY_SIZE(acpi_smo8800_ids), hid); - if (i < 0) - goto smo88xx_not_found; - - kfree(info); - - *return_value = NULL; - return AE_CTRL_TERMINATE; - -smo88xx_not_found: - kfree(info); - return AE_OK; -} - -static bool is_dell_system_with_lis3lv02d(void) +/* Register optional targets */ +static void i801_probe_optional_targets(struct i801_priv *priv) { - void *err = ERR_PTR(-ENOENT); - - if (!dmi_match(DMI_SYS_VENDOR, "Dell Inc.")) - return false; - - /* - * Check that ACPI device SMO88xx is present and is functioning. - * Function acpi_get_devices() already filters all ACPI devices - * which are not present or are not functioning. - * ACPI device SMO88xx represents our ST microelectronics lis3lv02d - * accelerometer but unfortunately ACPI does not provide any other - * information (like I2C address). - */ - acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL, &err); - - return !IS_ERR(err); -} - -/* - * Accelerometer's I2C address is not specified in DMI nor ACPI, - * so it is needed to define mapping table based on DMI product names. - */ -static const struct { - const char *dmi_product_name; - unsigned short i2c_addr; -} dell_lis3lv02d_devices[] = { - /* - * Dell platform team told us that these Latitude devices have - * ST microelectronics accelerometer at I2C address 0x29. - */ - { "Latitude E5250", 0x29 }, - { "Latitude E5450", 0x29 }, - { "Latitude E5550", 0x29 }, - { "Latitude E6440", 0x29 }, - { "Latitude E6440 ATG", 0x29 }, - { "Latitude E6540", 0x29 }, - /* - * Additional individual entries were added after verification. - */ - { "Latitude 5480", 0x29 }, - { "Vostro V131", 0x1d }, - { "Vostro 5568", 0x29 }, -}; - -static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv) -{ - struct i2c_board_info info; - const char *dmi_product_name; - int i; - - dmi_product_name = dmi_get_system_info(DMI_PRODUCT_NAME); - for (i = 0; i < ARRAY_SIZE(dell_lis3lv02d_devices); ++i) { - if (strcmp(dmi_product_name, - dell_lis3lv02d_devices[i].dmi_product_name) == 0) - break; - } - - if (i == ARRAY_SIZE(dell_lis3lv02d_devices)) { - dev_warn(&priv->pci_dev->dev, - "Accelerometer lis3lv02d is present on SMBus but its" - " address is unknown, skipping registration\n"); - return; - } - - memset(&info, 0, sizeof(struct i2c_board_info)); - info.addr = dell_lis3lv02d_devices[i].i2c_addr; - strscpy(info.type, "lis3lv02d", I2C_NAME_SIZE); - i2c_new_client_device(&priv->adapter, &info); -} - -/* Register optional slaves */ -static void i801_probe_optional_slaves(struct i801_priv *priv) -{ - /* Only register slaves on main SMBus channel */ + /* Only register targets on main SMBus channel */ if (priv->features & FEATURE_IDF) return; @@ -1291,26 +1181,22 @@ static void i801_probe_optional_slaves(struct i801_priv *priv) if (dmi_name_in_vendors("FUJITSU")) dmi_walk(dmi_check_onboard_devices, &priv->adapter); - if (is_dell_system_with_lis3lv02d()) - register_dell_lis3lv02d_i2c_device(priv); - /* Instantiate SPD EEPROMs unless the SMBus is multiplexed */ -#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) - if (!priv->mux_drvdata) +#ifdef CONFIG_I2C_I801_MUX + if (!priv->mux_pdev) #endif - i2c_register_spd(&priv->adapter); + i2c_register_spd_write_enable(&priv->adapter); } #else static void __init input_apanel_init(void) {} -static void i801_probe_optional_slaves(struct i801_priv *priv) {} +static void i801_probe_optional_targets(struct i801_priv *priv) {} #endif /* CONFIG_X86 && CONFIG_DMI */ -#if IS_ENABLED(CONFIG_I2C_MUX_GPIO) && defined CONFIG_DMI +#ifdef CONFIG_I2C_I801_MUX static struct i801_mux_config i801_mux_config_asus_z8_d12 = { .gpio_chip = "gpio_ich", .values = { 0x02, 0x03 }, .n_values = 2, - .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD }, .gpios = { 52, 53 }, .n_gpios = 2, }; @@ -1319,7 +1205,6 @@ static struct i801_mux_config i801_mux_config_asus_z8_d18 = { .gpio_chip = "gpio_ich", .values = { 0x02, 0x03, 0x01 }, .n_values = 3, - .classes = { I2C_CLASS_SPD, I2C_CLASS_SPD, I2C_CLASS_SPD }, .gpios = { 52, 53 }, .n_gpios = 2, }; @@ -1391,6 +1276,23 @@ static const struct dmi_system_id mux_dmi_table[] = { { } }; +static int i801_notifier_call(struct notifier_block *nb, unsigned long action, + void *data) +{ + struct i801_priv *priv = container_of(nb, struct i801_priv, mux_notifier_block); + struct device *dev = data; + + if (action != BUS_NOTIFY_ADD_DEVICE || + dev->type != &i2c_adapter_type || + i2c_root_adapter(dev) != &priv->adapter) + return NOTIFY_DONE; + + /* Call i2c_register_spd for muxed child segments */ + i2c_register_spd_write_enable(to_i2c_adapter(dev)); + + return NOTIFY_OK; +} + /* Setup multiplexing if needed */ static void i801_add_mux(struct i801_priv *priv) { @@ -1398,18 +1300,20 @@ static void i801_add_mux(struct i801_priv *priv) const struct i801_mux_config *mux_config; struct i2c_mux_gpio_platform_data gpio_data; struct gpiod_lookup_table *lookup; + const struct dmi_system_id *id; int i; - if (!priv->mux_drvdata) + id = dmi_first_match(mux_dmi_table); + if (!id) return; - mux_config = priv->mux_drvdata; + + mux_config = id->driver_data; /* Prepare the platform data */ memset(&gpio_data, 0, sizeof(struct i2c_mux_gpio_platform_data)); gpio_data.parent = priv->adapter.nr; gpio_data.values = mux_config->values; gpio_data.n_values = mux_config->n_values; - gpio_data.classes = mux_config->classes; gpio_data.idle = I2C_MUX_GPIO_NO_IDLE; /* Register GPIO descriptor lookup table */ @@ -1423,8 +1327,10 @@ static void i801_add_mux(struct i801_priv *priv) lookup->table[i] = GPIO_LOOKUP(mux_config->gpio_chip, mux_config->gpios[i], "mux", 0); gpiod_add_lookup_table(lookup); - priv->lookup = lookup; + priv->mux_notifier_block.notifier_call = i801_notifier_call; + if (bus_register_notifier(&i2c_bus_type, &priv->mux_notifier_block)) + return; /* * Register the mux device, we use PLATFORM_DEVID_NONE here * because since we are referring to the GPIO chip by name we are @@ -1437,49 +1343,26 @@ static void i801_add_mux(struct i801_priv *priv) sizeof(struct i2c_mux_gpio_platform_data)); if (IS_ERR(priv->mux_pdev)) { gpiod_remove_lookup_table(lookup); + devm_kfree(dev, lookup); dev_err(dev, "Failed to register i2c-mux-gpio device\n"); + } else { + priv->lookup = lookup; } } static void i801_del_mux(struct i801_priv *priv) { + bus_unregister_notifier(&i2c_bus_type, &priv->mux_notifier_block); platform_device_unregister(priv->mux_pdev); gpiod_remove_lookup_table(priv->lookup); } - -static unsigned int i801_get_adapter_class(struct i801_priv *priv) -{ - const struct dmi_system_id *id; - const struct i801_mux_config *mux_config; - unsigned int class = I2C_CLASS_HWMON | I2C_CLASS_SPD; - int i; - - id = dmi_first_match(mux_dmi_table); - if (id) { - /* Remove branch classes from trunk */ - mux_config = id->driver_data; - for (i = 0; i < mux_config->n_values; i++) - class &= ~mux_config->classes[i]; - - /* Remember for later */ - priv->mux_drvdata = mux_config; - } - - return class; -} #else static inline void i801_add_mux(struct i801_priv *priv) { } static inline void i801_del_mux(struct i801_priv *priv) { } - -static inline unsigned int i801_get_adapter_class(struct i801_priv *priv) -{ - return I2C_CLASS_HWMON | I2C_CLASS_SPD; -} #endif static struct platform_device * -i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev, - struct resource *tco_res) +i801_add_tco_spt(struct pci_dev *pci_dev, struct resource *tco_res) { static const struct itco_wdt_platform_data pldata = { .name = "Intel PCH", @@ -1510,8 +1393,7 @@ i801_add_tco_spt(struct i801_priv *priv, struct pci_dev *pci_dev, } static struct platform_device * -i801_add_tco_cnl(struct i801_priv *priv, struct pci_dev *pci_dev, - struct resource *tco_res) +i801_add_tco_cnl(struct pci_dev *pci_dev, struct resource *tco_res) { static const struct itco_wdt_platform_data pldata = { .name = "Intel PCH", @@ -1551,19 +1433,19 @@ static void i801_add_tco(struct i801_priv *priv) res->flags = IORESOURCE_IO; if (priv->features & FEATURE_TCO_CNL) - priv->tco_pdev = i801_add_tco_cnl(priv, pci_dev, tco_res); + priv->tco_pdev = i801_add_tco_cnl(pci_dev, tco_res); else - priv->tco_pdev = i801_add_tco_spt(priv, pci_dev, tco_res); + priv->tco_pdev = i801_add_tco_spt(pci_dev, tco_res); if (IS_ERR(priv->tco_pdev)) - dev_warn(&pci_dev->dev, "failed to create iTCO device\n"); + pci_warn(pci_dev, "failed to create iTCO device\n"); } #ifdef CONFIG_ACPI static bool i801_acpi_is_smbus_ioport(const struct i801_priv *priv, acpi_physical_address address) { - return address >= priv->smba && + return address >= pci_resource_start(priv->pci_dev, SMBBAR) && address <= pci_resource_end(priv->pci_dev, SMBBAR); } @@ -1580,13 +1462,13 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, * further access from the driver itself. This device is now owned * by the system firmware. */ - mutex_lock(&priv->acpi_lock); + i2c_lock_bus(&priv->adapter, I2C_LOCK_SEGMENT); if (!priv->acpi_reserved && i801_acpi_is_smbus_ioport(priv, address)) { priv->acpi_reserved = true; - dev_warn(&pdev->dev, "BIOS is accessing SMBus registers\n"); - dev_warn(&pdev->dev, "Driver SMBus register access inhibited\n"); + pci_warn(pdev, "BIOS is accessing SMBus registers\n"); + pci_warn(pdev, "Driver SMBus register access inhibited\n"); /* * BIOS is accessing the host controller so prevent it from @@ -1600,7 +1482,7 @@ i801_acpi_io_handler(u32 function, acpi_physical_address address, u32 bits, else status = acpi_os_write_port(address, (u32)*value, bits); - mutex_unlock(&priv->acpi_lock); + i2c_unlock_bus(&priv->adapter, I2C_LOCK_SEGMENT); return status; } @@ -1638,9 +1520,15 @@ static void i801_setup_hstcfg(struct i801_priv *priv) pci_write_config_byte(priv->pci_dev, SMBHSTCFG, hstcfg); } +static void i801_restore_regs(struct i801_priv *priv) +{ + iowrite8(priv->original_hstcnt, SMBHSTCNT(priv)); + pci_write_config_byte(priv->pci_dev, SMBHSTCFG, priv->original_hstcfg); +} + static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) { - int err, i; + int err, i, bar = SMBBAR; struct i801_priv *priv; priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL); @@ -1649,12 +1537,11 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) i2c_set_adapdata(&priv->adapter, priv); priv->adapter.owner = THIS_MODULE; - priv->adapter.class = i801_get_adapter_class(priv); + priv->adapter.class = I2C_CLASS_HWMON; priv->adapter.algo = &smbus_algorithm; priv->adapter.dev.parent = &dev->dev; - ACPI_COMPANION_SET(&priv->adapter.dev, ACPI_COMPANION(&dev->dev)); + acpi_use_parent_companion(&priv->adapter.dev); priv->adapter.retries = 3; - mutex_init(&priv->acpi_lock); priv->pci_dev = dev; priv->features = id->driver_data; @@ -1662,63 +1549,62 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) /* Disable features on user request */ for (i = 0; i < ARRAY_SIZE(i801_feature_names); i++) { if (priv->features & disable_features & (1 << i)) - dev_notice(&dev->dev, "%s disabled by user\n", - i801_feature_names[i]); + pci_notice(dev, "%s disabled by user\n", i801_feature_names[i]); } priv->features &= ~disable_features; - err = pcim_enable_device(dev); + /* The block process call uses block buffer mode */ + if (!(priv->features & FEATURE_BLOCK_BUFFER)) + priv->features &= ~FEATURE_BLOCK_PROC; + + /* + * Do not call pcim_enable_device(), because the device has to remain + * enabled on driver detach. See i801_remove() for the reasoning. + */ + err = pci_enable_device(dev); if (err) { - dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n", - err); + pci_err(dev, "Failed to enable SMBus PCI device (%d)\n", err); return err; } - pcim_pin_device(dev); /* Determine the address of the SMBus area */ - priv->smba = pci_resource_start(dev, SMBBAR); - if (!priv->smba) { - dev_err(&dev->dev, - "SMBus base address uninitialized, upgrade BIOS\n"); + if (!pci_resource_start(dev, SMBBAR)) { + pci_err(dev, "SMBus base address uninitialized, upgrade BIOS\n"); return -ENODEV; } if (i801_acpi_probe(priv)) return -ENODEV; - err = pcim_iomap_regions(dev, 1 << SMBBAR, DRV_NAME); - if (err) { - dev_err(&dev->dev, - "Failed to request SMBus region 0x%lx-0x%Lx\n", - priv->smba, - (unsigned long long)pci_resource_end(dev, SMBBAR)); + if (pci_resource_flags(dev, SMBBAR_MMIO) & IORESOURCE_MEM) + bar = SMBBAR_MMIO; + + priv->smba = pcim_iomap_region(dev, bar, DRV_NAME); + if (IS_ERR(priv->smba)) { + pci_err(dev, "Failed to request SMBus region %pr\n", + pci_resource_n(dev, bar)); i801_acpi_remove(priv); - return err; + return PTR_ERR(priv->smba); } - pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &priv->original_hstcfg); + pci_read_config_byte(dev, SMBHSTCFG, &priv->original_hstcfg); i801_setup_hstcfg(priv); if (!(priv->original_hstcfg & SMBHSTCFG_HST_EN)) - dev_info(&dev->dev, "Enabling SMBus device\n"); + pci_info(dev, "Enabling SMBus device\n"); if (priv->original_hstcfg & SMBHSTCFG_SMB_SMI_EN) { - dev_dbg(&dev->dev, "SMBus using interrupt SMI#\n"); + pci_dbg(dev, "SMBus using interrupt SMI#\n"); /* Disable SMBus interrupt feature if SMBus using SMI# */ priv->features &= ~FEATURE_IRQ; } if (priv->original_hstcfg & SMBHSTCFG_SPD_WD) - dev_info(&dev->dev, "SPD Write Disable is set\n"); + pci_info(dev, "SPD Write Disable is set\n"); /* Clear special mode bits */ if (priv->features & (FEATURE_SMBUS_PEC | FEATURE_BLOCK_BUFFER)) - outb_p(inb_p(SMBAUXCTL(priv)) & + iowrite8(ioread8(SMBAUXCTL(priv)) & ~(SMBAUXCTL_CRC | SMBAUXCTL_E32B), SMBAUXCTL(priv)); - /* Remember original Interrupt and Host Notify settings */ - priv->original_hstcnt = inb_p(SMBHSTCNT(priv)) & ~SMBHSTCNT_KILL; - if (priv->features & FEATURE_HOST_NOTIFY) - priv->original_slvcmd = inb_p(SMBSLVCMD(priv)); - /* Default timeout in interrupt mode: 200 ms */ priv->adapter.timeout = HZ / 5; @@ -1731,7 +1617,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) /* Complain if an interrupt is already pending */ pci_read_config_word(priv->pci_dev, PCI_STATUS, &pcists); if (pcists & PCI_STATUS_INTERRUPT) - dev_warn(&dev->dev, "An interrupt is pending!\n"); + pci_warn(dev, "An interrupt is pending!\n"); } if (priv->features & FEATURE_IRQ) { @@ -1740,29 +1626,46 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) err = devm_request_irq(&dev->dev, dev->irq, i801_isr, IRQF_SHARED, DRV_NAME, priv); if (err) { - dev_err(&dev->dev, "Failed to allocate irq %d: %d\n", - dev->irq, err); + pci_err(dev, "Failed to allocate irq %d: %d\n", dev->irq, err); priv->features &= ~FEATURE_IRQ; } } - dev_info(&dev->dev, "SMBus using %s\n", + pci_info(dev, "SMBus using %s\n", priv->features & FEATURE_IRQ ? "PCI interrupt" : "polling"); + /* Host notification uses an interrupt */ + if (!(priv->features & FEATURE_IRQ)) + priv->features &= ~FEATURE_HOST_NOTIFY; + + /* Remember original Interrupt and Host Notify settings */ + priv->original_hstcnt = ioread8(SMBHSTCNT(priv)) & ~SMBHSTCNT_KILL; + if (priv->features & FEATURE_HOST_NOTIFY) + priv->original_slvcmd = ioread8(SMBSLVCMD(priv)); + i801_add_tco(priv); + /* + * adapter.name is used by platform code to find the main I801 adapter + * to instantiante i2c_clients, do not change. + */ snprintf(priv->adapter.name, sizeof(priv->adapter.name), - "SMBus I801 adapter at %04lx", priv->smba); + "SMBus %s adapter at %s", + (priv->features & FEATURE_IDF) ? "I801 IDF" : "I801", + pci_name(dev)); + err = i2c_add_adapter(&priv->adapter); if (err) { + platform_device_unregister(priv->tco_pdev); i801_acpi_remove(priv); + i801_restore_regs(priv); return err; } i801_enable_host_notify(&priv->adapter); - i801_probe_optional_slaves(priv); /* We ignore errors - multiplexing is optional */ i801_add_mux(priv); + i801_probe_optional_targets(priv); pci_set_drvdata(dev, priv); @@ -1779,12 +1682,10 @@ static void i801_remove(struct pci_dev *dev) { struct i801_priv *priv = pci_get_drvdata(dev); - outb_p(priv->original_hstcnt, SMBHSTCNT(priv)); i801_disable_host_notify(priv); i801_del_mux(priv); i2c_del_adapter(&priv->adapter); i801_acpi_remove(priv); - pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); platform_device_unregister(priv->tco_pdev); @@ -1792,6 +1693,8 @@ static void i801_remove(struct pci_dev *dev) if (!priv->acpi_reserved) pm_runtime_get_noresume(&dev->dev); + i801_restore_regs(priv); + /* * do not call pci_disable_device(dev) since it can cause hard hangs on * some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010) @@ -1802,19 +1705,18 @@ static void i801_shutdown(struct pci_dev *dev) { struct i801_priv *priv = pci_get_drvdata(dev); - /* Restore config registers to avoid hard hang on some systems */ - outb_p(priv->original_hstcnt, SMBHSTCNT(priv)); i801_disable_host_notify(priv); - pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg); + /* Restore config registers to avoid hard hang on some systems */ + i801_restore_regs(priv); } -#ifdef CONFIG_PM_SLEEP static int i801_suspend(struct device *dev) { struct i801_priv *priv = dev_get_drvdata(dev); - outb_p(priv->original_hstcnt, SMBHSTCNT(priv)); - pci_write_config_byte(priv->pci_dev, SMBHSTCFG, priv->original_hstcfg); + i2c_mark_adapter_suspended(&priv->adapter); + i801_restore_regs(priv); + return 0; } @@ -1824,12 +1726,12 @@ static int i801_resume(struct device *dev) i801_setup_hstcfg(priv); i801_enable_host_notify(&priv->adapter); + i2c_mark_adapter_resumed(&priv->adapter); return 0; } -#endif -static SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(i801_pm_ops, i801_suspend, i801_resume); static struct pci_driver i801_driver = { .name = DRV_NAME, @@ -1838,21 +1740,16 @@ static struct pci_driver i801_driver = { .remove = i801_remove, .shutdown = i801_shutdown, .driver = { - .pm = &i801_pm_ops, + .pm = pm_sleep_ptr(&i801_pm_ops), .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; -static int __init i2c_i801_init(void) +static int __init i2c_i801_init(struct pci_driver *drv) { if (dmi_name_in_vendors("FUJITSU")) input_apanel_init(); - return pci_register_driver(&i801_driver); -} - -static void __exit i2c_i801_exit(void) -{ - pci_unregister_driver(&i801_driver); + return pci_register_driver(drv); } MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>"); @@ -1860,5 +1757,4 @@ MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); MODULE_DESCRIPTION("I801 SMBus driver"); MODULE_LICENSE("GPL"); -module_init(i2c_i801_init); -module_exit(i2c_i801_exit); +module_driver(i801_driver, i2c_i801_init, pci_unregister_driver); diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index eeb80e34f9ad..6bf45d752ff9 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -37,9 +37,10 @@ #include <asm/irq.h> #include <linux/io.h> #include <linux/i2c.h> +#include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> -#include <linux/of_platform.h> +#include <linux/platform_device.h> #include "i2c-ibm_iic.h" @@ -135,11 +136,11 @@ static void iic_dev_init(struct ibm_iic_private* dev) DBG("%d: init\n", dev->idx); - /* Clear master address */ + /* Clear remote target address */ out_8(&iic->lmadr, 0); out_8(&iic->hmadr, 0); - /* Clear slave address */ + /* Clear local target address */ out_8(&iic->lsadr, 0); out_8(&iic->hsadr, 0); @@ -336,7 +337,7 @@ static irqreturn_t iic_handler(int irq, void *dev_id) } /* - * Get master transfer result and clear errors if any. + * Get controller transfer result and clear errors if any. * Returns the number of actually transferred bytes or error (<0) */ static int iic_xfer_result(struct ibm_iic_private* dev) @@ -351,7 +352,7 @@ static int iic_xfer_result(struct ibm_iic_private* dev) out_8(&iic->extsts, EXTSTS_IRQP | EXTSTS_IRQD | EXTSTS_LA | EXTSTS_ICT | EXTSTS_XFRA); - /* Flush master data buffer */ + /* Flush controller data buffer */ out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB); /* Is bus free? @@ -400,7 +401,7 @@ static void iic_abort_xfer(struct ibm_iic_private* dev) } /* - * Wait for master transfer to complete. + * Wait for controller transfer to complete. * It puts current process to sleep until we get interrupt or timeout expires. * Returns the number of transferred bytes or error (<0) */ @@ -451,9 +452,6 @@ static int iic_wait_for_tc(struct ibm_iic_private* dev){ return ret; } -/* - * Low level master transfer routine - */ static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm, int combined_xfer) { @@ -510,25 +508,21 @@ static int iic_xfer_bytes(struct ibm_iic_private* dev, struct i2c_msg* pm, return ret > 0 ? 0 : ret; } -/* - * Set target slave address for master transfer - */ +/* Set remote target address for transfer */ static inline void iic_address(struct ibm_iic_private* dev, struct i2c_msg* msg) { volatile struct iic_regs __iomem *iic = dev->vaddr; - u16 addr = msg->addr; DBG2("%d: iic_address, 0x%03x (%d-bit)\n", dev->idx, - addr, msg->flags & I2C_M_TEN ? 10 : 7); + msg->addr, msg->flags & I2C_M_TEN ? 10 : 7); - if (msg->flags & I2C_M_TEN){ + if (msg->flags & I2C_M_TEN) { out_8(&iic->cntl, CNTL_AMD); - out_8(&iic->lmadr, addr); - out_8(&iic->hmadr, 0xf0 | ((addr >> 7) & 0x06)); - } - else { + out_8(&iic->lmadr, i2c_10bit_addr_lo_from_msg(msg)); + out_8(&iic->hmadr, i2c_10bit_addr_hi_from_msg(msg) & ~I2C_M_RD); + } else { out_8(&iic->cntl, 0); - out_8(&iic->lmadr, addr << 1); + out_8(&iic->lmadr, i2c_8bit_addr_from_msg(msg) & ~I2C_M_RD); } } @@ -545,7 +539,7 @@ static inline int iic_address_neq(const struct i2c_msg* p1, } /* - * Generic master transfer entrypoint. + * Generic transfer entrypoint. * Returns the number of processed messages or error (<0) */ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) @@ -603,11 +597,11 @@ static int iic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) } } else { - /* Flush master data buffer (just in case) */ + /* Flush controller data buffer (just in case) */ out_8(&iic->mdcntl, in_8(&iic->mdcntl) | MDCNTL_FMDB); } - /* Load slave address */ + /* Load target address */ iic_address(dev, &msgs[0]); /* Do real transfer */ @@ -623,8 +617,8 @@ static u32 iic_func(struct i2c_adapter *adap) } static const struct i2c_algorithm iic_algo = { - .master_xfer = iic_xfer, - .functionality = iic_func + .xfer = iic_xfer, + .functionality = iic_func }; /* @@ -694,10 +688,8 @@ static int iic_probe(struct platform_device *ofdev) int ret; dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) { - dev_err(&ofdev->dev, "failed to allocate device data\n"); + if (!dev) return -ENOMEM; - } platform_set_drvdata(ofdev, dev); @@ -740,7 +732,7 @@ static int iic_probe(struct platform_device *ofdev) adap->dev.of_node = of_node_get(np); strscpy(adap->name, "IBM IIC", sizeof(adap->name)); i2c_set_adapdata(adap, dev); - adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + adap->class = I2C_CLASS_HWMON; adap->algo = &iic_algo; adap->timeout = HZ; @@ -769,7 +761,7 @@ error_cleanup: /* * Cleanup initialized IIC interface */ -static int iic_remove(struct platform_device *ofdev) +static void iic_remove(struct platform_device *ofdev) { struct ibm_iic_private *dev = platform_get_drvdata(ofdev); @@ -782,8 +774,6 @@ static int iic_remove(struct platform_device *ofdev) iounmap(dev->vaddr); kfree(dev); - - return 0; } static const struct of_device_id ibm_iic_match[] = { @@ -798,7 +788,7 @@ static struct platform_driver ibm_iic_driver = { .of_match_table = ibm_iic_match, }, .probe = iic_probe, - .remove = iic_remove, + .remove = iic_remove, }; module_platform_driver(ibm_iic_driver); diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c index 8e987945ed45..88192c25c44c 100644 --- a/drivers/i2c/busses/i2c-img-scb.c +++ b/drivers/i2c/busses/i2c-img-scb.c @@ -257,7 +257,7 @@ #define IMG_I2C_TIMEOUT (msecs_to_jiffies(1000)) /* - * Worst incs are 1 (innacurate) and 16*256 (irregular). + * Worst incs are 1 (inaccurate) and 16*256 (irregular). * So a sensible inc is the logarithmic mean: 64 (2^6), which is * in the middle of the valid range (0-127). */ @@ -831,7 +831,7 @@ next_atomic_cmd: */ static void img_i2c_check_timer(struct timer_list *t) { - struct img_i2c *i2c = from_timer(i2c, t, check_timer); + struct img_i2c *i2c = timer_container_of(i2c, t, check_timer); unsigned long flags; unsigned int line_status; @@ -913,7 +913,7 @@ static unsigned int img_i2c_auto(struct img_i2c *i2c, static irqreturn_t img_i2c_isr(int irq, void *dev_id) { - struct img_i2c *i2c = (struct img_i2c *)dev_id; + struct img_i2c *i2c = dev_id; u32 int_status, line_status; /* We handle transaction completion AFTER accessing registers */ unsigned int hret; @@ -1122,19 +1122,15 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, time_left = wait_for_completion_timeout(&i2c->msg_complete, IMG_I2C_TIMEOUT); - del_timer_sync(&i2c->check_timer); + timer_delete_sync(&i2c->check_timer); - if (time_left == 0) { - dev_err(adap->dev.parent, "i2c transfer timed out\n"); + if (time_left == 0) i2c->msg_status = -ETIMEDOUT; - break; - } if (i2c->msg_status) break; } - pm_runtime_mark_last_busy(adap->dev.parent); pm_runtime_put_autosuspend(adap->dev.parent); return i2c->msg_status ? i2c->msg_status : num; @@ -1146,7 +1142,7 @@ static u32 img_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm img_i2c_algo = { - .master_xfer = img_i2c_xfer, + .xfer = img_i2c_xfer, .functionality = img_i2c_func, }; @@ -1168,7 +1164,6 @@ static int img_i2c_init(struct img_i2c *i2c) "Unknown hardware revision (%d.%d.%d.%d)\n", (rev >> 24) & 0xff, (rev >> 16) & 0xff, (rev >> 8) & 0xff, rev & 0xff); - pm_runtime_mark_last_busy(i2c->adap.dev.parent); pm_runtime_put_autosuspend(i2c->adap.dev.parent); return -EINVAL; } @@ -1320,7 +1315,6 @@ static int img_i2c_init(struct img_i2c *i2c) /* Perform a synchronous sequence to reset the bus */ ret = img_i2c_reset_bus(i2c); - pm_runtime_mark_last_busy(i2c->adap.dev.parent); pm_runtime_put_autosuspend(i2c->adap.dev.parent); return ret; @@ -1413,7 +1407,7 @@ rpm_disable: return ret; } -static int img_i2c_remove(struct platform_device *dev) +static void img_i2c_remove(struct platform_device *dev) { struct img_i2c *i2c = platform_get_drvdata(dev); @@ -1421,8 +1415,6 @@ static int img_i2c_remove(struct platform_device *dev) pm_runtime_disable(&dev->dev); if (!pm_runtime_status_suspended(&dev->dev)) img_i2c_runtime_suspend(&dev->dev); - - return 0; } static int img_i2c_runtime_suspend(struct device *dev) @@ -1456,7 +1448,6 @@ static int img_i2c_runtime_resume(struct device *dev) return 0; } -#ifdef CONFIG_PM_SLEEP static int img_i2c_suspend(struct device *dev) { struct img_i2c *i2c = dev_get_drvdata(dev); @@ -1484,13 +1475,10 @@ static int img_i2c_resume(struct device *dev) return 0; } -#endif /* CONFIG_PM_SLEEP */ static const struct dev_pm_ops img_i2c_pm = { - SET_RUNTIME_PM_OPS(img_i2c_runtime_suspend, - img_i2c_runtime_resume, - NULL) - SET_SYSTEM_SLEEP_PM_OPS(img_i2c_suspend, img_i2c_resume) + RUNTIME_PM_OPS(img_i2c_runtime_suspend, img_i2c_runtime_resume, NULL) + SYSTEM_SLEEP_PM_OPS(img_i2c_suspend, img_i2c_resume) }; static const struct of_device_id img_scb_i2c_match[] = { @@ -1503,7 +1491,7 @@ static struct platform_driver img_scb_i2c_driver = { .driver = { .name = "img-i2c-scb", .of_match_table = img_scb_i2c_match, - .pm = &img_i2c_pm, + .pm = pm_ptr(&img_i2c_pm), }, .probe = img_i2c_probe, .remove = img_i2c_remove, diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index 188f2a36d2fd..2a0962a0b441 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -8,16 +8,18 @@ #include <linux/clk.h> #include <linux/completion.h> #include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/dmaengine.h> #include <linux/err.h> #include <linux/errno.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -30,6 +32,7 @@ #define LPI2C_MCR 0x10 /* i2c contrl register */ #define LPI2C_MSR 0x14 /* i2c status register */ #define LPI2C_MIER 0x18 /* i2c interrupt enable */ +#define LPI2C_MDER 0x1C /* i2c DMA enable */ #define LPI2C_MCFGR0 0x20 /* i2c master configuration */ #define LPI2C_MCFGR1 0x24 /* i2c master configuration */ #define LPI2C_MCFGR2 0x28 /* i2c master configuration */ @@ -41,6 +44,20 @@ #define LPI2C_MTDR 0x60 /* i2c master TX data register */ #define LPI2C_MRDR 0x70 /* i2c master RX data register */ +#define LPI2C_SCR 0x110 /* i2c target control register */ +#define LPI2C_SSR 0x114 /* i2c target status register */ +#define LPI2C_SIER 0x118 /* i2c target interrupt enable */ +#define LPI2C_SDER 0x11C /* i2c target DMA enable */ +#define LPI2C_SCFGR0 0x120 /* i2c target configuration */ +#define LPI2C_SCFGR1 0x124 /* i2c target configuration */ +#define LPI2C_SCFGR2 0x128 /* i2c target configuration */ +#define LPI2C_SAMR 0x140 /* i2c target address match */ +#define LPI2C_SASR 0x150 /* i2c target address status */ +#define LPI2C_STAR 0x154 /* i2c target transmit ACK */ +#define LPI2C_STDR 0x160 /* i2c target transmit data */ +#define LPI2C_SRDR 0x170 /* i2c target receive data */ +#define LPI2C_SRDROR 0x178 /* i2c target receive data read only */ + /* i2c command */ #define TRAN_DATA 0X00 #define RECV_DATA 0X01 @@ -71,11 +88,50 @@ #define MCFGR1_AUTOSTOP BIT(8) #define MCFGR1_IGNACK BIT(9) #define MRDR_RXEMPTY BIT(14) +#define MDER_TDDE BIT(0) +#define MDER_RDDE BIT(1) + +#define SCR_SEN BIT(0) +#define SCR_RST BIT(1) +#define SCR_FILTEN BIT(4) +#define SCR_RTF BIT(8) +#define SCR_RRF BIT(9) +#define SSR_TDF BIT(0) +#define SSR_RDF BIT(1) +#define SSR_AVF BIT(2) +#define SSR_TAF BIT(3) +#define SSR_RSF BIT(8) +#define SSR_SDF BIT(9) +#define SSR_BEF BIT(10) +#define SSR_FEF BIT(11) +#define SSR_SBF BIT(24) +#define SSR_BBF BIT(25) +#define SSR_CLEAR_BITS (SSR_RSF | SSR_SDF | SSR_BEF | SSR_FEF) +#define SIER_TDIE BIT(0) +#define SIER_RDIE BIT(1) +#define SIER_AVIE BIT(2) +#define SIER_TAIE BIT(3) +#define SIER_RSIE BIT(8) +#define SIER_SDIE BIT(9) +#define SIER_BEIE BIT(10) +#define SIER_FEIE BIT(11) +#define SIER_AM0F BIT(12) +#define SCFGR1_RXSTALL BIT(1) +#define SCFGR1_TXDSTALL BIT(2) +#define SCFGR2_FILTSDA_SHIFT 24 +#define SCFGR2_FILTSCL_SHIFT 16 +#define SCFGR2_CLKHOLD(x) (x) +#define SCFGR2_FILTSDA(x) ((x) << SCFGR2_FILTSDA_SHIFT) +#define SCFGR2_FILTSCL(x) ((x) << SCFGR2_FILTSCL_SHIFT) +#define SASR_READ_REQ 0x1 +#define SLAVE_INT_FLAG (SIER_TDIE | SIER_RDIE | SIER_AVIE | \ + SIER_SDIE | SIER_BEIE) #define I2C_CLK_RATIO 2 #define CHUNK_DATA 256 #define I2C_PM_TIMEOUT 10 /* ms */ +#define I2C_DMA_THRESHOLD 8 /* bytes */ enum lpi2c_imx_mode { STANDARD, /* 100+Kbps */ @@ -92,6 +148,24 @@ enum lpi2c_imx_pincfg { FOUR_PIN_PP, }; +struct lpi2c_imx_dma { + bool using_pio_mode; + u8 rx_cmd_buf_len; + u8 *dma_buf; + u16 *rx_cmd_buf; + unsigned int dma_len; + unsigned int tx_burst_num; + unsigned int rx_burst_num; + unsigned long dma_msg_flag; + resource_size_t phy_addr; + dma_addr_t dma_tx_addr; + dma_addr_t dma_addr; + enum dma_data_direction dma_data_dir; + enum dma_transfer_direction dma_transfer_dir; + struct dma_chan *chan_tx; + struct dma_chan *chan_rx; +}; + struct lpi2c_imx_struct { struct i2c_adapter adapter; int num_clks; @@ -100,6 +174,7 @@ struct lpi2c_imx_struct { __u8 *rx_buf; __u8 *tx_buf; struct completion complete; + unsigned long rate_per; unsigned int msglen; unsigned int delivered; unsigned int block_data; @@ -107,41 +182,54 @@ struct lpi2c_imx_struct { unsigned int txfifosize; unsigned int rxfifosize; enum lpi2c_imx_mode mode; + struct i2c_bus_recovery_info rinfo; + bool can_use_dma; + struct lpi2c_imx_dma *dma; + struct i2c_client *target; }; +#define lpi2c_imx_read_msr_poll_timeout(atomic, val, cond) \ + (atomic ? readl_poll_timeout_atomic(lpi2c_imx->base + LPI2C_MSR, val, \ + cond, 0, 500000) : \ + readl_poll_timeout(lpi2c_imx->base + LPI2C_MSR, val, cond, \ + 0, 500000)) + static void lpi2c_imx_intctrl(struct lpi2c_imx_struct *lpi2c_imx, unsigned int enable) { writel(enable, lpi2c_imx->base + LPI2C_MIER); } -static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx) +static int lpi2c_imx_bus_busy(struct lpi2c_imx_struct *lpi2c_imx, bool atomic) { - unsigned long orig_jiffies = jiffies; unsigned int temp; + int err; - while (1) { - temp = readl(lpi2c_imx->base + LPI2C_MSR); - - /* check for arbitration lost, clear if set */ - if (temp & MSR_ALF) { - writel(temp, lpi2c_imx->base + LPI2C_MSR); - return -EAGAIN; - } + err = lpi2c_imx_read_msr_poll_timeout(atomic, temp, + temp & (MSR_ALF | MSR_BBF | MSR_MBF)); - if (temp & (MSR_BBF | MSR_MBF)) - break; + /* check for arbitration lost, clear if set */ + if (temp & MSR_ALF) { + writel(temp, lpi2c_imx->base + LPI2C_MSR); + return -EAGAIN; + } - if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { - dev_dbg(&lpi2c_imx->adapter.dev, "bus not work\n"); - return -ETIMEDOUT; - } - schedule(); + /* check for bus not busy */ + if (err) { + dev_dbg(&lpi2c_imx->adapter.dev, "bus not work\n"); + if (lpi2c_imx->adapter.bus_recovery_info) + i2c_recover_bus(&lpi2c_imx->adapter); + return -ETIMEDOUT; } return 0; } +static u32 lpi2c_imx_txfifo_cnt(struct lpi2c_imx_struct *lpi2c_imx) +{ + return readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff; +} + static void lpi2c_imx_set_mode(struct lpi2c_imx_struct *lpi2c_imx) { unsigned int bitrate = lpi2c_imx->bitrate; @@ -162,7 +250,7 @@ static void lpi2c_imx_set_mode(struct lpi2c_imx_struct *lpi2c_imx) } static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx, - struct i2c_msg *msgs) + struct i2c_msg *msgs, bool atomic) { unsigned int temp; @@ -174,41 +262,37 @@ static int lpi2c_imx_start(struct lpi2c_imx_struct *lpi2c_imx, temp = i2c_8bit_addr_from_msg(msgs) | (GEN_START << 8); writel(temp, lpi2c_imx->base + LPI2C_MTDR); - return lpi2c_imx_bus_busy(lpi2c_imx); + return lpi2c_imx_bus_busy(lpi2c_imx, atomic); } -static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx) +static void lpi2c_imx_stop(struct lpi2c_imx_struct *lpi2c_imx, bool atomic) { - unsigned long orig_jiffies = jiffies; unsigned int temp; + int err; writel(GEN_STOP << 8, lpi2c_imx->base + LPI2C_MTDR); - do { - temp = readl(lpi2c_imx->base + LPI2C_MSR); - if (temp & MSR_SDF) - break; - - if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { - dev_dbg(&lpi2c_imx->adapter.dev, "stop timeout\n"); - break; - } - schedule(); + err = lpi2c_imx_read_msr_poll_timeout(atomic, temp, temp & MSR_SDF); - } while (1); + if (err) { + dev_dbg(&lpi2c_imx->adapter.dev, "stop timeout\n"); + if (lpi2c_imx->adapter.bus_recovery_info) + i2c_recover_bus(&lpi2c_imx->adapter); + } } /* CLKLO = I2C_CLK_RATIO * CLKHI, SETHOLD = CLKHI, DATAVD = CLKHI/2 */ static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx) { - u8 prescale, filt, sethold, clkhi, clklo, datavd; - unsigned int clk_rate, clk_cycle; + u8 prescale, filt, sethold, datavd; + unsigned int clk_rate, clk_cycle, clkhi, clklo; enum lpi2c_imx_pincfg pincfg; unsigned int temp; lpi2c_imx_set_mode(lpi2c_imx); - clk_rate = clk_get_rate(lpi2c_imx->clks[0].clk); + clk_rate = lpi2c_imx->rate_per; + if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST) filt = 0; else @@ -217,7 +301,7 @@ static int lpi2c_imx_config(struct lpi2c_imx_struct *lpi2c_imx) for (prescale = 0; prescale <= 7; prescale++) { clk_cycle = clk_rate / ((1 << prescale) * lpi2c_imx->bitrate) - 3 - (filt >> 1); - clkhi = (clk_cycle + I2C_CLK_RATIO) / (I2C_CLK_RATIO + 1); + clkhi = DIV_ROUND_UP(clk_cycle, I2C_CLK_RATIO + 1); clklo = clk_cycle - clkhi; if (clklo < 64) break; @@ -279,7 +363,6 @@ static int lpi2c_imx_master_enable(struct lpi2c_imx_struct *lpi2c_imx) return 0; rpm_put: - pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent); pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent); return ret; @@ -293,41 +376,39 @@ static int lpi2c_imx_master_disable(struct lpi2c_imx_struct *lpi2c_imx) temp &= ~MCR_MEN; writel(temp, lpi2c_imx->base + LPI2C_MCR); - pm_runtime_mark_last_busy(lpi2c_imx->adapter.dev.parent); pm_runtime_put_autosuspend(lpi2c_imx->adapter.dev.parent); return 0; } -static int lpi2c_imx_msg_complete(struct lpi2c_imx_struct *lpi2c_imx) +static int lpi2c_imx_pio_msg_complete(struct lpi2c_imx_struct *lpi2c_imx) { - unsigned long timeout; + unsigned long time_left; - timeout = wait_for_completion_timeout(&lpi2c_imx->complete, HZ); + time_left = wait_for_completion_timeout(&lpi2c_imx->complete, HZ); - return timeout ? 0 : -ETIMEDOUT; + return time_left ? 0 : -ETIMEDOUT; } -static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx) +static int lpi2c_imx_txfifo_empty(struct lpi2c_imx_struct *lpi2c_imx, bool atomic) { - unsigned long orig_jiffies = jiffies; - u32 txcnt; - - do { - txcnt = readl(lpi2c_imx->base + LPI2C_MFSR) & 0xff; + unsigned int temp; + int err; - if (readl(lpi2c_imx->base + LPI2C_MSR) & MSR_NDF) { - dev_dbg(&lpi2c_imx->adapter.dev, "NDF detected\n"); - return -EIO; - } + err = lpi2c_imx_read_msr_poll_timeout(atomic, temp, + (temp & MSR_NDF) || !lpi2c_imx_txfifo_cnt(lpi2c_imx)); - if (time_after(jiffies, orig_jiffies + msecs_to_jiffies(500))) { - dev_dbg(&lpi2c_imx->adapter.dev, "txfifo empty timeout\n"); - return -ETIMEDOUT; - } - schedule(); + if (temp & MSR_NDF) { + dev_dbg(&lpi2c_imx->adapter.dev, "NDF detected\n"); + return -EIO; + } - } while (txcnt); + if (err) { + dev_dbg(&lpi2c_imx->adapter.dev, "txfifo empty timeout\n"); + if (lpi2c_imx->adapter.bus_recovery_info) + i2c_recover_bus(&lpi2c_imx->adapter); + return -ETIMEDOUT; + } return 0; } @@ -351,7 +432,7 @@ static void lpi2c_imx_set_rx_watermark(struct lpi2c_imx_struct *lpi2c_imx) writel(temp << 16, lpi2c_imx->base + LPI2C_MFCR); } -static void lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx) +static bool lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx, bool atomic) { unsigned int data, txcnt; @@ -366,13 +447,19 @@ static void lpi2c_imx_write_txfifo(struct lpi2c_imx_struct *lpi2c_imx) txcnt++; } - if (lpi2c_imx->delivered < lpi2c_imx->msglen) - lpi2c_imx_intctrl(lpi2c_imx, MIER_TDIE | MIER_NDIE); - else + if (lpi2c_imx->delivered < lpi2c_imx->msglen) { + if (!atomic) + lpi2c_imx_intctrl(lpi2c_imx, MIER_TDIE | MIER_NDIE); + return false; + } + + if (!atomic) complete(&lpi2c_imx->complete); + + return true; } -static void lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx) +static bool lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx, bool atomic) { unsigned int blocklen, remaining; unsigned int temp, data; @@ -397,8 +484,9 @@ static void lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx) remaining = lpi2c_imx->msglen - lpi2c_imx->delivered; if (!remaining) { - complete(&lpi2c_imx->complete); - return; + if (!atomic) + complete(&lpi2c_imx->complete); + return true; } /* not finished, still waiting for rx data */ @@ -416,7 +504,10 @@ static void lpi2c_imx_read_rxfifo(struct lpi2c_imx_struct *lpi2c_imx) writel(temp, lpi2c_imx->base + LPI2C_MTDR); } - lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE); + if (!atomic) + lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE); + + return false; } static void lpi2c_imx_write(struct lpi2c_imx_struct *lpi2c_imx, @@ -424,11 +515,29 @@ static void lpi2c_imx_write(struct lpi2c_imx_struct *lpi2c_imx, { lpi2c_imx->tx_buf = msgs->buf; lpi2c_imx_set_tx_watermark(lpi2c_imx); - lpi2c_imx_write_txfifo(lpi2c_imx); + lpi2c_imx_write_txfifo(lpi2c_imx, false); } -static void lpi2c_imx_read(struct lpi2c_imx_struct *lpi2c_imx, - struct i2c_msg *msgs) +static int lpi2c_imx_write_atomic(struct lpi2c_imx_struct *lpi2c_imx, + struct i2c_msg *msgs) +{ + u32 temp; + int err; + + lpi2c_imx->tx_buf = msgs->buf; + + err = lpi2c_imx_read_msr_poll_timeout(true, temp, + (temp & MSR_NDF) || + lpi2c_imx_write_txfifo(lpi2c_imx, true)); + + if (temp & MSR_NDF) + return -EIO; + + return err; +} + +static void lpi2c_imx_read_init(struct lpi2c_imx_struct *lpi2c_imx, + struct i2c_msg *msgs) { unsigned int temp; @@ -439,12 +548,479 @@ static void lpi2c_imx_read(struct lpi2c_imx_struct *lpi2c_imx, temp = msgs->len > CHUNK_DATA ? CHUNK_DATA - 1 : msgs->len - 1; temp |= (RECV_DATA << 8); writel(temp, lpi2c_imx->base + LPI2C_MTDR); +} + +static bool lpi2c_imx_read_chunk_atomic(struct lpi2c_imx_struct *lpi2c_imx) +{ + u32 rxcnt; + + rxcnt = (readl(lpi2c_imx->base + LPI2C_MFSR) >> 16) & 0xFF; + if (!rxcnt) + return false; + + if (!lpi2c_imx_read_rxfifo(lpi2c_imx, true)) + return false; + + return true; +} + +static int lpi2c_imx_read_atomic(struct lpi2c_imx_struct *lpi2c_imx, + struct i2c_msg *msgs) +{ + u32 temp; + int tmo_us; + + tmo_us = 1000000; + do { + if (lpi2c_imx_read_chunk_atomic(lpi2c_imx)) + return 0; + + temp = readl(lpi2c_imx->base + LPI2C_MSR); + + if (temp & MSR_NDF) + return -EIO; + + udelay(100); + tmo_us -= 100; + } while (tmo_us > 0); + + return -ETIMEDOUT; +} + +static bool is_use_dma(struct lpi2c_imx_struct *lpi2c_imx, struct i2c_msg *msg) +{ + if (!lpi2c_imx->can_use_dma) + return false; + + /* + * When the length of data is less than I2C_DMA_THRESHOLD, + * cpu mode is used directly to avoid low performance. + */ + return !(msg->len < I2C_DMA_THRESHOLD); +} + +static int lpi2c_imx_pio_xfer(struct lpi2c_imx_struct *lpi2c_imx, + struct i2c_msg *msg) +{ + reinit_completion(&lpi2c_imx->complete); + + if (msg->flags & I2C_M_RD) { + lpi2c_imx_read_init(lpi2c_imx, msg); + lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE | MIER_NDIE); + } else { + lpi2c_imx_write(lpi2c_imx, msg); + } + + return lpi2c_imx_pio_msg_complete(lpi2c_imx); +} + +static int lpi2c_imx_pio_xfer_atomic(struct lpi2c_imx_struct *lpi2c_imx, + struct i2c_msg *msg) +{ + if (msg->flags & I2C_M_RD) { + lpi2c_imx_read_init(lpi2c_imx, msg); + return lpi2c_imx_read_atomic(lpi2c_imx, msg); + } + + return lpi2c_imx_write_atomic(lpi2c_imx, msg); +} + +static int lpi2c_imx_dma_timeout_calculate(struct lpi2c_imx_struct *lpi2c_imx) +{ + unsigned long time = 0; + + time = 8 * lpi2c_imx->dma->dma_len * 1000 / lpi2c_imx->bitrate; + + /* Add extra second for scheduler related activities */ + time += 1; + + /* Double calculated time */ + return secs_to_jiffies(time); +} + +static int lpi2c_imx_alloc_rx_cmd_buf(struct lpi2c_imx_struct *lpi2c_imx) +{ + struct lpi2c_imx_dma *dma = lpi2c_imx->dma; + u16 rx_remain = dma->dma_len; + int cmd_num; + u16 temp; + + /* + * Calculate the number of rx command words via the DMA TX channel + * writing into command register based on the i2c msg len, and build + * the rx command words buffer. + */ + cmd_num = DIV_ROUND_UP(rx_remain, CHUNK_DATA); + dma->rx_cmd_buf = kcalloc(cmd_num, sizeof(u16), GFP_KERNEL); + dma->rx_cmd_buf_len = cmd_num * sizeof(u16); - lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE | MIER_NDIE); + if (!dma->rx_cmd_buf) { + dev_err(&lpi2c_imx->adapter.dev, "Alloc RX cmd buffer failed\n"); + return -ENOMEM; + } + + for (int i = 0; i < cmd_num ; i++) { + temp = rx_remain > CHUNK_DATA ? CHUNK_DATA - 1 : rx_remain - 1; + temp |= (RECV_DATA << 8); + rx_remain -= CHUNK_DATA; + dma->rx_cmd_buf[i] = temp; + } + + return 0; +} + +static int lpi2c_imx_dma_msg_complete(struct lpi2c_imx_struct *lpi2c_imx) +{ + unsigned long time_left, time; + + time = lpi2c_imx_dma_timeout_calculate(lpi2c_imx); + time_left = wait_for_completion_timeout(&lpi2c_imx->complete, time); + if (time_left == 0) { + dev_err(&lpi2c_imx->adapter.dev, "I/O Error in DMA Data Transfer\n"); + return -ETIMEDOUT; + } + + return 0; +} + +static void lpi2c_dma_unmap(struct lpi2c_imx_dma *dma) +{ + struct dma_chan *chan = dma->dma_data_dir == DMA_FROM_DEVICE + ? dma->chan_rx : dma->chan_tx; + + dma_unmap_single(chan->device->dev, dma->dma_addr, + dma->dma_len, dma->dma_data_dir); + + dma->dma_data_dir = DMA_NONE; +} + +static void lpi2c_cleanup_rx_cmd_dma(struct lpi2c_imx_dma *dma) +{ + dmaengine_terminate_sync(dma->chan_tx); + dma_unmap_single(dma->chan_tx->device->dev, dma->dma_tx_addr, + dma->rx_cmd_buf_len, DMA_TO_DEVICE); } -static int lpi2c_imx_xfer(struct i2c_adapter *adapter, - struct i2c_msg *msgs, int num) +static void lpi2c_cleanup_dma(struct lpi2c_imx_dma *dma) +{ + if (dma->dma_data_dir == DMA_FROM_DEVICE) + dmaengine_terminate_sync(dma->chan_rx); + else if (dma->dma_data_dir == DMA_TO_DEVICE) + dmaengine_terminate_sync(dma->chan_tx); + + lpi2c_dma_unmap(dma); +} + +static void lpi2c_dma_callback(void *data) +{ + struct lpi2c_imx_struct *lpi2c_imx = (struct lpi2c_imx_struct *)data; + + complete(&lpi2c_imx->complete); +} + +static int lpi2c_dma_rx_cmd_submit(struct lpi2c_imx_struct *lpi2c_imx) +{ + struct dma_async_tx_descriptor *rx_cmd_desc; + struct lpi2c_imx_dma *dma = lpi2c_imx->dma; + struct dma_chan *txchan = dma->chan_tx; + dma_cookie_t cookie; + + dma->dma_tx_addr = dma_map_single(txchan->device->dev, + dma->rx_cmd_buf, dma->rx_cmd_buf_len, + DMA_TO_DEVICE); + if (dma_mapping_error(txchan->device->dev, dma->dma_tx_addr)) { + dev_err(&lpi2c_imx->adapter.dev, "DMA map failed, use pio\n"); + return -EINVAL; + } + + rx_cmd_desc = dmaengine_prep_slave_single(txchan, dma->dma_tx_addr, + dma->rx_cmd_buf_len, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!rx_cmd_desc) { + dev_err(&lpi2c_imx->adapter.dev, "DMA prep slave sg failed, use pio\n"); + goto desc_prepare_err_exit; + } + + cookie = dmaengine_submit(rx_cmd_desc); + if (dma_submit_error(cookie)) { + dev_err(&lpi2c_imx->adapter.dev, "submitting DMA failed, use pio\n"); + goto submit_err_exit; + } + + dma_async_issue_pending(txchan); + + return 0; + +desc_prepare_err_exit: + dma_unmap_single(txchan->device->dev, dma->dma_tx_addr, + dma->rx_cmd_buf_len, DMA_TO_DEVICE); + return -EINVAL; + +submit_err_exit: + dma_unmap_single(txchan->device->dev, dma->dma_tx_addr, + dma->rx_cmd_buf_len, DMA_TO_DEVICE); + dmaengine_desc_free(rx_cmd_desc); + return -EINVAL; +} + +static int lpi2c_dma_submit(struct lpi2c_imx_struct *lpi2c_imx) +{ + struct lpi2c_imx_dma *dma = lpi2c_imx->dma; + struct dma_async_tx_descriptor *desc; + struct dma_chan *chan; + dma_cookie_t cookie; + + if (dma->dma_msg_flag & I2C_M_RD) { + chan = dma->chan_rx; + dma->dma_data_dir = DMA_FROM_DEVICE; + dma->dma_transfer_dir = DMA_DEV_TO_MEM; + } else { + chan = dma->chan_tx; + dma->dma_data_dir = DMA_TO_DEVICE; + dma->dma_transfer_dir = DMA_MEM_TO_DEV; + } + + dma->dma_addr = dma_map_single(chan->device->dev, + dma->dma_buf, dma->dma_len, dma->dma_data_dir); + if (dma_mapping_error(chan->device->dev, dma->dma_addr)) { + dev_err(&lpi2c_imx->adapter.dev, "DMA map failed, use pio\n"); + return -EINVAL; + } + + desc = dmaengine_prep_slave_single(chan, dma->dma_addr, + dma->dma_len, dma->dma_transfer_dir, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + dev_err(&lpi2c_imx->adapter.dev, "DMA prep slave sg failed, use pio\n"); + goto desc_prepare_err_exit; + } + + reinit_completion(&lpi2c_imx->complete); + desc->callback = lpi2c_dma_callback; + desc->callback_param = lpi2c_imx; + + cookie = dmaengine_submit(desc); + if (dma_submit_error(cookie)) { + dev_err(&lpi2c_imx->adapter.dev, "submitting DMA failed, use pio\n"); + goto submit_err_exit; + } + + /* Can't switch to PIO mode when DMA have started transfer */ + dma->using_pio_mode = false; + + dma_async_issue_pending(chan); + + return 0; + +desc_prepare_err_exit: + lpi2c_dma_unmap(dma); + return -EINVAL; + +submit_err_exit: + lpi2c_dma_unmap(dma); + dmaengine_desc_free(desc); + return -EINVAL; +} + +static int lpi2c_imx_find_max_burst_num(unsigned int fifosize, unsigned int len) +{ + unsigned int i; + + for (i = fifosize / 2; i > 0; i--) + if (!(len % i)) + break; + + return i; +} + +/* + * For a highest DMA efficiency, tx/rx burst number should be calculated according + * to the FIFO depth. + */ +static void lpi2c_imx_dma_burst_num_calculate(struct lpi2c_imx_struct *lpi2c_imx) +{ + struct lpi2c_imx_dma *dma = lpi2c_imx->dma; + unsigned int cmd_num; + + if (dma->dma_msg_flag & I2C_M_RD) { + /* + * One RX cmd word can trigger DMA receive no more than 256 bytes. + * The number of RX cmd words should be calculated based on the data + * length. + */ + cmd_num = DIV_ROUND_UP(dma->dma_len, CHUNK_DATA); + dma->tx_burst_num = lpi2c_imx_find_max_burst_num(lpi2c_imx->txfifosize, + cmd_num); + dma->rx_burst_num = lpi2c_imx_find_max_burst_num(lpi2c_imx->rxfifosize, + dma->dma_len); + } else { + dma->tx_burst_num = lpi2c_imx_find_max_burst_num(lpi2c_imx->txfifosize, + dma->dma_len); + } +} + +static int lpi2c_dma_config(struct lpi2c_imx_struct *lpi2c_imx) +{ + struct lpi2c_imx_dma *dma = lpi2c_imx->dma; + struct dma_slave_config rx = {}, tx = {}; + int ret; + + lpi2c_imx_dma_burst_num_calculate(lpi2c_imx); + + if (dma->dma_msg_flag & I2C_M_RD) { + tx.dst_addr = dma->phy_addr + LPI2C_MTDR; + tx.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES; + tx.dst_maxburst = dma->tx_burst_num; + tx.direction = DMA_MEM_TO_DEV; + ret = dmaengine_slave_config(dma->chan_tx, &tx); + if (ret < 0) + return ret; + + rx.src_addr = dma->phy_addr + LPI2C_MRDR; + rx.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + rx.src_maxburst = dma->rx_burst_num; + rx.direction = DMA_DEV_TO_MEM; + ret = dmaengine_slave_config(dma->chan_rx, &rx); + if (ret < 0) + return ret; + } else { + tx.dst_addr = dma->phy_addr + LPI2C_MTDR; + tx.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + tx.dst_maxburst = dma->tx_burst_num; + tx.direction = DMA_MEM_TO_DEV; + ret = dmaengine_slave_config(dma->chan_tx, &tx); + if (ret < 0) + return ret; + } + + return 0; +} + +static void lpi2c_dma_enable(struct lpi2c_imx_struct *lpi2c_imx) +{ + struct lpi2c_imx_dma *dma = lpi2c_imx->dma; + /* + * TX interrupt will be triggered when the number of words in + * the transmit FIFO is equal or less than TX watermark. + * RX interrupt will be triggered when the number of words in + * the receive FIFO is greater than RX watermark. + * In order to trigger the DMA interrupt, TX watermark should be + * set equal to the DMA TX burst number but RX watermark should + * be set less than the DMA RX burst number. + */ + if (dma->dma_msg_flag & I2C_M_RD) { + /* Set I2C TX/RX watermark */ + writel(dma->tx_burst_num | (dma->rx_burst_num - 1) << 16, + lpi2c_imx->base + LPI2C_MFCR); + /* Enable I2C DMA TX/RX function */ + writel(MDER_TDDE | MDER_RDDE, lpi2c_imx->base + LPI2C_MDER); + } else { + /* Set I2C TX watermark */ + writel(dma->tx_burst_num, lpi2c_imx->base + LPI2C_MFCR); + /* Enable I2C DMA TX function */ + writel(MDER_TDDE, lpi2c_imx->base + LPI2C_MDER); + } + + /* Enable NACK detected */ + lpi2c_imx_intctrl(lpi2c_imx, MIER_NDIE); +}; + +/* + * When lpi2c is in TX DMA mode we can use one DMA TX channel to write + * data word into TXFIFO, but in RX DMA mode it is different. + * + * The LPI2C MTDR register is a command data and transmit data register. + * Bits 8-10 are the command data field and Bits 0-7 are the transmit + * data field. When the LPI2C master needs to read data, the number of + * bytes to read should be set in the command field and RECV_DATA should + * be set into the command data field to receive (DATA[7:0] + 1) bytes. + * The recv data command word is made of RECV_DATA in the command data + * field and the number of bytes to read in transmit data field. When the + * length of data to be read exceeds 256 bytes, recv data command word + * needs to be written to TXFIFO multiple times. + * + * So when in RX DMA mode, the TX channel also must to be configured to + * send RX command words and the RX command word must be set in advance + * before transmitting. + */ +static int lpi2c_imx_dma_xfer(struct lpi2c_imx_struct *lpi2c_imx, + struct i2c_msg *msg) +{ + struct lpi2c_imx_dma *dma = lpi2c_imx->dma; + int ret; + + /* When DMA mode fails before transferring, CPU mode can be used. */ + dma->using_pio_mode = true; + + dma->dma_len = msg->len; + dma->dma_msg_flag = msg->flags; + dma->dma_buf = i2c_get_dma_safe_msg_buf(msg, I2C_DMA_THRESHOLD); + if (!dma->dma_buf) + return -ENOMEM; + + ret = lpi2c_dma_config(lpi2c_imx); + if (ret) { + dev_err(&lpi2c_imx->adapter.dev, "Failed to configure DMA (%d)\n", ret); + goto disable_dma; + } + + lpi2c_dma_enable(lpi2c_imx); + + ret = lpi2c_dma_submit(lpi2c_imx); + if (ret) { + dev_err(&lpi2c_imx->adapter.dev, "DMA submission failed (%d)\n", ret); + goto disable_dma; + } + + if (dma->dma_msg_flag & I2C_M_RD) { + ret = lpi2c_imx_alloc_rx_cmd_buf(lpi2c_imx); + if (ret) + goto disable_cleanup_data_dma; + + ret = lpi2c_dma_rx_cmd_submit(lpi2c_imx); + if (ret) + goto disable_cleanup_data_dma; + } + + ret = lpi2c_imx_dma_msg_complete(lpi2c_imx); + if (ret) + goto disable_cleanup_all_dma; + + /* When encountering NACK in transfer, clean up all DMA transfers */ + if ((readl(lpi2c_imx->base + LPI2C_MSR) & MSR_NDF) && !ret) { + ret = -EIO; + goto disable_cleanup_all_dma; + } + + if (dma->dma_msg_flag & I2C_M_RD) + dma_unmap_single(dma->chan_tx->device->dev, dma->dma_tx_addr, + dma->rx_cmd_buf_len, DMA_TO_DEVICE); + lpi2c_dma_unmap(dma); + + goto disable_dma; + +disable_cleanup_all_dma: + if (dma->dma_msg_flag & I2C_M_RD) + lpi2c_cleanup_rx_cmd_dma(dma); +disable_cleanup_data_dma: + lpi2c_cleanup_dma(dma); +disable_dma: + /* Disable I2C DMA function */ + writel(0, lpi2c_imx->base + LPI2C_MDER); + + if (dma->dma_msg_flag & I2C_M_RD) + kfree(dma->rx_cmd_buf); + + if (ret) + i2c_put_dma_safe_msg_buf(dma->dma_buf, msg, false); + else + i2c_put_dma_safe_msg_buf(dma->dma_buf, msg, true); + + return ret; +} + +static int lpi2c_imx_xfer_common(struct i2c_adapter *adapter, + struct i2c_msg *msgs, int num, bool atomic) { struct lpi2c_imx_struct *lpi2c_imx = i2c_get_adapdata(adapter); unsigned int temp; @@ -455,7 +1031,7 @@ static int lpi2c_imx_xfer(struct i2c_adapter *adapter, return result; for (i = 0; i < num; i++) { - result = lpi2c_imx_start(lpi2c_imx, &msgs[i]); + result = lpi2c_imx_start(lpi2c_imx, &msgs[i], atomic); if (result) goto disable; @@ -463,28 +1039,37 @@ static int lpi2c_imx_xfer(struct i2c_adapter *adapter, if (num == 1 && msgs[0].len == 0) goto stop; + lpi2c_imx->rx_buf = NULL; + lpi2c_imx->tx_buf = NULL; lpi2c_imx->delivered = 0; lpi2c_imx->msglen = msgs[i].len; - init_completion(&lpi2c_imx->complete); - if (msgs[i].flags & I2C_M_RD) - lpi2c_imx_read(lpi2c_imx, &msgs[i]); - else - lpi2c_imx_write(lpi2c_imx, &msgs[i]); + if (atomic) { + result = lpi2c_imx_pio_xfer_atomic(lpi2c_imx, &msgs[i]); + } else { + init_completion(&lpi2c_imx->complete); + + if (is_use_dma(lpi2c_imx, &msgs[i])) { + result = lpi2c_imx_dma_xfer(lpi2c_imx, &msgs[i]); + if (result && lpi2c_imx->dma->using_pio_mode) + result = lpi2c_imx_pio_xfer(lpi2c_imx, &msgs[i]); + } else { + result = lpi2c_imx_pio_xfer(lpi2c_imx, &msgs[i]); + } + } - result = lpi2c_imx_msg_complete(lpi2c_imx); if (result) goto stop; if (!(msgs[i].flags & I2C_M_RD)) { - result = lpi2c_imx_txfifo_empty(lpi2c_imx); + result = lpi2c_imx_txfifo_empty(lpi2c_imx, atomic); if (result) goto stop; } } stop: - lpi2c_imx_stop(lpi2c_imx); + lpi2c_imx_stop(lpi2c_imx, atomic); temp = readl(lpi2c_imx->base + LPI2C_MSR); if ((temp & MSR_NDF) && !result) @@ -500,26 +1085,269 @@ disable: return (result < 0) ? result : num; } -static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id) +static int lpi2c_imx_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) { - struct lpi2c_imx_struct *lpi2c_imx = dev_id; + return lpi2c_imx_xfer_common(adapter, msgs, num, false); +} + +static int lpi2c_imx_xfer_atomic(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) +{ + return lpi2c_imx_xfer_common(adapter, msgs, num, true); +} + +static irqreturn_t lpi2c_imx_target_isr(struct lpi2c_imx_struct *lpi2c_imx, + u32 ssr, u32 sier_filter) +{ + u8 value; + u32 sasr; + + /* Arbitration lost */ + if (sier_filter & SSR_BEF) { + writel(0, lpi2c_imx->base + LPI2C_SIER); + return IRQ_HANDLED; + } + + /* Address detected */ + if (sier_filter & SSR_AVF) { + sasr = readl(lpi2c_imx->base + LPI2C_SASR); + if (SASR_READ_REQ & sasr) { + /* Read request */ + i2c_slave_event(lpi2c_imx->target, I2C_SLAVE_READ_REQUESTED, &value); + writel(value, lpi2c_imx->base + LPI2C_STDR); + goto ret; + } else { + /* Write request */ + i2c_slave_event(lpi2c_imx->target, I2C_SLAVE_WRITE_REQUESTED, &value); + } + } + + if (sier_filter & SSR_SDF) + /* STOP */ + i2c_slave_event(lpi2c_imx->target, I2C_SLAVE_STOP, &value); + + if (sier_filter & SSR_TDF) { + /* Target send data */ + i2c_slave_event(lpi2c_imx->target, I2C_SLAVE_READ_PROCESSED, &value); + writel(value, lpi2c_imx->base + LPI2C_STDR); + } + + if (sier_filter & SSR_RDF) { + /* Target receive data */ + value = readl(lpi2c_imx->base + LPI2C_SRDR); + i2c_slave_event(lpi2c_imx->target, I2C_SLAVE_WRITE_RECEIVED, &value); + } + +ret: + /* Clear SSR */ + writel(ssr & SSR_CLEAR_BITS, lpi2c_imx->base + LPI2C_SSR); + return IRQ_HANDLED; +} + +static irqreturn_t lpi2c_imx_master_isr(struct lpi2c_imx_struct *lpi2c_imx) +{ + unsigned int enabled; unsigned int temp; + enabled = readl(lpi2c_imx->base + LPI2C_MIER); + lpi2c_imx_intctrl(lpi2c_imx, 0); temp = readl(lpi2c_imx->base + LPI2C_MSR); - - if (temp & MSR_RDF) - lpi2c_imx_read_rxfifo(lpi2c_imx); - - if (temp & MSR_TDF) - lpi2c_imx_write_txfifo(lpi2c_imx); + temp &= enabled; if (temp & MSR_NDF) complete(&lpi2c_imx->complete); + else if (temp & MSR_RDF) + lpi2c_imx_read_rxfifo(lpi2c_imx, false); + else if (temp & MSR_TDF) + lpi2c_imx_write_txfifo(lpi2c_imx, false); return IRQ_HANDLED; } +static irqreturn_t lpi2c_imx_isr(int irq, void *dev_id) +{ + struct lpi2c_imx_struct *lpi2c_imx = dev_id; + + if (lpi2c_imx->target) { + u32 scr = readl(lpi2c_imx->base + LPI2C_SCR); + u32 ssr = readl(lpi2c_imx->base + LPI2C_SSR); + u32 sier_filter = ssr & readl(lpi2c_imx->base + LPI2C_SIER); + + /* + * The target is enabled and an interrupt has been triggered. + * Enter the target's irq handler. + */ + if ((scr & SCR_SEN) && sier_filter) + return lpi2c_imx_target_isr(lpi2c_imx, ssr, sier_filter); + } + + /* + * Otherwise the interrupt has been triggered by the master. + * Enter the master's irq handler. + */ + return lpi2c_imx_master_isr(lpi2c_imx); +} + +static void lpi2c_imx_target_init(struct lpi2c_imx_struct *lpi2c_imx) +{ + u32 temp; + + /* reset target module */ + writel(SCR_RST, lpi2c_imx->base + LPI2C_SCR); + writel(0, lpi2c_imx->base + LPI2C_SCR); + + /* Set target address */ + writel((lpi2c_imx->target->addr << 1), lpi2c_imx->base + LPI2C_SAMR); + + writel(SCFGR1_RXSTALL | SCFGR1_TXDSTALL, lpi2c_imx->base + LPI2C_SCFGR1); + + /* + * set SCFGR2: FILTSDA, FILTSCL and CLKHOLD + * + * FILTSCL/FILTSDA can eliminate signal skew. It should generally be + * set to the same value and should be set >= 50ns. + * + * CLKHOLD is only used when clock stretching is enabled, but it will + * extend the clock stretching to ensure there is an additional delay + * between the target driving SDA and the target releasing the SCL pin. + * + * CLKHOLD setting is crucial for lpi2c target. When master read data + * from target, if there is a delay caused by cpu idle, excessive load, + * or other delays between two bytes in one message transmission, it + * will cause a short interval time between the driving SDA signal and + * releasing SCL signal. The lpi2c master will mistakenly think it is a stop + * signal resulting in an arbitration failure. This issue can be avoided + * by setting CLKHOLD. + * + * In order to ensure lpi2c function normally when the lpi2c speed is as + * low as 100kHz, CLKHOLD should be set to 3 and it is also compatible with + * higher clock frequency like 400kHz and 1MHz. + */ + temp = SCFGR2_FILTSDA(2) | SCFGR2_FILTSCL(2) | SCFGR2_CLKHOLD(3); + writel(temp, lpi2c_imx->base + LPI2C_SCFGR2); + + /* + * Enable module: + * SCR_FILTEN can enable digital filter and output delay counter for LPI2C + * target mode. So SCR_FILTEN need be asserted when enable SDA/SCL FILTER + * and CLKHOLD. + */ + writel(SCR_SEN | SCR_FILTEN, lpi2c_imx->base + LPI2C_SCR); + + /* Enable interrupt from i2c module */ + writel(SLAVE_INT_FLAG, lpi2c_imx->base + LPI2C_SIER); +} + +static int lpi2c_imx_register_target(struct i2c_client *client) +{ + struct lpi2c_imx_struct *lpi2c_imx = i2c_get_adapdata(client->adapter); + int ret; + + if (lpi2c_imx->target) + return -EBUSY; + + lpi2c_imx->target = client; + + ret = pm_runtime_resume_and_get(lpi2c_imx->adapter.dev.parent); + if (ret < 0) { + dev_err(&lpi2c_imx->adapter.dev, "failed to resume i2c controller"); + return ret; + } + + lpi2c_imx_target_init(lpi2c_imx); + + return 0; +} + +static int lpi2c_imx_unregister_target(struct i2c_client *client) +{ + struct lpi2c_imx_struct *lpi2c_imx = i2c_get_adapdata(client->adapter); + int ret; + + if (!lpi2c_imx->target) + return -EINVAL; + + /* Reset target address. */ + writel(0, lpi2c_imx->base + LPI2C_SAMR); + + writel(SCR_RST, lpi2c_imx->base + LPI2C_SCR); + writel(0, lpi2c_imx->base + LPI2C_SCR); + + lpi2c_imx->target = NULL; + + ret = pm_runtime_put_sync(lpi2c_imx->adapter.dev.parent); + if (ret < 0) + dev_err(&lpi2c_imx->adapter.dev, "failed to suspend i2c controller"); + + return ret; +} + +static int lpi2c_imx_init_recovery_info(struct lpi2c_imx_struct *lpi2c_imx, + struct platform_device *pdev) +{ + struct i2c_bus_recovery_info *bri = &lpi2c_imx->rinfo; + + bri->pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(bri->pinctrl)) + return PTR_ERR(bri->pinctrl); + + lpi2c_imx->adapter.bus_recovery_info = bri; + + return 0; +} + +static void dma_exit(struct device *dev, struct lpi2c_imx_dma *dma) +{ + if (dma->chan_rx) + dma_release_channel(dma->chan_rx); + + if (dma->chan_tx) + dma_release_channel(dma->chan_tx); + + devm_kfree(dev, dma); +} + +static int lpi2c_dma_init(struct device *dev, dma_addr_t phy_addr) +{ + struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev); + struct lpi2c_imx_dma *dma; + int ret; + + dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); + if (!dma) + return -ENOMEM; + + dma->phy_addr = phy_addr; + + /* Prepare for TX DMA: */ + dma->chan_tx = dma_request_chan(dev, "tx"); + if (IS_ERR(dma->chan_tx)) { + ret = PTR_ERR(dma->chan_tx); + if (ret != -ENODEV && ret != -EPROBE_DEFER) + dev_err(dev, "can't request DMA tx channel (%d)\n", ret); + dma->chan_tx = NULL; + goto dma_exit; + } + + /* Prepare for RX DMA: */ + dma->chan_rx = dma_request_chan(dev, "rx"); + if (IS_ERR(dma->chan_rx)) { + ret = PTR_ERR(dma->chan_rx); + if (ret != -ENODEV && ret != -EPROBE_DEFER) + dev_err(dev, "can't request DMA rx channel (%d)\n", ret); + dma->chan_rx = NULL; + goto dma_exit; + } + + lpi2c_imx->can_use_dma = true; + lpi2c_imx->dma = dma; + return 0; + +dma_exit: + dma_exit(dev, dma); + return ret; +} + static u32 lpi2c_imx_func(struct i2c_adapter *adapter) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | @@ -527,19 +1355,24 @@ static u32 lpi2c_imx_func(struct i2c_adapter *adapter) } static const struct i2c_algorithm lpi2c_imx_algo = { - .master_xfer = lpi2c_imx_xfer, - .functionality = lpi2c_imx_func, + .xfer = lpi2c_imx_xfer, + .xfer_atomic = lpi2c_imx_xfer_atomic, + .functionality = lpi2c_imx_func, + .reg_target = lpi2c_imx_register_target, + .unreg_target = lpi2c_imx_unregister_target, }; static const struct of_device_id lpi2c_imx_of_match[] = { { .compatible = "fsl,imx7ulp-lpi2c" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, lpi2c_imx_of_match); static int lpi2c_imx_probe(struct platform_device *pdev) { struct lpi2c_imx_struct *lpi2c_imx; + struct resource *res; + dma_addr_t phy_addr; unsigned int temp; int irq, ret; @@ -547,7 +1380,7 @@ static int lpi2c_imx_probe(struct platform_device *pdev) if (!lpi2c_imx) return -ENOMEM; - lpi2c_imx->base = devm_platform_ioremap_resource(pdev, 0); + lpi2c_imx->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(lpi2c_imx->base)) return PTR_ERR(lpi2c_imx->base); @@ -561,12 +1394,11 @@ static int lpi2c_imx_probe(struct platform_device *pdev) lpi2c_imx->adapter.dev.of_node = pdev->dev.of_node; strscpy(lpi2c_imx->adapter.name, pdev->name, sizeof(lpi2c_imx->adapter.name)); + phy_addr = (dma_addr_t)res->start; ret = devm_clk_bulk_get_all(&pdev->dev, &lpi2c_imx->clks); - if (ret < 0) { - dev_err(&pdev->dev, "can't get I2C peripheral clock, ret=%d\n", ret); - return ret; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "can't get I2C peripheral clock\n"); lpi2c_imx->num_clks = ret; ret = of_property_read_u32(pdev->dev.of_node, @@ -574,12 +1406,10 @@ static int lpi2c_imx_probe(struct platform_device *pdev) if (ret) lpi2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ; - ret = devm_request_irq(&pdev->dev, irq, lpi2c_imx_isr, 0, + ret = devm_request_irq(&pdev->dev, irq, lpi2c_imx_isr, IRQF_NO_SUSPEND, pdev->name, lpi2c_imx); - if (ret) { - dev_err(&pdev->dev, "can't claim irq %d\n", irq); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "can't claim irq %d\n", irq); i2c_set_adapdata(&lpi2c_imx->adapter, lpi2c_imx); platform_set_drvdata(pdev, lpi2c_imx); @@ -588,6 +1418,20 @@ static int lpi2c_imx_probe(struct platform_device *pdev) if (ret) return ret; + /* + * Lock the parent clock rate to avoid getting parent clock upon + * each transfer + */ + ret = devm_clk_rate_exclusive_get(&pdev->dev, lpi2c_imx->clks[0].clk); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "can't lock I2C peripheral clock rate\n"); + + lpi2c_imx->rate_per = clk_get_rate(lpi2c_imx->clks[0].clk); + if (!lpi2c_imx->rate_per) + return dev_err_probe(&pdev->dev, -EINVAL, + "can't get I2C peripheral clock rate\n"); + pm_runtime_set_autosuspend_delay(&pdev->dev, I2C_PM_TIMEOUT); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_get_noresume(&pdev->dev); @@ -598,11 +1442,24 @@ static int lpi2c_imx_probe(struct platform_device *pdev) lpi2c_imx->txfifosize = 1 << (temp & 0x0f); lpi2c_imx->rxfifosize = 1 << ((temp >> 8) & 0x0f); + /* Init optional bus recovery function */ + ret = lpi2c_imx_init_recovery_info(lpi2c_imx, pdev); + /* Give it another chance if pinctrl used is not ready yet */ + if (ret == -EPROBE_DEFER) + goto rpm_disable; + + /* Init DMA */ + ret = lpi2c_dma_init(&pdev->dev, phy_addr); + if (ret) { + if (ret == -EPROBE_DEFER) + goto rpm_disable; + dev_info(&pdev->dev, "use pio mode\n"); + } + ret = i2c_add_adapter(&lpi2c_imx->adapter); if (ret) goto rpm_disable; - pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); dev_info(&lpi2c_imx->adapter.dev, "LPI2C adapter registered\n"); @@ -610,14 +1467,14 @@ static int lpi2c_imx_probe(struct platform_device *pdev) return 0; rpm_disable: - pm_runtime_put(&pdev->dev); - pm_runtime_disable(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); return ret; } -static int lpi2c_imx_remove(struct platform_device *pdev) +static void lpi2c_imx_remove(struct platform_device *pdev) { struct lpi2c_imx_struct *lpi2c_imx = platform_get_drvdata(pdev); @@ -625,15 +1482,13 @@ static int lpi2c_imx_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); - - return 0; } static int __maybe_unused lpi2c_runtime_suspend(struct device *dev) { struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev); - clk_bulk_disable_unprepare(lpi2c_imx->num_clks, lpi2c_imx->clks); + clk_bulk_disable(lpi2c_imx->num_clks, lpi2c_imx->clks); pinctrl_pm_select_sleep_state(dev); return 0; @@ -645,7 +1500,7 @@ static int __maybe_unused lpi2c_runtime_resume(struct device *dev) int ret; pinctrl_pm_select_default_state(dev); - ret = clk_bulk_prepare_enable(lpi2c_imx->num_clks, lpi2c_imx->clks); + ret = clk_bulk_enable(lpi2c_imx->num_clks, lpi2c_imx->clks); if (ret) { dev_err(dev, "failed to enable I2C clock, ret=%d\n", ret); return ret; @@ -654,9 +1509,67 @@ static int __maybe_unused lpi2c_runtime_resume(struct device *dev) return 0; } +static int __maybe_unused lpi2c_suspend_noirq(struct device *dev) +{ + return pm_runtime_force_suspend(dev); +} + +static int __maybe_unused lpi2c_resume_noirq(struct device *dev) +{ + struct lpi2c_imx_struct *lpi2c_imx = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_force_resume(dev); + if (ret) + return ret; + + /* + * If the I2C module powers down during system suspend, + * the register values will be lost. Therefore, reinitialize + * the target when the system resumes. + */ + if (lpi2c_imx->target) + lpi2c_imx_target_init(lpi2c_imx); + + return 0; +} + +static int lpi2c_suspend(struct device *dev) +{ + /* + * Some I2C devices may need the I2C controller to remain active + * during resume_noirq() or suspend_noirq(). If the controller is + * autosuspended, there is no way to wake it up once runtime PM is + * disabled (in suspend_late()). + * + * During system resume, the I2C controller will be available only + * after runtime PM is re-enabled (in resume_early()). However, this + * may be too late for some devices. + * + * Wake up the controller in the suspend() callback while runtime PM + * is still enabled. The I2C controller will remain available until + * the suspend_noirq() callback (pm_runtime_force_suspend()) is + * called. During resume, the I2C controller can be restored by the + * resume_noirq() callback (pm_runtime_force_resume()). + * + * Finally, the resume() callback re-enables autosuspend, ensuring + * the I2C controller remains available until the system enters + * suspend_noirq() and from resume_noirq(). + */ + return pm_runtime_resume_and_get(dev); +} + +static int lpi2c_resume(struct device *dev) +{ + pm_runtime_put_autosuspend(dev); + + return 0; +} + static const struct dev_pm_ops lpi2c_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) + SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(lpi2c_suspend_noirq, + lpi2c_resume_noirq) + SYSTEM_SLEEP_PM_OPS(lpi2c_suspend, lpi2c_resume) SET_RUNTIME_PM_OPS(lpi2c_runtime_suspend, lpi2c_runtime_resume, NULL) }; diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index cf5bacf3a488..dcce882f3eba 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -17,12 +17,13 @@ * Copyright (C) 2008 Darius Augulis <darius.augulis at teltonika.lt> * * Copyright 2013 Freescale Semiconductor, Inc. - * Copyright 2020 NXP + * Copyright 2020, 2024 NXP * */ #include <linux/acpi.h> #include <linux/clk.h> +#include <linux/cleanup.h> #include <linux/completion.h> #include <linux/delay.h> #include <linux/dma-mapping.h> @@ -41,7 +42,6 @@ #include <linux/hrtimer.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/of_dma.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_data/i2c-imx.h> @@ -85,6 +85,7 @@ #define IMX_I2C_REGSHIFT 2 #define VF610_I2C_REGSHIFT 0 +#define S32G_I2C_REGSHIFT 0 /* Bits of IMX I2C registers */ #define I2SR_RXAK 0x01 @@ -166,9 +167,34 @@ static struct imx_i2c_clk_pair vf610_i2c_clk_div[] = { { 3840, 0x3F }, { 4096, 0x7B }, { 5120, 0x7D }, { 6144, 0x7E }, }; +/* S32G2/S32G3 clock divider, register value pairs */ +static struct imx_i2c_clk_pair s32g2_i2c_clk_div[] = { + { 34, 0x00 }, { 36, 0x01 }, { 38, 0x02 }, { 40, 0x03 }, + { 42, 0x04 }, { 44, 0x05 }, { 46, 0x06 }, { 48, 0x09 }, + { 52, 0x0A }, { 54, 0x07 }, { 56, 0x0B }, { 60, 0x0C }, + { 64, 0x0D }, { 68, 0x40 }, { 72, 0x0E }, { 76, 0x42 }, + { 80, 0x12 }, { 84, 0x0F }, { 88, 0x13 }, { 96, 0x14 }, + { 104, 0x15 }, { 108, 0x47 }, { 112, 0x19 }, { 120, 0x16 }, + { 128, 0x1A }, { 136, 0x80 }, { 144, 0x17 }, { 152, 0x82 }, + { 160, 0x1C }, { 168, 0x84 }, { 176, 0x1D }, { 192, 0x21 }, + { 208, 0x1E }, { 216, 0x87 }, { 224, 0x22 }, { 240, 0x56 }, + { 256, 0x1F }, { 288, 0x24 }, { 320, 0x25 }, { 336, 0x8F }, + { 352, 0x93 }, { 356, 0x5D }, { 358, 0x98 }, { 384, 0x26 }, + { 416, 0x56 }, { 448, 0x2A }, { 480, 0x27 }, { 512, 0x2B }, + { 576, 0x2C }, { 640, 0x2D }, { 704, 0x9D }, { 768, 0x2E }, + { 832, 0x9D }, { 896, 0x32 }, { 960, 0x2F }, { 1024, 0x33 }, + { 1152, 0x34 }, { 1280, 0x35 }, { 1536, 0x36 }, { 1792, 0x3A }, + { 1920, 0x37 }, { 2048, 0x3B }, { 2304, 0x74 }, { 2560, 0x3D }, + { 3072, 0x3E }, { 3584, 0x7A }, { 3840, 0x3F }, { 4096, 0x7B }, + { 4608, 0x7C }, { 5120, 0x7D }, { 6144, 0x7E }, { 7168, 0xBA }, + { 7680, 0x7F }, { 8192, 0xBB }, { 9216, 0xBC }, { 10240, 0xBD }, + { 12288, 0xBE }, { 15360, 0xBF }, +}; + enum imx_i2c_type { IMX1_I2C, IMX21_I2C, + S32G_I2C, VF610_I2C, }; @@ -198,6 +224,17 @@ struct imx_i2c_dma { enum dma_data_direction dma_data_dir; }; +enum imx_i2c_state { + IMX_I2C_STATE_DONE, + IMX_I2C_STATE_FAILED, + IMX_I2C_STATE_WRITE, + IMX_I2C_STATE_DMA, + IMX_I2C_STATE_READ, + IMX_I2C_STATE_READ_CONTINUE, + IMX_I2C_STATE_READ_BLOCK_DATA, + IMX_I2C_STATE_READ_BLOCK_DATA_LEN, +}; + struct imx_i2c_struct { struct i2c_adapter adapter; struct clk *clk; @@ -213,14 +250,18 @@ struct imx_i2c_struct { const struct imx_i2c_hwdata *hwdata; struct i2c_bus_recovery_info rinfo; - struct pinctrl *pinctrl; - struct pinctrl_state *pinctrl_pins_default; - struct pinctrl_state *pinctrl_pins_gpio; - struct imx_i2c_dma *dma; struct i2c_client *slave; enum i2c_slave_event last_slave_event; + struct i2c_msg *msg; + unsigned int msg_buf_idx; + int isr_result; + bool is_lastmsg; + enum imx_i2c_state state; + + bool multi_master; + /* For checking slave events. */ spinlock_t slave_lock; struct hrtimer slave_timer; @@ -263,7 +304,15 @@ static struct imx_i2c_hwdata vf610_i2c_hwdata = { .ndivs = ARRAY_SIZE(vf610_i2c_clk_div), .i2sr_clr_opcode = I2SR_CLR_OPCODE_W1C, .i2cr_ien_opcode = I2CR_IEN_OPCODE_0, +}; +static const struct imx_i2c_hwdata s32g2_i2c_hwdata = { + .devtype = S32G_I2C, + .regshift = S32G_I2C_REGSHIFT, + .clk_div = s32g2_i2c_clk_div, + .ndivs = ARRAY_SIZE(s32g2_i2c_clk_div), + .i2sr_clr_opcode = I2SR_CLR_OPCODE_W1C, + .i2cr_ien_opcode = I2CR_IEN_OPCODE_0, }; static const struct platform_device_id imx_i2c_devtype[] = { @@ -287,12 +336,14 @@ static const struct of_device_id i2c_imx_dt_ids[] = { { .compatible = "fsl,imx6sll-i2c", .data = &imx6_i2c_hwdata, }, { .compatible = "fsl,imx6sx-i2c", .data = &imx6_i2c_hwdata, }, { .compatible = "fsl,imx6ul-i2c", .data = &imx6_i2c_hwdata, }, + { .compatible = "fsl,imx7d-i2c", .data = &imx6_i2c_hwdata, }, { .compatible = "fsl,imx7s-i2c", .data = &imx6_i2c_hwdata, }, { .compatible = "fsl,imx8mm-i2c", .data = &imx6_i2c_hwdata, }, { .compatible = "fsl,imx8mn-i2c", .data = &imx6_i2c_hwdata, }, { .compatible = "fsl,imx8mp-i2c", .data = &imx6_i2c_hwdata, }, { .compatible = "fsl,imx8mq-i2c", .data = &imx6_i2c_hwdata, }, { .compatible = "fsl,vf610-i2c", .data = &vf610_i2c_hwdata, }, + { .compatible = "nxp,s32g2-i2c", .data = &s32g2_i2c_hwdata, }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids); @@ -347,17 +398,16 @@ static void i2c_imx_reset_regs(struct imx_i2c_struct *i2c_imx) } /* Functions for DMA support */ -static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, - dma_addr_t phy_addr) +static int i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, dma_addr_t phy_addr) { struct imx_i2c_dma *dma; struct dma_slave_config dma_sconfig; - struct device *dev = &i2c_imx->adapter.dev; + struct device *dev = i2c_imx->adapter.dev.parent; int ret; dma = devm_kzalloc(dev, sizeof(*dma), GFP_KERNEL); if (!dma) - return; + return -ENOMEM; dma->chan_tx = dma_request_chan(dev, "tx"); if (IS_ERR(dma->chan_tx)) { @@ -402,7 +452,7 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx, dev_info(dev, "using %s (tx) and %s (rx) for DMA transfers\n", dma_chan_name(dma->chan_tx), dma_chan_name(dma->chan_rx)); - return; + return 0; fail_rx: dma_release_channel(dma->chan_rx); @@ -410,6 +460,8 @@ fail_tx: dma_release_channel(dma->chan_tx); fail_al: devm_kfree(dev, dma); + + return ret; } static void i2c_imx_dma_callback(void *arg) @@ -483,6 +535,7 @@ static void i2c_imx_dma_free(struct imx_i2c_struct *i2c_imx) static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool atomic) { + bool multi_master = i2c_imx->multi_master; unsigned long orig_jiffies = jiffies; unsigned int temp; @@ -490,12 +543,12 @@ static int i2c_imx_bus_busy(struct imx_i2c_struct *i2c_imx, int for_busy, bool a temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); /* check for arbitration lost */ - if (temp & I2SR_IAL) { + if (multi_master && (temp & I2SR_IAL)) { i2c_imx_clear_irq(i2c_imx, I2SR_IAL); return -EAGAIN; } - if (for_busy && (temp & I2SR_IBB)) { + if (for_busy && (!multi_master || (temp & I2SR_IBB))) { i2c_imx->stopped = 0; break; } @@ -545,8 +598,8 @@ static int i2c_imx_trx_complete(struct imx_i2c_struct *i2c_imx, bool atomic) return -ETIMEDOUT; } - /* check for arbitration lost */ - if (i2c_imx->i2csr & I2SR_IAL) { + /* In multi-master mode check for arbitration lost */ + if (i2c_imx->multi_master && (i2c_imx->i2csr & I2SR_IAL)) { dev_dbg(&i2c_imx->adapter.dev, "<%s> Arbitration lost\n", __func__); i2c_imx_clear_irq(i2c_imx, I2SR_IAL); @@ -570,8 +623,8 @@ static int i2c_imx_acked(struct imx_i2c_struct *i2c_imx) return 0; } -static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, - unsigned int i2c_clk_rate) +static int i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, + unsigned int i2c_clk_rate) { struct imx_i2c_clk_pair *i2c_clk_div = i2c_imx->hwdata->clk_div; unsigned int div; @@ -586,7 +639,11 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, /* Divider value calculation */ if (i2c_imx->cur_clk == i2c_clk_rate) - return; + return 0; + + /* Keep the denominator of the following program always NOT equal to 0. */ + if (!(i2c_clk_rate / 2)) + return -EINVAL; i2c_imx->cur_clk = i2c_clk_rate; @@ -617,6 +674,8 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx, dev_dbg(&i2c_imx->adapter.dev, "IFDR[IC]=0x%x, REAL DIV=%d\n", i2c_clk_div[i].val, i2c_clk_div[i].div); #endif + + return 0; } static int i2c_imx_clk_notifier_call(struct notifier_block *nb, @@ -626,11 +685,12 @@ static int i2c_imx_clk_notifier_call(struct notifier_block *nb, struct imx_i2c_struct *i2c_imx = container_of(nb, struct imx_i2c_struct, clk_change_nb); + int ret = 0; if (action & POST_RATE_CHANGE) - i2c_imx_set_clk(i2c_imx, ndata->new_rate); + ret = i2c_imx_set_clk(i2c_imx, ndata->new_rate); - return NOTIFY_OK; + return notifier_from_errno(ret); } static int i2c_imx_start(struct imx_i2c_struct *i2c_imx, bool atomic) @@ -692,7 +752,7 @@ static void i2c_imx_stop(struct imx_i2c_struct *i2c_imx, bool atomic) i2c_imx_bus_busy(i2c_imx, 0, atomic); /* Disable I2C controller */ - temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN, + temp = i2c_imx->hwdata->i2cr_ien_opcode ^ I2CR_IEN; imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); } @@ -804,6 +864,11 @@ static irqreturn_t i2c_imx_slave_handle(struct imx_i2c_struct *i2c_imx, ctl &= ~I2CR_MTX; imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + + /* flag the last byte as processed */ + i2c_imx_slave_event(i2c_imx, + I2C_SLAVE_READ_PROCESSED, &value); + i2c_imx_slave_finish_op(i2c_imx); return IRQ_HANDLED; } @@ -827,13 +892,13 @@ static enum hrtimer_restart i2c_imx_slave_timeout(struct hrtimer *t) struct imx_i2c_struct *i2c_imx = container_of(t, struct imx_i2c_struct, slave_timer); unsigned int ctl, status; - unsigned long flags; - spin_lock_irqsave(&i2c_imx->slave_lock, flags); + guard(spinlock_irqsave)(&i2c_imx->slave_lock); + status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); i2c_imx_slave_handle(i2c_imx, status, ctl); - spin_unlock_irqrestore(&i2c_imx->slave_lock, flags); + return HRTIMER_NORESTART; } @@ -903,11 +968,157 @@ static int i2c_imx_unreg_slave(struct i2c_client *client) return ret; } +static inline int i2c_imx_isr_acked(struct imx_i2c_struct *i2c_imx) +{ + i2c_imx->isr_result = 0; + + if (imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR) & I2SR_RXAK) { + i2c_imx->state = IMX_I2C_STATE_FAILED; + i2c_imx->isr_result = -ENXIO; + wake_up(&i2c_imx->queue); + } + + return i2c_imx->isr_result; +} + +static inline int i2c_imx_isr_write(struct imx_i2c_struct *i2c_imx) +{ + int result; + + result = i2c_imx_isr_acked(i2c_imx); + if (result) + return result; + + if (i2c_imx->msg->len == i2c_imx->msg_buf_idx) + return 0; + + imx_i2c_write_reg(i2c_imx->msg->buf[i2c_imx->msg_buf_idx++], i2c_imx, IMX_I2C_I2DR); + + return 1; +} + +static inline int i2c_imx_isr_read(struct imx_i2c_struct *i2c_imx) +{ + int result; + unsigned int temp; + + result = i2c_imx_isr_acked(i2c_imx); + if (result) + return result; + + /* setup bus to read data */ + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp &= ~I2CR_MTX; + if ((i2c_imx->msg->len - 1) || (i2c_imx->msg->flags & I2C_M_RECV_LEN)) + temp &= ~I2CR_TXAK; + + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */ + + return 0; +} + +static inline void i2c_imx_isr_read_continue(struct imx_i2c_struct *i2c_imx) +{ + unsigned int temp; + + if ((i2c_imx->msg->len - 1) == i2c_imx->msg_buf_idx) { + if (i2c_imx->is_lastmsg) { + /* + * It must generate STOP before read I2DR to prevent + * controller from generating another clock cycle + */ + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + if (!(temp & I2CR_MSTA)) + i2c_imx->stopped = 1; + temp &= ~(I2CR_MSTA | I2CR_MTX); + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + } else { + /* + * For i2c master receiver repeat restart operation like: + * read -> repeat MSTA -> read/write + * The controller must set MTX before read the last byte in + * the first read operation, otherwise the first read cost + * one extra clock cycle. + */ + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp |= I2CR_MTX; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + } + } else if (i2c_imx->msg_buf_idx == (i2c_imx->msg->len - 2)) { + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp |= I2CR_TXAK; + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + } + + i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); +} + +static inline void i2c_imx_isr_read_block_data_len(struct imx_i2c_struct *i2c_imx) +{ + u8 len = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + + if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) { + i2c_imx->isr_result = -EPROTO; + i2c_imx->state = IMX_I2C_STATE_FAILED; + wake_up(&i2c_imx->queue); + } + i2c_imx->msg->len += len; + i2c_imx->msg->buf[i2c_imx->msg_buf_idx++] = len; +} + static irqreturn_t i2c_imx_master_isr(struct imx_i2c_struct *i2c_imx, unsigned int status) { - /* save status register */ - i2c_imx->i2csr = status; - wake_up(&i2c_imx->queue); + /* + * This state machine handles I2C reception and transmission in non-DMA + * mode. We must process all the data in the ISR to reduce the delay + * between two consecutive messages. If the data is not processed in + * the ISR, SMBus devices may timeout, leading to a bus error. + */ + switch (i2c_imx->state) { + case IMX_I2C_STATE_DMA: + i2c_imx->i2csr = status; + wake_up(&i2c_imx->queue); + break; + + case IMX_I2C_STATE_READ: + if (i2c_imx_isr_read(i2c_imx)) + break; + i2c_imx->state = IMX_I2C_STATE_READ_CONTINUE; + break; + + case IMX_I2C_STATE_READ_CONTINUE: + i2c_imx_isr_read_continue(i2c_imx); + if (i2c_imx->msg_buf_idx == i2c_imx->msg->len) { + i2c_imx->state = IMX_I2C_STATE_DONE; + wake_up(&i2c_imx->queue); + } + break; + + case IMX_I2C_STATE_READ_BLOCK_DATA: + if (i2c_imx_isr_read(i2c_imx)) + break; + i2c_imx->state = IMX_I2C_STATE_READ_BLOCK_DATA_LEN; + break; + + case IMX_I2C_STATE_READ_BLOCK_DATA_LEN: + i2c_imx_isr_read_block_data_len(i2c_imx); + i2c_imx->state = IMX_I2C_STATE_READ_CONTINUE; + break; + + case IMX_I2C_STATE_WRITE: + if (i2c_imx_isr_write(i2c_imx)) + break; + i2c_imx->state = IMX_I2C_STATE_DONE; + wake_up(&i2c_imx->queue); + break; + + default: + i2c_imx->i2csr = status; + i2c_imx->state = IMX_I2C_STATE_FAILED; + i2c_imx->isr_result = -EINVAL; + wake_up(&i2c_imx->queue); + } return IRQ_HANDLED; } @@ -916,32 +1127,26 @@ static irqreturn_t i2c_imx_isr(int irq, void *dev_id) { struct imx_i2c_struct *i2c_imx = dev_id; unsigned int ctl, status; - unsigned long flags; - spin_lock_irqsave(&i2c_imx->slave_lock, flags); - status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); - ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + scoped_guard(spinlock_irqsave, &i2c_imx->slave_lock) { + status = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR); + ctl = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + + if (!(status & I2SR_IIF)) + return IRQ_NONE; - if (status & I2SR_IIF) { i2c_imx_clear_irq(i2c_imx, I2SR_IIF); + if (i2c_imx->slave) { - if (!(ctl & I2CR_MSTA)) { - irqreturn_t ret; - - ret = i2c_imx_slave_handle(i2c_imx, - status, ctl); - spin_unlock_irqrestore(&i2c_imx->slave_lock, - flags); - return ret; - } + if (!(ctl & I2CR_MSTA)) + return i2c_imx_slave_handle(i2c_imx, + status, ctl); + i2c_imx_slave_finish_op(i2c_imx); } - spin_unlock_irqrestore(&i2c_imx->slave_lock, flags); - return i2c_imx_master_isr(i2c_imx, status); } - spin_unlock_irqrestore(&i2c_imx->slave_lock, flags); - return IRQ_NONE; + return i2c_imx_master_isr(i2c_imx, status); } static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, @@ -954,6 +1159,8 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, struct imx_i2c_dma *dma = i2c_imx->dma; struct device *dev = &i2c_imx->adapter.dev; + i2c_imx->state = IMX_I2C_STATE_DMA; + dma->chan_using = dma->chan_tx; dma->dma_transfer_dir = DMA_MEM_TO_DEV; dma->dma_data_dir = DMA_TO_DEVICE; @@ -1006,6 +1213,42 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, return i2c_imx_acked(i2c_imx); } +static int i2c_imx_prepare_read(struct imx_i2c_struct *i2c_imx, + struct i2c_msg *msgs, bool use_dma) +{ + int result; + unsigned int temp = 0; + + /* write slave address */ + imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); + result = i2c_imx_trx_complete(i2c_imx, !use_dma); + if (result) + return result; + result = i2c_imx_acked(i2c_imx); + if (result) + return result; + + dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__); + + /* setup bus to read data */ + temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); + temp &= ~I2CR_MTX; + + /* + * Reset the I2CR_TXAK flag initially for SMBus block read since the + * length is unknown + */ + if (msgs->len - 1) + temp &= ~I2CR_TXAK; + if (use_dma) + temp |= I2CR_DMAEN; + + imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); + imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */ + + return 0; +} + static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bool is_lastmsg) { @@ -1016,6 +1259,13 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, struct imx_i2c_dma *dma = i2c_imx->dma; struct device *dev = &i2c_imx->adapter.dev; + i2c_imx->state = IMX_I2C_STATE_DMA; + + result = i2c_imx_prepare_read(i2c_imx, msgs, true); + if (result) + return result; + + dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__); dma->chan_using = dma->chan_rx; dma->dma_transfer_dir = DMA_DEV_TO_MEM; @@ -1092,8 +1342,8 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, return 0; } -static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, - bool atomic) +static int i2c_imx_atomic_write(struct imx_i2c_struct *i2c_imx, + struct i2c_msg *msgs) { int i, result; @@ -1102,7 +1352,7 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, /* write slave address */ imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); - result = i2c_imx_trx_complete(i2c_imx, atomic); + result = i2c_imx_trx_complete(i2c_imx, true); if (result) return result; result = i2c_imx_acked(i2c_imx); @@ -1116,7 +1366,7 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, "<%s> write byte: B%d=0x%X\n", __func__, i, msgs->buf[i]); imx_i2c_write_reg(msgs->buf[i], i2c_imx, IMX_I2C_I2DR); - result = i2c_imx_trx_complete(i2c_imx, atomic); + result = i2c_imx_trx_complete(i2c_imx, true); if (result) return result; result = i2c_imx_acked(i2c_imx); @@ -1126,55 +1376,54 @@ static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, return 0; } -static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, - bool is_lastmsg, bool atomic) +static int i2c_imx_write(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs) +{ + dev_dbg(&i2c_imx->adapter.dev, "<%s> write slave address: addr=0x%x\n", + __func__, i2c_8bit_addr_from_msg(msgs)); + + i2c_imx->state = IMX_I2C_STATE_WRITE; + i2c_imx->msg = msgs; + i2c_imx->msg_buf_idx = 0; + + /* + * By writing the device address we start the state machine in the ISR. + * The ISR will report when it is done or when it fails. + */ + imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); + wait_event_timeout(i2c_imx->queue, + i2c_imx->state == IMX_I2C_STATE_DONE || + i2c_imx->state == IMX_I2C_STATE_FAILED, + (msgs->len + 1) * HZ / 10); + if (i2c_imx->state == IMX_I2C_STATE_FAILED) { + dev_dbg(&i2c_imx->adapter.dev, "<%s> write failed with %d\n", + __func__, i2c_imx->isr_result); + return i2c_imx->isr_result; + } + if (i2c_imx->state != IMX_I2C_STATE_DONE) { + dev_err(&i2c_imx->adapter.dev, "<%s> write timedout\n", __func__); + return -ETIMEDOUT; + } + return 0; +} + +static int i2c_imx_atomic_read(struct imx_i2c_struct *i2c_imx, + struct i2c_msg *msgs, bool is_lastmsg) { int i, result; unsigned int temp; int block_data = msgs->flags & I2C_M_RECV_LEN; - int use_dma = i2c_imx->dma && msgs->flags & I2C_M_DMA_SAFE && - msgs->len >= DMA_THRESHOLD && !block_data; - - dev_dbg(&i2c_imx->adapter.dev, - "<%s> write slave address: addr=0x%x\n", - __func__, i2c_8bit_addr_from_msg(msgs)); - /* write slave address */ - imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); - result = i2c_imx_trx_complete(i2c_imx, atomic); - if (result) - return result; - result = i2c_imx_acked(i2c_imx); + result = i2c_imx_prepare_read(i2c_imx, msgs, false); if (result) return result; - dev_dbg(&i2c_imx->adapter.dev, "<%s> setup bus\n", __func__); - - /* setup bus to read data */ - temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR); - temp &= ~I2CR_MTX; - - /* - * Reset the I2CR_TXAK flag initially for SMBus block read since the - * length is unknown - */ - if ((msgs->len - 1) || block_data) - temp &= ~I2CR_TXAK; - if (use_dma) - temp |= I2CR_DMAEN; - imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); - imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); /* dummy read */ - dev_dbg(&i2c_imx->adapter.dev, "<%s> read data\n", __func__); - if (use_dma) - return i2c_imx_dma_read(i2c_imx, msgs, is_lastmsg); - /* read data */ for (i = 0; i < msgs->len; i++) { u8 len = 0; - result = i2c_imx_trx_complete(i2c_imx, atomic); + result = i2c_imx_trx_complete(i2c_imx, true); if (result) return result; /* @@ -1205,7 +1454,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, temp &= ~(I2CR_MSTA | I2CR_MTX); imx_i2c_write_reg(temp, i2c_imx, IMX_I2C_I2CR); if (!i2c_imx->stopped) - i2c_imx_bus_busy(i2c_imx, 0, atomic); + i2c_imx_bus_busy(i2c_imx, 0, true); } else { /* * For i2c master receiver repeat restart operation like: @@ -1236,6 +1485,48 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, return 0; } +static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, + bool is_lastmsg) +{ + int block_data = msgs->flags & I2C_M_RECV_LEN; + + dev_dbg(&i2c_imx->adapter.dev, + "<%s> write slave address: addr=0x%x\n", + __func__, i2c_8bit_addr_from_msg(msgs)); + + i2c_imx->is_lastmsg = is_lastmsg; + + if (block_data) + i2c_imx->state = IMX_I2C_STATE_READ_BLOCK_DATA; + else + i2c_imx->state = IMX_I2C_STATE_READ; + i2c_imx->msg = msgs; + i2c_imx->msg_buf_idx = 0; + + /* + * By writing the device address we start the state machine in the ISR. + * The ISR will report when it is done or when it fails. + */ + imx_i2c_write_reg(i2c_8bit_addr_from_msg(msgs), i2c_imx, IMX_I2C_I2DR); + wait_event_timeout(i2c_imx->queue, + i2c_imx->state == IMX_I2C_STATE_DONE || + i2c_imx->state == IMX_I2C_STATE_FAILED, + (msgs->len + 1) * HZ / 10); + if (i2c_imx->state == IMX_I2C_STATE_FAILED) { + dev_dbg(&i2c_imx->adapter.dev, "<%s> read failed with %d\n", + __func__, i2c_imx->isr_result); + return i2c_imx->isr_result; + } + if (i2c_imx->state != IMX_I2C_STATE_DONE) { + dev_err(&i2c_imx->adapter.dev, "<%s> read timedout\n", __func__); + return -ETIMEDOUT; + } + if (!i2c_imx->stopped) + return i2c_imx_bus_busy(i2c_imx, 0, false); + + return 0; +} + static int i2c_imx_xfer_common(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num, bool atomic) { @@ -1243,6 +1534,7 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter, int result; bool is_lastmsg = false; struct imx_i2c_struct *i2c_imx = i2c_get_adapdata(adapter); + int use_dma = 0; /* Start I2C transfer */ result = i2c_imx_start(i2c_imx, atomic); @@ -1295,15 +1587,25 @@ static int i2c_imx_xfer_common(struct i2c_adapter *adapter, (temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0), (temp & I2SR_RXAK ? 1 : 0)); #endif + + use_dma = i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD && + msgs[i].flags & I2C_M_DMA_SAFE; if (msgs[i].flags & I2C_M_RD) { - result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg, atomic); + int block_data = msgs->flags & I2C_M_RECV_LEN; + + if (atomic) + result = i2c_imx_atomic_read(i2c_imx, &msgs[i], is_lastmsg); + else if (use_dma && !block_data) + result = i2c_imx_dma_read(i2c_imx, &msgs[i], is_lastmsg); + else + result = i2c_imx_read(i2c_imx, &msgs[i], is_lastmsg); } else { - if (!atomic && - i2c_imx->dma && msgs[i].len >= DMA_THRESHOLD && - msgs[i].flags & I2C_M_DMA_SAFE) + if (atomic) + result = i2c_imx_atomic_write(i2c_imx, &msgs[i]); + else if (use_dma) result = i2c_imx_dma_write(i2c_imx, &msgs[i]); else - result = i2c_imx_write(i2c_imx, &msgs[i], atomic); + result = i2c_imx_write(i2c_imx, &msgs[i]); } if (result) goto fail0; @@ -1335,7 +1637,6 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter, result = i2c_imx_xfer_common(adapter, msgs, num, false); - pm_runtime_mark_last_busy(i2c_imx->adapter.dev.parent); pm_runtime_put_autosuspend(i2c_imx->adapter.dev.parent); return result; @@ -1358,24 +1659,6 @@ static int i2c_imx_xfer_atomic(struct i2c_adapter *adapter, return result; } -static void i2c_imx_prepare_recovery(struct i2c_adapter *adap) -{ - struct imx_i2c_struct *i2c_imx; - - i2c_imx = container_of(adap, struct imx_i2c_struct, adapter); - - pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_gpio); -} - -static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap) -{ - struct imx_i2c_struct *i2c_imx; - - i2c_imx = container_of(adap, struct imx_i2c_struct, adapter); - - pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_default); -} - /* * We switch SCL and SDA to their GPIO function and do some bitbanging * for bus recovery. These alternative pinmux settings can be @@ -1386,39 +1669,13 @@ static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap) static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, struct platform_device *pdev) { - struct i2c_bus_recovery_info *rinfo = &i2c_imx->rinfo; - - i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev); - if (!i2c_imx->pinctrl || IS_ERR(i2c_imx->pinctrl)) { - dev_info(&pdev->dev, "can't get pinctrl, bus recovery not supported\n"); - return PTR_ERR(i2c_imx->pinctrl); - } - - i2c_imx->pinctrl_pins_default = pinctrl_lookup_state(i2c_imx->pinctrl, - PINCTRL_STATE_DEFAULT); - i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl, - "gpio"); - rinfo->sda_gpiod = devm_gpiod_get(&pdev->dev, "sda", GPIOD_IN); - rinfo->scl_gpiod = devm_gpiod_get(&pdev->dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN); - - if (PTR_ERR(rinfo->sda_gpiod) == -EPROBE_DEFER || - PTR_ERR(rinfo->scl_gpiod) == -EPROBE_DEFER) { - return -EPROBE_DEFER; - } else if (IS_ERR(rinfo->sda_gpiod) || - IS_ERR(rinfo->scl_gpiod) || - IS_ERR(i2c_imx->pinctrl_pins_default) || - IS_ERR(i2c_imx->pinctrl_pins_gpio)) { - dev_dbg(&pdev->dev, "recovery information incomplete\n"); - return 0; - } + struct i2c_bus_recovery_info *bri = &i2c_imx->rinfo; - dev_dbg(&pdev->dev, "using scl%s for recovery\n", - rinfo->sda_gpiod ? ",sda" : ""); + bri->pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(bri->pinctrl)) + return PTR_ERR(bri->pinctrl); - rinfo->prepare_recovery = i2c_imx_prepare_recovery; - rinfo->unprepare_recovery = i2c_imx_unprepare_recovery; - rinfo->recover_bus = i2c_generic_scl_recovery; - i2c_imx->adapter.bus_recovery_info = rinfo; + i2c_imx->adapter.bus_recovery_info = bri; return 0; } @@ -1430,11 +1687,11 @@ static u32 i2c_imx_func(struct i2c_adapter *adapter) } static const struct i2c_algorithm i2c_imx_algo = { - .master_xfer = i2c_imx_xfer, - .master_xfer_atomic = i2c_imx_xfer_atomic, + .xfer = i2c_imx_xfer, + .xfer_atomic = i2c_imx_xfer_atomic, .functionality = i2c_imx_func, - .reg_slave = i2c_imx_reg_slave, - .unreg_slave = i2c_imx_unreg_slave, + .reg_slave = i2c_imx_reg_slave, + .unreg_slave = i2c_imx_unreg_slave, }; static int i2c_imx_probe(struct platform_device *pdev) @@ -1449,11 +1706,11 @@ static int i2c_imx_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) - return irq; + return dev_err_probe(&pdev->dev, irq, "can't get IRQ\n"); base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(base)) - return PTR_ERR(base); + return dev_err_probe(&pdev->dev, PTR_ERR(base), "can't get IO memory\n"); phy_addr = (dma_addr_t)res->start; i2c_imx = devm_kzalloc(&pdev->dev, sizeof(*i2c_imx), GFP_KERNEL); @@ -1461,8 +1718,8 @@ static int i2c_imx_probe(struct platform_device *pdev) return -ENOMEM; spin_lock_init(&i2c_imx->slave_lock); - hrtimer_init(&i2c_imx->slave_timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); - i2c_imx->slave_timer.function = i2c_imx_slave_timeout; + hrtimer_setup(&i2c_imx->slave_timer, i2c_imx_slave_timeout, CLOCK_MONOTONIC, + HRTIMER_MODE_ABS); match = device_get_match_data(&pdev->dev); if (match) @@ -1482,17 +1739,11 @@ static int i2c_imx_probe(struct platform_device *pdev) ACPI_COMPANION_SET(&i2c_imx->adapter.dev, ACPI_COMPANION(&pdev->dev)); /* Get I2C clock */ - i2c_imx->clk = devm_clk_get(&pdev->dev, NULL); + i2c_imx->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(i2c_imx->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(i2c_imx->clk), "can't get I2C clock\n"); - ret = clk_prepare_enable(i2c_imx->clk); - if (ret) { - dev_err(&pdev->dev, "can't enable I2C clock, ret=%d\n", ret); - return ret; - } - /* Init queue */ init_waitqueue_head(&i2c_imx->queue); @@ -1512,13 +1763,19 @@ static int i2c_imx_probe(struct platform_device *pdev) goto rpm_disable; /* Request IRQ */ - ret = request_threaded_irq(irq, i2c_imx_isr, NULL, IRQF_SHARED, - pdev->name, i2c_imx); + ret = request_irq(irq, i2c_imx_isr, IRQF_SHARED | IRQF_NO_SUSPEND, + pdev->name, i2c_imx); if (ret) { dev_err(&pdev->dev, "can't claim irq %d\n", irq); goto rpm_disable; } + /* + * We use the single-master property for backward compatibility. + * By default multi master mode is enabled. + */ + i2c_imx->multi_master = !of_property_read_bool(pdev->dev.of_node, "single-master"); + /* Set up clock divider */ i2c_imx->bitrate = I2C_MAX_STANDARD_MODE_FREQ; ret = of_property_read_u32(pdev->dev.of_node, @@ -1527,7 +1784,11 @@ static int i2c_imx_probe(struct platform_device *pdev) i2c_imx->bitrate = pdata->bitrate; i2c_imx->clk_change_nb.notifier_call = i2c_imx_clk_notifier_call; clk_notifier_register(i2c_imx->clk, &i2c_imx->clk_change_nb); - i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk)); + ret = i2c_imx_set_clk(i2c_imx, clk_get_rate(i2c_imx->clk)); + if (ret < 0) { + dev_err(&pdev->dev, "can't get I2C clock\n"); + goto clk_notifier_unregister; + } i2c_imx_reset_regs(i2c_imx); @@ -1537,12 +1798,29 @@ static int i2c_imx_probe(struct platform_device *pdev) if (ret == -EPROBE_DEFER) goto clk_notifier_unregister; + /* + * DMA mode should be optional for I2C, when encountering DMA errors, + * no need to exit I2C probe. Only print warning to show DMA error and + * use PIO mode directly to ensure I2C bus available as much as possible. + */ + ret = i2c_imx_dma_request(i2c_imx, phy_addr); + if (ret) { + if (ret == -EPROBE_DEFER) { + dev_err_probe(&pdev->dev, ret, "can't get DMA channels\n"); + goto clk_notifier_unregister; + } else if (ret == -ENODEV) { + dev_dbg(&pdev->dev, "Only use PIO mode\n"); + } else { + dev_warn(&pdev->dev, "Failed to setup DMA (%pe), only use PIO mode\n", + ERR_PTR(ret)); + } + } + /* Add I2C adapter */ ret = i2c_add_numbered_adapter(&i2c_imx->adapter); if (ret < 0) goto clk_notifier_unregister; - pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", irq); @@ -1551,9 +1829,6 @@ static int i2c_imx_probe(struct platform_device *pdev) i2c_imx->adapter.name); dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); - /* Init DMA config if supported */ - i2c_imx_dma_request(i2c_imx, phy_addr); - return 0; /* Return OK */ clk_notifier_unregister: @@ -1564,11 +1839,10 @@ rpm_disable: pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); - clk_disable_unprepare(i2c_imx->clk); return ret; } -static int i2c_imx_remove(struct platform_device *pdev) +static void i2c_imx_remove(struct platform_device *pdev) { struct imx_i2c_struct *i2c_imx = platform_get_drvdata(pdev); int irq, ret; @@ -1590,7 +1864,6 @@ static int i2c_imx_remove(struct platform_device *pdev) imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IFDR); imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2CR); imx_i2c_write_reg(0, i2c_imx, IMX_I2C_I2SR); - clk_disable(i2c_imx->clk); } clk_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb); @@ -1598,28 +1871,27 @@ static int i2c_imx_remove(struct platform_device *pdev) if (irq >= 0) free_irq(irq, i2c_imx); - clk_unprepare(i2c_imx->clk); - pm_runtime_put_noidle(&pdev->dev); pm_runtime_disable(&pdev->dev); - - return 0; } -static int __maybe_unused i2c_imx_runtime_suspend(struct device *dev) +static int i2c_imx_runtime_suspend(struct device *dev) { struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev); clk_disable(i2c_imx->clk); - - return 0; + return pinctrl_pm_select_sleep_state(dev); } -static int __maybe_unused i2c_imx_runtime_resume(struct device *dev) +static int i2c_imx_runtime_resume(struct device *dev) { struct imx_i2c_struct *i2c_imx = dev_get_drvdata(dev); int ret; + ret = pinctrl_pm_select_default_state(dev); + if (ret) + return ret; + ret = clk_enable(i2c_imx->clk); if (ret) dev_err(dev, "can't enable I2C clock, ret=%d\n", ret); @@ -1627,9 +1899,43 @@ static int __maybe_unused i2c_imx_runtime_resume(struct device *dev) return ret; } +static int i2c_imx_suspend(struct device *dev) +{ + /* + * Some I2C devices may need the I2C controller to remain active + * during resume_noirq() or suspend_noirq(). If the controller is + * autosuspended, there is no way to wake it up once runtime PM is + * disabled (in suspend_late()). + * + * During system resume, the I2C controller will be available only + * after runtime PM is re-enabled (in resume_early()). However, this + * may be too late for some devices. + * + * Wake up the controller in the suspend() callback while runtime PM + * is still enabled. The I2C controller will remain available until + * the suspend_noirq() callback (pm_runtime_force_suspend()) is + * called. During resume, the I2C controller can be restored by the + * resume_noirq() callback (pm_runtime_force_resume()). + * + * Finally, the resume() callback re-enables autosuspend, ensuring + * the I2C controller remains available until the system enters + * suspend_noirq() and from resume_noirq(). + */ + return pm_runtime_resume_and_get(dev); +} + +static int i2c_imx_resume(struct device *dev) +{ + pm_runtime_put_autosuspend(dev); + + return 0; +} + static const struct dev_pm_ops i2c_imx_pm_ops = { - SET_RUNTIME_PM_OPS(i2c_imx_runtime_suspend, - i2c_imx_runtime_resume, NULL) + NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SYSTEM_SLEEP_PM_OPS(i2c_imx_suspend, i2c_imx_resume) + RUNTIME_PM_OPS(i2c_imx_runtime_suspend, i2c_imx_runtime_resume, NULL) }; static struct platform_driver i2c_imx_driver = { @@ -1637,7 +1943,7 @@ static struct platform_driver i2c_imx_driver = { .remove = i2c_imx_remove, .driver = { .name = DRIVER_NAME, - .pm = &i2c_imx_pm_ops, + .pm = pm_ptr(&i2c_imx_pm_ops), .of_match_table = i2c_imx_dt_ids, .acpi_match_table = i2c_imx_acpi_ids, }, diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index 4a6ff54d87fe..ce5ca5b90b39 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -22,7 +22,7 @@ * - Make it work with IXP46x chips * - Cleanup function names, coding style, etc * - * - writing to slave address causes latchup on iop331. + * - writing to local target address causes latchup on iop331. * fix: driver refuses to address self. */ @@ -234,7 +234,7 @@ iop3xx_i2c_send_target_addr(struct i2c_algo_iop3xx_data *iop3xx_adap, int status; int rc; - /* avoid writing to my slave address (hangs on 80331), + /* avoid writing to local target address (hangs on 80331), * forbidden in Intel developer manual */ if (msg->addr == MYSAR) { @@ -349,12 +349,9 @@ iop3xx_i2c_handle_msg(struct i2c_adapter *i2c_adap, struct i2c_msg *pmsg) } } -/* - * master_xfer() - main read/write entry - */ static int -iop3xx_i2c_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, - int num) +iop3xx_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, + int num) { struct i2c_algo_iop3xx_data *iop3xx_adap = i2c_adap->algo_data; int im = 0; @@ -384,11 +381,11 @@ iop3xx_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm iop3xx_i2c_algo = { - .master_xfer = iop3xx_i2c_master_xfer, - .functionality = iop3xx_i2c_func, + .xfer = iop3xx_i2c_xfer, + .functionality = iop3xx_i2c_func, }; -static int +static void iop3xx_i2c_remove(struct platform_device *pdev) { struct i2c_adapter *padapter = platform_get_drvdata(pdev); @@ -408,8 +405,6 @@ iop3xx_i2c_remove(struct platform_device *pdev) release_mem_region(res->start, IOP3XX_I2C_IO_SIZE); kfree(adapter_data); kfree(padapter); - - return 0; } static int @@ -480,7 +475,7 @@ iop3xx_i2c_probe(struct platform_device *pdev) memcpy(new_adapter->name, pdev->name, strlen(pdev->name)); new_adapter->owner = THIS_MODULE; - new_adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + new_adapter->class = I2C_CLASS_HWMON; new_adapter->dev.parent = &pdev->dev; new_adapter->dev.of_node = pdev->dev.of_node; new_adapter->nr = pdev->id; diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c index 2dc7ada06ac5..a2ac992f9cb0 100644 --- a/drivers/i2c/busses/i2c-isch.c +++ b/drivers/i2c/busses/i2c-isch.c @@ -1,41 +1,39 @@ // SPDX-License-Identifier: GPL-2.0-only /* - i2c-isch.c - Linux kernel driver for Intel SCH chipset SMBus - - Based on i2c-piix4.c - Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and - Philip Edelbrock <phil@netroedge.com> - - Intel SCH support - Copyright (c) 2007 - 2008 Jacob Jun Pan <jacob.jun.pan@intel.com> - -*/ + * Linux kernel driver for Intel SCH chipset SMBus + * - Based on i2c-piix4.c + * Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and + * Philip Edelbrock <phil@netroedge.com> + * - Intel SCH support + * Copyright (c) 2007 - 2008 Jacob Jun Pan <jacob.jun.pan@intel.com> + */ -/* - Supports: - Intel SCH chipsets (AF82US15W, AF82US15L, AF82UL11L) - Note: we assume there can only be one device, with one SMBus interface. -*/ +/* Supports: Intel SCH chipsets (AF82US15W, AF82US15L, AF82UL11L) */ +#include <linux/container_of.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/gfp_types.h> +#include <linux/i2c.h> +#include <linux/iopoll.h> +#include <linux/ioport.h> #include <linux/module.h> #include <linux/platform_device.h> -#include <linux/kernel.h> -#include <linux/delay.h> +#include <linux/sprintf.h> #include <linux/stddef.h> -#include <linux/ioport.h> -#include <linux/i2c.h> -#include <linux/io.h> +#include <linux/string_choices.h> +#include <linux/types.h> /* SCH SMBus address offsets */ -#define SMBHSTCNT (0 + sch_smba) -#define SMBHSTSTS (1 + sch_smba) -#define SMBHSTCLK (2 + sch_smba) -#define SMBHSTADD (4 + sch_smba) /* TSA */ -#define SMBHSTCMD (5 + sch_smba) -#define SMBHSTDAT0 (6 + sch_smba) -#define SMBHSTDAT1 (7 + sch_smba) -#define SMBBLKDAT (0x20 + sch_smba) - -/* Other settings */ -#define MAX_RETRIES 5000 +#define SMBHSTCNT 0x00 +#define SMBHSTSTS 0x01 +#define SMBHSTCLK 0x02 +#define SMBHSTADD 0x04 /* TSA */ +#define SMBHSTCMD 0x05 +#define SMBHSTDAT0 0x06 +#define SMBHSTDAT1 0x07 +#define SMBBLKDAT 0x20 /* I2C constants */ #define SCH_QUICK 0x00 @@ -44,110 +42,134 @@ #define SCH_WORD_DATA 0x03 #define SCH_BLOCK_DATA 0x05 -static unsigned short sch_smba; -static struct i2c_adapter sch_adapter; +struct sch_i2c { + struct i2c_adapter adapter; + void __iomem *smba; +}; + static int backbone_speed = 33000; /* backbone speed in kHz */ -module_param(backbone_speed, int, S_IRUSR | S_IWUSR); +module_param(backbone_speed, int, 0600); MODULE_PARM_DESC(backbone_speed, "Backbone speed in kHz, (default = 33000)"); -/* - * Start the i2c transaction -- the i2c_access will prepare the transaction - * and this function will execute it. - * return 0 for success and others for failure. +static inline u8 sch_io_rd8(struct sch_i2c *priv, unsigned int offset) +{ + return ioread8(priv->smba + offset); +} + +static inline void sch_io_wr8(struct sch_i2c *priv, unsigned int offset, u8 value) +{ + iowrite8(value, priv->smba + offset); +} + +static inline u16 sch_io_rd16(struct sch_i2c *priv, unsigned int offset) +{ + return ioread16(priv->smba + offset); +} + +static inline void sch_io_wr16(struct sch_i2c *priv, unsigned int offset, u16 value) +{ + iowrite16(value, priv->smba + offset); +} + +/** + * sch_transaction - Start the i2c transaction + * @adap: the i2c adapter pointer + * + * The sch_access() will prepare the transaction and + * this function will execute it. + * + * Return: 0 for success and others for failure. */ -static int sch_transaction(void) +static int sch_transaction(struct i2c_adapter *adap) { + struct sch_i2c *priv = container_of(adap, struct sch_i2c, adapter); int temp; - int result = 0; - int retries = 0; + int rc; - dev_dbg(&sch_adapter.dev, "Transaction (pre): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT), - inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0), - inb(SMBHSTDAT1)); + dev_dbg(&adap->dev, + "Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", + sch_io_rd8(priv, SMBHSTCNT), sch_io_rd8(priv, SMBHSTCMD), + sch_io_rd8(priv, SMBHSTADD), + sch_io_rd8(priv, SMBHSTDAT0), sch_io_rd8(priv, SMBHSTDAT1)); /* Make sure the SMBus host is ready to start transmitting */ - temp = inb(SMBHSTSTS) & 0x0f; + temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f; if (temp) { /* Can not be busy since we checked it in sch_access */ - if (temp & 0x01) { - dev_dbg(&sch_adapter.dev, "Completion (%02x). " - "Clear...\n", temp); - } - if (temp & 0x06) { - dev_dbg(&sch_adapter.dev, "SMBus error (%02x). " - "Resetting...\n", temp); - } - outb(temp, SMBHSTSTS); - temp = inb(SMBHSTSTS) & 0x0f; + if (temp & 0x01) + dev_dbg(&adap->dev, "Completion (%02x). Clear...\n", temp); + if (temp & 0x06) + dev_dbg(&adap->dev, "SMBus error (%02x). Resetting...\n", temp); + sch_io_wr8(priv, SMBHSTSTS, temp); + temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f; if (temp) { - dev_err(&sch_adapter.dev, - "SMBus is not ready: (%02x)\n", temp); + dev_err(&adap->dev, "SMBus is not ready: (%02x)\n", temp); return -EAGAIN; } } - /* start the transaction by setting bit 4 */ - outb(inb(SMBHSTCNT) | 0x10, SMBHSTCNT); - - do { - usleep_range(100, 200); - temp = inb(SMBHSTSTS) & 0x0f; - } while ((temp & 0x08) && (retries++ < MAX_RETRIES)); + /* Start the transaction by setting bit 4 */ + temp = sch_io_rd8(priv, SMBHSTCNT); + temp |= 0x10; + sch_io_wr8(priv, SMBHSTCNT, temp); + rc = read_poll_timeout(sch_io_rd8, temp, !(temp & 0x08), 200, 500000, true, priv, SMBHSTSTS); /* If the SMBus is still busy, we give up */ - if (retries > MAX_RETRIES) { - dev_err(&sch_adapter.dev, "SMBus Timeout!\n"); - result = -ETIMEDOUT; - } - if (temp & 0x04) { - result = -EIO; - dev_dbg(&sch_adapter.dev, "Bus collision! SMBus may be " - "locked until next hard reset. (sorry!)\n"); - /* Clock stops and slave is stuck in mid-transmission */ + if (rc) { + dev_err(&adap->dev, "SMBus Timeout!\n"); + } else if (temp & 0x04) { + rc = -EIO; + dev_dbg(&adap->dev, "Bus collision! SMBus may be locked until next hard reset. (sorry!)\n"); + /* Clock stops and target is stuck in mid-transmission */ } else if (temp & 0x02) { - result = -EIO; - dev_err(&sch_adapter.dev, "Error: no response!\n"); + rc = -EIO; + dev_err(&adap->dev, "Error: no response!\n"); } else if (temp & 0x01) { - dev_dbg(&sch_adapter.dev, "Post complete!\n"); - outb(temp, SMBHSTSTS); - temp = inb(SMBHSTSTS) & 0x07; + dev_dbg(&adap->dev, "Post complete!\n"); + sch_io_wr8(priv, SMBHSTSTS, temp & 0x0f); + temp = sch_io_rd8(priv, SMBHSTSTS) & 0x07; if (temp & 0x06) { /* Completion clear failed */ - dev_dbg(&sch_adapter.dev, "Failed reset at end of " - "transaction (%02x), Bus error!\n", temp); + dev_dbg(&adap->dev, + "Failed reset at end of transaction (%02x), Bus error!\n", temp); } } else { - result = -ENXIO; - dev_dbg(&sch_adapter.dev, "No such address.\n"); + rc = -ENXIO; + dev_dbg(&adap->dev, "No such address.\n"); } - dev_dbg(&sch_adapter.dev, "Transaction (post): CNT=%02x, CMD=%02x, " - "ADD=%02x, DAT0=%02x, DAT1=%02x\n", inb(SMBHSTCNT), - inb(SMBHSTCMD), inb(SMBHSTADD), inb(SMBHSTDAT0), - inb(SMBHSTDAT1)); - return result; + dev_dbg(&adap->dev, "Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, DAT1=%02x\n", + sch_io_rd8(priv, SMBHSTCNT), sch_io_rd8(priv, SMBHSTCMD), + sch_io_rd8(priv, SMBHSTADD), + sch_io_rd8(priv, SMBHSTDAT0), sch_io_rd8(priv, SMBHSTDAT1)); + return rc; } -/* - * This is the main access entry for i2c-sch access - * adap is i2c_adapter pointer, addr is the i2c device bus address, read_write - * (0 for read and 1 for write), size is i2c transaction type and data is the - * union of transaction for data to be transferred or data read from bus. - * return 0 for success and others for failure. +/** + * sch_access - the main access entry for i2c-sch access + * @adap: the i2c adapter pointer + * @addr: the i2c device bus address + * @flags: I2C_CLIENT_* flags (usually zero or I2C_CLIENT_PEC) + * @read_write: 0 for read and 1 for write + * @command: Byte interpreted by slave, for protocols which use such bytes + * @size: the i2c transaction type + * @data: the union of transaction for data to be transferred or data read from bus + * + * Return: 0 for success and others for failure. */ static s32 sch_access(struct i2c_adapter *adap, u16 addr, unsigned short flags, char read_write, u8 command, int size, union i2c_smbus_data *data) { + struct sch_i2c *priv = container_of(adap, struct sch_i2c, adapter); int i, len, temp, rc; /* Make sure the SMBus host is not busy */ - temp = inb(SMBHSTSTS) & 0x0f; + temp = sch_io_rd8(priv, SMBHSTSTS) & 0x0f; if (temp & 0x08) { - dev_dbg(&sch_adapter.dev, "SMBus busy (%02x)\n", temp); + dev_dbg(&adap->dev, "SMBus busy (%02x)\n", temp); return -EAGAIN; } - temp = inw(SMBHSTCLK); + temp = sch_io_rd16(priv, SMBHSTCLK); if (!temp) { /* * We can't determine if we have 33 or 25 MHz clock for @@ -155,50 +177,48 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr, * 100 kHz. If we actually run at 25 MHz the bus will be * run ~75 kHz instead which should do no harm. */ - dev_notice(&sch_adapter.dev, - "Clock divider uninitialized. Setting defaults\n"); - outw(backbone_speed / (4 * 100), SMBHSTCLK); + dev_notice(&adap->dev, "Clock divider uninitialized. Setting defaults\n"); + sch_io_wr16(priv, SMBHSTCLK, backbone_speed / (4 * 100)); } - dev_dbg(&sch_adapter.dev, "access size: %d %s\n", size, - (read_write)?"READ":"WRITE"); + dev_dbg(&adap->dev, "access size: %d %s\n", size, str_read_write(read_write)); switch (size) { case I2C_SMBUS_QUICK: - outb((addr << 1) | read_write, SMBHSTADD); + sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write); size = SCH_QUICK; break; case I2C_SMBUS_BYTE: - outb((addr << 1) | read_write, SMBHSTADD); + sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write); if (read_write == I2C_SMBUS_WRITE) - outb(command, SMBHSTCMD); + sch_io_wr8(priv, SMBHSTCMD, command); size = SCH_BYTE; break; case I2C_SMBUS_BYTE_DATA: - outb((addr << 1) | read_write, SMBHSTADD); - outb(command, SMBHSTCMD); + sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write); + sch_io_wr8(priv, SMBHSTCMD, command); if (read_write == I2C_SMBUS_WRITE) - outb(data->byte, SMBHSTDAT0); + sch_io_wr8(priv, SMBHSTDAT0, data->byte); size = SCH_BYTE_DATA; break; case I2C_SMBUS_WORD_DATA: - outb((addr << 1) | read_write, SMBHSTADD); - outb(command, SMBHSTCMD); + sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write); + sch_io_wr8(priv, SMBHSTCMD, command); if (read_write == I2C_SMBUS_WRITE) { - outb(data->word & 0xff, SMBHSTDAT0); - outb((data->word & 0xff00) >> 8, SMBHSTDAT1); + sch_io_wr8(priv, SMBHSTDAT0, data->word >> 0); + sch_io_wr8(priv, SMBHSTDAT1, data->word >> 8); } size = SCH_WORD_DATA; break; case I2C_SMBUS_BLOCK_DATA: - outb((addr << 1) | read_write, SMBHSTADD); - outb(command, SMBHSTCMD); + sch_io_wr8(priv, SMBHSTADD, (addr << 1) | read_write); + sch_io_wr8(priv, SMBHSTCMD, command); if (read_write == I2C_SMBUS_WRITE) { len = data->block[0]; if (len == 0 || len > I2C_SMBUS_BLOCK_MAX) return -EINVAL; - outb(len, SMBHSTDAT0); + sch_io_wr8(priv, SMBHSTDAT0, len); for (i = 1; i <= len; i++) - outb(data->block[i], SMBBLKDAT+i-1); + sch_io_wr8(priv, SMBBLKDAT + i - 1, data->block[i]); } size = SCH_BLOCK_DATA; break; @@ -206,10 +226,13 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr, dev_warn(&adap->dev, "Unsupported transaction %d\n", size); return -EOPNOTSUPP; } - dev_dbg(&sch_adapter.dev, "write size %d to 0x%04x\n", size, SMBHSTCNT); - outb((inb(SMBHSTCNT) & 0xb0) | (size & 0x7), SMBHSTCNT); + dev_dbg(&adap->dev, "write size %d to 0x%04x\n", size, SMBHSTCNT); + + temp = sch_io_rd8(priv, SMBHSTCNT); + temp = (temp & 0xb0) | (size & 0x7); + sch_io_wr8(priv, SMBHSTCNT, temp); - rc = sch_transaction(); + rc = sch_transaction(adap); if (rc) /* Error in transaction */ return rc; @@ -219,17 +242,18 @@ static s32 sch_access(struct i2c_adapter *adap, u16 addr, switch (size) { case SCH_BYTE: case SCH_BYTE_DATA: - data->byte = inb(SMBHSTDAT0); + data->byte = sch_io_rd8(priv, SMBHSTDAT0); break; case SCH_WORD_DATA: - data->word = inb(SMBHSTDAT0) + (inb(SMBHSTDAT1) << 8); + data->word = (sch_io_rd8(priv, SMBHSTDAT0) << 0) + + (sch_io_rd8(priv, SMBHSTDAT1) << 8); break; case SCH_BLOCK_DATA: - data->block[0] = inb(SMBHSTDAT0); + data->block[0] = sch_io_rd8(priv, SMBHSTDAT0); if (data->block[0] == 0 || data->block[0] > I2C_SMBUS_BLOCK_MAX) return -EPROTO; for (i = 1; i <= data->block[0]; i++) - data->block[i] = inb(SMBBLKDAT+i-1); + data->block[i] = sch_io_rd8(priv, SMBBLKDAT + i - 1); break; } return 0; @@ -247,53 +271,34 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = sch_func, }; -static struct i2c_adapter sch_adapter = { - .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, - .algo = &smbus_algorithm, -}; - -static int smbus_sch_probe(struct platform_device *dev) +static int smbus_sch_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; + struct sch_i2c *priv; struct resource *res; - int retval; - res = platform_get_resource(dev, IORESOURCE_IO, 0); - if (!res) - return -EBUSY; + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; - if (!devm_request_region(&dev->dev, res->start, resource_size(res), - dev->name)) { - dev_err(&dev->dev, "SMBus region 0x%x already in use!\n", - sch_smba); + res = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (!res) return -EBUSY; - } - sch_smba = res->start; + priv->smba = devm_ioport_map(dev, res->start, resource_size(res)); + if (!priv->smba) + return dev_err_probe(dev, -EBUSY, "SMBus region %pR already in use!\n", res); - dev_dbg(&dev->dev, "SMBA = 0x%X\n", sch_smba); + /* Set up the sysfs linkage to our parent device */ + priv->adapter.dev.parent = dev; + priv->adapter.owner = THIS_MODULE; + priv->adapter.class = I2C_CLASS_HWMON; + priv->adapter.algo = &smbus_algorithm; - /* set up the sysfs linkage to our parent device */ - sch_adapter.dev.parent = &dev->dev; + snprintf(priv->adapter.name, sizeof(priv->adapter.name), + "SMBus SCH adapter at %04x", (unsigned short)res->start); - snprintf(sch_adapter.name, sizeof(sch_adapter.name), - "SMBus SCH adapter at %04x", sch_smba); - - retval = i2c_add_adapter(&sch_adapter); - if (retval) - sch_smba = 0; - - return retval; -} - -static int smbus_sch_remove(struct platform_device *pdev) -{ - if (sch_smba) { - i2c_del_adapter(&sch_adapter); - sch_smba = 0; - } - - return 0; + return devm_i2c_add_adapter(dev, &priv->adapter); } static struct platform_driver smbus_sch_driver = { @@ -301,7 +306,6 @@ static struct platform_driver smbus_sch_driver = { .name = "isch_smbus", }, .probe = smbus_sch_probe, - .remove = smbus_sch_remove, }; module_platform_driver(smbus_sch_driver); diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index c74985d77b0e..7aaefb21416a 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -382,6 +382,15 @@ static int ismt_process_desc(const struct ismt_desc *desc, } /** + * ismt_kill_transaction() - kill current transaction + * @priv: iSMT private data + */ +static void ismt_kill_transaction(struct ismt_priv *priv) +{ + writel(ISMT_GCTRL_KILL, priv->smba + ISMT_GR_GCTRL); +} + +/** * ismt_access() - process an SMBus command * @adap: the i2c host adapter * @addr: address of the i2c/SMBus target @@ -623,7 +632,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, dma_unmap_single(dev, dma_addr, dma_size, dma_direction); if (unlikely(!time_left)) { - dev_err(dev, "completion wait timed out\n"); + ismt_kill_transaction(priv); ret = -ETIMEDOUT; goto out; } @@ -924,7 +933,7 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id) return err; } - err = pci_request_region(pdev, SMBBAR, ismt_driver.name); + err = pcim_request_region(pdev, SMBBAR, ismt_driver.name); if (err) { dev_err(&pdev->dev, "Failed to request SMBus region 0x%lx-0x%lx\n", diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c index baa7319eee53..664a5471d933 100644 --- a/drivers/i2c/busses/i2c-jz4780.c +++ b/drivers/i2c/busses/i2c-jz4780.c @@ -18,7 +18,7 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/sched.h> #include <linux/slab.h> @@ -565,7 +565,7 @@ static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c, int idx) { int ret = 0; - long timeout; + unsigned long time_left; int wait_time = JZ4780_I2C_TIMEOUT * (len + 5); unsigned short tmp; unsigned long flags; @@ -600,10 +600,10 @@ static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c, spin_unlock_irqrestore(&i2c->lock, flags); - timeout = wait_for_completion_timeout(&i2c->trans_waitq, - msecs_to_jiffies(wait_time)); + time_left = wait_for_completion_timeout(&i2c->trans_waitq, + msecs_to_jiffies(wait_time)); - if (!timeout) { + if (!time_left) { dev_err(&i2c->adap.dev, "irq read timeout\n"); dev_dbg(&i2c->adap.dev, "send cmd count:%d %d\n", i2c->cmd, i2c->cmd_buf[i2c->cmd]); @@ -627,7 +627,7 @@ static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c, { int ret = 0; int wait_time = JZ4780_I2C_TIMEOUT * (len + 5); - long timeout; + unsigned long time_left; unsigned short tmp; unsigned long flags; @@ -655,14 +655,14 @@ static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c, spin_unlock_irqrestore(&i2c->lock, flags); - timeout = wait_for_completion_timeout(&i2c->trans_waitq, - msecs_to_jiffies(wait_time)); - if (timeout && !i2c->stop_hold) { + time_left = wait_for_completion_timeout(&i2c->trans_waitq, + msecs_to_jiffies(wait_time)); + if (time_left && !i2c->stop_hold) { unsigned short i2c_sta; int write_in_process; - timeout = JZ4780_I2C_TIMEOUT * 100; - for (; timeout > 0; timeout--) { + time_left = JZ4780_I2C_TIMEOUT * 100; + for (; time_left > 0; time_left--) { i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA); write_in_process = (i2c_sta & JZ4780_I2C_STA_MSTACT) || @@ -673,7 +673,7 @@ static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c, } } - if (!timeout) { + if (!time_left) { dev_err(&i2c->adap.dev, "write wait timeout\n"); ret = -EIO; } @@ -730,8 +730,8 @@ static u32 jz4780_i2c_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm jz4780_i2c_algorithm = { - .master_xfer = jz4780_i2c_xfer, - .functionality = jz4780_i2c_functionality, + .xfer = jz4780_i2c_xfer, + .functionality = jz4780_i2c_functionality, }; static const struct ingenic_i2c_config jz4780_i2c_config = { @@ -792,26 +792,22 @@ static int jz4780_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); - i2c->clk = devm_clk_get(&pdev->dev, NULL); + i2c->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(i2c->clk)) return PTR_ERR(i2c->clk); - ret = clk_prepare_enable(i2c->clk); - if (ret) - return ret; - ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", &clk_freq); if (ret) { dev_err(&pdev->dev, "clock-frequency not specified in DT\n"); - goto err; + return ret; } i2c->speed = clk_freq / 1000; if (i2c->speed == 0) { ret = -EINVAL; dev_err(&pdev->dev, "clock-frequency minimum is 1000\n"); - goto err; + return ret; } jz4780_i2c_set_speed(i2c); @@ -827,31 +823,26 @@ static int jz4780_i2c_probe(struct platform_device *pdev) ret = platform_get_irq(pdev, 0); if (ret < 0) - goto err; + return ret; i2c->irq = ret; + ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0, dev_name(&pdev->dev), i2c); if (ret) - goto err; + return ret; ret = i2c_add_adapter(&i2c->adap); if (ret < 0) - goto err; + return ret; return 0; - -err: - clk_disable_unprepare(i2c->clk); - return ret; } -static int jz4780_i2c_remove(struct platform_device *pdev) +static void jz4780_i2c_remove(struct platform_device *pdev) { struct jz4780_i2c *i2c = platform_get_drvdata(pdev); - clk_disable_unprepare(i2c->clk); i2c_del_adapter(&i2c->adap); - return 0; } static struct platform_driver jz4780_i2c_driver = { diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c new file mode 100644 index 000000000000..d42c03ef5db5 --- /dev/null +++ b/drivers/i2c/busses/i2c-k1.c @@ -0,0 +1,628 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2024-2025 Troy Mitchell <troymitchell988@gmail.com> + */ + +#include <linux/bitfield.h> + #include <linux/clk.h> + #include <linux/i2c.h> + #include <linux/iopoll.h> + #include <linux/module.h> + #include <linux/of_address.h> + #include <linux/platform_device.h> + +/* spacemit i2c registers */ +#define SPACEMIT_ICR 0x0 /* Control register */ +#define SPACEMIT_ISR 0x4 /* Status register */ +#define SPACEMIT_IDBR 0xc /* Data buffer register */ +#define SPACEMIT_IRCR 0x18 /* Reset cycle counter */ +#define SPACEMIT_IBMR 0x1c /* Bus monitor register */ + +/* SPACEMIT_ICR register fields */ +#define SPACEMIT_CR_START BIT(0) /* start bit */ +#define SPACEMIT_CR_STOP BIT(1) /* stop bit */ +#define SPACEMIT_CR_ACKNAK BIT(2) /* send ACK(0) or NAK(1) */ +#define SPACEMIT_CR_TB BIT(3) /* transfer byte bit */ +/* Bits 4-7 are reserved */ +#define SPACEMIT_CR_MODE_FAST BIT(8) /* bus mode (master operation) */ +/* Bit 9 is reserved */ +#define SPACEMIT_CR_UR BIT(10) /* unit reset */ +#define SPACEMIT_CR_RSTREQ BIT(11) /* i2c bus reset request */ +/* Bit 12 is reserved */ +#define SPACEMIT_CR_SCLE BIT(13) /* master clock enable */ +#define SPACEMIT_CR_IUE BIT(14) /* unit enable */ +/* Bits 15-17 are reserved */ +#define SPACEMIT_CR_ALDIE BIT(18) /* enable arbitration interrupt */ +#define SPACEMIT_CR_DTEIE BIT(19) /* enable TX interrupts */ +#define SPACEMIT_CR_DRFIE BIT(20) /* enable RX interrupts */ +#define SPACEMIT_CR_GCD BIT(21) /* general call disable */ +#define SPACEMIT_CR_BEIE BIT(22) /* enable bus error ints */ +/* Bits 23-24 are reserved */ +#define SPACEMIT_CR_MSDIE BIT(25) /* master STOP detected int enable */ +#define SPACEMIT_CR_MSDE BIT(26) /* master STOP detected enable */ +#define SPACEMIT_CR_TXDONEIE BIT(27) /* transaction done int enable */ +#define SPACEMIT_CR_TXEIE BIT(28) /* transmit FIFO empty int enable */ +#define SPACEMIT_CR_RXHFIE BIT(29) /* receive FIFO half-full int enable */ +#define SPACEMIT_CR_RXFIE BIT(30) /* receive FIFO full int enable */ +#define SPACEMIT_CR_RXOVIE BIT(31) /* receive FIFO overrun int enable */ + +#define SPACEMIT_I2C_INT_CTRL_MASK (SPACEMIT_CR_ALDIE | SPACEMIT_CR_DTEIE | \ + SPACEMIT_CR_DRFIE | SPACEMIT_CR_BEIE | \ + SPACEMIT_CR_TXDONEIE | SPACEMIT_CR_TXEIE | \ + SPACEMIT_CR_RXHFIE | SPACEMIT_CR_RXFIE | \ + SPACEMIT_CR_RXOVIE | SPACEMIT_CR_MSDIE) + +/* SPACEMIT_ISR register fields */ +/* Bits 0-13 are reserved */ +#define SPACEMIT_SR_ACKNAK BIT(14) /* ACK/NACK status */ +#define SPACEMIT_SR_UB BIT(15) /* unit busy */ +#define SPACEMIT_SR_IBB BIT(16) /* i2c bus busy */ +#define SPACEMIT_SR_EBB BIT(17) /* early bus busy */ +#define SPACEMIT_SR_ALD BIT(18) /* arbitration loss detected */ +#define SPACEMIT_SR_ITE BIT(19) /* TX buffer empty */ +#define SPACEMIT_SR_IRF BIT(20) /* RX buffer full */ +#define SPACEMIT_SR_GCAD BIT(21) /* general call address detected */ +#define SPACEMIT_SR_BED BIT(22) /* bus error no ACK/NAK */ +#define SPACEMIT_SR_SAD BIT(23) /* slave address detected */ +#define SPACEMIT_SR_SSD BIT(24) /* slave stop detected */ +/* Bit 25 is reserved */ +#define SPACEMIT_SR_MSD BIT(26) /* master stop detected */ +#define SPACEMIT_SR_TXDONE BIT(27) /* transaction done */ +#define SPACEMIT_SR_TXE BIT(28) /* TX FIFO empty */ +#define SPACEMIT_SR_RXHF BIT(29) /* RX FIFO half-full */ +#define SPACEMIT_SR_RXF BIT(30) /* RX FIFO full */ +#define SPACEMIT_SR_RXOV BIT(31) /* RX FIFO overrun */ + +#define SPACEMIT_I2C_INT_STATUS_MASK (SPACEMIT_SR_RXOV | SPACEMIT_SR_RXF | SPACEMIT_SR_RXHF | \ + SPACEMIT_SR_TXE | SPACEMIT_SR_TXDONE | SPACEMIT_SR_MSD | \ + SPACEMIT_SR_SSD | SPACEMIT_SR_SAD | SPACEMIT_SR_BED | \ + SPACEMIT_SR_GCAD | SPACEMIT_SR_IRF | SPACEMIT_SR_ITE | \ + SPACEMIT_SR_ALD) + +#define SPACEMIT_RCR_SDA_GLITCH_NOFIX BIT(7) /* bypass the SDA glitch fix */ +/* the cycles of SCL during bus reset */ +#define SPACEMIT_RCR_FIELD_RST_CYC GENMASK(3, 0) + +/* SPACEMIT_IBMR register fields */ +#define SPACEMIT_BMR_SDA BIT(0) /* SDA line level */ +#define SPACEMIT_BMR_SCL BIT(1) /* SCL line level */ + +/* i2c bus recover timeout: us */ +#define SPACEMIT_I2C_BUS_BUSY_TIMEOUT 100000 + +#define SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ 100000 /* Hz */ +#define SPACEMIT_I2C_MAX_FAST_MODE_FREQ 400000 /* Hz */ + +#define SPACEMIT_SR_ERR (SPACEMIT_SR_BED | SPACEMIT_SR_RXOV | SPACEMIT_SR_ALD) + +#define SPACEMIT_BUS_RESET_CLK_CNT_MAX 9 + +enum spacemit_i2c_state { + SPACEMIT_STATE_IDLE, + SPACEMIT_STATE_START, + SPACEMIT_STATE_READ, + SPACEMIT_STATE_WRITE, +}; + +/* i2c-spacemit driver's main struct */ +struct spacemit_i2c_dev { + struct device *dev; + struct i2c_adapter adapt; + + /* hardware resources */ + void __iomem *base; + int irq; + u32 clock_freq; + + struct i2c_msg *msgs; + u32 msg_num; + + /* index of the current message being processed */ + u32 msg_idx; + u8 *msg_buf; + /* the number of unprocessed bytes remaining in the current message */ + u32 unprocessed; + + enum spacemit_i2c_state state; + bool read; + struct completion complete; + u32 status; +}; + +static void spacemit_i2c_enable(struct spacemit_i2c_dev *i2c) +{ + u32 val; + + val = readl(i2c->base + SPACEMIT_ICR); + val |= SPACEMIT_CR_IUE; + writel(val, i2c->base + SPACEMIT_ICR); +} + +static void spacemit_i2c_disable(struct spacemit_i2c_dev *i2c) +{ + u32 val; + + val = readl(i2c->base + SPACEMIT_ICR); + val &= ~SPACEMIT_CR_IUE; + writel(val, i2c->base + SPACEMIT_ICR); +} + +static void spacemit_i2c_reset(struct spacemit_i2c_dev *i2c) +{ + writel(SPACEMIT_CR_UR, i2c->base + SPACEMIT_ICR); + udelay(5); + writel(0, i2c->base + SPACEMIT_ICR); +} + +static int spacemit_i2c_handle_err(struct spacemit_i2c_dev *i2c) +{ + dev_dbg(i2c->dev, "i2c error status: 0x%08x\n", i2c->status); + + /* Arbitration Loss Detected */ + if (i2c->status & SPACEMIT_SR_ALD) { + spacemit_i2c_reset(i2c); + return -EAGAIN; + } + + /* Bus Error No ACK/NAK */ + if (i2c->status & SPACEMIT_SR_BED) + spacemit_i2c_reset(i2c); + + return i2c->status & SPACEMIT_SR_ACKNAK ? -ENXIO : -EIO; +} + +static void spacemit_i2c_conditionally_reset_bus(struct spacemit_i2c_dev *i2c) +{ + u32 status; + u8 clk_cnt; + + /* if bus is locked, reset unit. 0: locked */ + status = readl(i2c->base + SPACEMIT_IBMR); + if ((status & SPACEMIT_BMR_SDA) && (status & SPACEMIT_BMR_SCL)) + return; + + spacemit_i2c_reset(i2c); + usleep_range(10, 20); + + for (clk_cnt = 0; clk_cnt < SPACEMIT_BUS_RESET_CLK_CNT_MAX; clk_cnt++) { + status = readl(i2c->base + SPACEMIT_IBMR); + if (status & SPACEMIT_BMR_SDA) + return; + + /* There's nothing left to save here, we are about to exit */ + writel(FIELD_PREP(SPACEMIT_RCR_FIELD_RST_CYC, 1), + i2c->base + SPACEMIT_IRCR); + writel(SPACEMIT_CR_RSTREQ, i2c->base + SPACEMIT_ICR); + usleep_range(20, 30); + } + + /* check sda again here */ + status = readl(i2c->base + SPACEMIT_IBMR); + if (!(status & SPACEMIT_BMR_SDA)) + dev_warn_ratelimited(i2c->dev, "unit reset failed\n"); +} + +static int spacemit_i2c_wait_bus_idle(struct spacemit_i2c_dev *i2c) +{ + int ret; + u32 val; + + val = readl(i2c->base + SPACEMIT_ISR); + if (!(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB))) + return 0; + + ret = readl_poll_timeout(i2c->base + SPACEMIT_ISR, + val, !(val & (SPACEMIT_SR_UB | SPACEMIT_SR_IBB)), + 1500, SPACEMIT_I2C_BUS_BUSY_TIMEOUT); + if (ret) + spacemit_i2c_reset(i2c); + + return ret; +} + +static void spacemit_i2c_check_bus_release(struct spacemit_i2c_dev *i2c) +{ + /* in case bus is not released after transfer completes */ + if (readl(i2c->base + SPACEMIT_ISR) & SPACEMIT_SR_EBB) { + spacemit_i2c_conditionally_reset_bus(i2c); + usleep_range(90, 150); + } +} + +static inline void +spacemit_i2c_clear_int_status(struct spacemit_i2c_dev *i2c, u32 mask) +{ + writel(mask & SPACEMIT_I2C_INT_STATUS_MASK, i2c->base + SPACEMIT_ISR); +} + +static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c) +{ + u32 val; + + /* + * Unmask interrupt bits for all xfer mode: + * bus error, arbitration loss detected. + * For transaction complete signal, we use master stop + * interrupt, so we don't need to unmask SPACEMIT_CR_TXDONEIE. + */ + val = SPACEMIT_CR_BEIE | SPACEMIT_CR_ALDIE; + + /* + * Unmask interrupt bits for interrupt xfer mode: + * When IDBR receives a byte, an interrupt is triggered. + * + * For the tx empty interrupt, it will be enabled in the + * i2c_start function. + * Otherwise, it will cause an erroneous empty interrupt before i2c_start. + */ + val |= SPACEMIT_CR_DRFIE; + + if (i2c->clock_freq == SPACEMIT_I2C_MAX_FAST_MODE_FREQ) + val |= SPACEMIT_CR_MODE_FAST; + + /* disable response to general call */ + val |= SPACEMIT_CR_GCD; + + /* enable SCL clock output */ + val |= SPACEMIT_CR_SCLE; + + /* enable master stop detected */ + val |= SPACEMIT_CR_MSDE | SPACEMIT_CR_MSDIE; + + writel(val, i2c->base + SPACEMIT_ICR); + + /* + * The glitch fix in the K1 I2C controller introduces a delay + * on restart signals, so we disable the fix here. + */ + val = readl(i2c->base + SPACEMIT_IRCR); + val |= SPACEMIT_RCR_SDA_GLITCH_NOFIX; + writel(val, i2c->base + SPACEMIT_IRCR); + + spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK); +} + +static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c) +{ + u32 target_addr_rw, val; + struct i2c_msg *cur_msg = i2c->msgs + i2c->msg_idx; + + i2c->read = !!(cur_msg->flags & I2C_M_RD); + + i2c->state = SPACEMIT_STATE_START; + + target_addr_rw = (cur_msg->addr & 0x7f) << 1; + if (cur_msg->flags & I2C_M_RD) + target_addr_rw |= 1; + + writel(target_addr_rw, i2c->base + SPACEMIT_IDBR); + + /* send start pulse */ + val = readl(i2c->base + SPACEMIT_ICR); + val &= ~SPACEMIT_CR_STOP; + val |= SPACEMIT_CR_START | SPACEMIT_CR_TB | SPACEMIT_CR_DTEIE; + writel(val, i2c->base + SPACEMIT_ICR); +} + +static int spacemit_i2c_xfer_msg(struct spacemit_i2c_dev *i2c) +{ + unsigned long time_left; + struct i2c_msg *msg; + + for (i2c->msg_idx = 0; i2c->msg_idx < i2c->msg_num; i2c->msg_idx++) { + msg = &i2c->msgs[i2c->msg_idx]; + i2c->msg_buf = msg->buf; + i2c->unprocessed = msg->len; + i2c->status = 0; + + reinit_completion(&i2c->complete); + + spacemit_i2c_start(i2c); + + time_left = wait_for_completion_timeout(&i2c->complete, + i2c->adapt.timeout); + if (!time_left) { + dev_err(i2c->dev, "msg completion timeout\n"); + spacemit_i2c_conditionally_reset_bus(i2c); + spacemit_i2c_reset(i2c); + return -ETIMEDOUT; + } + + if (i2c->status & SPACEMIT_SR_ERR) + return spacemit_i2c_handle_err(i2c); + } + + return 0; +} + +static bool spacemit_i2c_is_last_msg(struct spacemit_i2c_dev *i2c) +{ + if (i2c->msg_idx != i2c->msg_num - 1) + return false; + + if (i2c->read) + return i2c->unprocessed == 1; + + return !i2c->unprocessed; +} + +static void spacemit_i2c_handle_write(struct spacemit_i2c_dev *i2c) +{ + /* if transfer completes, SPACEMIT_ISR will handle it */ + if (i2c->status & SPACEMIT_SR_MSD) + return; + + if (i2c->unprocessed) { + writel(*i2c->msg_buf++, i2c->base + SPACEMIT_IDBR); + i2c->unprocessed--; + return; + } + + /* SPACEMIT_STATE_IDLE avoids trigger next byte */ + i2c->state = SPACEMIT_STATE_IDLE; + complete(&i2c->complete); +} + +static void spacemit_i2c_handle_read(struct spacemit_i2c_dev *i2c) +{ + if (i2c->unprocessed) { + *i2c->msg_buf++ = readl(i2c->base + SPACEMIT_IDBR); + i2c->unprocessed--; + } + + /* if transfer completes, SPACEMIT_ISR will handle it */ + if (i2c->status & (SPACEMIT_SR_MSD | SPACEMIT_SR_ACKNAK)) + return; + + /* it has to append stop bit in icr that read last byte */ + if (i2c->unprocessed) + return; + + /* SPACEMIT_STATE_IDLE avoids trigger next byte */ + i2c->state = SPACEMIT_STATE_IDLE; + complete(&i2c->complete); +} + +static void spacemit_i2c_handle_start(struct spacemit_i2c_dev *i2c) +{ + i2c->state = i2c->read ? SPACEMIT_STATE_READ : SPACEMIT_STATE_WRITE; + if (i2c->state == SPACEMIT_STATE_WRITE) + spacemit_i2c_handle_write(i2c); +} + +static void spacemit_i2c_err_check(struct spacemit_i2c_dev *i2c) +{ + u32 val; + + /* + * Send transaction complete signal: + * error happens, detect master stop + */ + if (!(i2c->status & (SPACEMIT_SR_ERR | SPACEMIT_SR_MSD))) + return; + + /* + * Here the transaction is already done, we don't need any + * other interrupt signals from now, in case any interrupt + * happens before spacemit_i2c_xfer to disable irq and i2c unit, + * we mask all the interrupt signals and clear the interrupt + * status. + */ + val = readl(i2c->base + SPACEMIT_ICR); + val &= ~SPACEMIT_I2C_INT_CTRL_MASK; + writel(val, i2c->base + SPACEMIT_ICR); + + spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK); + + i2c->state = SPACEMIT_STATE_IDLE; + complete(&i2c->complete); +} + +static irqreturn_t spacemit_i2c_irq_handler(int irq, void *devid) +{ + struct spacemit_i2c_dev *i2c = devid; + u32 status, val; + + status = readl(i2c->base + SPACEMIT_ISR); + if (!status) + return IRQ_HANDLED; + + i2c->status = status; + + spacemit_i2c_clear_int_status(i2c, status); + + if (i2c->status & SPACEMIT_SR_ERR) + goto err_out; + + val = readl(i2c->base + SPACEMIT_ICR); + val &= ~(SPACEMIT_CR_TB | SPACEMIT_CR_ACKNAK | SPACEMIT_CR_STOP | SPACEMIT_CR_START); + + switch (i2c->state) { + case SPACEMIT_STATE_START: + spacemit_i2c_handle_start(i2c); + break; + case SPACEMIT_STATE_READ: + spacemit_i2c_handle_read(i2c); + break; + case SPACEMIT_STATE_WRITE: + spacemit_i2c_handle_write(i2c); + break; + default: + break; + } + + if (i2c->state != SPACEMIT_STATE_IDLE) { + val |= SPACEMIT_CR_TB | SPACEMIT_CR_ALDIE; + + if (spacemit_i2c_is_last_msg(i2c)) { + /* trigger next byte with stop */ + val |= SPACEMIT_CR_STOP; + + if (i2c->read) + val |= SPACEMIT_CR_ACKNAK; + } + writel(val, i2c->base + SPACEMIT_ICR); + } + +err_out: + spacemit_i2c_err_check(i2c); + return IRQ_HANDLED; +} + +static void spacemit_i2c_calc_timeout(struct spacemit_i2c_dev *i2c) +{ + unsigned long timeout; + int idx = 0, cnt = 0; + + for (; idx < i2c->msg_num; idx++) + cnt += (i2c->msgs + idx)->len + 1; + + /* + * Multiply by 9 because each byte in I2C transmission requires + * 9 clock cycles: 8 bits of data plus 1 ACK/NACK bit. + */ + timeout = cnt * 9 * USEC_PER_SEC / i2c->clock_freq; + + i2c->adapt.timeout = usecs_to_jiffies(timeout + USEC_PER_SEC / 10) / i2c->msg_num; +} + +static int spacemit_i2c_xfer(struct i2c_adapter *adapt, struct i2c_msg *msgs, int num) +{ + struct spacemit_i2c_dev *i2c = i2c_get_adapdata(adapt); + int ret; + + i2c->msgs = msgs; + i2c->msg_num = num; + + spacemit_i2c_calc_timeout(i2c); + + spacemit_i2c_init(i2c); + + spacemit_i2c_enable(i2c); + + ret = spacemit_i2c_wait_bus_idle(i2c); + if (!ret) { + ret = spacemit_i2c_xfer_msg(i2c); + if (ret < 0) + dev_dbg(i2c->dev, "i2c transfer error: %d\n", ret); + } else { + spacemit_i2c_check_bus_release(i2c); + } + + spacemit_i2c_disable(i2c); + + if (ret == -ETIMEDOUT || ret == -EAGAIN) + dev_err(i2c->dev, "i2c transfer failed, ret %d err 0x%lx\n", + ret, i2c->status & SPACEMIT_SR_ERR); + + return ret < 0 ? ret : num; +} + +static u32 spacemit_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); +} + +static const struct i2c_algorithm spacemit_i2c_algo = { + .xfer = spacemit_i2c_xfer, + .functionality = spacemit_i2c_func, +}; + +static int spacemit_i2c_probe(struct platform_device *pdev) +{ + struct clk *clk; + struct device *dev = &pdev->dev; + struct device_node *of_node = pdev->dev.of_node; + struct spacemit_i2c_dev *i2c; + int ret; + + i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + ret = of_property_read_u32(of_node, "clock-frequency", &i2c->clock_freq); + if (ret && ret != -EINVAL) + dev_warn(dev, "failed to read clock-frequency property: %d\n", ret); + + /* For now, this driver doesn't support high-speed. */ + if (!i2c->clock_freq || i2c->clock_freq > SPACEMIT_I2C_MAX_FAST_MODE_FREQ) { + dev_warn(dev, "unsupported clock frequency %u; using %u\n", + i2c->clock_freq, SPACEMIT_I2C_MAX_FAST_MODE_FREQ); + i2c->clock_freq = SPACEMIT_I2C_MAX_FAST_MODE_FREQ; + } else if (i2c->clock_freq < SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ) { + dev_warn(dev, "unsupported clock frequency %u; using %u\n", + i2c->clock_freq, SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ); + i2c->clock_freq = SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ; + } + + i2c->dev = &pdev->dev; + + i2c->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(i2c->base)) + return dev_err_probe(dev, PTR_ERR(i2c->base), "failed to do ioremap"); + + i2c->irq = platform_get_irq(pdev, 0); + if (i2c->irq < 0) + return dev_err_probe(dev, i2c->irq, "failed to get irq resource"); + + ret = devm_request_irq(i2c->dev, i2c->irq, spacemit_i2c_irq_handler, + IRQF_NO_SUSPEND | IRQF_ONESHOT, dev_name(i2c->dev), i2c); + if (ret) + return dev_err_probe(dev, ret, "failed to request irq"); + + clk = devm_clk_get_enabled(dev, "func"); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "failed to enable func clock"); + + clk = devm_clk_get_enabled(dev, "bus"); + if (IS_ERR(clk)) + return dev_err_probe(dev, PTR_ERR(clk), "failed to enable bus clock"); + + spacemit_i2c_reset(i2c); + + i2c_set_adapdata(&i2c->adapt, i2c); + i2c->adapt.owner = THIS_MODULE; + i2c->adapt.algo = &spacemit_i2c_algo; + i2c->adapt.dev.parent = i2c->dev; + i2c->adapt.nr = pdev->id; + + i2c->adapt.dev.of_node = of_node; + + strscpy(i2c->adapt.name, "spacemit-i2c-adapter", sizeof(i2c->adapt.name)); + + init_completion(&i2c->complete); + + platform_set_drvdata(pdev, i2c); + + ret = i2c_add_numbered_adapter(&i2c->adapt); + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to add i2c adapter"); + + return 0; +} + +static void spacemit_i2c_remove(struct platform_device *pdev) +{ + struct spacemit_i2c_dev *i2c = platform_get_drvdata(pdev); + + i2c_del_adapter(&i2c->adapt); +} + +static const struct of_device_id spacemit_i2c_of_match[] = { + { .compatible = "spacemit,k1-i2c", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, spacemit_i2c_of_match); + +static struct platform_driver spacemit_i2c_driver = { + .probe = spacemit_i2c_probe, + .remove = spacemit_i2c_remove, + .driver = { + .name = "i2c-k1", + .of_match_table = spacemit_i2c_of_match, + }, +}; +module_platform_driver(spacemit_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("I2C bus driver for SpacemiT K1 SoC"); diff --git a/drivers/i2c/busses/i2c-keba.c b/drivers/i2c/busses/i2c-keba.c new file mode 100644 index 000000000000..9420c8b342b5 --- /dev/null +++ b/drivers/i2c/busses/i2c-keba.c @@ -0,0 +1,594 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) KEBA Industrial Automation Gmbh 2024 + * + * Driver for KEBA I2C controller FPGA IP core + */ + +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/module.h> +#include <linux/misc/keba.h> + +#define KI2C "i2c-keba" + +#define KI2C_CAPABILITY_REG 0x02 +#define KI2C_CAPABILITY_CRYPTO 0x01 +#define KI2C_CAPABILITY_DC 0x02 + +#define KI2C_CONTROL_REG 0x04 +#define KI2C_CONTROL_MEN 0x01 +#define KI2C_CONTROL_MSTA 0x02 +#define KI2C_CONTROL_RSTA 0x04 +#define KI2C_CONTROL_MTX 0x08 +#define KI2C_CONTROL_TXAK 0x10 +#define KI2C_CONTROL_DISABLE 0x00 + +#define KI2C_CONTROL_DC_REG 0x05 +#define KI2C_CONTROL_DC_SDA 0x01 +#define KI2C_CONTROL_DC_SCL 0x02 + +#define KI2C_STATUS_REG 0x08 +#define KI2C_STATUS_IN_USE 0x01 +#define KI2C_STATUS_ACK_CYC 0x02 +#define KI2C_STATUS_RXAK 0x04 +#define KI2C_STATUS_MCF 0x08 + +#define KI2C_STATUS_DC_REG 0x09 +#define KI2C_STATUS_DC_SDA 0x01 +#define KI2C_STATUS_DC_SCL 0x02 + +#define KI2C_DATA_REG 0x0c + +#define KI2C_INUSE_SLEEP_US (2 * USEC_PER_MSEC) +#define KI2C_INUSE_TIMEOUT_US (10 * USEC_PER_SEC) + +#define KI2C_POLL_DELAY_US 5 + +struct ki2c { + struct keba_i2c_auxdev *auxdev; + void __iomem *base; + struct i2c_adapter adapter; + + struct i2c_client **client; + int client_size; +}; + +static int ki2c_inuse_lock(struct ki2c *ki2c) +{ + u8 sts; + int ret; + + /* + * The I2C controller has an IN_USE bit for locking access to the + * controller. This enables the use of I2C controller by other none + * Linux processors. + * + * If the I2C controller is free, then the first read returns + * IN_USE == 0. After that the I2C controller is locked and further + * reads of IN_USE return 1. + * + * The I2C controller is unlocked by writing 1 into IN_USE. + * + * The IN_USE bit acts as a hardware semaphore for the I2C controller. + * Poll for semaphore, but sleep while polling to free the CPU. + */ + ret = readb_poll_timeout(ki2c->base + KI2C_STATUS_REG, + sts, (sts & KI2C_STATUS_IN_USE) == 0, + KI2C_INUSE_SLEEP_US, KI2C_INUSE_TIMEOUT_US); + if (ret) + dev_err(&ki2c->auxdev->auxdev.dev, "%s err!\n", __func__); + + return ret; +} + +static void ki2c_inuse_unlock(struct ki2c *ki2c) +{ + /* unlock the controller by writing 1 into IN_USE */ + iowrite8(KI2C_STATUS_IN_USE, ki2c->base + KI2C_STATUS_REG); +} + +static int ki2c_wait_for_bit(void __iomem *addr, u8 mask, unsigned long timeout) +{ + u8 val; + + return readb_poll_timeout(addr, val, (val & mask), KI2C_POLL_DELAY_US, + jiffies_to_usecs(timeout)); +} + +static int ki2c_wait_for_mcf(struct ki2c *ki2c) +{ + return ki2c_wait_for_bit(ki2c->base + KI2C_STATUS_REG, KI2C_STATUS_MCF, + ki2c->adapter.timeout); +} + +static int ki2c_wait_for_data(struct ki2c *ki2c) +{ + int ret; + + ret = ki2c_wait_for_mcf(ki2c); + if (ret < 0) + return ret; + + return ki2c_wait_for_bit(ki2c->base + KI2C_STATUS_REG, + KI2C_STATUS_ACK_CYC, + ki2c->adapter.timeout); +} + +static int ki2c_wait_for_data_ack(struct ki2c *ki2c) +{ + unsigned int reg; + int ret; + + ret = ki2c_wait_for_data(ki2c); + if (ret < 0) + return ret; + + /* RXAK == 0 means ACK reveived */ + reg = ioread8(ki2c->base + KI2C_STATUS_REG); + if (reg & KI2C_STATUS_RXAK) + return -EIO; + + return 0; +} + +static int ki2c_has_capability(struct ki2c *ki2c, unsigned int cap) +{ + unsigned int reg = ioread8(ki2c->base + KI2C_CAPABILITY_REG); + + return (reg & cap) != 0; +} + +static int ki2c_get_scl(struct ki2c *ki2c) +{ + unsigned int reg = ioread8(ki2c->base + KI2C_STATUS_DC_REG); + + /* capability KI2C_CAPABILITY_DC required */ + return (reg & KI2C_STATUS_DC_SCL) != 0; +} + +static int ki2c_get_sda(struct ki2c *ki2c) +{ + unsigned int reg = ioread8(ki2c->base + KI2C_STATUS_DC_REG); + + /* capability KI2C_CAPABILITY_DC required */ + return (reg & KI2C_STATUS_DC_SDA) != 0; +} + +static void ki2c_set_scl(struct ki2c *ki2c, int val) +{ + u8 control_dc; + + /* capability KI2C_CAPABILITY_DC and KI2C_CONTROL_MEN = 0 reqired */ + control_dc = ioread8(ki2c->base + KI2C_CONTROL_DC_REG); + if (val) + control_dc |= KI2C_CONTROL_DC_SCL; + else + control_dc &= ~KI2C_CONTROL_DC_SCL; + iowrite8(control_dc, ki2c->base + KI2C_CONTROL_DC_REG); +} + +/* + * Resetting bus bitwise is done by checking SDA and applying clock cycles as + * long as SDA is low. 9 clock cycles are applied at most. + * + * Clock cycles are generated and udelay() determines the duration of clock + * cycles. Generated clock rate is 100 KHz and so duration of both clock levels + * is: delay in ns = (10^6 / 100) / 2 + */ +#define KI2C_RECOVERY_CLK_CNT (9 * 2) +#define KI2C_RECOVERY_UDELAY 5 +static int ki2c_reset_bus_bitwise(struct ki2c *ki2c) +{ + int val = 1; + int ret = 0; + int i; + + /* disable I2C controller (MEN = 0) to get direct access to SCL/SDA */ + iowrite8(0, ki2c->base + KI2C_CONTROL_REG); + + /* generate clock cycles */ + ki2c_set_scl(ki2c, val); + udelay(KI2C_RECOVERY_UDELAY); + for (i = 0; i < KI2C_RECOVERY_CLK_CNT; i++) { + if (val) { + /* SCL shouldn't be low here */ + if (!ki2c_get_scl(ki2c)) { + dev_err(&ki2c->auxdev->auxdev.dev, + "SCL is stuck low!\n"); + ret = -EBUSY; + break; + } + + /* break if SDA is high */ + if (ki2c_get_sda(ki2c)) + break; + } + + val = !val; + ki2c_set_scl(ki2c, val); + udelay(KI2C_RECOVERY_UDELAY); + } + + if (!ki2c_get_sda(ki2c)) { + dev_err(&ki2c->auxdev->auxdev.dev, "SDA is still low!\n"); + ret = -EBUSY; + } + + /* reenable controller */ + iowrite8(KI2C_CONTROL_MEN, ki2c->base + KI2C_CONTROL_REG); + + return ret; +} + +/* + * Resetting bus bytewise is done by writing start bit, 9 data bits and stop + * bit. + * + * This is not 100% safe. If target is an EEPROM and a write access was + * interrupted during the ACK cycle, this approach might not be able to recover + * the bus. The reason is, that after the 9 clock cycles the EEPROM will be in + * ACK cycle again and will hold SDA low like it did before the start of the + * routine. Furthermore the EEPROM might get written one additional byte with + * 0xff into it. Thus, use bitwise approach whenever possible, especially when + * EEPROMs are on the bus. + */ +static int ki2c_reset_bus_bytewise(struct ki2c *ki2c) +{ + int ret; + + /* hold data line high for 9 clock cycles */ + iowrite8(0xFF, ki2c->base + KI2C_DATA_REG); + + /* create start condition */ + iowrite8(KI2C_CONTROL_MEN | KI2C_CONTROL_MTX | KI2C_CONTROL_MSTA | KI2C_CONTROL_TXAK, + ki2c->base + KI2C_CONTROL_REG); + ret = ki2c_wait_for_mcf(ki2c); + if (ret < 0) { + dev_err(&ki2c->auxdev->auxdev.dev, "Start condition failed\n"); + + return ret; + } + + /* create stop condition */ + iowrite8(KI2C_CONTROL_MEN | KI2C_CONTROL_MTX | KI2C_CONTROL_TXAK, + ki2c->base + KI2C_CONTROL_REG); + ret = ki2c_wait_for_mcf(ki2c); + if (ret < 0) + dev_err(&ki2c->auxdev->auxdev.dev, "Stop condition failed\n"); + + return ret; +} + +static int ki2c_reset_bus(struct ki2c *ki2c) +{ + int ret; + + ret = ki2c_inuse_lock(ki2c); + if (ret < 0) + return ret; + + /* + * If the I2C controller is capable of direct control of SCL/SDA, then a + * bitwise reset is used. Otherwise fall back to bytewise reset. + */ + if (ki2c_has_capability(ki2c, KI2C_CAPABILITY_DC)) + ret = ki2c_reset_bus_bitwise(ki2c); + else + ret = ki2c_reset_bus_bytewise(ki2c); + + ki2c_inuse_unlock(ki2c); + + return ret; +} + +static void ki2c_write_target_addr(struct ki2c *ki2c, struct i2c_msg *m) +{ + u8 addr; + + addr = m->addr << 1; + /* Bit 0 signals RD/WR */ + if (m->flags & I2C_M_RD) + addr |= 0x01; + + iowrite8(addr, ki2c->base + KI2C_DATA_REG); +} + +static int ki2c_start_addr(struct ki2c *ki2c, struct i2c_msg *m) +{ + int ret; + + /* + * Store target address byte in the controller. This has to be done + * before sending START condition. + */ + ki2c_write_target_addr(ki2c, m); + + /* enable controller for TX */ + iowrite8(KI2C_CONTROL_MEN | KI2C_CONTROL_MTX, + ki2c->base + KI2C_CONTROL_REG); + + /* send START condition and target address byte */ + iowrite8(KI2C_CONTROL_MEN | KI2C_CONTROL_MTX | KI2C_CONTROL_MSTA, + ki2c->base + KI2C_CONTROL_REG); + + ret = ki2c_wait_for_data_ack(ki2c); + if (ret < 0) + /* + * For EEPROMs this is normal behavior during internal write + * operation. + */ + dev_dbg(&ki2c->auxdev->auxdev.dev, + "%s wait for ACK err at 0x%02x!\n", __func__, m->addr); + + return ret; +} + +static int ki2c_repstart_addr(struct ki2c *ki2c, struct i2c_msg *m) +{ + int ret; + + /* repeated start and write is not supported */ + if ((m->flags & I2C_M_RD) == 0) { + dev_err(&ki2c->auxdev->auxdev.dev, + "Repeated start not supported for writes\n"); + return -EINVAL; + } + + /* send repeated start */ + iowrite8(KI2C_CONTROL_MEN | KI2C_CONTROL_MSTA | KI2C_CONTROL_RSTA, + ki2c->base + KI2C_CONTROL_REG); + + ret = ki2c_wait_for_mcf(ki2c); + if (ret < 0) { + dev_err(&ki2c->auxdev->auxdev.dev, + "%s wait for MCF err at 0x%02x!\n", __func__, m->addr); + return ret; + } + + /* write target-address byte */ + ki2c_write_target_addr(ki2c, m); + + ret = ki2c_wait_for_data_ack(ki2c); + if (ret < 0) + dev_err(&ki2c->auxdev->auxdev.dev, + "%s wait for ACK err at 0x%02x!\n", __func__, m->addr); + + return ret; +} + +static void ki2c_stop(struct ki2c *ki2c) +{ + iowrite8(KI2C_CONTROL_MEN, ki2c->base + KI2C_CONTROL_REG); + ki2c_wait_for_mcf(ki2c); +} + +static int ki2c_write(struct ki2c *ki2c, const u8 *data, int len) +{ + int ret; + int i; + + for (i = 0; i < len; i++) { + /* write data byte */ + iowrite8(data[i], ki2c->base + KI2C_DATA_REG); + + ret = ki2c_wait_for_data_ack(ki2c); + if (ret < 0) + return ret; + } + + return 0; +} + +static int ki2c_read(struct ki2c *ki2c, u8 *data, int len) +{ + u8 control; + int ret; + int i; + + if (len == 0) + return 0; /* nothing to do */ + + control = KI2C_CONTROL_MEN | KI2C_CONTROL_MSTA; + + /* if just one byte => send tx-nack after transfer */ + if (len == 1) + control |= KI2C_CONTROL_TXAK; + + iowrite8(control, ki2c->base + KI2C_CONTROL_REG); + + /* dummy read to start transfer on bus */ + ioread8(ki2c->base + KI2C_DATA_REG); + + for (i = 0; i < len; i++) { + ret = ki2c_wait_for_data(ki2c); + if (ret < 0) + return ret; + + if (i == len - 2) + /* send tx-nack after transfer of last byte */ + iowrite8(KI2C_CONTROL_MEN | KI2C_CONTROL_MSTA | KI2C_CONTROL_TXAK, + ki2c->base + KI2C_CONTROL_REG); + else if (i == len - 1) + /* + * switch to TX on last byte, so that reading DATA + * register does not trigger another read transfer + */ + iowrite8(KI2C_CONTROL_MEN | KI2C_CONTROL_MSTA | KI2C_CONTROL_MTX, + ki2c->base + KI2C_CONTROL_REG); + + /* read byte and start next transfer (if not last byte) */ + data[i] = ioread8(ki2c->base + KI2C_DATA_REG); + } + + return len; +} + +static int ki2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct ki2c *ki2c = i2c_get_adapdata(adap); + int ret; + int i; + + ret = ki2c_inuse_lock(ki2c); + if (ret < 0) + return ret; + + for (i = 0; i < num; i++) { + struct i2c_msg *m = &msgs[i]; + + if (i == 0) + ret = ki2c_start_addr(ki2c, m); + else + ret = ki2c_repstart_addr(ki2c, m); + if (ret < 0) + break; + + if (m->flags & I2C_M_RD) + ret = ki2c_read(ki2c, m->buf, m->len); + else + ret = ki2c_write(ki2c, m->buf, m->len); + if (ret < 0) + break; + } + + ki2c_stop(ki2c); + + ki2c_inuse_unlock(ki2c); + + return ret < 0 ? ret : num; +} + +static void ki2c_unregister_devices(struct ki2c *ki2c) +{ + int i; + + for (i = 0; i < ki2c->client_size; i++) + i2c_unregister_device(ki2c->client[i]); +} + +static int ki2c_register_devices(struct ki2c *ki2c) +{ + struct i2c_board_info *info = ki2c->auxdev->info; + int i; + + /* register all known I2C devices */ + for (i = 0; i < ki2c->client_size; i++) { + struct i2c_client *client; + unsigned short const addr_list[2] = { info[i].addr, + I2C_CLIENT_END }; + + client = i2c_new_scanned_device(&ki2c->adapter, &info[i], + addr_list, NULL); + if (!IS_ERR(client)) { + ki2c->client[i] = client; + } else if (PTR_ERR(client) != -ENODEV) { + ki2c->client_size = i; + ki2c_unregister_devices(ki2c); + + return PTR_ERR(client); + } + } + + return 0; +} + +static u32 ki2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm ki2c_algo = { + .xfer = ki2c_xfer, + .functionality = ki2c_func, +}; + +static int ki2c_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *id) +{ + struct device *dev = &auxdev->dev; + struct i2c_adapter *adap; + struct ki2c *ki2c; + int ret; + + ki2c = devm_kzalloc(dev, sizeof(*ki2c), GFP_KERNEL); + if (!ki2c) + return -ENOMEM; + ki2c->auxdev = container_of(auxdev, struct keba_i2c_auxdev, auxdev); + ki2c->client = devm_kcalloc(dev, ki2c->auxdev->info_size, + sizeof(*ki2c->client), GFP_KERNEL); + if (!ki2c->client) + return -ENOMEM; + ki2c->client_size = ki2c->auxdev->info_size; + auxiliary_set_drvdata(auxdev, ki2c); + + ki2c->base = devm_ioremap_resource(dev, &ki2c->auxdev->io); + if (IS_ERR(ki2c->base)) + return PTR_ERR(ki2c->base); + + adap = &ki2c->adapter; + strscpy(adap->name, "KEBA I2C adapter", sizeof(adap->name)); + adap->owner = THIS_MODULE; + adap->class = I2C_CLASS_HWMON; + adap->algo = &ki2c_algo; + adap->dev.parent = dev; + + i2c_set_adapdata(adap, ki2c); + + /* enable controller */ + iowrite8(KI2C_CONTROL_MEN, ki2c->base + KI2C_CONTROL_REG); + + /* reset bus before probing I2C devices */ + ret = ki2c_reset_bus(ki2c); + if (ret) + goto out; + + ret = devm_i2c_add_adapter(dev, adap); + if (ret) { + dev_err(dev, "Failed to add adapter (%d)!\n", ret); + goto out; + } + + ret = ki2c_register_devices(ki2c); + if (ret) { + dev_err(dev, "Failed to register devices (%d)!\n", ret); + goto out; + } + + return 0; + +out: + iowrite8(KI2C_CONTROL_DISABLE, ki2c->base + KI2C_CONTROL_REG); + return ret; +} + +static void ki2c_remove(struct auxiliary_device *auxdev) +{ + struct ki2c *ki2c = auxiliary_get_drvdata(auxdev); + + ki2c_unregister_devices(ki2c); + + /* disable controller */ + iowrite8(KI2C_CONTROL_DISABLE, ki2c->base + KI2C_CONTROL_REG); + + auxiliary_set_drvdata(auxdev, NULL); +} + +static const struct auxiliary_device_id ki2c_devtype_aux[] = { + { .name = "keba.i2c" }, + { } +}; +MODULE_DEVICE_TABLE(auxiliary, ki2c_devtype_aux); + +static struct auxiliary_driver ki2c_driver_aux = { + .name = KI2C, + .id_table = ki2c_devtype_aux, + .probe = ki2c_probe, + .remove = ki2c_remove, +}; +module_auxiliary_driver(ki2c_driver_aux); + +MODULE_AUTHOR("Gerhard Engleder <eg@keba.com>"); +MODULE_DESCRIPTION("KEBA I2C bus controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-kempld.c b/drivers/i2c/busses/i2c-kempld.c index cf857cf22507..9b4c7cba62b6 100644 --- a/drivers/i2c/busses/i2c-kempld.c +++ b/drivers/i2c/busses/i2c-kempld.c @@ -115,9 +115,7 @@ static int kempld_i2c_process(struct kempld_i2c_data *i2c) if (i2c->state == STATE_ADDR) { /* 10 bit address? */ if (i2c->msg->flags & I2C_M_TEN) { - addr = 0xf0 | ((i2c->msg->addr >> 7) & 0x6); - /* Set read bit if necessary */ - addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0; + addr = i2c_10bit_addr_hi_from_msg(msg); i2c->state = STATE_ADDR10; } else { addr = i2c_8bit_addr_from_msg(i2c->msg); @@ -132,10 +130,12 @@ static int kempld_i2c_process(struct kempld_i2c_data *i2c) /* Second part of 10 bit addressing */ if (i2c->state == STATE_ADDR10) { - kempld_write8(pld, KEMPLD_I2C_DATA, i2c->msg->addr & 0xff); + addr = i2c_10bit_addr_lo_from_msg(msg); + i2c->state = STATE_START; + + kempld_write8(pld, KEMPLD_I2C_DATA, addr); kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE); - i2c->state = STATE_START; return 0; } @@ -276,15 +276,14 @@ static u32 kempld_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm kempld_i2c_algorithm = { - .master_xfer = kempld_i2c_xfer, - .functionality = kempld_i2c_func, + .xfer = kempld_i2c_xfer, + .functionality = kempld_i2c_func, }; static const struct i2c_adapter kempld_i2c_adapter = { .owner = THIS_MODULE, .name = "i2c-kempld", - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD | - I2C_CLASS_DEPRECATED, + .class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED, .algo = &kempld_i2c_algorithm, }; @@ -329,7 +328,7 @@ static int kempld_i2c_probe(struct platform_device *pdev) return 0; } -static int kempld_i2c_remove(struct platform_device *pdev) +static void kempld_i2c_remove(struct platform_device *pdev) { struct kempld_i2c_data *i2c = platform_get_drvdata(pdev); struct kempld_device_data *pld = i2c->pld; @@ -348,14 +347,11 @@ static int kempld_i2c_remove(struct platform_device *pdev) kempld_release_mutex(pld); i2c_del_adapter(&i2c->adap); - - return 0; } -#ifdef CONFIG_PM -static int kempld_i2c_suspend(struct platform_device *pdev, pm_message_t state) +static int kempld_i2c_suspend(struct device *dev) { - struct kempld_i2c_data *i2c = platform_get_drvdata(pdev); + struct kempld_i2c_data *i2c = dev_get_drvdata(dev); struct kempld_device_data *pld = i2c->pld; u8 ctrl; @@ -368,9 +364,9 @@ static int kempld_i2c_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int kempld_i2c_resume(struct platform_device *pdev) +static int kempld_i2c_resume(struct device *dev) { - struct kempld_i2c_data *i2c = platform_get_drvdata(pdev); + struct kempld_i2c_data *i2c = dev_get_drvdata(dev); struct kempld_device_data *pld = i2c->pld; kempld_get_mutex(pld); @@ -379,19 +375,17 @@ static int kempld_i2c_resume(struct platform_device *pdev) return 0; } -#else -#define kempld_i2c_suspend NULL -#define kempld_i2c_resume NULL -#endif + +static DEFINE_SIMPLE_DEV_PM_OPS(kempld_i2c_pm_ops, + kempld_i2c_suspend, kempld_i2c_resume); static struct platform_driver kempld_i2c_driver = { .driver = { .name = "kempld-i2c", + .pm = pm_sleep_ptr(&kempld_i2c_pm_ops), }, .probe = kempld_i2c_probe, .remove = kempld_i2c_remove, - .suspend = kempld_i2c_suspend, - .resume = kempld_i2c_resume, }; module_platform_driver(kempld_i2c_driver); diff --git a/drivers/i2c/busses/i2c-ljca.c b/drivers/i2c/busses/i2c-ljca.c new file mode 100644 index 000000000000..93274f0c2d72 --- /dev/null +++ b/drivers/i2c/busses/i2c-ljca.c @@ -0,0 +1,343 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Intel La Jolla Cove Adapter USB-I2C driver + * + * Copyright (c) 2023, Intel Corporation. + */ + +#include <linux/acpi.h> +#include <linux/auxiliary_bus.h> +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/dev_printk.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/usb/ljca.h> + +/* I2C init flags */ +#define LJCA_I2C_INIT_FLAG_MODE BIT(0) +#define LJCA_I2C_INIT_FLAG_MODE_POLLING FIELD_PREP(LJCA_I2C_INIT_FLAG_MODE, 0) +#define LJCA_I2C_INIT_FLAG_MODE_INTERRUPT FIELD_PREP(LJCA_I2C_INIT_FLAG_MODE, 1) + +#define LJCA_I2C_INIT_FLAG_ADDR_16BIT BIT(0) + +#define LJCA_I2C_INIT_FLAG_FREQ GENMASK(2, 1) +#define LJCA_I2C_INIT_FLAG_FREQ_100K FIELD_PREP(LJCA_I2C_INIT_FLAG_FREQ, 0) +#define LJCA_I2C_INIT_FLAG_FREQ_400K FIELD_PREP(LJCA_I2C_INIT_FLAG_FREQ, 1) +#define LJCA_I2C_INIT_FLAG_FREQ_1M FIELD_PREP(LJCA_I2C_INIT_FLAG_FREQ, 2) + +#define LJCA_I2C_BUF_SIZE 60u +#define LJCA_I2C_MAX_XFER_SIZE (LJCA_I2C_BUF_SIZE - sizeof(struct ljca_i2c_rw_packet)) + +/* I2C commands */ +enum ljca_i2c_cmd { + LJCA_I2C_INIT = 1, + LJCA_I2C_XFER, + LJCA_I2C_START, + LJCA_I2C_STOP, + LJCA_I2C_READ, + LJCA_I2C_WRITE, +}; + +enum ljca_xfer_type { + LJCA_I2C_WRITE_XFER_TYPE, + LJCA_I2C_READ_XFER_TYPE, +}; + +/* I2C raw commands: Init/Start/Read/Write/Stop */ +struct ljca_i2c_rw_packet { + u8 id; + __le16 len; + u8 data[] __counted_by(len); +} __packed; + +struct ljca_i2c_dev { + struct ljca_client *ljca; + struct ljca_i2c_info *i2c_info; + struct i2c_adapter adap; + + u8 obuf[LJCA_I2C_BUF_SIZE]; + u8 ibuf[LJCA_I2C_BUF_SIZE]; +}; + +static int ljca_i2c_init(struct ljca_i2c_dev *ljca_i2c, u8 id) +{ + struct ljca_i2c_rw_packet *w_packet = + (struct ljca_i2c_rw_packet *)ljca_i2c->obuf; + int ret; + + w_packet->id = id; + w_packet->len = cpu_to_le16(sizeof(*w_packet->data)); + w_packet->data[0] = LJCA_I2C_INIT_FLAG_FREQ_400K; + + ret = ljca_transfer(ljca_i2c->ljca, LJCA_I2C_INIT, (u8 *)w_packet, + struct_size(w_packet, data, 1), NULL, 0); + + return ret < 0 ? ret : 0; +} + +static int ljca_i2c_start(struct ljca_i2c_dev *ljca_i2c, u8 target_addr, + enum ljca_xfer_type type) +{ + struct ljca_i2c_rw_packet *w_packet = + (struct ljca_i2c_rw_packet *)ljca_i2c->obuf; + struct ljca_i2c_rw_packet *r_packet = + (struct ljca_i2c_rw_packet *)ljca_i2c->ibuf; + s16 rp_len; + int ret; + + w_packet->id = ljca_i2c->i2c_info->id; + w_packet->len = cpu_to_le16(sizeof(*w_packet->data)); + w_packet->data[0] = (target_addr << 1) | type; + + ret = ljca_transfer(ljca_i2c->ljca, LJCA_I2C_START, (u8 *)w_packet, + struct_size(w_packet, data, 1), (u8 *)r_packet, + LJCA_I2C_BUF_SIZE); + if (ret < 0 || ret < sizeof(*r_packet)) + return ret < 0 ? ret : -EIO; + + rp_len = le16_to_cpu(r_packet->len); + if (rp_len < 0 || r_packet->id != w_packet->id) { + dev_dbg(&ljca_i2c->adap.dev, + "i2c start failed len: %d id: %d %d\n", + rp_len, r_packet->id, w_packet->id); + return -EIO; + } + + return 0; +} + +static void ljca_i2c_stop(struct ljca_i2c_dev *ljca_i2c) +{ + struct ljca_i2c_rw_packet *w_packet = + (struct ljca_i2c_rw_packet *)ljca_i2c->obuf; + struct ljca_i2c_rw_packet *r_packet = + (struct ljca_i2c_rw_packet *)ljca_i2c->ibuf; + s16 rp_len; + int ret; + + w_packet->id = ljca_i2c->i2c_info->id; + w_packet->len = cpu_to_le16(sizeof(*w_packet->data)); + w_packet->data[0] = 0; + + ret = ljca_transfer(ljca_i2c->ljca, LJCA_I2C_STOP, (u8 *)w_packet, + struct_size(w_packet, data, 1), (u8 *)r_packet, + LJCA_I2C_BUF_SIZE); + if (ret < 0 || ret < sizeof(*r_packet)) { + dev_dbg(&ljca_i2c->adap.dev, + "i2c stop failed ret: %d id: %d\n", + ret, w_packet->id); + return; + } + + rp_len = le16_to_cpu(r_packet->len); + if (rp_len < 0 || r_packet->id != w_packet->id) + dev_dbg(&ljca_i2c->adap.dev, + "i2c stop failed len: %d id: %d %d\n", + rp_len, r_packet->id, w_packet->id); +} + +static int ljca_i2c_pure_read(struct ljca_i2c_dev *ljca_i2c, u8 *data, u8 len) +{ + struct ljca_i2c_rw_packet *w_packet = + (struct ljca_i2c_rw_packet *)ljca_i2c->obuf; + struct ljca_i2c_rw_packet *r_packet = + (struct ljca_i2c_rw_packet *)ljca_i2c->ibuf; + s16 rp_len; + int ret; + + w_packet->id = ljca_i2c->i2c_info->id; + w_packet->len = cpu_to_le16(len); + w_packet->data[0] = 0; + + ret = ljca_transfer(ljca_i2c->ljca, LJCA_I2C_READ, (u8 *)w_packet, + struct_size(w_packet, data, 1), (u8 *)r_packet, + LJCA_I2C_BUF_SIZE); + if (ret < 0 || ret < sizeof(*r_packet)) + return ret < 0 ? ret : -EIO; + + rp_len = le16_to_cpu(r_packet->len); + if (rp_len != len || r_packet->id != w_packet->id) { + dev_dbg(&ljca_i2c->adap.dev, + "i2c raw read failed len: %d id: %d %d\n", + rp_len, r_packet->id, w_packet->id); + return -EIO; + } + + memcpy(data, r_packet->data, len); + + return 0; +} + +static int ljca_i2c_read(struct ljca_i2c_dev *ljca_i2c, u8 target_addr, u8 *data, + u8 len) +{ + int ret; + + ret = ljca_i2c_start(ljca_i2c, target_addr, LJCA_I2C_READ_XFER_TYPE); + if (!ret) + ret = ljca_i2c_pure_read(ljca_i2c, data, len); + + ljca_i2c_stop(ljca_i2c); + + return ret; +} + +static int ljca_i2c_pure_write(struct ljca_i2c_dev *ljca_i2c, u8 *data, u8 len) +{ + struct ljca_i2c_rw_packet *w_packet = + (struct ljca_i2c_rw_packet *)ljca_i2c->obuf; + struct ljca_i2c_rw_packet *r_packet = + (struct ljca_i2c_rw_packet *)ljca_i2c->ibuf; + s16 rplen; + int ret; + + w_packet->id = ljca_i2c->i2c_info->id; + w_packet->len = cpu_to_le16(len); + memcpy(w_packet->data, data, len); + + ret = ljca_transfer(ljca_i2c->ljca, LJCA_I2C_WRITE, (u8 *)w_packet, + struct_size(w_packet, data, len), (u8 *)r_packet, + LJCA_I2C_BUF_SIZE); + if (ret < 0 || ret < sizeof(*r_packet)) + return ret < 0 ? ret : -EIO; + + rplen = le16_to_cpu(r_packet->len); + if (rplen != len || r_packet->id != w_packet->id) { + dev_dbg(&ljca_i2c->adap.dev, + "i2c write failed len: %d id: %d/%d\n", + rplen, r_packet->id, w_packet->id); + return -EIO; + } + + return 0; +} + +static int ljca_i2c_write(struct ljca_i2c_dev *ljca_i2c, u8 target_addr, + u8 *data, u8 len) +{ + int ret; + + ret = ljca_i2c_start(ljca_i2c, target_addr, LJCA_I2C_WRITE_XFER_TYPE); + if (!ret) + ret = ljca_i2c_pure_write(ljca_i2c, data, len); + + ljca_i2c_stop(ljca_i2c); + + return ret; +} + +static int ljca_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msg, + int num) +{ + struct ljca_i2c_dev *ljca_i2c; + struct i2c_msg *cur_msg; + int i, ret; + + ljca_i2c = i2c_get_adapdata(adapter); + if (!ljca_i2c) + return -EINVAL; + + for (i = 0; i < num; i++) { + cur_msg = &msg[i]; + if (cur_msg->flags & I2C_M_RD) + ret = ljca_i2c_read(ljca_i2c, cur_msg->addr, + cur_msg->buf, cur_msg->len); + else + ret = ljca_i2c_write(ljca_i2c, cur_msg->addr, + cur_msg->buf, cur_msg->len); + + if (ret) + return ret; + } + + return num; +} + +static u32 ljca_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); +} + +static const struct i2c_adapter_quirks ljca_i2c_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN, + .max_read_len = LJCA_I2C_MAX_XFER_SIZE, + .max_write_len = LJCA_I2C_MAX_XFER_SIZE, +}; + +static const struct i2c_algorithm ljca_i2c_algo = { + .xfer = ljca_i2c_xfer, + .functionality = ljca_i2c_func, +}; + +static int ljca_i2c_probe(struct auxiliary_device *auxdev, + const struct auxiliary_device_id *aux_dev_id) +{ + struct ljca_client *ljca = auxiliary_dev_to_ljca_client(auxdev); + struct ljca_i2c_dev *ljca_i2c; + int ret; + + ljca_i2c = devm_kzalloc(&auxdev->dev, sizeof(*ljca_i2c), GFP_KERNEL); + if (!ljca_i2c) + return -ENOMEM; + + ljca_i2c->ljca = ljca; + ljca_i2c->i2c_info = dev_get_platdata(&auxdev->dev); + + ljca_i2c->adap.owner = THIS_MODULE; + ljca_i2c->adap.class = I2C_CLASS_HWMON; + ljca_i2c->adap.algo = &ljca_i2c_algo; + ljca_i2c->adap.quirks = &ljca_i2c_quirks; + ljca_i2c->adap.dev.parent = &auxdev->dev; + + snprintf(ljca_i2c->adap.name, sizeof(ljca_i2c->adap.name), "%s-%s-%d", + dev_name(&auxdev->dev), dev_name(auxdev->dev.parent), + ljca_i2c->i2c_info->id); + + device_set_node(&ljca_i2c->adap.dev, dev_fwnode(&auxdev->dev)); + + i2c_set_adapdata(&ljca_i2c->adap, ljca_i2c); + auxiliary_set_drvdata(auxdev, ljca_i2c); + + ret = ljca_i2c_init(ljca_i2c, ljca_i2c->i2c_info->id); + if (ret) + return dev_err_probe(&auxdev->dev, -EIO, + "i2c init failed id: %d\n", + ljca_i2c->i2c_info->id); + + ret = devm_i2c_add_adapter(&auxdev->dev, &ljca_i2c->adap); + if (ret) + return ret; + + if (has_acpi_companion(&ljca_i2c->adap.dev)) + acpi_dev_clear_dependencies(ACPI_COMPANION(&ljca_i2c->adap.dev)); + + return 0; +} + +static void ljca_i2c_remove(struct auxiliary_device *auxdev) +{ + struct ljca_i2c_dev *ljca_i2c = auxiliary_get_drvdata(auxdev); + + i2c_del_adapter(&ljca_i2c->adap); +} + +static const struct auxiliary_device_id ljca_i2c_id_table[] = { + { "usb_ljca.ljca-i2c", 0 }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(auxiliary, ljca_i2c_id_table); + +static struct auxiliary_driver ljca_i2c_driver = { + .probe = ljca_i2c_probe, + .remove = ljca_i2c_remove, + .id_table = ljca_i2c_id_table, +}; +module_auxiliary_driver(ljca_i2c_driver); + +MODULE_AUTHOR("Wentong Wu <wentong.wu@intel.com>"); +MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>"); +MODULE_AUTHOR("Lixu Zhang <lixu.zhang@intel.com>"); +MODULE_DESCRIPTION("Intel La Jolla Cove Adapter USB-I2C driver"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("LJCA"); diff --git a/drivers/i2c/busses/i2c-lpc2k.c b/drivers/i2c/busses/i2c-lpc2k.c index 8fff6fbb7065..ccd13c4fb83e 100644 --- a/drivers/i2c/busses/i2c-lpc2k.c +++ b/drivers/i2c/busses/i2c-lpc2k.c @@ -20,7 +20,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/sched.h> #include <linux/time.h> @@ -51,7 +50,7 @@ /* * 26 possible I2C status codes, but codes applicable only - * to master are listed here and used in this driver + * to controller mode are listed here and used in this driver */ enum { M_BUS_ERROR = 0x00, @@ -158,7 +157,7 @@ static void i2c_lpc2k_pump_msg(struct lpc2k_i2c *i2c) break; case MR_ADDR_R_ACK: - /* Receive first byte from slave */ + /* Receive first byte from target */ if (i2c->msg->len == 1) { /* Last byte, return NACK */ writel(LPC24XX_AA, i2c->base + LPC24XX_I2CONCLR); @@ -197,7 +196,7 @@ static void i2c_lpc2k_pump_msg(struct lpc2k_i2c *i2c) } /* - * One pre-last data input, send NACK to tell the slave that + * One pre-last data input, send NACK to tell the target that * this is going to be the last data byte to be transferred. */ if (i2c->msg_idx >= i2c->msg->len - 2) { @@ -339,8 +338,8 @@ static u32 i2c_lpc2k_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm i2c_lpc2k_algorithm = { - .master_xfer = i2c_lpc2k_xfer, - .functionality = i2c_lpc2k_functionality, + .xfer = i2c_lpc2k_xfer, + .functionality = i2c_lpc2k_functionality, }; static int i2c_lpc2k_probe(struct platform_device *pdev) @@ -365,23 +364,17 @@ static int i2c_lpc2k_probe(struct platform_device *pdev) init_waitqueue_head(&i2c->wait); - i2c->clk = devm_clk_get(&pdev->dev, NULL); + i2c->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(i2c->clk)) { - dev_err(&pdev->dev, "error getting clock\n"); + dev_err(&pdev->dev, "failed to enable clock.\n"); return PTR_ERR(i2c->clk); } - ret = clk_prepare_enable(i2c->clk); - if (ret) { - dev_err(&pdev->dev, "unable to enable clock.\n"); - return ret; - } - ret = devm_request_irq(&pdev->dev, i2c->irq, i2c_lpc2k_handler, 0, dev_name(&pdev->dev), i2c); if (ret < 0) { dev_err(&pdev->dev, "can't request interrupt.\n"); - goto fail_clk; + return ret; } disable_irq_nosync(i2c->irq); @@ -397,8 +390,7 @@ static int i2c_lpc2k_probe(struct platform_device *pdev) clkrate = clk_get_rate(i2c->clk); if (clkrate == 0) { dev_err(&pdev->dev, "can't get I2C base clock\n"); - ret = -EINVAL; - goto fail_clk; + return -EINVAL; } /* Setup I2C dividers to generate clock with proper duty cycle */ @@ -424,28 +416,20 @@ static int i2c_lpc2k_probe(struct platform_device *pdev) ret = i2c_add_adapter(&i2c->adap); if (ret < 0) - goto fail_clk; + return ret; dev_info(&pdev->dev, "LPC2K I2C adapter\n"); return 0; - -fail_clk: - clk_disable_unprepare(i2c->clk); - return ret; } -static int i2c_lpc2k_remove(struct platform_device *dev) +static void i2c_lpc2k_remove(struct platform_device *dev) { struct lpc2k_i2c *i2c = platform_get_drvdata(dev); i2c_del_adapter(&i2c->adap); - clk_disable_unprepare(i2c->clk); - - return 0; } -#ifdef CONFIG_PM static int i2c_lpc2k_suspend(struct device *dev) { struct lpc2k_i2c *i2c = dev_get_drvdata(dev); @@ -458,8 +442,13 @@ static int i2c_lpc2k_suspend(struct device *dev) static int i2c_lpc2k_resume(struct device *dev) { struct lpc2k_i2c *i2c = dev_get_drvdata(dev); + int ret; - clk_enable(i2c->clk); + ret = clk_enable(i2c->clk); + if (ret) { + dev_err(dev, "failed to enable clock.\n"); + return ret; + } i2c_lpc2k_reset(i2c); return 0; @@ -470,11 +459,6 @@ static const struct dev_pm_ops i2c_lpc2k_dev_pm_ops = { .resume_noirq = i2c_lpc2k_resume, }; -#define I2C_LPC2K_DEV_PM_OPS (&i2c_lpc2k_dev_pm_ops) -#else -#define I2C_LPC2K_DEV_PM_OPS NULL -#endif - static const struct of_device_id lpc2k_i2c_match[] = { { .compatible = "nxp,lpc1788-i2c" }, {}, @@ -483,10 +467,10 @@ MODULE_DEVICE_TABLE(of, lpc2k_i2c_match); static struct platform_driver i2c_lpc2k_driver = { .probe = i2c_lpc2k_probe, - .remove = i2c_lpc2k_remove, + .remove = i2c_lpc2k_remove, .driver = { .name = "lpc2k-i2c", - .pm = I2C_LPC2K_DEV_PM_OPS, + .pm = pm_sleep_ptr(&i2c_lpc2k_dev_pm_ops), .of_match_table = lpc2k_i2c_match, }, }; diff --git a/drivers/i2c/busses/i2c-ls2x.c b/drivers/i2c/busses/i2c-ls2x.c new file mode 100644 index 000000000000..b475dd27b7af --- /dev/null +++ b/drivers/i2c/busses/i2c-ls2x.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Loongson-2K/Loongson LS7A I2C controller mode driver + * + * Copyright (C) 2013 Loongson Technology Corporation Limited. + * Copyright (C) 2014-2017 Lemote, Inc. + * Copyright (C) 2018-2022 Loongson Technology Corporation Limited. + * + * Originally written by liushaozong + * Rewritten for mainline by Binbin Zhou <zhoubinbin@loongson.cn> + */ + +#include <linux/bitfield.h> +#include <linux/bits.h> +#include <linux/completion.h> +#include <linux/device.h> +#include <linux/iopoll.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/units.h> + +/* I2C Registers */ +#define I2C_LS2X_PRER_LO 0x0 /* Freq Division Low Byte Register */ +#define I2C_LS2X_PRER_HI 0x1 /* Freq Division High Byte Register */ +#define I2C_LS2X_CTR 0x2 /* Control Register */ +#define I2C_LS2X_TXR 0x3 /* Transport Data Register */ +#define I2C_LS2X_RXR 0x3 /* Receive Data Register */ +#define I2C_LS2X_CR 0x4 /* Command Control Register */ +#define I2C_LS2X_SR 0x4 /* State Register */ + +/* Command Control Register Bit */ +#define LS2X_CR_START BIT(7) /* Start signal */ +#define LS2X_CR_STOP BIT(6) /* Stop signal */ +#define LS2X_CR_READ BIT(5) /* Read signal */ +#define LS2X_CR_WRITE BIT(4) /* Write signal */ +#define LS2X_CR_ACK BIT(3) /* Response signal */ +#define LS2X_CR_IACK BIT(0) /* Interrupt response signal */ + +/* State Register Bit */ +#define LS2X_SR_NOACK BIT(7) /* Receive NACK */ +#define LS2X_SR_BUSY BIT(6) /* Bus busy state */ +#define LS2X_SR_AL BIT(5) /* Arbitration lost */ +#define LS2X_SR_TIP BIT(1) /* Transmission state */ +#define LS2X_SR_IF BIT(0) /* Interrupt flag */ + +/* Control Register Bit */ +#define LS2X_CTR_EN BIT(7) /* 0: I2c frequency setting 1: Normal */ +#define LS2X_CTR_IEN BIT(6) /* Enable i2c interrupt */ +#define LS2X_CTR_MST BIT(5) /* 0: Target mode 1: Controller mode */ +#define CTR_FREQ_MASK GENMASK(7, 6) +#define CTR_READY_MASK GENMASK(7, 5) + +/* The PCLK frequency from LPB */ +#define LS2X_I2C_PCLK_FREQ (50 * HZ_PER_MHZ) + +/* The default bus frequency, which is an empirical value */ +#define LS2X_I2C_FREQ_STD (33 * HZ_PER_KHZ) + +struct ls2x_i2c_priv { + struct i2c_adapter adapter; + void __iomem *base; + struct i2c_timings i2c_t; + struct completion cmd_complete; +}; + +/* + * Interrupt service routine. + * This gets called whenever an I2C interrupt occurs. + */ +static irqreturn_t ls2x_i2c_isr(int this_irq, void *dev_id) +{ + struct ls2x_i2c_priv *priv = dev_id; + + if (!(readb(priv->base + I2C_LS2X_SR) & LS2X_SR_IF)) + return IRQ_NONE; + + writeb(LS2X_CR_IACK, priv->base + I2C_LS2X_CR); + complete(&priv->cmd_complete); + return IRQ_HANDLED; +} + +/* + * The ls2x i2c controller supports standard mode and fast mode, so the + * maximum bus frequency is '400kHz'. + * The bus frequency is set to the empirical value of '33KHz' by default, + * but it can also be taken from ACPI or FDT for compatibility with more + * devices. + */ +static void ls2x_i2c_adjust_bus_speed(struct ls2x_i2c_priv *priv) +{ + u16 val; + struct i2c_timings *t = &priv->i2c_t; + struct device *dev = priv->adapter.dev.parent; + u32 acpi_speed = i2c_acpi_find_bus_speed(dev); + + i2c_parse_fw_timings(dev, t, false); + + if (acpi_speed || t->bus_freq_hz) + t->bus_freq_hz = max(t->bus_freq_hz, acpi_speed); + else + t->bus_freq_hz = LS2X_I2C_FREQ_STD; + + /* + * According to the chip manual, we can only access the registers as bytes, + * otherwise the high bits will be truncated. + * So set the I2C frequency with a sequential writeb() instead of writew(). + */ + val = LS2X_I2C_PCLK_FREQ / (5 * t->bus_freq_hz) - 1; + writeb(FIELD_GET(GENMASK(7, 0), val), priv->base + I2C_LS2X_PRER_LO); + writeb(FIELD_GET(GENMASK(15, 8), val), priv->base + I2C_LS2X_PRER_HI); +} + +static void ls2x_i2c_init(struct ls2x_i2c_priv *priv) +{ + /* Set i2c frequency setting mode and disable interrupts. */ + writeb(readb(priv->base + I2C_LS2X_CTR) & ~CTR_FREQ_MASK, + priv->base + I2C_LS2X_CTR); + + ls2x_i2c_adjust_bus_speed(priv); + + /* Set i2c normal operating mode and enable interrupts. */ + writeb(readb(priv->base + I2C_LS2X_CTR) | CTR_READY_MASK, + priv->base + I2C_LS2X_CTR); +} + +static int ls2x_i2c_xfer_byte(struct ls2x_i2c_priv *priv, u8 txdata, u8 *rxdatap) +{ + u8 rxdata; + unsigned long time_left; + + writeb(txdata, priv->base + I2C_LS2X_CR); + + time_left = wait_for_completion_timeout(&priv->cmd_complete, + priv->adapter.timeout); + if (!time_left) + return -ETIMEDOUT; + + rxdata = readb(priv->base + I2C_LS2X_SR); + if (rxdatap) + *rxdatap = rxdata; + + return 0; +} + +static int ls2x_i2c_send_byte(struct ls2x_i2c_priv *priv, u8 txdata) +{ + int ret; + u8 rxdata; + + ret = ls2x_i2c_xfer_byte(priv, txdata, &rxdata); + if (ret) + return ret; + + if (rxdata & LS2X_SR_AL) + return -EAGAIN; + + if (rxdata & LS2X_SR_NOACK) + return -ENXIO; + + return 0; +} + +static int ls2x_i2c_stop(struct ls2x_i2c_priv *priv) +{ + u8 value; + + writeb(LS2X_CR_STOP, priv->base + I2C_LS2X_CR); + return readb_poll_timeout(priv->base + I2C_LS2X_SR, value, + !(value & LS2X_SR_BUSY), 100, + jiffies_to_usecs(priv->adapter.timeout)); +} + +static int ls2x_i2c_start(struct ls2x_i2c_priv *priv, struct i2c_msg *msgs) +{ + reinit_completion(&priv->cmd_complete); + + writeb(i2c_8bit_addr_from_msg(msgs), priv->base + I2C_LS2X_TXR); + return ls2x_i2c_send_byte(priv, LS2X_CR_START | LS2X_CR_WRITE); +} + +static int ls2x_i2c_rx(struct ls2x_i2c_priv *priv, struct i2c_msg *msg) +{ + int ret; + u8 rxdata, *buf = msg->buf; + u16 len = msg->len; + + /* Contains steps to send start condition and address. */ + ret = ls2x_i2c_start(priv, msg); + if (ret) + return ret; + + while (len--) { + ret = ls2x_i2c_xfer_byte(priv, + LS2X_CR_READ | (len ? 0 : LS2X_CR_ACK), + &rxdata); + if (ret) + return ret; + + *buf++ = readb(priv->base + I2C_LS2X_RXR); + } + + return 0; +} + +static int ls2x_i2c_tx(struct ls2x_i2c_priv *priv, struct i2c_msg *msg) +{ + int ret; + u8 *buf = msg->buf; + u16 len = msg->len; + + /* Contains steps to send start condition and address. */ + ret = ls2x_i2c_start(priv, msg); + if (ret) + return ret; + + while (len--) { + writeb(*buf++, priv->base + I2C_LS2X_TXR); + + ret = ls2x_i2c_send_byte(priv, LS2X_CR_WRITE); + if (ret) + return ret; + } + + return 0; +} + +static int ls2x_i2c_xfer_one(struct ls2x_i2c_priv *priv, + struct i2c_msg *msg, bool stop) +{ + int ret; + + if (msg->flags & I2C_M_RD) + ret = ls2x_i2c_rx(priv, msg); + else + ret = ls2x_i2c_tx(priv, msg); + + if (ret < 0) { + /* Fatel error. Needs reinit. */ + if (ret == -ETIMEDOUT) + ls2x_i2c_init(priv); + + return ret; + } + + if (stop) { + /* Failed to issue STOP. Needs reinit. */ + ret = ls2x_i2c_stop(priv); + if (ret) + ls2x_i2c_init(priv); + } + + return ret; +} + +static int ls2x_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + int ret; + struct i2c_msg *msg, *emsg = msgs + num; + struct ls2x_i2c_priv *priv = i2c_get_adapdata(adap); + + for (msg = msgs; msg < emsg; msg++) { + ret = ls2x_i2c_xfer_one(priv, msg, msg == emsg - 1); + if (ret) + return ret; + } + + return num; +} + +static unsigned int ls2x_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm ls2x_i2c_algo = { + .xfer = ls2x_i2c_xfer, + .functionality = ls2x_i2c_func, +}; + +static int ls2x_i2c_probe(struct platform_device *pdev) +{ + int ret, irq; + struct i2c_adapter *adap; + struct ls2x_i2c_priv *priv; + struct device *dev = &pdev->dev; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* Map hardware registers */ + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + /* Add the i2c adapter */ + adap = &priv->adapter; + adap->retries = 5; + adap->nr = pdev->id; + adap->dev.parent = dev; + adap->owner = THIS_MODULE; + adap->algo = &ls2x_i2c_algo; + adap->timeout = msecs_to_jiffies(100); + device_set_node(&adap->dev, dev_fwnode(dev)); + i2c_set_adapdata(adap, priv); + strscpy(adap->name, pdev->name, sizeof(adap->name)); + init_completion(&priv->cmd_complete); + platform_set_drvdata(pdev, priv); + + ls2x_i2c_init(priv); + + ret = devm_request_irq(dev, irq, ls2x_i2c_isr, IRQF_SHARED, "ls2x-i2c", + priv); + if (ret < 0) + return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq); + + return devm_i2c_add_adapter(dev, adap); +} + +static int ls2x_i2c_suspend(struct device *dev) +{ + struct ls2x_i2c_priv *priv = dev_get_drvdata(dev); + + /* Disable interrupts */ + writeb(readb(priv->base + I2C_LS2X_CTR) & ~LS2X_CTR_IEN, + priv->base + I2C_LS2X_CTR); + + return 0; +} + +static int ls2x_i2c_resume(struct device *dev) +{ + ls2x_i2c_init(dev_get_drvdata(dev)); + return 0; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(ls2x_i2c_pm_ops, + ls2x_i2c_suspend, ls2x_i2c_resume, NULL); + +static const struct of_device_id ls2x_i2c_id_table[] = { + { .compatible = "loongson,ls2k-i2c" }, + { .compatible = "loongson,ls7a-i2c" }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, ls2x_i2c_id_table); + +static const struct acpi_device_id ls2x_i2c_acpi_match[] = { + { "LOON0004" }, /* Loongson LS7A */ + { } +}; +MODULE_DEVICE_TABLE(acpi, ls2x_i2c_acpi_match); + +static struct platform_driver ls2x_i2c_driver = { + .probe = ls2x_i2c_probe, + .driver = { + .name = "ls2x-i2c", + .pm = pm_sleep_ptr(&ls2x_i2c_pm_ops), + .of_match_table = ls2x_i2c_id_table, + .acpi_match_table = ls2x_i2c_acpi_match, + }, +}; +module_platform_driver(ls2x_i2c_driver); + +MODULE_DESCRIPTION("Loongson LS2X I2C Bus driver"); +MODULE_AUTHOR("Loongson Technology Corporation Limited"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-mchp-pci1xxxx.c b/drivers/i2c/busses/i2c-mchp-pci1xxxx.c index 09af75921147..bc0f1a0c8ee1 100644 --- a/drivers/i2c/busses/i2c-mchp-pci1xxxx.c +++ b/drivers/i2c/busses/i2c-mchp-pci1xxxx.c @@ -48,9 +48,9 @@ * SR_HOLD_TIME_XK_TICKS field will indicate the number of ticks of the * baud clock required to program 'Hold Time' at X KHz. */ -#define SR_HOLD_TIME_100K_TICKS 133 -#define SR_HOLD_TIME_400K_TICKS 20 -#define SR_HOLD_TIME_1000K_TICKS 11 +#define SR_HOLD_TIME_100K_TICKS 150 +#define SR_HOLD_TIME_400K_TICKS 20 +#define SR_HOLD_TIME_1000K_TICKS 12 #define SMB_CORE_COMPLETION_REG_OFF3 (SMBUS_MAST_CORE_ADDR_BASE + 0x23) @@ -65,17 +65,17 @@ * the baud clock required to program 'fair idle delay' at X KHz. Fair idle * delay establishes the MCTP T(IDLE_DELAY) period. */ -#define FAIR_BUS_IDLE_MIN_100K_TICKS 969 -#define FAIR_BUS_IDLE_MIN_400K_TICKS 157 -#define FAIR_BUS_IDLE_MIN_1000K_TICKS 157 +#define FAIR_BUS_IDLE_MIN_100K_TICKS 992 +#define FAIR_BUS_IDLE_MIN_400K_TICKS 500 +#define FAIR_BUS_IDLE_MIN_1000K_TICKS 500 /* * FAIR_IDLE_DELAY_XK_TICKS field will indicate the number of ticks of the * baud clock required to satisfy the fairness protocol at X KHz. */ -#define FAIR_IDLE_DELAY_100K_TICKS 1000 -#define FAIR_IDLE_DELAY_400K_TICKS 500 -#define FAIR_IDLE_DELAY_1000K_TICKS 500 +#define FAIR_IDLE_DELAY_100K_TICKS 963 +#define FAIR_IDLE_DELAY_400K_TICKS 156 +#define FAIR_IDLE_DELAY_1000K_TICKS 156 #define SMB_IDLE_SCALING_100K \ ((FAIR_IDLE_DELAY_100K_TICKS << 16) | FAIR_BUS_IDLE_MIN_100K_TICKS) @@ -105,7 +105,7 @@ */ #define BUS_CLK_100K_LOW_PERIOD_TICKS 156 #define BUS_CLK_400K_LOW_PERIOD_TICKS 41 -#define BUS_CLK_1000K_LOW_PERIOD_TICKS 15 +#define BUS_CLK_1000K_LOW_PERIOD_TICKS 15 /* * BUS_CLK_XK_HIGH_PERIOD_TICKS field defines the number of I2C Baud Clock @@ -131,7 +131,7 @@ */ #define CLK_SYNC_100K 4 #define CLK_SYNC_400K 4 -#define CLK_SYNC_1000K 4 +#define CLK_SYNC_1000K 4 #define SMB_CORE_DATA_TIMING_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x40) @@ -142,25 +142,25 @@ * determines the SCLK hold time following SDAT driven low during the first * START bit in a transfer. */ -#define FIRST_START_HOLD_100K_TICKS 22 -#define FIRST_START_HOLD_400K_TICKS 16 -#define FIRST_START_HOLD_1000K_TICKS 6 +#define FIRST_START_HOLD_100K_TICKS 23 +#define FIRST_START_HOLD_400K_TICKS 8 +#define FIRST_START_HOLD_1000K_TICKS 12 /* * STOP_SETUP_XK_TICKS will indicate the number of ticks of the baud clock * required to program 'STOP_SETUP' timer at X KHz. This timer determines the * SDAT setup time from the rising edge of SCLK for a STOP condition. */ -#define STOP_SETUP_100K_TICKS 157 +#define STOP_SETUP_100K_TICKS 150 #define STOP_SETUP_400K_TICKS 20 -#define STOP_SETUP_1000K_TICKS 12 +#define STOP_SETUP_1000K_TICKS 12 /* * RESTART_SETUP_XK_TICKS will indicate the number of ticks of the baud clock * required to program 'RESTART_SETUP' timer at X KHz. This timer determines the * SDAT setup time from the rising edge of SCLK for a repeated START condition. */ -#define RESTART_SETUP_100K_TICKS 157 +#define RESTART_SETUP_100K_TICKS 156 #define RESTART_SETUP_400K_TICKS 20 #define RESTART_SETUP_1000K_TICKS 12 @@ -169,7 +169,7 @@ * required to program 'DATA_HOLD' timer at X KHz. This timer determines the * SDAT hold time following SCLK driven low. */ -#define DATA_HOLD_100K_TICKS 2 +#define DATA_HOLD_100K_TICKS 12 #define DATA_HOLD_400K_TICKS 2 #define DATA_HOLD_1000K_TICKS 2 @@ -190,35 +190,35 @@ * Bus Idle Minimum time = BUS_IDLE_MIN[7:0] x Baud_Clock_Period x * (BUS_IDLE_MIN_XK_TICKS[7] ? 4,1) */ -#define BUS_IDLE_MIN_100K_TICKS 167UL -#define BUS_IDLE_MIN_400K_TICKS 139UL -#define BUS_IDLE_MIN_1000K_TICKS 133UL +#define BUS_IDLE_MIN_100K_TICKS 36UL +#define BUS_IDLE_MIN_400K_TICKS 10UL +#define BUS_IDLE_MIN_1000K_TICKS 4UL /* * CTRL_CUM_TIME_OUT_XK_TICKS defines SMBus Controller Cumulative Time-Out. * SMBus Controller Cumulative Time-Out duration = * CTRL_CUM_TIME_OUT_XK_TICKS[7:0] x Baud_Clock_Period x 2048 */ -#define CTRL_CUM_TIME_OUT_100K_TICKS 159 -#define CTRL_CUM_TIME_OUT_400K_TICKS 159 -#define CTRL_CUM_TIME_OUT_1000K_TICKS 159 +#define CTRL_CUM_TIME_OUT_100K_TICKS 76 +#define CTRL_CUM_TIME_OUT_400K_TICKS 76 +#define CTRL_CUM_TIME_OUT_1000K_TICKS 76 /* * TARGET_CUM_TIME_OUT_XK_TICKS defines SMBus Target Cumulative Time-Out duration. * SMBus Target Cumulative Time-Out duration = TARGET_CUM_TIME_OUT_XK_TICKS[7:0] x * Baud_Clock_Period x 4096 */ -#define TARGET_CUM_TIME_OUT_100K_TICKS 199 -#define TARGET_CUM_TIME_OUT_400K_TICKS 199 -#define TARGET_CUM_TIME_OUT_1000K_TICKS 199 +#define TARGET_CUM_TIME_OUT_100K_TICKS 95 +#define TARGET_CUM_TIME_OUT_400K_TICKS 95 +#define TARGET_CUM_TIME_OUT_1000K_TICKS 95 /* * CLOCK_HIGH_TIME_OUT_XK defines Clock High time out period. * Clock High time out period = CLOCK_HIGH_TIME_OUT_XK[7:0] x Baud_Clock_Period x 8 */ -#define CLOCK_HIGH_TIME_OUT_100K_TICKS 204 -#define CLOCK_HIGH_TIME_OUT_400K_TICKS 204 -#define CLOCK_HIGH_TIME_OUT_1000K_TICKS 204 +#define CLOCK_HIGH_TIME_OUT_100K_TICKS 97 +#define CLOCK_HIGH_TIME_OUT_400K_TICKS 97 +#define CLOCK_HIGH_TIME_OUT_1000K_TICKS 97 #define TO_SCALING_100K \ ((BUS_IDLE_MIN_100K_TICKS << 24) | (CTRL_CUM_TIME_OUT_100K_TICKS << 16) | \ @@ -1048,7 +1048,7 @@ static u32 pci1xxxx_i2c_get_funcs(struct i2c_adapter *adap) } static const struct i2c_algorithm pci1xxxx_i2c_algo = { - .master_xfer = pci1xxxx_i2c_xfer, + .xfer = pci1xxxx_i2c_xfer, .functionality = pci1xxxx_i2c_get_funcs, }; @@ -1118,8 +1118,10 @@ static int pci1xxxx_i2c_resume(struct device *dev) static DEFINE_SIMPLE_DEV_PM_OPS(pci1xxxx_i2c_pm_ops, pci1xxxx_i2c_suspend, pci1xxxx_i2c_resume); -static void pci1xxxx_i2c_shutdown(struct pci1xxxx_i2c *i2c) +static void pci1xxxx_i2c_shutdown(void *data) { + struct pci1xxxx_i2c *i2c = data; + pci1xxxx_i2c_config_padctrl(i2c, false); pci1xxxx_i2c_configure_core_reg(i2c, false); } @@ -1156,7 +1158,7 @@ static int pci1xxxx_i2c_probe_pci(struct pci_dev *pdev, init_completion(&i2c->i2c_xfer_done); pci1xxxx_i2c_init(i2c); - ret = devm_add_action(dev, (void (*)(void *))pci1xxxx_i2c_shutdown, i2c); + ret = devm_add_action(dev, pci1xxxx_i2c_shutdown, i2c); if (ret) return ret; diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 889eff06b78f..0d9032953e48 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -15,7 +15,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/types.h> @@ -449,8 +448,8 @@ static u32 meson_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm meson_i2c_algorithm = { - .master_xfer = meson_i2c_xfer, - .master_xfer_atomic = meson_i2c_xfer_atomic, + .xfer = meson_i2c_xfer, + .xfer_atomic = meson_i2c_xfer_atomic, .functionality = meson_i2c_func, }; @@ -535,14 +534,12 @@ static int meson_i2c_probe(struct platform_device *pdev) return 0; } -static int meson_i2c_remove(struct platform_device *pdev) +static void meson_i2c_remove(struct platform_device *pdev) { struct meson_i2c *i2c = platform_get_drvdata(pdev); i2c_del_adapter(&i2c->adap); clk_disable_unprepare(i2c->clk); - - return 0; } static const struct meson_i2c_data i2c_meson6_data = { @@ -568,7 +565,7 @@ MODULE_DEVICE_TABLE(of, meson_i2c_match); static struct platform_driver meson_i2c_driver = { .probe = meson_i2c_probe, - .remove = meson_i2c_remove, + .remove = meson_i2c_remove, .driver = { .name = "meson-i2c", .of_match_table = meson_i2c_match, diff --git a/drivers/i2c/busses/i2c-microchip-corei2c.c b/drivers/i2c/busses/i2c-microchip-corei2c.c index 4d7e9b25f018..c8599733633e 100644 --- a/drivers/i2c/busses/i2c-microchip-corei2c.c +++ b/drivers/i2c/busses/i2c-microchip-corei2c.c @@ -76,6 +76,8 @@ #define CORE_I2C_FREQ (0x14) #define CORE_I2C_GLITCHREG (0x18) #define CORE_I2C_SLAVE1_ADDR (0x1c) +#define CORE_I2C_SMBUS_MSG_WR (0x0) +#define CORE_I2C_SMBUS_MSG_RD (0x1) #define PCLK_DIV_960 (CTRL_CR2) #define PCLK_DIV_256 (0) @@ -93,27 +95,35 @@ * @base: pointer to register struct * @dev: device reference * @i2c_clk: clock reference for i2c input clock + * @msg_queue: pointer to the messages requiring sending * @buf: pointer to msg buffer for easier use * @msg_complete: xfer completion object * @adapter: core i2c abstraction * @msg_err: error code for completed message * @bus_clk_rate: current i2c bus clock rate * @isr_status: cached copy of local ISR status + * @total_num: total number of messages to be sent/received + * @current_num: index of the current message being sent/received * @msg_len: number of bytes transferred in msg * @addr: address of the current slave + * @restart_needed: whether or not a repeated start is required after current message */ struct mchp_corei2c_dev { void __iomem *base; struct device *dev; struct clk *i2c_clk; + struct i2c_msg *msg_queue; u8 *buf; struct completion msg_complete; struct i2c_adapter adapter; int msg_err; + int total_num; + int current_num; u32 bus_clk_rate; u32 isr_status; u16 msg_len; u8 addr; + bool restart_needed; }; static void mchp_corei2c_core_disable(struct mchp_corei2c_dev *idev) @@ -222,6 +232,47 @@ static int mchp_corei2c_fill_tx(struct mchp_corei2c_dev *idev) return 0; } +static void mchp_corei2c_next_msg(struct mchp_corei2c_dev *idev) +{ + struct i2c_msg *this_msg; + u8 ctrl; + + if (idev->current_num >= idev->total_num) { + complete(&idev->msg_complete); + return; + } + + /* + * If there's been an error, the isr needs to return control + * to the "main" part of the driver, so as not to keep sending + * messages once it completes and clears the SI bit. + */ + if (idev->msg_err) { + complete(&idev->msg_complete); + return; + } + + this_msg = idev->msg_queue++; + + if (idev->current_num < (idev->total_num - 1)) { + struct i2c_msg *next_msg = idev->msg_queue; + + idev->restart_needed = next_msg->flags & I2C_M_RD; + } else { + idev->restart_needed = false; + } + + idev->addr = i2c_8bit_addr_from_msg(this_msg); + idev->msg_len = this_msg->len; + idev->buf = this_msg->buf; + + ctrl = readb(idev->base + CORE_I2C_CTRL); + ctrl |= CTRL_STA; + writeb(ctrl, idev->base + CORE_I2C_CTRL); + + idev->current_num++; +} + static irqreturn_t mchp_corei2c_handle_isr(struct mchp_corei2c_dev *idev) { u32 status = idev->isr_status; @@ -238,8 +289,6 @@ static irqreturn_t mchp_corei2c_handle_isr(struct mchp_corei2c_dev *idev) ctrl &= ~CTRL_STA; writeb(idev->addr, idev->base + CORE_I2C_DATA); writeb(ctrl, idev->base + CORE_I2C_CTRL); - if (idev->msg_len == 0) - finished = true; break; case STATUS_M_ARB_LOST: idev->msg_err = -EAGAIN; @@ -247,10 +296,14 @@ static irqreturn_t mchp_corei2c_handle_isr(struct mchp_corei2c_dev *idev) break; case STATUS_M_SLAW_ACK: case STATUS_M_TX_DATA_ACK: - if (idev->msg_len > 0) + if (idev->msg_len > 0) { mchp_corei2c_fill_tx(idev); - else - last_byte = true; + } else { + if (idev->restart_needed) + finished = true; + else + last_byte = true; + } break; case STATUS_M_TX_DATA_NACK: case STATUS_M_SLAR_NACK: @@ -287,7 +340,7 @@ static irqreturn_t mchp_corei2c_handle_isr(struct mchp_corei2c_dev *idev) mchp_corei2c_stop(idev); if (last_byte || finished) - complete(&idev->msg_complete); + mchp_corei2c_next_msg(idev); return IRQ_HANDLED; } @@ -311,21 +364,48 @@ static irqreturn_t mchp_corei2c_isr(int irq, void *_dev) return ret; } -static int mchp_corei2c_xfer_msg(struct mchp_corei2c_dev *idev, - struct i2c_msg *msg) +static int mchp_corei2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) { - u8 ctrl; + struct mchp_corei2c_dev *idev = i2c_get_adapdata(adap); + struct i2c_msg *this_msg = msgs; unsigned long time_left; + u8 ctrl; + + mchp_corei2c_core_enable(idev); - idev->addr = i2c_8bit_addr_from_msg(msg); - idev->msg_len = msg->len; - idev->buf = msg->buf; + /* + * The isr controls the flow of a transfer, this info needs to be saved + * to a location that it can access the queue information from. + */ + idev->restart_needed = false; + idev->msg_queue = msgs; + idev->total_num = num; + idev->current_num = 0; + + /* + * But the first entry to the isr is triggered by the start in this + * function, so the first message needs to be "dequeued". + */ + idev->addr = i2c_8bit_addr_from_msg(this_msg); + idev->msg_len = this_msg->len; + idev->buf = this_msg->buf; idev->msg_err = 0; - reinit_completion(&idev->msg_complete); + if (idev->total_num > 1) { + struct i2c_msg *next_msg = msgs + 1; - mchp_corei2c_core_enable(idev); + idev->restart_needed = next_msg->flags & I2C_M_RD; + } + + idev->current_num++; + idev->msg_queue++; + + reinit_completion(&idev->msg_complete); + /* + * Send the first start to pass control to the isr + */ ctrl = readb(idev->base + CORE_I2C_CTRL); ctrl |= CTRL_STA; writeb(ctrl, idev->base + CORE_I2C_CTRL); @@ -335,32 +415,124 @@ static int mchp_corei2c_xfer_msg(struct mchp_corei2c_dev *idev, if (!time_left) return -ETIMEDOUT; - return idev->msg_err; + if (idev->msg_err) + return idev->msg_err; + + return num; } -static int mchp_corei2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num) +static u32 mchp_corei2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static int mchp_corei2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags, + char read_write, u8 command, + int size, union i2c_smbus_data *data) { + struct i2c_msg msgs[2]; struct mchp_corei2c_dev *idev = i2c_get_adapdata(adap); - int i, ret; + u8 tx_buf[I2C_SMBUS_BLOCK_MAX + 2]; + u8 rx_buf[I2C_SMBUS_BLOCK_MAX + 1]; + int num_msgs = 1; + int ret; - for (i = 0; i < num; i++) { - ret = mchp_corei2c_xfer_msg(idev, msgs++); - if (ret) - return ret; + msgs[CORE_I2C_SMBUS_MSG_WR].addr = addr; + msgs[CORE_I2C_SMBUS_MSG_WR].flags = 0; + + if (read_write == I2C_SMBUS_READ && size <= I2C_SMBUS_BYTE) + msgs[CORE_I2C_SMBUS_MSG_WR].flags = I2C_M_RD; + + if (read_write == I2C_SMBUS_WRITE && size <= I2C_SMBUS_WORD_DATA) + msgs[CORE_I2C_SMBUS_MSG_WR].len = size; + + if (read_write == I2C_SMBUS_WRITE && size > I2C_SMBUS_BYTE) { + msgs[CORE_I2C_SMBUS_MSG_WR].buf = tx_buf; + msgs[CORE_I2C_SMBUS_MSG_WR].buf[0] = command; } - return num; -} + if (read_write == I2C_SMBUS_READ && size >= I2C_SMBUS_BYTE_DATA) { + msgs[CORE_I2C_SMBUS_MSG_WR].buf = tx_buf; + msgs[CORE_I2C_SMBUS_MSG_WR].buf[0] = command; + msgs[CORE_I2C_SMBUS_MSG_RD].addr = addr; + msgs[CORE_I2C_SMBUS_MSG_RD].flags = I2C_M_RD; + num_msgs = 2; + } -static u32 mchp_corei2c_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + if (read_write == I2C_SMBUS_READ && size > I2C_SMBUS_QUICK) + msgs[CORE_I2C_SMBUS_MSG_WR].len = 1; + + switch (size) { + case I2C_SMBUS_QUICK: + msgs[CORE_I2C_SMBUS_MSG_WR].buf = NULL; + return 0; + case I2C_SMBUS_BYTE: + if (read_write == I2C_SMBUS_WRITE) + msgs[CORE_I2C_SMBUS_MSG_WR].buf = &command; + else + msgs[CORE_I2C_SMBUS_MSG_WR].buf = &data->byte; + break; + case I2C_SMBUS_BYTE_DATA: + if (read_write == I2C_SMBUS_WRITE) { + msgs[CORE_I2C_SMBUS_MSG_WR].buf[1] = data->byte; + } else { + msgs[CORE_I2C_SMBUS_MSG_RD].len = size - 1; + msgs[CORE_I2C_SMBUS_MSG_RD].buf = &data->byte; + } + break; + case I2C_SMBUS_WORD_DATA: + if (read_write == I2C_SMBUS_WRITE) { + msgs[CORE_I2C_SMBUS_MSG_WR].buf[1] = data->word & 0xFF; + msgs[CORE_I2C_SMBUS_MSG_WR].buf[2] = (data->word >> 8) & 0xFF; + } else { + msgs[CORE_I2C_SMBUS_MSG_RD].len = size - 1; + msgs[CORE_I2C_SMBUS_MSG_RD].buf = rx_buf; + } + break; + case I2C_SMBUS_BLOCK_DATA: + if (read_write == I2C_SMBUS_WRITE) { + int data_len; + + data_len = data->block[0]; + msgs[CORE_I2C_SMBUS_MSG_WR].len = data_len + 2; + for (int i = 0; i <= data_len; i++) + msgs[CORE_I2C_SMBUS_MSG_WR].buf[i + 1] = data->block[i]; + } else { + msgs[CORE_I2C_SMBUS_MSG_RD].len = I2C_SMBUS_BLOCK_MAX + 1; + msgs[CORE_I2C_SMBUS_MSG_RD].buf = rx_buf; + } + break; + default: + return -EOPNOTSUPP; + } + + ret = mchp_corei2c_xfer(&idev->adapter, msgs, num_msgs); + if (ret < 0) + return ret; + + if (read_write == I2C_SMBUS_WRITE || size <= I2C_SMBUS_BYTE_DATA) + return 0; + + switch (size) { + case I2C_SMBUS_WORD_DATA: + data->word = (rx_buf[0] | (rx_buf[1] << 8)); + break; + case I2C_SMBUS_BLOCK_DATA: + if (rx_buf[0] > I2C_SMBUS_BLOCK_MAX) + rx_buf[0] = I2C_SMBUS_BLOCK_MAX; + /* As per protocol first member of block is size of the block. */ + for (int i = 0; i <= rx_buf[0]; i++) + data->block[i] = rx_buf[i]; + break; + } + + return 0; } static const struct i2c_algorithm mchp_corei2c_algo = { - .master_xfer = mchp_corei2c_xfer, + .xfer = mchp_corei2c_xfer, .functionality = mchp_corei2c_func, + .smbus_xfer = mchp_corei2c_smbus_xfer, }; static int mchp_corei2c_probe(struct platform_device *pdev) @@ -378,9 +550,8 @@ static int mchp_corei2c_probe(struct platform_device *pdev) return PTR_ERR(idev->base); irq = platform_get_irq(pdev, 0); - if (irq <= 0) - return dev_err_probe(&pdev->dev, -ENXIO, - "invalid IRQ %d for I2C controller\n", irq); + if (irq < 0) + return irq; idev->i2c_clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(idev->i2c_clk)) @@ -446,14 +617,12 @@ static int mchp_corei2c_probe(struct platform_device *pdev) return 0; } -static int mchp_corei2c_remove(struct platform_device *pdev) +static void mchp_corei2c_remove(struct platform_device *pdev) { struct mchp_corei2c_dev *idev = platform_get_drvdata(pdev); clk_disable_unprepare(idev->i2c_clk); i2c_del_adapter(&idev->adapter); - - return 0; } static const struct of_device_id mchp_corei2c_of_match[] = { diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c index 1810d5791b3d..8345f7e6385d 100644 --- a/drivers/i2c/busses/i2c-mlxbf.c +++ b/drivers/i2c/busses/i2c-mlxbf.c @@ -12,12 +12,14 @@ #include <linux/interrupt.h> #include <linux/i2c.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mutex.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/string.h> +#include <linux/string_choices.h> /* Defines what functionality is present. */ #define MLXBF_I2C_FUNC_SMBUS_BLOCK \ @@ -196,6 +198,7 @@ #define MLXBF_I2C_MASK_8 GENMASK(7, 0) #define MLXBF_I2C_MASK_16 GENMASK(15, 0) +#define MLXBF_I2C_MASK_32 GENMASK(31, 0) #define MLXBF_I2C_MST_ADDR_OFFSET 0x200 @@ -222,7 +225,7 @@ #define MLXBF_I2C_MASTER_ENABLE \ (MLXBF_I2C_MASTER_LOCK_BIT | MLXBF_I2C_MASTER_BUSY_BIT | \ - MLXBF_I2C_MASTER_START_BIT | MLXBF_I2C_MASTER_STOP_BIT) + MLXBF_I2C_MASTER_START_BIT) #define MLXBF_I2C_MASTER_ENABLE_WRITE \ (MLXBF_I2C_MASTER_ENABLE | MLXBF_I2C_MASTER_CTL_WRITE_BIT) @@ -336,6 +339,7 @@ enum { MLXBF_I2C_F_SMBUS_BLOCK = BIT(5), MLXBF_I2C_F_SMBUS_PEC = BIT(6), MLXBF_I2C_F_SMBUS_PROCESS_CALL = BIT(7), + MLXBF_I2C_F_WRITE_WITHOUT_STOP = BIT(8), }; /* Mellanox BlueField chip type. */ @@ -495,65 +499,6 @@ static u8 mlxbf_i2c_bus_count; static struct mutex mlxbf_i2c_bus_lock; -/* - * Function to poll a set of bits at a specific address; it checks whether - * the bits are equal to zero when eq_zero is set to 'true', and not equal - * to zero when eq_zero is set to 'false'. - * Note that the timeout is given in microseconds. - */ -static u32 mlxbf_i2c_poll(void __iomem *io, u32 addr, u32 mask, - bool eq_zero, u32 timeout) -{ - u32 bits; - - timeout = (timeout / MLXBF_I2C_POLL_FREQ_IN_USEC) + 1; - - do { - bits = readl(io + addr) & mask; - if (eq_zero ? bits == 0 : bits != 0) - return eq_zero ? 1 : bits; - udelay(MLXBF_I2C_POLL_FREQ_IN_USEC); - } while (timeout-- != 0); - - return 0; -} - -/* - * SW must make sure that the SMBus Master GW is idle before starting - * a transaction. Accordingly, this function polls the Master FSM stop - * bit; it returns false when the bit is asserted, true if not. - */ -static bool mlxbf_i2c_smbus_master_wait_for_idle(struct mlxbf_i2c_priv *priv) -{ - u32 mask = MLXBF_I2C_SMBUS_MASTER_FSM_STOP_MASK; - u32 addr = priv->chip->smbus_master_fsm_off; - u32 timeout = MLXBF_I2C_SMBUS_TIMEOUT; - - if (mlxbf_i2c_poll(priv->mst->io, addr, mask, true, timeout)) - return true; - - return false; -} - -/* - * wait for the lock to be released before acquiring it. - */ -static bool mlxbf_i2c_smbus_master_lock(struct mlxbf_i2c_priv *priv) -{ - if (mlxbf_i2c_poll(priv->mst->io, MLXBF_I2C_SMBUS_MASTER_GW, - MLXBF_I2C_MASTER_LOCK_BIT, true, - MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT)) - return true; - - return false; -} - -static void mlxbf_i2c_smbus_master_unlock(struct mlxbf_i2c_priv *priv) -{ - /* Clear the gw to clear the lock */ - writel(0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW); -} - static bool mlxbf_i2c_smbus_transaction_success(u32 master_status, u32 cause_status) { @@ -583,6 +528,7 @@ static int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv) { u32 master_status_bits; u32 cause_status_bits; + u32 bits; /* * GW busy bit is raised by the driver and cleared by the HW @@ -591,9 +537,9 @@ static int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv) * then read the cause and master status bits to determine if * errors occurred during the transaction. */ - mlxbf_i2c_poll(priv->mst->io, MLXBF_I2C_SMBUS_MASTER_GW, - MLXBF_I2C_MASTER_BUSY_BIT, true, - MLXBF_I2C_SMBUS_TIMEOUT); + readl_poll_timeout_atomic(priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW, + bits, !(bits & MLXBF_I2C_MASTER_BUSY_BIT), + MLXBF_I2C_POLL_FREQ_IN_USEC, MLXBF_I2C_SMBUS_TIMEOUT); /* Read cause status bits. */ cause_status_bits = readl(priv->mst_cause->io + @@ -694,16 +640,19 @@ static void mlxbf_i2c_smbus_read_data(struct mlxbf_i2c_priv *priv, } static int mlxbf_i2c_smbus_enable(struct mlxbf_i2c_priv *priv, u8 slave, - u8 len, u8 block_en, u8 pec_en, bool read) + u8 len, u8 block_en, u8 pec_en, bool read, + bool stop) { - u32 command; + u32 command = 0; /* Set Master GW control word. */ + if (stop) + command |= MLXBF_I2C_MASTER_STOP_BIT; if (read) { - command = MLXBF_I2C_MASTER_ENABLE_READ; + command |= MLXBF_I2C_MASTER_ENABLE_READ; command |= rol32(len, MLXBF_I2C_MASTER_READ_SHIFT); } else { - command = MLXBF_I2C_MASTER_ENABLE_WRITE; + command |= MLXBF_I2C_MASTER_ENABLE_WRITE; command |= rol32(len, MLXBF_I2C_MASTER_WRITE_SHIFT); } command |= rol32(slave, MLXBF_I2C_MASTER_SLV_ADDR_SHIFT); @@ -738,9 +687,12 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, u8 op_idx, data_idx, data_len, write_len, read_len; struct mlxbf_i2c_smbus_operation *operation; u8 read_en, write_en, block_en, pec_en; - u8 slave, flags, addr; + bool stop_after_write = true; + u8 slave, addr; u8 *read_buf; - int ret = 0; + u32 flags; + u32 bits; + int ret; if (request->operation_cnt > MLXBF_I2C_SMBUS_MAX_OP_CNT) return -EINVAL; @@ -760,11 +712,22 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, * Try to acquire the smbus gw lock before any reads of the GW register since * a read sets the lock. */ - if (WARN_ON(!mlxbf_i2c_smbus_master_lock(priv))) + ret = readl_poll_timeout_atomic(priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW, + bits, !(bits & MLXBF_I2C_MASTER_LOCK_BIT), + MLXBF_I2C_POLL_FREQ_IN_USEC, + MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT); + if (WARN_ON(ret)) return -EBUSY; - /* Check whether the HW is idle */ - if (WARN_ON(!mlxbf_i2c_smbus_master_wait_for_idle(priv))) { + /* + * SW must make sure that the SMBus Master GW is idle before starting + * a transaction. Accordingly, this call polls the Master FSM stop bit; + * it returns -ETIMEDOUT when the bit is asserted, 0 if not. + */ + ret = readl_poll_timeout_atomic(priv->mst->io + priv->chip->smbus_master_fsm_off, + bits, !(bits & MLXBF_I2C_SMBUS_MASTER_FSM_STOP_MASK), + MLXBF_I2C_POLL_FREQ_IN_USEC, MLXBF_I2C_SMBUS_TIMEOUT); + if (WARN_ON(ret)) { ret = -EBUSY; goto out_unlock; } @@ -799,7 +762,16 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, memcpy(data_desc + data_idx, operation->buffer, operation->length); data_idx += operation->length; + + /* + * The stop condition can be skipped when writing on the bus + * to implement a repeated start condition on the next read + * as required for several SMBus and I2C operations. + */ + if (flags & MLXBF_I2C_F_WRITE_WITHOUT_STOP) + stop_after_write = false; } + /* * We assume that read operations are performed only once per * SMBus transaction. *TBD* protect this statement so it won't @@ -825,7 +797,7 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, if (write_en) { ret = mlxbf_i2c_smbus_enable(priv, slave, write_len, block_en, - pec_en, 0); + pec_en, 0, stop_after_write); if (ret) goto out_unlock; } @@ -835,7 +807,7 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, mlxbf_i2c_smbus_write_data(priv, (const u8 *)&addr, 1, MLXBF_I2C_MASTER_DATA_DESC_ADDR, true); ret = mlxbf_i2c_smbus_enable(priv, slave, read_len, block_en, - pec_en, 1); + pec_en, 1, true); if (!ret) { /* Get Master GW data descriptor. */ mlxbf_i2c_smbus_read_data(priv, data_desc, read_len + 1, @@ -855,7 +827,8 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, } out_unlock: - mlxbf_i2c_smbus_master_unlock(priv); + /* Clear the gw to clear the lock */ + writel(0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW); return ret; } @@ -940,6 +913,9 @@ mlxbf_i2c_smbus_i2c_block_func(struct mlxbf_i2c_smbus_request *request, request->operation[0].flags |= pec_check ? MLXBF_I2C_F_SMBUS_PEC : 0; request->operation[0].buffer = command; + if (read) + request->operation[0].flags |= MLXBF_I2C_F_WRITE_WITHOUT_STOP; + /* * As specified in the standard, the max number of bytes to read/write * per block operation is 32 bytes. In Golan code, the controller can @@ -1080,13 +1056,7 @@ static int mlxbf_i2c_init_resource(struct platform_device *pdev, if (!tmp_res) return -ENOMEM; - tmp_res->params = platform_get_resource(pdev, IORESOURCE_MEM, type); - if (!tmp_res->params) { - devm_kfree(dev, tmp_res); - return -EIO; - } - - tmp_res->io = devm_ioremap_resource(dev, tmp_res->params); + tmp_res->io = devm_platform_get_and_ioremap_resource(pdev, type, &tmp_res->params); if (IS_ERR(tmp_res->io)) { devm_kfree(dev, tmp_res); return PTR_ERR(tmp_res->io); @@ -1113,7 +1083,7 @@ static u32 mlxbf_i2c_get_ticks(struct mlxbf_i2c_priv *priv, u64 nanoseconds, * Frequency */ frequency = priv->frequency; - ticks = (nanoseconds * frequency) / MLXBF_I2C_FREQUENCY_1GHZ; + ticks = div_u64(nanoseconds * frequency, MLXBF_I2C_FREQUENCY_1GHZ); /* * The number of ticks is rounded down and if minimum is equal to 1 * then add one tick. @@ -1180,7 +1150,8 @@ static void mlxbf_i2c_set_timings(struct mlxbf_i2c_priv *priv, MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16); writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_THIGH_MAX_TBUF); - timer = timings->timeout; + timer = mlxbf_i2c_set_timer(priv, timings->timeout, false, + MLXBF_I2C_MASK_32, MLXBF_I2C_SHIFT_0); writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT); } @@ -1190,11 +1161,7 @@ enum mlxbf_i2c_timings_config { MLXBF_I2C_TIMING_CONFIG_1000KHZ, }; -/* - * Note that the mlxbf_i2c_timings->timeout value is not related to the - * bus frequency, it is impacted by the time it takes the driver to - * complete data transmission before transaction abort. - */ +/* Timing values are in nanoseconds */ static const struct mlxbf_i2c_timings mlxbf_i2c_timings[] = { [MLXBF_I2C_TIMING_CONFIG_100KHZ] = { .scl_high = 4810, @@ -1209,8 +1176,8 @@ static const struct mlxbf_i2c_timings mlxbf_i2c_timings[] = { .scl_fall = 50, .hold_data = 300, .buf = 20000, - .thigh_max = 5000, - .timeout = 106500 + .thigh_max = 50000, + .timeout = 35000000 }, [MLXBF_I2C_TIMING_CONFIG_400KHZ] = { .scl_high = 1011, @@ -1225,24 +1192,24 @@ static const struct mlxbf_i2c_timings mlxbf_i2c_timings[] = { .scl_fall = 50, .hold_data = 300, .buf = 20000, - .thigh_max = 5000, - .timeout = 106500 + .thigh_max = 50000, + .timeout = 35000000 }, [MLXBF_I2C_TIMING_CONFIG_1000KHZ] = { - .scl_high = 600, - .scl_low = 1300, + .scl_high = 383, + .scl_low = 460, .hold_start = 600, - .setup_start = 600, - .setup_stop = 600, - .setup_data = 100, + .setup_start = 260, + .setup_stop = 260, + .setup_data = 50, .sda_rise = 50, .sda_fall = 50, .scl_rise = 50, .scl_fall = 50, .hold_data = 300, - .buf = 20000, - .thigh_max = 5000, - .timeout = 106500 + .buf = 500, + .thigh_max = 50000, + .timeout = 35000000 } }; @@ -1493,9 +1460,8 @@ static u64 mlxbf_i2c_calculate_freq_from_tyu(struct mlxbf_i2c_resource *corepll_ * and PadFrequency, respectively. */ core_frequency = MLXBF_I2C_PLL_IN_FREQ * (++core_f); - core_frequency /= (++core_r) * (++core_od); - return core_frequency; + return div_u64(core_frequency, (++core_r) * (++core_od)); } static u64 mlxbf_i2c_calculate_freq_from_yu(struct mlxbf_i2c_resource *corepll_res) @@ -1524,9 +1490,8 @@ static u64 mlxbf_i2c_calculate_freq_from_yu(struct mlxbf_i2c_resource *corepll_r * and PadFrequency, respectively. */ corepll_frequency = (MLXBF_I2C_PLL_IN_FREQ * core_f) / MLNXBF_I2C_COREPLL_CONST; - corepll_frequency /= (++core_r) * (++core_od); - return corepll_frequency; + return div_u64(corepll_frequency, (++core_r) * (++core_od)); } static int mlxbf_i2c_calculate_corepll_freq(struct platform_device *pdev, @@ -1835,18 +1800,6 @@ static bool mlxbf_i2c_has_coalesce(struct mlxbf_i2c_priv *priv, bool *read, return true; } -static bool mlxbf_i2c_slave_wait_for_idle(struct mlxbf_i2c_priv *priv, - u32 timeout) -{ - u32 mask = MLXBF_I2C_CAUSE_S_GW_BUSY_FALL; - u32 addr = MLXBF_I2C_CAUSE_ARBITER; - - if (mlxbf_i2c_poll(priv->slv_cause->io, addr, mask, false, timeout)) - return true; - - return false; -} - static struct i2c_client *mlxbf_i2c_get_slave_from_addr( struct mlxbf_i2c_priv *priv, u8 addr) { @@ -1949,7 +1902,9 @@ static int mlxbf_i2c_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes) * Wait until the transfer is completed; the driver will wait * until the GW is idle, a cause will rise on fall of GW busy. */ - mlxbf_i2c_slave_wait_for_idle(priv, MLXBF_I2C_SMBUS_TIMEOUT); + readl_poll_timeout_atomic(priv->slv_cause->io + MLXBF_I2C_CAUSE_ARBITER, + data32, data32 & MLXBF_I2C_CAUSE_S_GW_BUSY_FALL, + MLXBF_I2C_POLL_FREQ_IN_USEC, MLXBF_I2C_SMBUS_TIMEOUT); clear_csr: /* Release the Slave GW. */ @@ -2098,21 +2053,21 @@ static s32 mlxbf_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, read ? &data->byte : &command, read, pec); dev_dbg(&adap->dev, "smbus %s byte, slave 0x%02x.\n", - read ? "read" : "write", addr); + str_read_write(read), addr); break; case I2C_SMBUS_BYTE_DATA: mlxbf_i2c_smbus_data_byte_func(&request, &command, &data->byte, read, pec); dev_dbg(&adap->dev, "smbus %s byte data at 0x%02x, slave 0x%02x.\n", - read ? "read" : "write", command, addr); + str_read_write(read), command, addr); break; case I2C_SMBUS_WORD_DATA: mlxbf_i2c_smbus_data_word_func(&request, &command, (u8 *)&data->word, read, pec); dev_dbg(&adap->dev, "smbus %s word data at 0x%02x, slave 0x%02x.\n", - read ? "read" : "write", command, addr); + str_read_write(read), command, addr); break; case I2C_SMBUS_I2C_BLOCK_DATA: @@ -2120,7 +2075,7 @@ static s32 mlxbf_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, mlxbf_i2c_smbus_i2c_block_func(&request, &command, data->block, &byte_cnt, read, pec); dev_dbg(&adap->dev, "i2c %s block data, %d bytes at 0x%02x, slave 0x%02x.\n", - read ? "read" : "write", byte_cnt, command, addr); + str_read_write(read), byte_cnt, command, addr); break; case I2C_SMBUS_BLOCK_DATA: @@ -2128,7 +2083,7 @@ static s32 mlxbf_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, mlxbf_i2c_smbus_block_func(&request, &command, data->block, &byte_cnt, read, pec); dev_dbg(&adap->dev, "smbus %s block data, %d bytes at 0x%02x, slave 0x%02x.\n", - read ? "read" : "write", byte_cnt, command, addr); + str_read_write(read), byte_cnt, command, addr); break; case I2C_FUNC_SMBUS_PROC_CALL: @@ -2323,10 +2278,8 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) ret = mlxbf_i2c_init_resource(pdev, &priv->smbus, MLXBF_I2C_SMBUS_RES); - if (ret < 0) { - dev_err(dev, "Cannot fetch smbus resource info"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot fetch smbus resource info"); priv->timer->io = priv->smbus->io; priv->mst->io = priv->smbus->io + MLXBF_I2C_MST_ADDR_OFFSET; @@ -2334,39 +2287,29 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) } else { ret = mlxbf_i2c_init_resource(pdev, &priv->timer, MLXBF_I2C_SMBUS_TIMER_RES); - if (ret < 0) { - dev_err(dev, "Cannot fetch timer resource info"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot fetch timer resource info"); ret = mlxbf_i2c_init_resource(pdev, &priv->mst, MLXBF_I2C_SMBUS_MST_RES); - if (ret < 0) { - dev_err(dev, "Cannot fetch master resource info"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot fetch master resource info"); ret = mlxbf_i2c_init_resource(pdev, &priv->slv, MLXBF_I2C_SMBUS_SLV_RES); - if (ret < 0) { - dev_err(dev, "Cannot fetch slave resource info"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot fetch slave resource info"); } ret = mlxbf_i2c_init_resource(pdev, &priv->mst_cause, MLXBF_I2C_MST_CAUSE_RES); - if (ret < 0) { - dev_err(dev, "Cannot fetch cause master resource info"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot fetch cause master resource info"); ret = mlxbf_i2c_init_resource(pdev, &priv->slv_cause, MLXBF_I2C_SLV_CAUSE_RES); - if (ret < 0) { - dev_err(dev, "Cannot fetch cause slave resource info"); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot fetch cause slave resource info"); adap = &priv->adap; adap->owner = THIS_MODULE; @@ -2397,11 +2340,9 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) * does not really hurt, then keep the code as is. */ ret = mlxbf_i2c_init_master(pdev, priv); - if (ret < 0) { - dev_err(dev, "failed to initialize smbus master %d", - priv->bus); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "failed to initialize smbus master %d", + priv->bus); mlxbf_i2c_init_timings(pdev, priv); @@ -2413,10 +2354,8 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, mlxbf_i2c_irq, IRQF_SHARED | IRQF_PROBE_SHARED, dev_name(dev), priv); - if (ret < 0) { - dev_err(dev, "Cannot get irq %d\n", irq); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "Cannot get irq %d\n", irq); priv->irq = irq; @@ -2433,7 +2372,7 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) return 0; } -static int mlxbf_i2c_remove(struct platform_device *pdev) +static void mlxbf_i2c_remove(struct platform_device *pdev) { struct mlxbf_i2c_priv *priv = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; @@ -2474,8 +2413,6 @@ static int mlxbf_i2c_remove(struct platform_device *pdev) devm_free_irq(dev, priv->irq, priv); i2c_del_adapter(&priv->adap); - - return 0; } static struct platform_driver mlxbf_i2c_driver = { diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 081f51ef0551..07d3cadbf510 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -22,6 +22,7 @@ #define MLXCPLD_I2C_BUS_NUM 1 #define MLXCPLD_I2C_DATA_REG_SZ 36 #define MLXCPLD_I2C_DATA_SZ_BIT BIT(5) +#define MLXCPLD_I2C_DATA_EXT2_SZ_BIT BIT(6) #define MLXCPLD_I2C_DATA_SZ_MASK GENMASK(6, 5) #define MLXCPLD_I2C_SMBUS_BLK_BIT BIT(7) #define MLXCPLD_I2C_MAX_ADDR_LEN 4 @@ -196,8 +197,8 @@ static int mlxcpld_i2c_check_status(struct mlxcpld_i2c_priv *priv, int *status) if (val & MLXCPLD_LPCI2C_TRANS_END) { if (val & MLXCPLD_LPCI2C_STATUS_NACK) /* - * The slave is unable to accept the data. No such - * slave, command not understood, or unable to accept + * The target is unable to accept the data. No such + * target, command not understood, or unable to accept * any more data. */ *status = MLXCPLD_LPCI2C_NACK_IND; @@ -279,7 +280,7 @@ static int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv) } /* - * Wait for master transfer to complete. + * Wait for transfer to complete. * It puts current process to sleep until we get interrupt or timeout expires. * Returns the number of transferred or read bytes or error (<0). */ @@ -314,7 +315,7 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) /* * Actual read data len will be always the same as * requested len. 0xff (line pull-up) will be returned - * if slave has no data to return. Thus don't read + * if target has no data to return. Thus don't read * MLXCPLD_LPCI2C_NUM_DAT_REG reg from CPLD. Only in case of * SMBus block read transaction data len can be different, * check this case. @@ -374,7 +375,7 @@ static void mlxcpld_i2c_xfer_msg(struct mlxcpld_i2c_priv *priv) } /* - * Set target slave address with command for master transfer. + * Set target address with command for transfer. * It should be latest executed function before CPLD transaction. */ cmd = (priv->xfer.msg[0].addr << 1) | priv->xfer.cmd; @@ -448,8 +449,8 @@ static u32 mlxcpld_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm mlxcpld_i2c_algo = { - .master_xfer = mlxcpld_i2c_xfer, - .functionality = mlxcpld_i2c_func + .xfer = mlxcpld_i2c_xfer, + .functionality = mlxcpld_i2c_func }; static const struct i2c_adapter_quirks mlxcpld_i2c_quirks = { @@ -466,10 +467,17 @@ static const struct i2c_adapter_quirks mlxcpld_i2c_quirks_ext = { .max_comb_1st_msg_len = 4, }; +static const struct i2c_adapter_quirks mlxcpld_i2c_quirks_ext2 = { + .flags = I2C_AQ_COMB_WRITE_THEN_READ, + .max_read_len = (MLXCPLD_I2C_DATA_REG_SZ - 4) * 4, + .max_write_len = (MLXCPLD_I2C_DATA_REG_SZ - 4) * 4 + MLXCPLD_I2C_MAX_ADDR_LEN, + .max_comb_1st_msg_len = 4, +}; + static struct i2c_adapter mlxcpld_i2c_adapter = { .owner = THIS_MODULE, .name = "i2c-mlxcpld", - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &mlxcpld_i2c_algo, .quirks = &mlxcpld_i2c_quirks, .retries = MLXCPLD_I2C_RETR_NUM, @@ -547,6 +555,8 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) /* Check support for extended transaction length */ if ((val & MLXCPLD_I2C_DATA_SZ_MASK) == MLXCPLD_I2C_DATA_SZ_BIT) mlxcpld_i2c_adapter.quirks = &mlxcpld_i2c_quirks_ext; + else if ((val & MLXCPLD_I2C_DATA_SZ_MASK) == MLXCPLD_I2C_DATA_EXT2_SZ_BIT) + mlxcpld_i2c_adapter.quirks = &mlxcpld_i2c_quirks_ext2; /* Check support for smbus block transaction */ if (val & MLXCPLD_I2C_SMBUS_BLK_BIT) priv->smbus_block = true; @@ -571,14 +581,12 @@ mlxcpld_i2_probe_failed: return err; } -static int mlxcpld_i2c_remove(struct platform_device *pdev) +static void mlxcpld_i2c_remove(struct platform_device *pdev) { struct mlxcpld_i2c_priv *priv = platform_get_drvdata(pdev); i2c_del_adapter(&priv->adap); mutex_destroy(&priv->lock); - - return 0; } static struct platform_driver mlxcpld_i2c_driver = { diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 81ac92bb4f6f..28c5c5c1fb7a 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -11,9 +11,10 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/sched/signal.h> +#include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> -#include <linux/of_platform.h> +#include <linux/platform_device.h> #include <linux/property.h> #include <linux/slab.h> @@ -29,8 +30,6 @@ #include <asm/mpc85xx.h> #include <sysdev/fsl_soc.h> -#define DRV_NAME "mpc-i2c" - #define MPC_I2C_CLOCK_LEGACY 0 #define MPC_I2C_CLOCK_PRESERVE (~0U) @@ -89,7 +88,6 @@ struct mpc_i2c { int irq; u32 real_clk; u8 fdr, dfsrr; - struct clk *clk_per; u32 cntl_bits; enum mpc_i2c_action action; struct i2c_msg *msgs; @@ -116,7 +114,7 @@ static inline void writeccr(struct mpc_i2c *i2c, u32 x) writeb(x, i2c->base + MPC_I2C_CR); } -/* Sometimes 9th clock pulse isn't generated, and slave doesn't release +/* Sometimes 9th clock pulse isn't generated, and target doesn't release * the bus, because it wants to send ACK. * Following sequence of enabling/disabling and sending start/stop generates * the 9 pulses, each with a START then ending with STOP, so it's all OK. @@ -305,24 +303,22 @@ static void mpc_i2c_setup_512x(struct device_node *node, struct mpc_i2c *i2c, u32 clock) { - struct device_node *node_ctrl; void __iomem *ctrl; - const u32 *pval; u32 idx; /* Enable I2C interrupts for mpc5121 */ - node_ctrl = of_find_compatible_node(NULL, NULL, - "fsl,mpc5121-i2c-ctrl"); + struct device_node *node_ctrl __free(device_node) = + of_find_compatible_node(NULL, NULL, "fsl,mpc5121-i2c-ctrl"); if (node_ctrl) { ctrl = of_iomap(node_ctrl, 0); if (ctrl) { + u64 addr; /* Interrupt enable bits for i2c-0/1/2: bit 24/26/28 */ - pval = of_get_property(node, "reg", NULL); - idx = (*pval & 0xff) / 0x20; + of_property_read_reg(node, 0, &addr, NULL); + idx = (addr & 0xff) / 0x20; setbits32(ctrl, 1 << (24 + idx * 2)); iounmap(ctrl); } - of_node_put(node_ctrl); } /* The clock setup for the 52xx works also fine for the 512x */ @@ -359,11 +355,11 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_8xxx[] = { static u32 mpc_i2c_get_sec_cfg_8xxx(void) { - struct device_node *node; u32 __iomem *reg; u32 val = 0; - node = of_find_node_by_name(NULL, "global-utilities"); + struct device_node *node __free(device_node) = + of_find_node_by_name(NULL, "global-utilities"); if (node) { const u32 *prop = of_get_property(node, "reg", NULL); if (prop) { @@ -384,7 +380,6 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void) iounmap(reg); } } - of_node_put(node); return val; } @@ -763,14 +758,13 @@ static int fsl_i2c_bus_recovery(struct i2c_adapter *adap) } static const struct i2c_algorithm mpc_algo = { - .master_xfer = mpc_xfer, + .xfer = mpc_xfer, .functionality = mpc_functionality, }; static struct i2c_adapter mpc_ops = { .owner = THIS_MODULE, .algo = &mpc_algo, - .timeout = HZ, }; static struct i2c_bus_recovery_info fsl_i2c_recovery_info = { @@ -781,12 +775,9 @@ static int fsl_i2c_probe(struct platform_device *op) { const struct mpc_i2c_data *data; struct mpc_i2c *i2c; - const u32 *prop; - u32 clock = MPC_I2C_CLOCK_LEGACY; - int result = 0; - int plen; struct clk *clk; - int err; + int result; + u32 clock; i2c = devm_kzalloc(&op->dev, sizeof(*i2c), GFP_KERNEL); if (!i2c) @@ -816,25 +807,19 @@ static int fsl_i2c_probe(struct platform_device *op) * enable clock for the I2C peripheral (non fatal), * keep a reference upon successful allocation */ - clk = devm_clk_get_optional(&op->dev, NULL); - if (IS_ERR(clk)) - return PTR_ERR(clk); - - err = clk_prepare_enable(clk); - if (err) { + clk = devm_clk_get_optional_enabled(&op->dev, NULL); + if (IS_ERR(clk)) { dev_err(&op->dev, "failed to enable clock\n"); - return err; + return PTR_ERR(clk); } - i2c->clk_per = clk; - if (of_property_read_bool(op->dev.of_node, "fsl,preserve-clocking")) { clock = MPC_I2C_CLOCK_PRESERVE; } else { - prop = of_get_property(op->dev.of_node, "clock-frequency", - &plen); - if (prop && plen == sizeof(u32)) - clock = *prop; + result = of_property_read_u32(op->dev.of_node, + "clock-frequency", &clock); + if (result) + clock = MPC_I2C_CLOCK_LEGACY; } data = device_get_match_data(&op->dev); @@ -842,16 +827,30 @@ static int fsl_i2c_probe(struct platform_device *op) data->setup(op->dev.of_node, i2c, clock); } else { /* Backwards compatibility */ - if (of_get_property(op->dev.of_node, "dfsrr", NULL)) + if (of_property_read_bool(op->dev.of_node, "dfsrr")) mpc_i2c_setup_8xxx(op->dev.of_node, i2c, clock); } - prop = of_get_property(op->dev.of_node, "fsl,timeout", &plen); - if (prop && plen == sizeof(u32)) { - mpc_ops.timeout = *prop * HZ / 1000000; + /* Sadly, we have to support two deprecated bindings here */ + result = of_property_read_u32(op->dev.of_node, + "i2c-transfer-timeout-us", + &mpc_ops.timeout); + if (result == -EINVAL) + result = of_property_read_u32(op->dev.of_node, + "i2c-scl-clk-low-timeout-us", + &mpc_ops.timeout); + if (result == -EINVAL) + result = of_property_read_u32(op->dev.of_node, + "fsl,timeout", &mpc_ops.timeout); + + if (!result) { + mpc_ops.timeout *= HZ / 1000000; if (mpc_ops.timeout < 5) mpc_ops.timeout = 5; + } else { + mpc_ops.timeout = HZ; } + dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1000000 / HZ); if (of_property_read_bool(op->dev.of_node, "fsl,i2c-erratum-a004447")) @@ -869,25 +868,16 @@ static int fsl_i2c_probe(struct platform_device *op) result = i2c_add_numbered_adapter(&i2c->adap); if (result) - goto fail_add; + return result; return 0; - - fail_add: - clk_disable_unprepare(i2c->clk_per); - - return result; }; -static int fsl_i2c_remove(struct platform_device *op) +static void fsl_i2c_remove(struct platform_device *op) { struct mpc_i2c *i2c = platform_get_drvdata(op); i2c_del_adapter(&i2c->adap); - - clk_disable_unprepare(i2c->clk_per); - - return 0; }; static int __maybe_unused mpc_i2c_suspend(struct device *dev) @@ -950,7 +940,7 @@ static struct platform_driver mpc_i2c_driver = { .probe = fsl_i2c_probe, .remove = fsl_i2c_remove, .driver = { - .name = DRV_NAME, + .name = "mpc-i2c", .of_match_table = mpc_i2c_of_match, .pm = &mpc_i2c_pm_ops, }, diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c index d80e59340d97..aefdbee1f03c 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -19,9 +19,7 @@ #include <linux/kernel.h> #include <linux/mm.h> #include <linux/module.h> -#include <linux/of_address.h> -#include <linux/of_device.h> -#include <linux/of_irq.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/scatterlist.h> #include <linux/sched.h> @@ -431,6 +429,18 @@ static const struct mtk_i2c_compatible mt8168_compat = { .max_dma_support = 33, }; +static const struct mtk_i2c_compatible mt7981_compat = { + .regs = mt_i2c_regs_v3, + .pmic_i2c = 0, + .dcm = 0, + .auto_restart = 1, + .aux_len_reg = 1, + .timing_adjust = 1, + .dma_sync = 1, + .ltiming_adjust = 1, + .max_dma_support = 33 +}; + static const struct mtk_i2c_compatible mt7986_compat = { .quirks = &mt7622_i2c_quirks, .regs = mt_i2c_regs_v1, @@ -516,6 +526,7 @@ static const struct of_device_id mtk_i2c_of_match[] = { { .compatible = "mediatek,mt6577-i2c", .data = &mt6577_compat }, { .compatible = "mediatek,mt6589-i2c", .data = &mt6589_compat }, { .compatible = "mediatek,mt7622-i2c", .data = &mt7622_compat }, + { .compatible = "mediatek,mt7981-i2c", .data = &mt7981_compat }, { .compatible = "mediatek,mt7986-i2c", .data = &mt7986_compat }, { .compatible = "mediatek,mt8168-i2c", .data = &mt8168_compat }, { .compatible = "mediatek,mt8173-i2c", .data = &mt8173_compat }, @@ -857,7 +868,7 @@ static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src, return 0; } -static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk) +static void mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk) { unsigned int clk_src; unsigned int step_cnt; @@ -927,9 +938,6 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk) break; } - - - return 0; } static void i2c_dump_register(struct mtk_i2c *i2c) @@ -1232,6 +1240,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap, { int ret; int left_num = num; + bool write_then_read_en = false; struct mtk_i2c *i2c = i2c_get_adapdata(adap); ret = clk_bulk_enable(I2C_MT65XX_CLK_MAX, i2c->clocks); @@ -1245,6 +1254,7 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap, if (!(msgs[0].flags & I2C_M_RD) && (msgs[1].flags & I2C_M_RD) && msgs[0].addr == msgs[1].addr) { i2c->auto_restart = 0; + write_then_read_en = true; } } @@ -1269,12 +1279,10 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap, else i2c->op = I2C_MASTER_WR; - if (!i2c->auto_restart) { - if (num > 1) { - /* combined two messages into one transaction */ - i2c->op = I2C_MASTER_WRRD; - left_num--; - } + if (write_then_read_en) { + /* combined two messages into one transaction */ + i2c->op = I2C_MASTER_WRRD; + left_num--; } /* always use DMA mode. */ @@ -1282,7 +1290,10 @@ static int mtk_i2c_transfer(struct i2c_adapter *adap, if (ret < 0) goto err_exit; - msgs++; + if (i2c->op == I2C_MASTER_WRRD) + msgs += 2; + else + msgs++; } /* the return value is number of executed messages */ ret = num; @@ -1295,12 +1306,9 @@ err_exit: static irqreturn_t mtk_i2c_irq(int irqno, void *dev_id) { struct mtk_i2c *i2c = dev_id; - u16 restart_flag = 0; + u16 restart_flag = i2c->auto_restart ? I2C_RS_TRANSFER : 0; u16 intr_stat; - if (i2c->auto_restart) - restart_flag = I2C_RS_TRANSFER; - intr_stat = mtk_i2c_readw(i2c, OFFSET_INTR_STAT); mtk_i2c_writew(i2c, intr_stat, OFFSET_INTR_STAT); @@ -1334,7 +1342,7 @@ static u32 mtk_i2c_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm mtk_i2c_algorithm = { - .master_xfer = mtk_i2c_transfer, + .xfer = mtk_i2c_transfer, .functionality = mtk_i2c_functionality, }; @@ -1366,20 +1374,17 @@ static int mtk_i2c_probe(struct platform_device *pdev) { int ret = 0; struct mtk_i2c *i2c; - struct resource *res; int i, irq, speed_clk; i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); if (!i2c) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2c->base = devm_ioremap_resource(&pdev->dev, res); + i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); if (IS_ERR(i2c->base)) return PTR_ERR(i2c->base); - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - i2c->pdmabase = devm_ioremap_resource(&pdev->dev, res); + i2c->pdmabase = devm_platform_get_and_ioremap_resource(pdev, 1, NULL); if (IS_ERR(i2c->pdmabase)) return PTR_ERR(i2c->pdmabase); @@ -1434,25 +1439,25 @@ static int mtk_i2c_probe(struct platform_device *pdev) if (IS_ERR(i2c->clocks[I2C_MT65XX_CLK_ARB].clk)) return PTR_ERR(i2c->clocks[I2C_MT65XX_CLK_ARB].clk); + i2c->clocks[I2C_MT65XX_CLK_PMIC].clk = devm_clk_get_optional(&pdev->dev, "pmic"); + if (IS_ERR(i2c->clocks[I2C_MT65XX_CLK_PMIC].clk)) { + dev_err(&pdev->dev, "cannot get pmic clock\n"); + return PTR_ERR(i2c->clocks[I2C_MT65XX_CLK_PMIC].clk); + } + if (i2c->have_pmic) { - i2c->clocks[I2C_MT65XX_CLK_PMIC].clk = devm_clk_get(&pdev->dev, "pmic"); - if (IS_ERR(i2c->clocks[I2C_MT65XX_CLK_PMIC].clk)) { + if (!i2c->clocks[I2C_MT65XX_CLK_PMIC].clk) { dev_err(&pdev->dev, "cannot get pmic clock\n"); - return PTR_ERR(i2c->clocks[I2C_MT65XX_CLK_PMIC].clk); + return -ENODEV; } speed_clk = I2C_MT65XX_CLK_PMIC; } else { - i2c->clocks[I2C_MT65XX_CLK_PMIC].clk = NULL; speed_clk = I2C_MT65XX_CLK_MAIN; } strscpy(i2c->adap.name, I2C_DRV_NAME, sizeof(i2c->adap.name)); - ret = mtk_i2c_set_speed(i2c, clk_get_rate(i2c->clocks[speed_clk].clk)); - if (ret) { - dev_err(&pdev->dev, "Failed to set the speed.\n"); - return -EINVAL; - } + mtk_i2c_set_speed(i2c, clk_get_rate(i2c->clocks[speed_clk].clk)); if (i2c->dev_comp->max_dma_support > 32) { ret = dma_set_mask(&pdev->dev, @@ -1495,18 +1500,15 @@ err_bulk_unprepare: return ret; } -static int mtk_i2c_remove(struct platform_device *pdev) +static void mtk_i2c_remove(struct platform_device *pdev) { struct mtk_i2c *i2c = platform_get_drvdata(pdev); i2c_del_adapter(&i2c->adap); clk_bulk_unprepare(I2C_MT65XX_CLK_MAX, i2c->clocks); - - return 0; } -#ifdef CONFIG_PM_SLEEP static int mtk_i2c_suspend_noirq(struct device *dev) { struct mtk_i2c *i2c = dev_get_drvdata(dev); @@ -1536,11 +1538,10 @@ static int mtk_i2c_resume_noirq(struct device *dev) return 0; } -#endif static const struct dev_pm_ops mtk_i2c_pm = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_i2c_suspend_noirq, - mtk_i2c_resume_noirq) + NOIRQ_SYSTEM_SLEEP_PM_OPS(mtk_i2c_suspend_noirq, + mtk_i2c_resume_noirq) }; static struct platform_driver mtk_i2c_driver = { @@ -1548,8 +1549,8 @@ static struct platform_driver mtk_i2c_driver = { .remove = mtk_i2c_remove, .driver = { .name = I2C_DRV_NAME, - .pm = &mtk_i2c_pm, - .of_match_table = of_match_ptr(mtk_i2c_of_match), + .pm = pm_sleep_ptr(&mtk_i2c_pm), + .of_match_table = mtk_i2c_of_match, }, }; diff --git a/drivers/i2c/busses/i2c-mt7621.c b/drivers/i2c/busses/i2c-mt7621.c index 20eda5738ac4..0a288c998419 100644 --- a/drivers/i2c/busses/i2c-mt7621.c +++ b/drivers/i2c/busses/i2c-mt7621.c @@ -16,7 +16,8 @@ #include <linux/io.h> #include <linux/iopoll.h> #include <linux/module.h> -#include <linux/of_platform.h> +#include <linux/of.h> +#include <linux/platform_device.h> #include <linux/reset.h> #define REG_SM0CFG2_REG 0x28 @@ -116,27 +117,27 @@ static int mtk_i2c_check_ack(struct mtk_i2c *i2c, u32 expected) return ((ack & ack_expected) == ack_expected) ? 0 : -ENXIO; } -static int mtk_i2c_master_start(struct mtk_i2c *i2c) +static int mtk_i2c_start(struct mtk_i2c *i2c) { iowrite32(SM0CTL1_START | SM0CTL1_TRI, i2c->base + REG_SM0CTL1_REG); return mtk_i2c_wait_idle(i2c); } -static int mtk_i2c_master_stop(struct mtk_i2c *i2c) +static int mtk_i2c_stop(struct mtk_i2c *i2c) { iowrite32(SM0CTL1_STOP | SM0CTL1_TRI, i2c->base + REG_SM0CTL1_REG); return mtk_i2c_wait_idle(i2c); } -static int mtk_i2c_master_cmd(struct mtk_i2c *i2c, u32 cmd, int page_len) +static int mtk_i2c_cmd(struct mtk_i2c *i2c, u32 cmd, int page_len) { iowrite32(cmd | SM0CTL1_TRI | SM0CTL1_PGLEN(page_len), i2c->base + REG_SM0CTL1_REG); return mtk_i2c_wait_idle(i2c); } -static int mtk_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num) +static int mtk_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) { struct mtk_i2c *i2c; struct i2c_msg *pmsg; @@ -156,29 +157,25 @@ static int mtk_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, goto err_timeout; /* start sequence */ - ret = mtk_i2c_master_start(i2c); + ret = mtk_i2c_start(i2c); if (ret) goto err_timeout; /* write address */ if (pmsg->flags & I2C_M_TEN) { /* 10 bits address */ - addr = 0xf0 | ((pmsg->addr >> 7) & 0x06); - addr |= (pmsg->addr & 0xff) << 8; - if (pmsg->flags & I2C_M_RD) - addr |= 1; - iowrite32(addr, i2c->base + REG_SM0D0_REG); - ret = mtk_i2c_master_cmd(i2c, SM0CTL1_WRITE, 2); - if (ret) - goto err_timeout; + addr = i2c_10bit_addr_hi_from_msg(pmsg); + addr |= i2c_10bit_addr_lo_from_msg(pmsg) << 8; + len = 2; } else { /* 7 bits address */ addr = i2c_8bit_addr_from_msg(pmsg); - iowrite32(addr, i2c->base + REG_SM0D0_REG); - ret = mtk_i2c_master_cmd(i2c, SM0CTL1_WRITE, 1); - if (ret) - goto err_timeout; + len = 1; } + iowrite32(addr, i2c->base + REG_SM0D0_REG); + ret = mtk_i2c_cmd(i2c, SM0CTL1_WRITE, len); + if (ret) + goto err_timeout; /* check address ACK */ if (!(pmsg->flags & I2C_M_IGNORE_NAK)) { @@ -201,7 +198,7 @@ static int mtk_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, cmd = SM0CTL1_WRITE; } - ret = mtk_i2c_master_cmd(i2c, cmd, page_len); + ret = mtk_i2c_cmd(i2c, cmd, page_len); if (ret) goto err_timeout; @@ -221,7 +218,7 @@ static int mtk_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } } - ret = mtk_i2c_master_stop(i2c); + ret = mtk_i2c_stop(i2c); if (ret) goto err_timeout; @@ -229,7 +226,7 @@ static int mtk_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, return i; err_ack: - ret = mtk_i2c_master_stop(i2c); + ret = mtk_i2c_stop(i2c); if (ret) goto err_timeout; return -ENXIO; @@ -246,8 +243,8 @@ static u32 mtk_i2c_func(struct i2c_adapter *a) } static const struct i2c_algorithm mtk_i2c_algo = { - .master_xfer = mtk_i2c_master_xfer, - .functionality = mtk_i2c_func, + .xfer = mtk_i2c_xfer, + .functionality = mtk_i2c_func, }; static const struct of_device_id i2c_mtk_dt_ids[] = { @@ -282,16 +279,11 @@ static int mtk_i2c_probe(struct platform_device *pdev) if (IS_ERR(i2c->base)) return PTR_ERR(i2c->base); - i2c->clk = devm_clk_get(&pdev->dev, NULL); + i2c->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(i2c->clk)) { - dev_err(&pdev->dev, "no clock defined\n"); + dev_err(&pdev->dev, "Failed to enable clock\n"); return PTR_ERR(i2c->clk); } - ret = clk_prepare_enable(i2c->clk); - if (ret) { - dev_err(&pdev->dev, "Unable to enable clock\n"); - return ret; - } i2c->dev = &pdev->dev; @@ -301,8 +293,7 @@ static int mtk_i2c_probe(struct platform_device *pdev) if (i2c->bus_freq == 0) { dev_warn(i2c->dev, "clock-frequency 0 not supported\n"); - ret = -EINVAL; - goto err_disable_clk; + return -EINVAL; } adap = &i2c->adap; @@ -320,26 +311,18 @@ static int mtk_i2c_probe(struct platform_device *pdev) ret = i2c_add_adapter(adap); if (ret < 0) - goto err_disable_clk; + return ret; dev_info(&pdev->dev, "clock %u kHz\n", i2c->bus_freq / 1000); return 0; - -err_disable_clk: - clk_disable_unprepare(i2c->clk); - - return ret; } -static int mtk_i2c_remove(struct platform_device *pdev) +static void mtk_i2c_remove(struct platform_device *pdev) { struct mtk_i2c *i2c = platform_get_drvdata(pdev); - clk_disable_unprepare(i2c->clk); i2c_del_adapter(&i2c->adap); - - return 0; } static struct platform_driver mtk_i2c_driver = { diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 047dfef7a657..1acba628e16c 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -19,16 +19,14 @@ #include <linux/platform_device.h> #include <linux/pinctrl/consumer.h> #include <linux/pm_runtime.h> +#include <linux/property.h> #include <linux/reset.h> #include <linux/io.h> #include <linux/of.h> -#include <linux/of_device.h> -#include <linux/of_irq.h> #include <linux/clk.h> #include <linux/err.h> #include <linux/delay.h> -#define MV64XXX_I2C_ADDR_ADDR(val) ((val & 0x7f) << 1) #define MV64XXX_I2C_BAUD_DIV_N(val) (val & 0x7) #define MV64XXX_I2C_BAUD_DIV_M(val) ((val & 0xf) << 3) @@ -90,8 +88,8 @@ enum { MV64XXX_I2C_STATE_WAITING_FOR_RESTART, MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK, MV64XXX_I2C_STATE_WAITING_FOR_ADDR_2_ACK, - MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK, - MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA, + MV64XXX_I2C_STATE_WAITING_FOR_TARGET_ACK, + MV64XXX_I2C_STATE_WAITING_FOR_TARGET_DATA, }; /* Driver actions */ @@ -177,22 +175,17 @@ static void mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg) { - u32 dir = 0; - drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK | MV64XXX_I2C_REG_CONTROL_TWSIEN; if (!drv_data->atomic) drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_INTEN; - if (msg->flags & I2C_M_RD) - dir = 1; - if (msg->flags & I2C_M_TEN) { - drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir; - drv_data->addr2 = (u32)msg->addr & 0xff; + drv_data->addr1 = i2c_10bit_addr_hi_from_msg(msg); + drv_data->addr2 = i2c_10bit_addr_lo_from_msg(msg); } else { - drv_data->addr1 = MV64XXX_I2C_ADDR_ADDR((u32)msg->addr) | dir; + drv_data->addr1 = i2c_8bit_addr_from_msg(msg); drv_data->addr2 = 0; } } @@ -280,7 +273,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) } else { drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; drv_data->state = - MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK; + MV64XXX_I2C_STATE_WAITING_FOR_TARGET_ACK; drv_data->bytes_left--; } break; @@ -308,7 +301,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) drv_data->action = MV64XXX_I2C_ACTION_RCV_DATA; drv_data->bytes_left--; } - drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA; + drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_TARGET_DATA; if ((drv_data->bytes_left == 1) || drv_data->aborting) drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_ACK; @@ -520,6 +513,17 @@ mv64xxx_i2c_intr(int irq, void *dev_id) while (readl(drv_data->reg_base + drv_data->reg_offsets.control) & MV64XXX_I2C_REG_CONTROL_IFLG) { + /* + * It seems that sometime the controller updates the status + * register only after it asserts IFLG in control register. + * This may result in weird bugs when in atomic mode. A delay + * of 100 ns before reading the status register solves this + * issue. This bug does not seem to appear when using + * interrupts. + */ + if (drv_data->atomic) + ndelay(100); + status = readl(drv_data->reg_base + drv_data->reg_offsets.status); mv64xxx_i2c_fsm(drv_data, status); mv64xxx_i2c_do_action(drv_data); @@ -762,7 +766,6 @@ mv64xxx_i2c_xfer_core(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) drv_data->num_msgs = 0; drv_data->msgs = NULL; - pm_runtime_mark_last_busy(&adap->dev); pm_runtime_put_autosuspend(&adap->dev); return ret; @@ -787,8 +790,8 @@ static int mv64xxx_i2c_xfer_atomic(struct i2c_adapter *adap, } static const struct i2c_algorithm mv64xxx_i2c_algo = { - .master_xfer = mv64xxx_i2c_xfer, - .master_xfer_atomic = mv64xxx_i2c_xfer_atomic, + .xfer = mv64xxx_i2c_xfer, + .xfer_atomic = mv64xxx_i2c_xfer_atomic, .functionality = mv64xxx_i2c_functionality, }; @@ -848,7 +851,7 @@ static int mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, struct device *dev) { - const struct of_device_id *device; + const struct mv64xxx_i2c_regs *data; struct device_node *np = dev->of_node; u32 bus_freq, tclk; int rc = 0; @@ -886,11 +889,11 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, */ drv_data->adapter.timeout = HZ; - device = of_match_device(mv64xxx_i2c_of_match_table, dev); - if (!device) + data = device_get_match_data(dev); + if (!data) return -ENODEV; - memcpy(&drv_data->reg_offsets, device->data, sizeof(drv_data->reg_offsets)); + memcpy(&drv_data->reg_offsets, data, sizeof(drv_data->reg_offsets)); /* * For controllers embedded in new SoCs activate the @@ -1073,7 +1076,7 @@ exit_disable_pm: return rc; } -static int +static void mv64xxx_i2c_remove(struct platform_device *pd) { struct mv64xxx_i2c_data *drv_data = platform_get_drvdata(pd); @@ -1083,8 +1086,6 @@ mv64xxx_i2c_remove(struct platform_device *pd) pm_runtime_disable(&pd->dev); if (!pm_runtime_status_suspended(&pd->dev)) mv64xxx_i2c_runtime_suspend(&pd->dev); - - return 0; } static const struct dev_pm_ops mv64xxx_i2c_pm_ops = { @@ -1096,7 +1097,7 @@ static const struct dev_pm_ops mv64xxx_i2c_pm_ops = { static struct platform_driver mv64xxx_i2c_driver = { .probe = mv64xxx_i2c_probe, - .remove = mv64xxx_i2c_remove, + .remove = mv64xxx_i2c_remove, .driver = { .name = MV64XXX_I2C_CTLR_NAME, .pm = &mv64xxx_i2c_pm_ops, diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index d113bed79545..08c9091a1e35 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -22,7 +22,6 @@ #include <linux/io.h> #include <linux/stmp_device.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/dma-mapping.h> #include <linux/dmaengine.h> #include <linux/dma/mxs-dma.h> @@ -171,7 +170,7 @@ static void mxs_i2c_dma_irq_callback(void *param) } static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, - struct i2c_msg *msg, uint32_t flags) + struct i2c_msg *msg, u8 *buf, uint32_t flags) { struct dma_async_tx_descriptor *desc; struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap); @@ -226,7 +225,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, } /* Queue the DMA data transfer. */ - sg_init_one(&i2c->sg_io[1], msg->buf, msg->len); + sg_init_one(&i2c->sg_io[1], buf, msg->len); dma_map_sg(i2c->dev, &i2c->sg_io[1], 1, DMA_FROM_DEVICE); desc = dmaengine_prep_slave_sg(i2c->dmach, &i2c->sg_io[1], 1, DMA_DEV_TO_MEM, @@ -259,7 +258,7 @@ static int mxs_i2c_dma_setup_xfer(struct i2c_adapter *adap, /* Queue the DMA data transfer. */ sg_init_table(i2c->sg_io, 2); sg_set_buf(&i2c->sg_io[0], &i2c->addr_data, 1); - sg_set_buf(&i2c->sg_io[1], msg->buf, msg->len); + sg_set_buf(&i2c->sg_io[1], buf, msg->len); dma_map_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); desc = dmaengine_prep_slave_sg(i2c->dmach, i2c->sg_io, 2, DMA_MEM_TO_DEV, @@ -563,6 +562,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, struct mxs_i2c_dev *i2c = i2c_get_adapdata(adap); int ret; int flags; + u8 *dma_buf; int use_pio = 0; unsigned long time_left; @@ -588,13 +588,20 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, if (ret && (ret != -ENXIO)) mxs_i2c_reset(i2c); } else { + dma_buf = i2c_get_dma_safe_msg_buf(msg, 1); + if (!dma_buf) + return -ENOMEM; + reinit_completion(&i2c->cmd_complete); - ret = mxs_i2c_dma_setup_xfer(adap, msg, flags); - if (ret) + ret = mxs_i2c_dma_setup_xfer(adap, msg, dma_buf, flags); + if (ret) { + i2c_put_dma_safe_msg_buf(dma_buf, msg, false); return ret; + } time_left = wait_for_completion_timeout(&i2c->cmd_complete, msecs_to_jiffies(1000)); + i2c_put_dma_safe_msg_buf(dma_buf, msg, true); if (!time_left) goto timeout; @@ -680,7 +687,7 @@ static irqreturn_t mxs_i2c_isr(int this_irq, void *dev_id) } static const struct i2c_algorithm mxs_i2c_algo = { - .master_xfer = mxs_i2c_xfer, + .xfer = mxs_i2c_xfer, .functionality = mxs_i2c_func, }; @@ -856,7 +863,7 @@ static int mxs_i2c_probe(struct platform_device *pdev) return 0; } -static int mxs_i2c_remove(struct platform_device *pdev) +static void mxs_i2c_remove(struct platform_device *pdev) { struct mxs_i2c_dev *i2c = platform_get_drvdata(pdev); @@ -866,8 +873,6 @@ static int mxs_i2c_remove(struct platform_device *pdev) dma_release_channel(i2c->dmach); writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET); - - return 0; } static struct platform_driver mxs_i2c_driver = { diff --git a/drivers/i2c/busses/i2c-nct6694.c b/drivers/i2c/busses/i2c-nct6694.c new file mode 100644 index 000000000000..1413ab6f9462 --- /dev/null +++ b/drivers/i2c/busses/i2c-nct6694.c @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Nuvoton NCT6694 I2C adapter driver based on USB interface. + * + * Copyright (C) 2025 Nuvoton Technology Corp. + */ + +#include <linux/i2c.h> +#include <linux/idr.h> +#include <linux/kernel.h> +#include <linux/mfd/nct6694.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +/* + * USB command module type for NCT6694 I2C controller. + * This defines the module type used for communication with the NCT6694 + * I2C controller over the USB interface. + */ +#define NCT6694_I2C_MOD 0x03 + +/* Command 00h - I2C Deliver */ +#define NCT6694_I2C_DELIVER 0x00 +#define NCT6694_I2C_DELIVER_SEL 0x00 + +#define NCT6694_I2C_MAX_XFER_SIZE 64 +#define NCT6694_I2C_MAX_DEVS 6 + +static unsigned char br_reg[NCT6694_I2C_MAX_DEVS] = {[0 ... (NCT6694_I2C_MAX_DEVS - 1)] = 0xFF}; + +module_param_array(br_reg, byte, NULL, 0644); +MODULE_PARM_DESC(br_reg, + "I2C Baudrate register per adapter: (0=25K, 1=50K, 2=100K, 3=200K, 4=400K, 5=800K, 6=1M), default=2"); + +enum nct6694_i2c_baudrate { + NCT6694_I2C_BR_25K = 0, + NCT6694_I2C_BR_50K, + NCT6694_I2C_BR_100K, + NCT6694_I2C_BR_200K, + NCT6694_I2C_BR_400K, + NCT6694_I2C_BR_800K, + NCT6694_I2C_BR_1M +}; + +struct __packed nct6694_i2c_deliver { + u8 port; + u8 br; + u8 addr; + u8 w_cnt; + u8 r_cnt; + u8 rsv[11]; + u8 write_data[NCT6694_I2C_MAX_XFER_SIZE]; + u8 read_data[NCT6694_I2C_MAX_XFER_SIZE]; +}; + +struct nct6694_i2c_data { + struct device *dev; + struct nct6694 *nct6694; + struct i2c_adapter adapter; + struct nct6694_i2c_deliver deliver; + unsigned char port; + unsigned char br; +}; + +static int nct6694_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct nct6694_i2c_data *data = adap->algo_data; + struct nct6694_i2c_deliver *deliver = &data->deliver; + static const struct nct6694_cmd_header cmd_hd = { + .mod = NCT6694_I2C_MOD, + .cmd = NCT6694_I2C_DELIVER, + .sel = NCT6694_I2C_DELIVER_SEL, + .len = cpu_to_le16(sizeof(*deliver)) + }; + int ret, i; + + for (i = 0; i < num; i++) { + struct i2c_msg *msg_temp = &msgs[i]; + + memset(deliver, 0, sizeof(*deliver)); + + deliver->port = data->port; + deliver->br = data->br; + deliver->addr = i2c_8bit_addr_from_msg(msg_temp); + if (msg_temp->flags & I2C_M_RD) { + deliver->r_cnt = msg_temp->len; + ret = nct6694_write_msg(data->nct6694, &cmd_hd, deliver); + if (ret < 0) + return ret; + + memcpy(msg_temp->buf, deliver->read_data, msg_temp->len); + } else { + deliver->w_cnt = msg_temp->len; + memcpy(deliver->write_data, msg_temp->buf, msg_temp->len); + ret = nct6694_write_msg(data->nct6694, &cmd_hd, deliver); + if (ret < 0) + return ret; + } + } + + return num; +} + +static u32 nct6694_i2c_func(struct i2c_adapter *adapter) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_adapter_quirks nct6694_i2c_quirks = { + .max_read_len = NCT6694_I2C_MAX_XFER_SIZE, + .max_write_len = NCT6694_I2C_MAX_XFER_SIZE, +}; + +static const struct i2c_algorithm nct6694_i2c_algo = { + .xfer = nct6694_i2c_xfer, + .functionality = nct6694_i2c_func, +}; + +static int nct6694_i2c_set_baudrate(struct nct6694_i2c_data *data) +{ + if (data->port >= NCT6694_I2C_MAX_DEVS) { + dev_err(data->dev, "Invalid I2C port index %d\n", data->port); + return -EINVAL; + } + + if (br_reg[data->port] > NCT6694_I2C_BR_1M) { + dev_warn(data->dev, "Invalid baudrate %d for I2C%d, using 100K\n", + br_reg[data->port], data->port); + br_reg[data->port] = NCT6694_I2C_BR_100K; + } + + data->br = br_reg[data->port]; + + return 0; +} + +static void nct6694_i2c_ida_free(void *d) +{ + struct nct6694_i2c_data *data = d; + struct nct6694 *nct6694 = data->nct6694; + + ida_free(&nct6694->i2c_ida, data->port); +} + +static int nct6694_i2c_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct nct6694 *nct6694 = dev_get_drvdata(dev->parent); + struct nct6694_i2c_data *data; + int ret; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->dev = dev; + data->nct6694 = nct6694; + + ret = ida_alloc(&nct6694->i2c_ida, GFP_KERNEL); + if (ret < 0) + return ret; + data->port = ret; + + ret = devm_add_action_or_reset(dev, nct6694_i2c_ida_free, data); + if (ret) + return ret; + + ret = nct6694_i2c_set_baudrate(data); + if (ret) + return ret; + + sprintf(data->adapter.name, "NCT6694 I2C Adapter %d", data->port); + data->adapter.owner = THIS_MODULE; + data->adapter.algo = &nct6694_i2c_algo; + data->adapter.quirks = &nct6694_i2c_quirks; + data->adapter.dev.parent = dev; + data->adapter.algo_data = data; + + platform_set_drvdata(pdev, data); + + return devm_i2c_add_adapter(dev, &data->adapter); +} + +static struct platform_driver nct6694_i2c_driver = { + .driver = { + .name = "nct6694-i2c", + }, + .probe = nct6694_i2c_probe, +}; + +module_platform_driver(nct6694_i2c_driver); + +MODULE_DESCRIPTION("USB-I2C adapter driver for NCT6694"); +MODULE_AUTHOR("Ming Yu <tmyu0@nuvoton.com>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:nct6694-i2c"); diff --git a/drivers/i2c/busses/i2c-nforce2-s4985.c b/drivers/i2c/busses/i2c-nforce2-s4985.c deleted file mode 100644 index 69a71bc9830d..000000000000 --- a/drivers/i2c/busses/i2c-nforce2-s4985.c +++ /dev/null @@ -1,240 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * i2c-nforce2-s4985.c - i2c-nforce2 extras for the Tyan S4985 motherboard - * - * Copyright (C) 2008 Jean Delvare <jdelvare@suse.de> - */ - -/* - * We select the channels by sending commands to the Philips - * PCA9556 chip at I2C address 0x18. The main adapter is used for - * the non-multiplexed part of the bus, and 4 virtual adapters - * are defined for the multiplexed addresses: 0x50-0x53 (memory - * module EEPROM) located on channels 1-4. We define one virtual - * adapter per CPU, which corresponds to one multiplexed channel: - * CPU0: virtual adapter 1, channel 1 - * CPU1: virtual adapter 2, channel 2 - * CPU2: virtual adapter 3, channel 3 - * CPU3: virtual adapter 4, channel 4 - */ - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/i2c.h> -#include <linux/mutex.h> - -extern struct i2c_adapter *nforce2_smbus; - -static struct i2c_adapter *s4985_adapter; -static struct i2c_algorithm *s4985_algo; - -/* Wrapper access functions for multiplexed SMBus */ -static DEFINE_MUTEX(nforce2_lock); - -static s32 nforce2_access_virt0(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data) -{ - int error; - - /* We exclude the multiplexed addresses */ - if ((addr & 0xfc) == 0x50 || (addr & 0xfc) == 0x30 - || addr == 0x18) - return -ENXIO; - - mutex_lock(&nforce2_lock); - error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write, - command, size, data); - mutex_unlock(&nforce2_lock); - - return error; -} - -/* We remember the last used channels combination so as to only switch - channels when it is really needed. This greatly reduces the SMBus - overhead, but also assumes that nobody will be writing to the PCA9556 - in our back. */ -static u8 last_channels; - -static inline s32 nforce2_access_channel(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data, - u8 channels) -{ - int error; - - /* We exclude the non-multiplexed addresses */ - if ((addr & 0xfc) != 0x50 && (addr & 0xfc) != 0x30) - return -ENXIO; - - mutex_lock(&nforce2_lock); - if (last_channels != channels) { - union i2c_smbus_data mplxdata; - mplxdata.byte = channels; - - error = nforce2_smbus->algo->smbus_xfer(adap, 0x18, 0, - I2C_SMBUS_WRITE, 0x01, - I2C_SMBUS_BYTE_DATA, - &mplxdata); - if (error) - goto UNLOCK; - last_channels = channels; - } - error = nforce2_smbus->algo->smbus_xfer(adap, addr, flags, read_write, - command, size, data); - -UNLOCK: - mutex_unlock(&nforce2_lock); - return error; -} - -static s32 nforce2_access_virt1(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data) -{ - /* CPU0: channel 1 enabled */ - return nforce2_access_channel(adap, addr, flags, read_write, command, - size, data, 0x02); -} - -static s32 nforce2_access_virt2(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data) -{ - /* CPU1: channel 2 enabled */ - return nforce2_access_channel(adap, addr, flags, read_write, command, - size, data, 0x04); -} - -static s32 nforce2_access_virt3(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data) -{ - /* CPU2: channel 3 enabled */ - return nforce2_access_channel(adap, addr, flags, read_write, command, - size, data, 0x08); -} - -static s32 nforce2_access_virt4(struct i2c_adapter *adap, u16 addr, - unsigned short flags, char read_write, - u8 command, int size, - union i2c_smbus_data *data) -{ - /* CPU3: channel 4 enabled */ - return nforce2_access_channel(adap, addr, flags, read_write, command, - size, data, 0x10); -} - -static int __init nforce2_s4985_init(void) -{ - int i, error; - union i2c_smbus_data ioconfig; - - if (!nforce2_smbus) - return -ENODEV; - - /* Configure the PCA9556 multiplexer */ - ioconfig.byte = 0x00; /* All I/O to output mode */ - error = i2c_smbus_xfer(nforce2_smbus, 0x18, 0, I2C_SMBUS_WRITE, 0x03, - I2C_SMBUS_BYTE_DATA, &ioconfig); - if (error) { - dev_err(&nforce2_smbus->dev, "PCA9556 configuration failed\n"); - error = -EIO; - goto ERROR0; - } - - /* Unregister physical bus */ - i2c_del_adapter(nforce2_smbus); - - printk(KERN_INFO "Enabling SMBus multiplexing for Tyan S4985\n"); - /* Define the 5 virtual adapters and algorithms structures */ - s4985_adapter = kcalloc(5, sizeof(struct i2c_adapter), GFP_KERNEL); - if (!s4985_adapter) { - error = -ENOMEM; - goto ERROR1; - } - s4985_algo = kcalloc(5, sizeof(struct i2c_algorithm), GFP_KERNEL); - if (!s4985_algo) { - error = -ENOMEM; - goto ERROR2; - } - - /* Fill in the new structures */ - s4985_algo[0] = *(nforce2_smbus->algo); - s4985_algo[0].smbus_xfer = nforce2_access_virt0; - s4985_adapter[0] = *nforce2_smbus; - s4985_adapter[0].algo = s4985_algo; - s4985_adapter[0].dev.parent = nforce2_smbus->dev.parent; - for (i = 1; i < 5; i++) { - s4985_algo[i] = *(nforce2_smbus->algo); - s4985_adapter[i] = *nforce2_smbus; - snprintf(s4985_adapter[i].name, sizeof(s4985_adapter[i].name), - "SMBus nForce2 adapter (CPU%d)", i - 1); - s4985_adapter[i].algo = s4985_algo + i; - s4985_adapter[i].dev.parent = nforce2_smbus->dev.parent; - } - s4985_algo[1].smbus_xfer = nforce2_access_virt1; - s4985_algo[2].smbus_xfer = nforce2_access_virt2; - s4985_algo[3].smbus_xfer = nforce2_access_virt3; - s4985_algo[4].smbus_xfer = nforce2_access_virt4; - - /* Register virtual adapters */ - for (i = 0; i < 5; i++) { - error = i2c_add_adapter(s4985_adapter + i); - if (error) { - printk(KERN_ERR "i2c-nforce2-s4985: " - "Virtual adapter %d registration " - "failed, module not inserted\n", i); - for (i--; i >= 0; i--) - i2c_del_adapter(s4985_adapter + i); - goto ERROR3; - } - } - - return 0; - -ERROR3: - kfree(s4985_algo); - s4985_algo = NULL; -ERROR2: - kfree(s4985_adapter); - s4985_adapter = NULL; -ERROR1: - /* Restore physical bus */ - i2c_add_adapter(nforce2_smbus); -ERROR0: - return error; -} - -static void __exit nforce2_s4985_exit(void) -{ - if (s4985_adapter) { - int i; - - for (i = 0; i < 5; i++) - i2c_del_adapter(s4985_adapter+i); - kfree(s4985_adapter); - s4985_adapter = NULL; - } - kfree(s4985_algo); - s4985_algo = NULL; - - /* Restore physical bus */ - if (i2c_add_adapter(nforce2_smbus)) - printk(KERN_ERR "i2c-nforce2-s4985: " - "Physical bus restoration failed\n"); -} - -MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); -MODULE_DESCRIPTION("S4985 SMBus multiplexing"); -MODULE_LICENSE("GPL"); - -module_init(nforce2_s4985_init); -module_exit(nforce2_s4985_exit); diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 777278386f58..d58a308582e4 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -117,20 +117,6 @@ static const struct dmi_system_id nforce2_dmi_blacklist2[] = { static struct pci_driver nforce2_driver; -/* For multiplexing support, we need a global reference to the 1st - SMBus channel */ -#if IS_ENABLED(CONFIG_I2C_NFORCE2_S4985) -struct i2c_adapter *nforce2_smbus; -EXPORT_SYMBOL_GPL(nforce2_smbus); - -static void nforce2_set_reference(struct i2c_adapter *adap) -{ - nforce2_smbus = adap; -} -#else -static inline void nforce2_set_reference(struct i2c_adapter *adap) { } -#endif - static void nforce2_abort(struct i2c_adapter *adap) { struct nforce2_smbus *smbus = adap->algo_data; @@ -327,8 +313,8 @@ static int nforce2_probe_smb(struct pci_dev *dev, int bar, int alt_reg, /* Older incarnations of the device used non-standard BARs */ u16 iobase; - if (pci_read_config_word(dev, alt_reg, &iobase) - != PCIBIOS_SUCCESSFUL) { + error = pci_read_config_word(dev, alt_reg, &iobase); + if (error != PCIBIOS_SUCCESSFUL) { dev_err(&dev->dev, "Error reading PCI config for %s\n", name); return -EIO; @@ -349,7 +335,7 @@ static int nforce2_probe_smb(struct pci_dev *dev, int bar, int alt_reg, return -EBUSY; } smbus->adapter.owner = THIS_MODULE; - smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + smbus->adapter.class = I2C_CLASS_HWMON; smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; smbus->adapter.dev.parent = &dev->dev; @@ -411,7 +397,6 @@ static int nforce2_probe(struct pci_dev *dev, const struct pci_device_id *id) return -ENODEV; } - nforce2_set_reference(&smbuses[0].adapter); return 0; } @@ -420,7 +405,6 @@ static void nforce2_remove(struct pci_dev *dev) { struct nforce2_smbus *smbuses = pci_get_drvdata(dev); - nforce2_set_reference(NULL); if (smbuses[0].base) { i2c_del_adapter(&smbuses[0].adapter); release_region(smbuses[0].base, smbuses[0].size); diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index a2d12a5b1c34..19b648fc094d 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -6,21 +6,31 @@ * I2C master mode controller driver, used in Nomadik 8815 * and Ux500 platforms. * + * The Mobileye EyeQ5 and EyeQ6H platforms are also supported; they use + * the same Ux500/DB8500 IP block with two quirks: + * - The memory bus only supports 32-bit accesses. + * - (only EyeQ5) A register must be configured for the I2C speed mode; + * it is located in a shared register region called OLB. + * * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> * Author: Sachin Verma <sachin.verma@st.com> */ -#include <linux/init.h> -#include <linux/module.h> #include <linux/amba/bus.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/err.h> +#include <linux/bitfield.h> #include <linux/clk.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/init.h> +#include <linux/interrupt.h> #include <linux/io.h> -#include <linux/pm_runtime.h> +#include <linux/mfd/syscon.h> +#include <linux/module.h> #include <linux/of.h> +#include <linux/of_device.h> #include <linux/pinctrl/consumer.h> +#include <linux/pm_runtime.h> +#include <linux/regmap.h> +#include <linux/slab.h> #define DRIVER_NAME "nmk-i2c" @@ -42,61 +52,63 @@ #define I2C_ICR (0x038) /* Control registers */ -#define I2C_CR_PE (0x1 << 0) /* Peripheral Enable */ -#define I2C_CR_OM (0x3 << 1) /* Operating mode */ -#define I2C_CR_SAM (0x1 << 3) /* Slave addressing mode */ -#define I2C_CR_SM (0x3 << 4) /* Speed mode */ -#define I2C_CR_SGCM (0x1 << 6) /* Slave general call mode */ -#define I2C_CR_FTX (0x1 << 7) /* Flush Transmit */ -#define I2C_CR_FRX (0x1 << 8) /* Flush Receive */ -#define I2C_CR_DMA_TX_EN (0x1 << 9) /* DMA Tx enable */ -#define I2C_CR_DMA_RX_EN (0x1 << 10) /* DMA Rx Enable */ -#define I2C_CR_DMA_SLE (0x1 << 11) /* DMA sync. logic enable */ -#define I2C_CR_LM (0x1 << 12) /* Loopback mode */ -#define I2C_CR_FON (0x3 << 13) /* Filtering on */ -#define I2C_CR_FS (0x3 << 15) /* Force stop enable */ +#define I2C_CR_PE BIT(0) /* Peripheral Enable */ +#define I2C_CR_OM GENMASK(2, 1) /* Operating mode */ +#define I2C_CR_SAM BIT(3) /* Slave addressing mode */ +#define I2C_CR_SM GENMASK(5, 4) /* Speed mode */ +#define I2C_CR_SGCM BIT(6) /* Slave general call mode */ +#define I2C_CR_FTX BIT(7) /* Flush Transmit */ +#define I2C_CR_FRX BIT(8) /* Flush Receive */ +#define I2C_CR_DMA_TX_EN BIT(9) /* DMA Tx enable */ +#define I2C_CR_DMA_RX_EN BIT(10) /* DMA Rx Enable */ +#define I2C_CR_DMA_SLE BIT(11) /* DMA sync. logic enable */ +#define I2C_CR_LM BIT(12) /* Loopback mode */ +#define I2C_CR_FON GENMASK(14, 13) /* Filtering on */ +#define I2C_CR_FS GENMASK(16, 15) /* Force stop enable */ + +/* Slave control register (SCR) */ +#define I2C_SCR_SLSU GENMASK(31, 16) /* Slave data setup time */ /* Master controller (MCR) register */ -#define I2C_MCR_OP (0x1 << 0) /* Operation */ -#define I2C_MCR_A7 (0x7f << 1) /* 7-bit address */ -#define I2C_MCR_EA10 (0x7 << 8) /* 10-bit Extended address */ -#define I2C_MCR_SB (0x1 << 11) /* Extended address */ -#define I2C_MCR_AM (0x3 << 12) /* Address type */ -#define I2C_MCR_STOP (0x1 << 14) /* Stop condition */ -#define I2C_MCR_LENGTH (0x7ff << 15) /* Transaction length */ +#define I2C_MCR_OP BIT(0) /* Operation */ +#define I2C_MCR_A7 GENMASK(7, 1) /* 7-bit address */ +#define I2C_MCR_EA10 GENMASK(10, 8) /* 10-bit Extended address */ +#define I2C_MCR_SB BIT(11) /* Extended address */ +#define I2C_MCR_AM GENMASK(13, 12) /* Address type */ +#define I2C_MCR_STOP BIT(14) /* Stop condition */ +#define I2C_MCR_LENGTH GENMASK(25, 15) /* Transaction length */ /* Status register (SR) */ -#define I2C_SR_OP (0x3 << 0) /* Operation */ -#define I2C_SR_STATUS (0x3 << 2) /* controller status */ -#define I2C_SR_CAUSE (0x7 << 4) /* Abort cause */ -#define I2C_SR_TYPE (0x3 << 7) /* Receive type */ -#define I2C_SR_LENGTH (0x7ff << 9) /* Transfer length */ +#define I2C_SR_OP GENMASK(1, 0) /* Operation */ +#define I2C_SR_STATUS GENMASK(3, 2) /* controller status */ +#define I2C_SR_CAUSE GENMASK(6, 4) /* Abort cause */ +#define I2C_SR_TYPE GENMASK(8, 7) /* Receive type */ +#define I2C_SR_LENGTH GENMASK(19, 9) /* Transfer length */ + +/* Baud-rate counter register (BRCR) */ +#define I2C_BRCR_BRCNT1 GENMASK(31, 16) /* Baud-rate counter 1 */ +#define I2C_BRCR_BRCNT2 GENMASK(15, 0) /* Baud-rate counter 2 */ /* Interrupt mask set/clear (IMSCR) bits */ -#define I2C_IT_TXFE (0x1 << 0) -#define I2C_IT_TXFNE (0x1 << 1) -#define I2C_IT_TXFF (0x1 << 2) -#define I2C_IT_TXFOVR (0x1 << 3) -#define I2C_IT_RXFE (0x1 << 4) -#define I2C_IT_RXFNF (0x1 << 5) -#define I2C_IT_RXFF (0x1 << 6) -#define I2C_IT_RFSR (0x1 << 16) -#define I2C_IT_RFSE (0x1 << 17) -#define I2C_IT_WTSR (0x1 << 18) -#define I2C_IT_MTD (0x1 << 19) -#define I2C_IT_STD (0x1 << 20) -#define I2C_IT_MAL (0x1 << 24) -#define I2C_IT_BERR (0x1 << 25) -#define I2C_IT_MTDWS (0x1 << 28) - -#define GEN_MASK(val, mask, sb) (((val) << (sb)) & (mask)) +#define I2C_IT_TXFE BIT(0) +#define I2C_IT_TXFNE BIT(1) +#define I2C_IT_TXFF BIT(2) +#define I2C_IT_TXFOVR BIT(3) +#define I2C_IT_RXFE BIT(4) +#define I2C_IT_RXFNF BIT(5) +#define I2C_IT_RXFF BIT(6) +#define I2C_IT_RFSR BIT(16) +#define I2C_IT_RFSE BIT(17) +#define I2C_IT_WTSR BIT(18) +#define I2C_IT_MTD BIT(19) +#define I2C_IT_STD BIT(20) +#define I2C_IT_MAL BIT(24) +#define I2C_IT_BERR BIT(25) +#define I2C_IT_MTDWS BIT(28) /* some bits in ICR are reserved */ #define I2C_CLEAR_ALL_INTS 0x131f007f -/* first three msb bits are reserved */ -#define IRQ_MASK(mask) (mask & 0x1fffffff) - /* maximum threshold value */ #define MAX_I2C_FIFO_THRESHOLD 15 @@ -107,6 +119,15 @@ enum i2c_freq_mode { I2C_FREQ_MODE_FAST_PLUS, /* up to 1 Mb/s */ }; +/* Mobileye EyeQ5 offset into a shared register region (called OLB) */ +#define NMK_I2C_EYEQ5_OLB_IOCR2 0x0B8 + +enum i2c_eyeq5_speed { + I2C_EYEQ5_SPEED_FAST, + I2C_EYEQ5_SPEED_FAST_PLUS, + I2C_EYEQ5_SPEED_HIGH_SPEED, +}; + /** * struct i2c_vendor_data - per-vendor variations * @has_mtdws: variant has the MTDWS bit @@ -131,6 +152,12 @@ enum i2c_operation { I2C_READ = 0x01 }; +enum i2c_operating_mode { + I2C_OM_SLAVE, + I2C_OM_MASTER, + I2C_OM_MASTER_OR_SLAVE, +}; + /** * struct i2c_nmk_client - client specific data * @slave_adr: 7-bit slave address @@ -159,11 +186,13 @@ struct i2c_nmk_client { * @clk_freq: clock frequency for the operation mode * @tft: Tx FIFO Threshold in bytes * @rft: Rx FIFO Threshold in bytes - * @timeout: Slave response timeout (ms) + * @timeout_usecs: Slave response timeout * @sm: speed mode * @stop: stop condition. - * @xfer_complete: acknowledge completion for a I2C message. + * @xfer_wq: xfer done wait queue. + * @xfer_done: xfer done boolean. * @result: controller propogated result. + * @has_32b_bus: controller is on a bus that only supports 32-bit accesses. */ struct nmk_i2c_dev { struct i2c_vendor_data *vendor; @@ -176,11 +205,13 @@ struct nmk_i2c_dev { u32 clk_freq; unsigned char tft; unsigned char rft; - int timeout; + u32 timeout_usecs; enum i2c_freq_mode sm; int stop; - struct completion xfer_complete; + struct wait_queue_head xfer_wq; + bool xfer_done; int result; + bool has_32b_bus; }; /* controller's abort causes */ @@ -204,18 +235,36 @@ static inline void i2c_clr_bit(void __iomem *reg, u32 mask) writel(readl(reg) & ~mask, reg); } +static inline u8 nmk_i2c_readb(const struct nmk_i2c_dev *priv, + unsigned long reg) +{ + if (priv->has_32b_bus) + return readl(priv->virtbase + reg); + else + return readb(priv->virtbase + reg); +} + +static inline void nmk_i2c_writeb(const struct nmk_i2c_dev *priv, u32 val, + unsigned long reg) +{ + if (priv->has_32b_bus) + writel(val, priv->virtbase + reg); + else + writeb(val, priv->virtbase + reg); +} + /** * flush_i2c_fifo() - This function flushes the I2C FIFO - * @dev: private data of I2C Driver + * @priv: private data of I2C Driver * * This function flushes the I2C Tx and Rx FIFOs. It returns * 0 on successful flushing of FIFO */ -static int flush_i2c_fifo(struct nmk_i2c_dev *dev) +static int flush_i2c_fifo(struct nmk_i2c_dev *priv) { #define LOOP_ATTEMPTS 10 + ktime_t timeout; int i; - unsigned long timeout; /* * flush the transmit and receive FIFO. The flushing @@ -224,19 +273,19 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev) * bits, until then no one must access Tx, Rx FIFO and * should poll on these bits waiting for the completion. */ - writel((I2C_CR_FTX | I2C_CR_FRX), dev->virtbase + I2C_CR); + writel((I2C_CR_FTX | I2C_CR_FRX), priv->virtbase + I2C_CR); for (i = 0; i < LOOP_ATTEMPTS; i++) { - timeout = jiffies + dev->adap.timeout; + timeout = ktime_add_us(ktime_get(), priv->timeout_usecs); - while (!time_after(jiffies, timeout)) { - if ((readl(dev->virtbase + I2C_CR) & + while (ktime_after(timeout, ktime_get())) { + if ((readl(priv->virtbase + I2C_CR) & (I2C_CR_FTX | I2C_CR_FRX)) == 0) - return 0; + return 0; } } - dev_err(&dev->adev->dev, + dev_err(&priv->adev->dev, "flushing operation timed out giving up after %d attempts", LOOP_ATTEMPTS); @@ -245,120 +294,121 @@ static int flush_i2c_fifo(struct nmk_i2c_dev *dev) /** * disable_all_interrupts() - Disable all interrupts of this I2c Bus - * @dev: private data of I2C Driver + * @priv: private data of I2C Driver */ -static void disable_all_interrupts(struct nmk_i2c_dev *dev) +static void disable_all_interrupts(struct nmk_i2c_dev *priv) { - u32 mask = IRQ_MASK(0); - writel(mask, dev->virtbase + I2C_IMSCR); + writel(0, priv->virtbase + I2C_IMSCR); } /** * clear_all_interrupts() - Clear all interrupts of I2C Controller - * @dev: private data of I2C Driver + * @priv: private data of I2C Driver */ -static void clear_all_interrupts(struct nmk_i2c_dev *dev) +static void clear_all_interrupts(struct nmk_i2c_dev *priv) { - u32 mask; - mask = IRQ_MASK(I2C_CLEAR_ALL_INTS); - writel(mask, dev->virtbase + I2C_ICR); + writel(I2C_CLEAR_ALL_INTS, priv->virtbase + I2C_ICR); } /** * init_hw() - initialize the I2C hardware - * @dev: private data of I2C Driver + * @priv: private data of I2C Driver */ -static int init_hw(struct nmk_i2c_dev *dev) +static int init_hw(struct nmk_i2c_dev *priv) { int stat; - stat = flush_i2c_fifo(dev); + stat = flush_i2c_fifo(priv); if (stat) goto exit; /* disable the controller */ - i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE); + i2c_clr_bit(priv->virtbase + I2C_CR, I2C_CR_PE); - disable_all_interrupts(dev); + disable_all_interrupts(priv); - clear_all_interrupts(dev); + clear_all_interrupts(priv); - dev->cli.operation = I2C_NO_OPERATION; + priv->cli.operation = I2C_NO_OPERATION; exit: return stat; } /* enable peripheral, master mode operation */ -#define DEFAULT_I2C_REG_CR ((1 << 1) | I2C_CR_PE) +#define DEFAULT_I2C_REG_CR (FIELD_PREP(I2C_CR_OM, I2C_OM_MASTER) | I2C_CR_PE) + +/* grab top three bits from extended I2C addresses */ +#define ADR_3MSB_BITS GENMASK(9, 7) /** * load_i2c_mcr_reg() - load the MCR register - * @dev: private data of controller + * @priv: private data of controller * @flags: message flags */ -static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *dev, u16 flags) +static u32 load_i2c_mcr_reg(struct nmk_i2c_dev *priv, u16 flags) { u32 mcr = 0; unsigned short slave_adr_3msb_bits; - mcr |= GEN_MASK(dev->cli.slave_adr, I2C_MCR_A7, 1); + mcr |= FIELD_PREP(I2C_MCR_A7, priv->cli.slave_adr); if (unlikely(flags & I2C_M_TEN)) { /* 10-bit address transaction */ - mcr |= GEN_MASK(2, I2C_MCR_AM, 12); + mcr |= FIELD_PREP(I2C_MCR_AM, 2); /* * Get the top 3 bits. * EA10 represents extended address in MCR. This includes * the extension (MSB bits) of the 7 bit address loaded * in A7 */ - slave_adr_3msb_bits = (dev->cli.slave_adr >> 7) & 0x7; + slave_adr_3msb_bits = FIELD_GET(ADR_3MSB_BITS, + priv->cli.slave_adr); - mcr |= GEN_MASK(slave_adr_3msb_bits, I2C_MCR_EA10, 8); + mcr |= FIELD_PREP(I2C_MCR_EA10, slave_adr_3msb_bits); } else { /* 7-bit address transaction */ - mcr |= GEN_MASK(1, I2C_MCR_AM, 12); + mcr |= FIELD_PREP(I2C_MCR_AM, 1); } /* start byte procedure not applied */ - mcr |= GEN_MASK(0, I2C_MCR_SB, 11); + mcr |= FIELD_PREP(I2C_MCR_SB, 0); /* check the operation, master read/write? */ - if (dev->cli.operation == I2C_WRITE) - mcr |= GEN_MASK(I2C_WRITE, I2C_MCR_OP, 0); + if (priv->cli.operation == I2C_WRITE) + mcr |= FIELD_PREP(I2C_MCR_OP, I2C_WRITE); else - mcr |= GEN_MASK(I2C_READ, I2C_MCR_OP, 0); + mcr |= FIELD_PREP(I2C_MCR_OP, I2C_READ); /* stop or repeated start? */ - if (dev->stop) - mcr |= GEN_MASK(1, I2C_MCR_STOP, 14); + if (priv->stop) + mcr |= FIELD_PREP(I2C_MCR_STOP, 1); else - mcr &= ~(GEN_MASK(1, I2C_MCR_STOP, 14)); + mcr &= ~FIELD_PREP(I2C_MCR_STOP, 1); - mcr |= GEN_MASK(dev->cli.count, I2C_MCR_LENGTH, 15); + mcr |= FIELD_PREP(I2C_MCR_LENGTH, priv->cli.count); return mcr; } /** * setup_i2c_controller() - setup the controller - * @dev: private data of controller + * @priv: private data of controller */ -static void setup_i2c_controller(struct nmk_i2c_dev *dev) +static void setup_i2c_controller(struct nmk_i2c_dev *priv) { - u32 brcr1, brcr2; + u32 brcr; u32 i2c_clk, div; u32 ns; u16 slsu; - writel(0x0, dev->virtbase + I2C_CR); - writel(0x0, dev->virtbase + I2C_HSMCR); - writel(0x0, dev->virtbase + I2C_TFTR); - writel(0x0, dev->virtbase + I2C_RFTR); - writel(0x0, dev->virtbase + I2C_DMAR); + writel(0x0, priv->virtbase + I2C_CR); + writel(0x0, priv->virtbase + I2C_HSMCR); + writel(0x0, priv->virtbase + I2C_TFTR); + writel(0x0, priv->virtbase + I2C_RFTR); + writel(0x0, priv->virtbase + I2C_DMAR); - i2c_clk = clk_get_rate(dev->clk); + i2c_clk = clk_get_rate(priv->clk); /* * set the slsu: @@ -373,7 +423,7 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) * slsu = cycles / (1000000000 / f) + 1 */ ns = DIV_ROUND_UP_ULL(1000000000ULL, i2c_clk); - switch (dev->sm) { + switch (priv->sm) { case I2C_FREQ_MODE_FAST: case I2C_FREQ_MODE_FAST_PLUS: slsu = DIV_ROUND_UP(100, ns); /* Fast */ @@ -388,154 +438,161 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev) } slsu += 1; - dev_dbg(&dev->adev->dev, "calculated SLSU = %04x\n", slsu); - writel(slsu << 16, dev->virtbase + I2C_SCR); + dev_dbg(&priv->adev->dev, "calculated SLSU = %04x\n", slsu); + writel(FIELD_PREP(I2C_SCR_SLSU, slsu), priv->virtbase + I2C_SCR); /* * The spec says, in case of std. mode the divider is * 2 whereas it is 3 for fast and fastplus mode of - * operation. TODO - high speed support. + * operation. */ - div = (dev->clk_freq > I2C_MAX_STANDARD_MODE_FREQ) ? 3 : 2; + div = (priv->clk_freq > I2C_MAX_STANDARD_MODE_FREQ) ? 3 : 2; /* * generate the mask for baud rate counters. The controller * has two baud rate counters. One is used for High speed * operation, and the other is for std, fast mode, fast mode - * plus operation. Currently we do not supprt high speed mode - * so set brcr1 to 0. + * plus operation. + * + * BRCR is a clock divider amount. Pick highest value that + * leads to rate strictly below target. Eg when asking for + * 400kHz you want a bus rate <=400kHz (and not >=400kHz). */ - brcr1 = 0 << 16; - brcr2 = (i2c_clk/(dev->clk_freq * div)) & 0xffff; + brcr = DIV_ROUND_UP(i2c_clk, priv->clk_freq * div); + + if (priv->sm == I2C_FREQ_MODE_HIGH_SPEED) + brcr = FIELD_PREP(I2C_BRCR_BRCNT1, brcr); + else + brcr = FIELD_PREP(I2C_BRCR_BRCNT2, brcr); /* set the baud rate counter register */ - writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR); + writel(brcr, priv->virtbase + I2C_BRCR); - /* - * set the speed mode. Currently we support - * only standard and fast mode of operation - * TODO - support for fast mode plus (up to 1Mb/s) - * and high speed (up to 3.4 Mb/s) - */ - if (dev->sm > I2C_FREQ_MODE_FAST) { - dev_err(&dev->adev->dev, - "do not support this mode defaulting to std. mode\n"); - brcr2 = i2c_clk / (I2C_MAX_STANDARD_MODE_FREQ * 2) & 0xffff; - writel((brcr1 | brcr2), dev->virtbase + I2C_BRCR); - writel(I2C_FREQ_MODE_STANDARD << 4, - dev->virtbase + I2C_CR); - } - writel(dev->sm << 4, dev->virtbase + I2C_CR); + /* set the speed mode */ + writel(FIELD_PREP(I2C_CR_SM, priv->sm), priv->virtbase + I2C_CR); /* set the Tx and Rx FIFO threshold */ - writel(dev->tft, dev->virtbase + I2C_TFTR); - writel(dev->rft, dev->virtbase + I2C_RFTR); + writel(priv->tft, priv->virtbase + I2C_TFTR); + writel(priv->rft, priv->virtbase + I2C_RFTR); +} + +static bool nmk_i2c_wait_xfer_done(struct nmk_i2c_dev *priv) +{ + if (priv->timeout_usecs < jiffies_to_usecs(1)) { + unsigned long timeout_usecs = priv->timeout_usecs; + ktime_t timeout = ktime_set(0, timeout_usecs * NSEC_PER_USEC); + + wait_event_hrtimeout(priv->xfer_wq, priv->xfer_done, timeout); + } else { + unsigned long timeout = usecs_to_jiffies(priv->timeout_usecs); + + wait_event_timeout(priv->xfer_wq, priv->xfer_done, timeout); + } + + return priv->xfer_done; } /** * read_i2c() - Read from I2C client device - * @dev: private data of I2C Driver + * @priv: private data of I2C Driver * @flags: message flags * * This function reads from i2c client device when controller is in * master mode. There is a completion timeout. If there is no transfer * before timeout error is returned. */ -static int read_i2c(struct nmk_i2c_dev *dev, u16 flags) +static int read_i2c(struct nmk_i2c_dev *priv, u16 flags) { - int status = 0; u32 mcr, irq_mask; - unsigned long timeout; + int status = 0; + bool xfer_done; - mcr = load_i2c_mcr_reg(dev, flags); - writel(mcr, dev->virtbase + I2C_MCR); + mcr = load_i2c_mcr_reg(priv, flags); + writel(mcr, priv->virtbase + I2C_MCR); /* load the current CR value */ - writel(readl(dev->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR, - dev->virtbase + I2C_CR); + writel(readl(priv->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR, + priv->virtbase + I2C_CR); /* enable the controller */ - i2c_set_bit(dev->virtbase + I2C_CR, I2C_CR_PE); + i2c_set_bit(priv->virtbase + I2C_CR, I2C_CR_PE); - init_completion(&dev->xfer_complete); + init_waitqueue_head(&priv->xfer_wq); + priv->xfer_done = false; /* enable interrupts by setting the mask */ irq_mask = (I2C_IT_RXFNF | I2C_IT_RXFF | I2C_IT_MAL | I2C_IT_BERR); - if (dev->stop || !dev->vendor->has_mtdws) + if (priv->stop || !priv->vendor->has_mtdws) irq_mask |= I2C_IT_MTD; else irq_mask |= I2C_IT_MTDWS; - irq_mask = I2C_CLEAR_ALL_INTS & IRQ_MASK(irq_mask); + irq_mask &= I2C_CLEAR_ALL_INTS; - writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask, - dev->virtbase + I2C_IMSCR); + writel(readl(priv->virtbase + I2C_IMSCR) | irq_mask, + priv->virtbase + I2C_IMSCR); - timeout = wait_for_completion_timeout( - &dev->xfer_complete, dev->adap.timeout); + xfer_done = nmk_i2c_wait_xfer_done(priv); - if (timeout == 0) { - /* Controller timed out */ - dev_err(&dev->adev->dev, "read from slave 0x%x timed out\n", - dev->cli.slave_adr); + if (!xfer_done) status = -ETIMEDOUT; - } + return status; } -static void fill_tx_fifo(struct nmk_i2c_dev *dev, int no_bytes) +static void fill_tx_fifo(struct nmk_i2c_dev *priv, int no_bytes) { int count; for (count = (no_bytes - 2); (count > 0) && - (dev->cli.count != 0); + (priv->cli.count != 0); count--) { /* write to the Tx FIFO */ - writeb(*dev->cli.buffer, - dev->virtbase + I2C_TFR); - dev->cli.buffer++; - dev->cli.count--; - dev->cli.xfer_bytes++; + nmk_i2c_writeb(priv, *priv->cli.buffer, I2C_TFR); + priv->cli.buffer++; + priv->cli.count--; + priv->cli.xfer_bytes++; } } /** * write_i2c() - Write data to I2C client. - * @dev: private data of I2C Driver + * @priv: private data of I2C Driver * @flags: message flags * * This function writes data to I2C client */ -static int write_i2c(struct nmk_i2c_dev *dev, u16 flags) +static int write_i2c(struct nmk_i2c_dev *priv, u16 flags) { - u32 status = 0; u32 mcr, irq_mask; - unsigned long timeout; + u32 status = 0; + bool xfer_done; - mcr = load_i2c_mcr_reg(dev, flags); + mcr = load_i2c_mcr_reg(priv, flags); - writel(mcr, dev->virtbase + I2C_MCR); + writel(mcr, priv->virtbase + I2C_MCR); /* load the current CR value */ - writel(readl(dev->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR, - dev->virtbase + I2C_CR); + writel(readl(priv->virtbase + I2C_CR) | DEFAULT_I2C_REG_CR, + priv->virtbase + I2C_CR); /* enable the controller */ - i2c_set_bit(dev->virtbase + I2C_CR, I2C_CR_PE); + i2c_set_bit(priv->virtbase + I2C_CR, I2C_CR_PE); - init_completion(&dev->xfer_complete); + init_waitqueue_head(&priv->xfer_wq); + priv->xfer_done = false; /* enable interrupts by settings the masks */ irq_mask = (I2C_IT_TXFOVR | I2C_IT_MAL | I2C_IT_BERR); /* Fill the TX FIFO with transmit data */ - fill_tx_fifo(dev, MAX_I2C_FIFO_THRESHOLD); + fill_tx_fifo(priv, MAX_I2C_FIFO_THRESHOLD); - if (dev->cli.count != 0) + if (priv->cli.count != 0) irq_mask |= I2C_IT_TXFNE; /* @@ -543,23 +600,22 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags) * set the MTDWS bit (Master Transaction Done Without Stop) * to start repeated start operation */ - if (dev->stop || !dev->vendor->has_mtdws) + if (priv->stop || !priv->vendor->has_mtdws) irq_mask |= I2C_IT_MTD; else irq_mask |= I2C_IT_MTDWS; - irq_mask = I2C_CLEAR_ALL_INTS & IRQ_MASK(irq_mask); + irq_mask &= I2C_CLEAR_ALL_INTS; - writel(readl(dev->virtbase + I2C_IMSCR) | irq_mask, - dev->virtbase + I2C_IMSCR); + writel(readl(priv->virtbase + I2C_IMSCR) | irq_mask, + priv->virtbase + I2C_IMSCR); - timeout = wait_for_completion_timeout( - &dev->xfer_complete, dev->adap.timeout); + xfer_done = nmk_i2c_wait_xfer_done(priv); - if (timeout == 0) { + if (!xfer_done) { /* Controller timed out */ - dev_err(&dev->adev->dev, "write to slave 0x%x timed out\n", - dev->cli.slave_adr); + dev_err(&priv->adev->dev, "write to slave 0x%x timed out\n", + priv->cli.slave_adr); status = -ETIMEDOUT; } @@ -568,44 +624,39 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags) /** * nmk_i2c_xfer_one() - transmit a single I2C message - * @dev: device with a message encoded into it + * @priv: device with a message encoded into it * @flags: message flags */ -static int nmk_i2c_xfer_one(struct nmk_i2c_dev *dev, u16 flags) +static int nmk_i2c_xfer_one(struct nmk_i2c_dev *priv, u16 flags) { int status; if (flags & I2C_M_RD) { /* read operation */ - dev->cli.operation = I2C_READ; - status = read_i2c(dev, flags); + priv->cli.operation = I2C_READ; + status = read_i2c(priv, flags); } else { /* write operation */ - dev->cli.operation = I2C_WRITE; - status = write_i2c(dev, flags); + priv->cli.operation = I2C_WRITE; + status = write_i2c(priv, flags); } - if (status || (dev->result)) { + if (status || priv->result) { u32 i2c_sr; u32 cause; - i2c_sr = readl(dev->virtbase + I2C_SR); - /* - * Check if the controller I2C operation status - * is set to ABORT(11b). - */ - if (((i2c_sr >> 2) & 0x3) == 0x3) { - /* get the abort cause */ - cause = (i2c_sr >> 4) & 0x7; - dev_err(&dev->adev->dev, "%s\n", + i2c_sr = readl(priv->virtbase + I2C_SR); + if (FIELD_GET(I2C_SR_STATUS, i2c_sr) == I2C_ABORT) { + cause = FIELD_GET(I2C_SR_CAUSE, i2c_sr); + dev_err(&priv->adev->dev, "%s\n", cause >= ARRAY_SIZE(abort_causes) ? "unknown reason" : abort_causes[cause]); } - (void) init_hw(dev); + init_hw(priv); - status = status ? status : dev->result; + status = status ? status : priv->result; } return status; @@ -663,24 +714,24 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, { int status = 0; int i; - struct nmk_i2c_dev *dev = i2c_get_adapdata(i2c_adap); + struct nmk_i2c_dev *priv = i2c_get_adapdata(i2c_adap); int j; - pm_runtime_get_sync(&dev->adev->dev); + pm_runtime_get_sync(&priv->adev->dev); /* Attempt three times to send the message queue */ for (j = 0; j < 3; j++) { /* setup the i2c controller */ - setup_i2c_controller(dev); + setup_i2c_controller(priv); for (i = 0; i < num_msgs; i++) { - dev->cli.slave_adr = msgs[i].addr; - dev->cli.buffer = msgs[i].buf; - dev->cli.count = msgs[i].len; - dev->stop = (i < (num_msgs - 1)) ? 0 : 1; - dev->result = 0; + priv->cli.slave_adr = msgs[i].addr; + priv->cli.buffer = msgs[i].buf; + priv->cli.count = msgs[i].len; + priv->stop = (i < (num_msgs - 1)) ? 0 : 1; + priv->result = 0; - status = nmk_i2c_xfer_one(dev, msgs[i].flags); + status = nmk_i2c_xfer_one(priv, msgs[i].flags); if (status != 0) break; } @@ -688,7 +739,7 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, break; } - pm_runtime_put_sync(&dev->adev->dev); + pm_runtime_put_sync(&priv->adev->dev); /* return the no. messages processed */ if (status) @@ -699,14 +750,14 @@ static int nmk_i2c_xfer(struct i2c_adapter *i2c_adap, /** * disable_interrupts() - disable the interrupts - * @dev: private data of controller + * @priv: private data of controller * @irq: interrupt number */ -static int disable_interrupts(struct nmk_i2c_dev *dev, u32 irq) +static int disable_interrupts(struct nmk_i2c_dev *priv, u32 irq) { - irq = IRQ_MASK(irq); - writel(readl(dev->virtbase + I2C_IMSCR) & ~(I2C_CLEAR_ALL_INTS & irq), - dev->virtbase + I2C_IMSCR); + irq &= I2C_CLEAR_ALL_INTS; + writel(readl(priv->virtbase + I2C_IMSCR) & ~irq, + priv->virtbase + I2C_IMSCR); return 0; } @@ -723,38 +774,39 @@ static int disable_interrupts(struct nmk_i2c_dev *dev, u32 irq) */ static irqreturn_t i2c_irq_handler(int irq, void *arg) { - struct nmk_i2c_dev *dev = arg; + struct nmk_i2c_dev *priv = arg; + struct device *dev = &priv->adev->dev; u32 tft, rft; u32 count; u32 misr, src; /* load Tx FIFO and Rx FIFO threshold values */ - tft = readl(dev->virtbase + I2C_TFTR); - rft = readl(dev->virtbase + I2C_RFTR); + tft = readl(priv->virtbase + I2C_TFTR); + rft = readl(priv->virtbase + I2C_RFTR); /* read interrupt status register */ - misr = readl(dev->virtbase + I2C_MISR); + misr = readl(priv->virtbase + I2C_MISR); src = __ffs(misr); - switch ((1 << src)) { + switch (BIT(src)) { /* Transmit FIFO nearly empty interrupt */ case I2C_IT_TXFNE: { - if (dev->cli.operation == I2C_READ) { + if (priv->cli.operation == I2C_READ) { /* * in read operation why do we care for writing? * so disable the Transmit FIFO interrupt */ - disable_interrupts(dev, I2C_IT_TXFNE); + disable_interrupts(priv, I2C_IT_TXFNE); } else { - fill_tx_fifo(dev, (MAX_I2C_FIFO_THRESHOLD - tft)); + fill_tx_fifo(priv, (MAX_I2C_FIFO_THRESHOLD - tft)); /* * if done, close the transfer by disabling the * corresponding TXFNE interrupt */ - if (dev->cli.count == 0) - disable_interrupts(dev, I2C_IT_TXFNE); + if (priv->cli.count == 0) + disable_interrupts(priv, I2C_IT_TXFNE); } } break; @@ -768,60 +820,63 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) case I2C_IT_RXFNF: for (count = rft; count > 0; count--) { /* Read the Rx FIFO */ - *dev->cli.buffer = readb(dev->virtbase + I2C_RFR); - dev->cli.buffer++; + *priv->cli.buffer = nmk_i2c_readb(priv, I2C_RFR); + priv->cli.buffer++; } - dev->cli.count -= rft; - dev->cli.xfer_bytes += rft; + priv->cli.count -= rft; + priv->cli.xfer_bytes += rft; break; /* Rx FIFO full */ case I2C_IT_RXFF: for (count = MAX_I2C_FIFO_THRESHOLD; count > 0; count--) { - *dev->cli.buffer = readb(dev->virtbase + I2C_RFR); - dev->cli.buffer++; + *priv->cli.buffer = nmk_i2c_readb(priv, I2C_RFR); + priv->cli.buffer++; } - dev->cli.count -= MAX_I2C_FIFO_THRESHOLD; - dev->cli.xfer_bytes += MAX_I2C_FIFO_THRESHOLD; + priv->cli.count -= MAX_I2C_FIFO_THRESHOLD; + priv->cli.xfer_bytes += MAX_I2C_FIFO_THRESHOLD; break; /* Master Transaction Done with/without stop */ case I2C_IT_MTD: case I2C_IT_MTDWS: - if (dev->cli.operation == I2C_READ) { - while (!(readl(dev->virtbase + I2C_RISR) + if (priv->cli.operation == I2C_READ) { + while (!(readl(priv->virtbase + I2C_RISR) & I2C_IT_RXFE)) { - if (dev->cli.count == 0) + if (priv->cli.count == 0) break; - *dev->cli.buffer = - readb(dev->virtbase + I2C_RFR); - dev->cli.buffer++; - dev->cli.count--; - dev->cli.xfer_bytes++; + *priv->cli.buffer = + nmk_i2c_readb(priv, I2C_RFR); + priv->cli.buffer++; + priv->cli.count--; + priv->cli.xfer_bytes++; } } - disable_all_interrupts(dev); - clear_all_interrupts(dev); + disable_all_interrupts(priv); + clear_all_interrupts(priv); - if (dev->cli.count) { - dev->result = -EIO; - dev_err(&dev->adev->dev, - "%lu bytes still remain to be xfered\n", - dev->cli.count); - (void) init_hw(dev); + if (priv->cli.count) { + priv->result = -EIO; + dev_err(dev, "%lu bytes still remain to be xfered\n", + priv->cli.count); + init_hw(priv); } - complete(&dev->xfer_complete); + priv->xfer_done = true; + wake_up(&priv->xfer_wq); + break; /* Master Arbitration lost interrupt */ case I2C_IT_MAL: - dev->result = -EIO; - (void) init_hw(dev); + priv->result = -EIO; + init_hw(priv); + + i2c_set_bit(priv->virtbase + I2C_ICR, I2C_IT_MAL); + priv->xfer_done = true; + wake_up(&priv->xfer_wq); - i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_MAL); - complete(&dev->xfer_complete); break; @@ -831,15 +886,20 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) * during the transaction. */ case I2C_IT_BERR: - dev->result = -EIO; - /* get the status */ - if (((readl(dev->virtbase + I2C_SR) >> 2) & 0x3) == I2C_ABORT) - (void) init_hw(dev); + { + u32 sr; - i2c_set_bit(dev->virtbase + I2C_ICR, I2C_IT_BERR); - complete(&dev->xfer_complete); + sr = readl(priv->virtbase + I2C_SR); + priv->result = -EIO; + if (FIELD_GET(I2C_SR_STATUS, sr) == I2C_ABORT) + init_hw(priv); - break; + i2c_set_bit(priv->virtbase + I2C_ICR, I2C_IT_BERR); + priv->xfer_done = true; + wake_up(&priv->xfer_wq); + + } + break; /* * Tx FIFO overrun interrupt. @@ -847,11 +907,13 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) * the Tx FIFO is full. */ case I2C_IT_TXFOVR: - dev->result = -EIO; - (void) init_hw(dev); + priv->result = -EIO; + init_hw(priv); + + dev_err(dev, "Tx Fifo Over run\n"); + priv->xfer_done = true; + wake_up(&priv->xfer_wq); - dev_err(&dev->adev->dev, "Tx Fifo Over run\n"); - complete(&dev->xfer_complete); break; @@ -863,17 +925,16 @@ static irqreturn_t i2c_irq_handler(int irq, void *arg) case I2C_IT_RFSE: case I2C_IT_WTSR: case I2C_IT_STD: - dev_err(&dev->adev->dev, "unhandled Interrupt\n"); + dev_err(dev, "unhandled Interrupt\n"); break; default: - dev_err(&dev->adev->dev, "spurious Interrupt..\n"); + dev_err(dev, "spurious Interrupt..\n"); break; } return IRQ_HANDLED; } -#ifdef CONFIG_PM_SLEEP static int nmk_i2c_suspend_late(struct device *dev) { int ret; @@ -890,15 +951,13 @@ static int nmk_i2c_resume_early(struct device *dev) { return pm_runtime_force_resume(dev); } -#endif -#ifdef CONFIG_PM static int nmk_i2c_runtime_suspend(struct device *dev) { struct amba_device *adev = to_amba_device(dev); - struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev); + struct nmk_i2c_dev *priv = amba_get_drvdata(adev); - clk_disable_unprepare(nmk_i2c->clk); + clk_disable_unprepare(priv->clk); pinctrl_pm_select_idle_state(dev); return 0; } @@ -906,10 +965,10 @@ static int nmk_i2c_runtime_suspend(struct device *dev) static int nmk_i2c_runtime_resume(struct device *dev) { struct amba_device *adev = to_amba_device(dev); - struct nmk_i2c_dev *nmk_i2c = amba_get_drvdata(adev); + struct nmk_i2c_dev *priv = amba_get_drvdata(adev); int ret; - ret = clk_prepare_enable(nmk_i2c->clk); + ret = clk_prepare_enable(priv->clk); if (ret) { dev_err(dev, "can't prepare_enable clock\n"); return ret; @@ -917,21 +976,18 @@ static int nmk_i2c_runtime_resume(struct device *dev) pinctrl_pm_select_default_state(dev); - ret = init_hw(nmk_i2c); + ret = init_hw(priv); if (ret) { - clk_disable_unprepare(nmk_i2c->clk); + clk_disable_unprepare(priv->clk); pinctrl_pm_select_idle_state(dev); } return ret; } -#endif static const struct dev_pm_ops nmk_i2c_pm = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(nmk_i2c_suspend_late, nmk_i2c_resume_early) - SET_RUNTIME_PM_OPS(nmk_i2c_runtime_suspend, - nmk_i2c_runtime_resume, - NULL) + LATE_SYSTEM_SLEEP_PM_OPS(nmk_i2c_suspend_late, nmk_i2c_resume_early) + RUNTIME_PM_OPS(nmk_i2c_runtime_suspend, nmk_i2c_runtime_resume, NULL) }; static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap) @@ -940,134 +996,191 @@ static unsigned int nmk_i2c_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm nmk_i2c_algo = { - .master_xfer = nmk_i2c_xfer, - .functionality = nmk_i2c_functionality + .xfer = nmk_i2c_xfer, + .functionality = nmk_i2c_functionality }; static void nmk_i2c_of_probe(struct device_node *np, - struct nmk_i2c_dev *nmk) + struct nmk_i2c_dev *priv) { + u32 timeout_usecs; + /* Default to 100 kHz if no frequency is given in the node */ - if (of_property_read_u32(np, "clock-frequency", &nmk->clk_freq)) - nmk->clk_freq = I2C_MAX_STANDARD_MODE_FREQ; + if (of_property_read_u32(np, "clock-frequency", &priv->clk_freq)) + priv->clk_freq = I2C_MAX_STANDARD_MODE_FREQ; + + if (priv->clk_freq <= I2C_MAX_STANDARD_MODE_FREQ) + priv->sm = I2C_FREQ_MODE_STANDARD; + else if (priv->clk_freq <= I2C_MAX_FAST_MODE_FREQ) + priv->sm = I2C_FREQ_MODE_FAST; + else if (priv->clk_freq <= I2C_MAX_FAST_MODE_PLUS_FREQ) + priv->sm = I2C_FREQ_MODE_FAST_PLUS; + else + priv->sm = I2C_FREQ_MODE_HIGH_SPEED; + priv->tft = 1; /* Tx FIFO threshold */ + priv->rft = 8; /* Rx FIFO threshold */ - /* This driver only supports 'standard' and 'fast' modes of operation. */ - if (nmk->clk_freq <= I2C_MAX_STANDARD_MODE_FREQ) - nmk->sm = I2C_FREQ_MODE_STANDARD; + /* Slave response timeout */ + if (!of_property_read_u32(np, "i2c-transfer-timeout-us", &timeout_usecs)) + priv->timeout_usecs = timeout_usecs; else - nmk->sm = I2C_FREQ_MODE_FAST; - nmk->tft = 1; /* Tx FIFO threshold */ - nmk->rft = 8; /* Rx FIFO threshold */ - nmk->timeout = 200; /* Slave response timeout(ms) */ + priv->timeout_usecs = 200 * USEC_PER_MSEC; } +static const unsigned int nmk_i2c_eyeq5_masks[] = { + GENMASK(5, 4), + GENMASK(7, 6), + GENMASK(9, 8), + GENMASK(11, 10), + GENMASK(13, 12), +}; + +static int nmk_i2c_eyeq5_probe(struct nmk_i2c_dev *priv) +{ + struct device *dev = &priv->adev->dev; + struct device_node *np = dev->of_node; + unsigned int mask, speed_mode; + struct regmap *olb; + unsigned int id; + + olb = syscon_regmap_lookup_by_phandle_args(np, "mobileye,olb", 1, &id); + if (IS_ERR(olb)) + return PTR_ERR(olb); + if (id >= ARRAY_SIZE(nmk_i2c_eyeq5_masks)) + return -ENOENT; + + if (priv->clk_freq <= 400000) + speed_mode = I2C_EYEQ5_SPEED_FAST; + else if (priv->clk_freq <= 1000000) + speed_mode = I2C_EYEQ5_SPEED_FAST_PLUS; + else + speed_mode = I2C_EYEQ5_SPEED_HIGH_SPEED; + + mask = nmk_i2c_eyeq5_masks[id]; + regmap_update_bits(olb, NMK_I2C_EYEQ5_OLB_IOCR2, + mask, speed_mode << __fls(mask)); + + return 0; +} + +#define NMK_I2C_EYEQ_FLAG_32B_BUS BIT(0) +#define NMK_I2C_EYEQ_FLAG_IS_EYEQ5 BIT(1) + +static const struct of_device_id nmk_i2c_eyeq_match_table[] = { + { + .compatible = "mobileye,eyeq5-i2c", + .data = (void *)(NMK_I2C_EYEQ_FLAG_32B_BUS | NMK_I2C_EYEQ_FLAG_IS_EYEQ5), + }, + { + .compatible = "mobileye,eyeq6h-i2c", + .data = (void *)NMK_I2C_EYEQ_FLAG_32B_BUS, + }, + { /* sentinel */ } +}; + static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) { - int ret = 0; - struct device_node *np = adev->dev.of_node; - struct nmk_i2c_dev *dev; - struct i2c_adapter *adap; struct i2c_vendor_data *vendor = id->data; u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1; + struct device_node *np = adev->dev.of_node; + const struct of_device_id *match; + struct device *dev = &adev->dev; + unsigned long match_flags = 0; + struct nmk_i2c_dev *priv; + struct i2c_adapter *adap; + int ret = 0; - dev = devm_kzalloc(&adev->dev, sizeof(struct nmk_i2c_dev), GFP_KERNEL); - if (!dev) { - dev_err(&adev->dev, "cannot allocate memory\n"); - ret = -ENOMEM; - goto err_no_mem; - } - dev->vendor = vendor; - dev->adev = adev; - nmk_i2c_of_probe(np, dev); - - if (dev->tft > max_fifo_threshold) { - dev_warn(&adev->dev, "requested TX FIFO threshold %u, adjusted down to %u\n", - dev->tft, max_fifo_threshold); - dev->tft = max_fifo_threshold; + /* + * We do not want to attach a .of_match_table to our amba driver. + * Do not convert to device_get_match_data(). + */ + match = of_match_device(nmk_i2c_eyeq_match_table, dev); + if (match) + match_flags = (unsigned long)match->data; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->vendor = vendor; + priv->adev = adev; + priv->has_32b_bus = match_flags & NMK_I2C_EYEQ_FLAG_32B_BUS; + nmk_i2c_of_probe(np, priv); + + if (match_flags & NMK_I2C_EYEQ_FLAG_IS_EYEQ5) { + ret = nmk_i2c_eyeq5_probe(priv); + if (ret) + return dev_err_probe(dev, ret, "failed OLB lookup\n"); } - if (dev->rft > max_fifo_threshold) { - dev_warn(&adev->dev, "requested RX FIFO threshold %u, adjusted down to %u\n", - dev->rft, max_fifo_threshold); - dev->rft = max_fifo_threshold; + if (priv->tft > max_fifo_threshold) { + dev_warn(dev, "requested TX FIFO threshold %u, adjusted down to %u\n", + priv->tft, max_fifo_threshold); + priv->tft = max_fifo_threshold; } - amba_set_drvdata(adev, dev); - - dev->virtbase = devm_ioremap(&adev->dev, adev->res.start, - resource_size(&adev->res)); - if (!dev->virtbase) { - ret = -ENOMEM; - goto err_no_mem; + if (priv->rft > max_fifo_threshold) { + dev_warn(dev, "requested RX FIFO threshold %u, adjusted down to %u\n", + priv->rft, max_fifo_threshold); + priv->rft = max_fifo_threshold; } - dev->irq = adev->irq[0]; - ret = devm_request_irq(&adev->dev, dev->irq, i2c_irq_handler, 0, - DRIVER_NAME, dev); - if (ret) { - dev_err(&adev->dev, "cannot claim the irq %d\n", dev->irq); - goto err_no_mem; - } + amba_set_drvdata(adev, priv); - dev->clk = devm_clk_get(&adev->dev, NULL); - if (IS_ERR(dev->clk)) { - dev_err(&adev->dev, "could not get i2c clock\n"); - ret = PTR_ERR(dev->clk); - goto err_no_mem; - } + priv->virtbase = devm_ioremap(dev, adev->res.start, + resource_size(&adev->res)); + if (!priv->virtbase) + return -ENOMEM; - ret = clk_prepare_enable(dev->clk); - if (ret) { - dev_err(&adev->dev, "can't prepare_enable clock\n"); - goto err_no_mem; - } + priv->irq = adev->irq[0]; + ret = devm_request_irq(dev, priv->irq, i2c_irq_handler, 0, + DRIVER_NAME, priv); + if (ret) + return dev_err_probe(dev, ret, + "cannot claim the irq %d\n", priv->irq); + + priv->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(priv->clk)) + return dev_err_probe(dev, PTR_ERR(priv->clk), + "could enable i2c clock\n"); - init_hw(dev); + init_hw(priv); - adap = &dev->adap; + adap = &priv->adap; adap->dev.of_node = np; - adap->dev.parent = &adev->dev; + adap->dev.parent = dev; adap->owner = THIS_MODULE; adap->class = I2C_CLASS_DEPRECATED; adap->algo = &nmk_i2c_algo; - adap->timeout = msecs_to_jiffies(dev->timeout); + adap->timeout = usecs_to_jiffies(priv->timeout_usecs); snprintf(adap->name, sizeof(adap->name), "Nomadik I2C at %pR", &adev->res); - i2c_set_adapdata(adap, dev); + i2c_set_adapdata(adap, priv); - dev_info(&adev->dev, + dev_info(dev, "initialize %s on virtual base %p\n", - adap->name, dev->virtbase); + adap->name, priv->virtbase); ret = i2c_add_adapter(adap); if (ret) - goto err_no_adap; + return ret; - pm_runtime_put(&adev->dev); + pm_runtime_put(dev); return 0; - - err_no_adap: - clk_disable_unprepare(dev->clk); - err_no_mem: - - return ret; } static void nmk_i2c_remove(struct amba_device *adev) { - struct resource *res = &adev->res; - struct nmk_i2c_dev *dev = amba_get_drvdata(adev); + struct nmk_i2c_dev *priv = amba_get_drvdata(adev); - i2c_del_adapter(&dev->adap); - flush_i2c_fifo(dev); - disable_all_interrupts(dev); - clear_all_interrupts(dev); + i2c_del_adapter(&priv->adap); + flush_i2c_fifo(priv); + disable_all_interrupts(priv); + clear_all_interrupts(priv); /* disable the controller */ - i2c_clr_bit(dev->virtbase + I2C_CR, I2C_CR_PE); - clk_disable_unprepare(dev->clk); - release_mem_region(res->start, resource_size(res)); + i2c_clr_bit(priv->virtbase + I2C_CR, I2C_CR_PE); } static struct i2c_vendor_data vendor_stn8815 = { @@ -1098,9 +1211,8 @@ MODULE_DEVICE_TABLE(amba, nmk_i2c_ids); static struct amba_driver nmk_i2c_driver = { .drv = { - .owner = THIS_MODULE, .name = DRIVER_NAME, - .pm = &nmk_i2c_pm, + .pm = pm_ptr(&nmk_i2c_pm), }, .id_table = nmk_i2c_ids, .probe = nmk_i2c_probe, diff --git a/drivers/i2c/busses/i2c-npcm7xx.c b/drivers/i2c/busses/i2c-npcm7xx.c index 38d5864d0cb5..8b7e15240fb0 100644 --- a/drivers/i2c/busses/i2c-npcm7xx.c +++ b/drivers/i2c/busses/i2c-npcm7xx.c @@ -17,7 +17,6 @@ #include <linux/mfd/syscon.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/regmap.h> @@ -137,11 +136,13 @@ enum i2c_addr { * Since the addr regs are sprinkled all over the address space, * use this array to get the address or each register. */ -#define I2C_NUM_OWN_ADDR 2 +#define I2C_NUM_OWN_ADDR 10 #define I2C_NUM_OWN_ADDR_SUPPORTED 2 static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = { - NPCM_I2CADDR1, NPCM_I2CADDR2, + NPCM_I2CADDR1, NPCM_I2CADDR2, NPCM_I2CADDR3, NPCM_I2CADDR4, + NPCM_I2CADDR5, NPCM_I2CADDR6, NPCM_I2CADDR7, NPCM_I2CADDR8, + NPCM_I2CADDR9, NPCM_I2CADDR10, }; #endif @@ -262,6 +263,265 @@ static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = { #define I2C_FREQ_MIN_HZ 10000 #define I2C_FREQ_MAX_HZ I2C_MAX_FAST_MODE_PLUS_FREQ +struct smb_timing_t { + u32 core_clk; + u8 hldt; + u8 dbcnt; + u16 sclfrq; + u8 scllt; + u8 sclht; + bool fast_mode; +}; + +static struct smb_timing_t smb_timing_100khz[] = { + { + .core_clk = 100000000, .hldt = 0x2A, .dbcnt = 0x4, + .sclfrq = 0xFB, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 62500000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x9D, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 50000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x7E, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 48000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x79, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 40000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x65, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 30000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x4C, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 29000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x49, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 26000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x42, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 25000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x3F, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 24000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x3D, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 20000000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x33, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 16180000, .hldt = 0x2A, .dbcnt = 0x1, + .sclfrq = 0x29, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 15000000, .hldt = 0x23, .dbcnt = 0x1, + .sclfrq = 0x26, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 13000000, .hldt = 0x1D, .dbcnt = 0x1, + .sclfrq = 0x21, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 12000000, .hldt = 0x1B, .dbcnt = 0x1, + .sclfrq = 0x1F, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 10000000, .hldt = 0x18, .dbcnt = 0x1, + .sclfrq = 0x1A, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 9000000, .hldt = 0x16, .dbcnt = 0x1, + .sclfrq = 0x17, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 8090000, .hldt = 0x14, .dbcnt = 0x1, + .sclfrq = 0x15, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 7500000, .hldt = 0x7, .dbcnt = 0x1, + .sclfrq = 0x13, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 6500000, .hldt = 0xE, .dbcnt = 0x1, + .sclfrq = 0x11, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, + { + .core_clk = 4000000, .hldt = 0x9, .dbcnt = 0x1, + .sclfrq = 0xB, .scllt = 0x0, .sclht = 0x0, + .fast_mode = false, + }, +}; + +static struct smb_timing_t smb_timing_400khz[] = { + { + .core_clk = 100000000, .hldt = 0x2A, .dbcnt = 0x3, + .sclfrq = 0x0, .scllt = 0x47, .sclht = 0x35, + .fast_mode = true, + }, + { + .core_clk = 62500000, .hldt = 0x2A, .dbcnt = 0x2, + .sclfrq = 0x0, .scllt = 0x2C, .sclht = 0x22, + .fast_mode = true, + }, + { + .core_clk = 50000000, .hldt = 0x21, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x24, .sclht = 0x1B, + .fast_mode = true, + }, + { + .core_clk = 48000000, .hldt = 0x1E, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x24, .sclht = 0x19, + .fast_mode = true, + }, + { + .core_clk = 40000000, .hldt = 0x1B, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x1E, .sclht = 0x14, + .fast_mode = true, + }, + { + .core_clk = 33000000, .hldt = 0x15, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x19, .sclht = 0x11, + .fast_mode = true, + }, + { + .core_clk = 30000000, .hldt = 0x15, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x19, .sclht = 0xD, + .fast_mode = true, + }, + { + .core_clk = 29000000, .hldt = 0x11, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x15, .sclht = 0x10, + .fast_mode = true, + }, + { + .core_clk = 26000000, .hldt = 0x10, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x13, .sclht = 0xE, + .fast_mode = true, + }, + { + .core_clk = 25000000, .hldt = 0xF, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x13, .sclht = 0xD, + .fast_mode = true, + }, + { + .core_clk = 24000000, .hldt = 0xD, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x12, .sclht = 0xD, + .fast_mode = true, + }, + { + .core_clk = 20000000, .hldt = 0xB, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0xF, .sclht = 0xA, + .fast_mode = true, + }, + { + .core_clk = 16180000, .hldt = 0xA, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0xC, .sclht = 0x9, + .fast_mode = true, + }, + { + .core_clk = 15000000, .hldt = 0x9, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0xB, .sclht = 0x8, + .fast_mode = true, + }, + { + .core_clk = 13000000, .hldt = 0x7, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0xA, .sclht = 0x7, + .fast_mode = true, + }, + { + .core_clk = 12000000, .hldt = 0x7, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0xA, .sclht = 0x6, + .fast_mode = true, + }, + { + .core_clk = 10000000, .hldt = 0x6, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x8, .sclht = 0x5, + .fast_mode = true, + }, +}; + +static struct smb_timing_t smb_timing_1000khz[] = { + { + .core_clk = 100000000, .hldt = 0x15, .dbcnt = 0x4, + .sclfrq = 0x0, .scllt = 0x1C, .sclht = 0x15, + .fast_mode = true, + }, + { + .core_clk = 62500000, .hldt = 0xF, .dbcnt = 0x3, + .sclfrq = 0x0, .scllt = 0x11, .sclht = 0xE, + .fast_mode = true, + }, + { + .core_clk = 50000000, .hldt = 0xA, .dbcnt = 0x2, + .sclfrq = 0x0, .scllt = 0xE, .sclht = 0xB, + .fast_mode = true, + }, + { + .core_clk = 48000000, .hldt = 0x9, .dbcnt = 0x2, + .sclfrq = 0x0, .scllt = 0xD, .sclht = 0xB, + .fast_mode = true, + }, + { + .core_clk = 41000000, .hldt = 0x9, .dbcnt = 0x2, + .sclfrq = 0x0, .scllt = 0xC, .sclht = 0x9, + .fast_mode = true, + }, + { + .core_clk = 40000000, .hldt = 0x8, .dbcnt = 0x2, + .sclfrq = 0x0, .scllt = 0xB, .sclht = 0x9, + .fast_mode = true, + }, + { + .core_clk = 33000000, .hldt = 0x7, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0xA, .sclht = 0x7, + .fast_mode = true, + }, + { + .core_clk = 25000000, .hldt = 0x4, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x7, .sclht = 0x6, + .fast_mode = true, + }, + { + .core_clk = 24000000, .hldt = 0x7, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x8, .sclht = 0x5, + .fast_mode = true, + }, + { + .core_clk = 20000000, .hldt = 0x4, .dbcnt = 0x1, + .sclfrq = 0x0, .scllt = 0x6, .sclht = 0x4, + .fast_mode = true, + }, +}; + struct npcm_i2c_data { u8 fifo_size; u32 segctl_init_val; @@ -327,13 +587,13 @@ struct npcm_i2c { u8 slv_rd_buf[MAX_I2C_HW_FIFO_SIZE]; u8 slv_wr_buf[MAX_I2C_HW_FIFO_SIZE]; #endif - struct dentry *debugfs; /* debugfs device directory */ u64 ber_cnt; u64 rec_succ_cnt; u64 rec_fail_cnt; u64 nack_cnt; u64 timeout_cnt; u64 tx_complete_cnt; + bool ber_state; /* Indicate the bus error state */ }; static inline void npcm_i2c_select_bank(struct npcm_i2c *bus, @@ -695,6 +955,7 @@ static void npcm_i2c_callback(struct npcm_i2c *bus, { struct i2c_msg *msgs; int msgs_num; + bool do_complete = false; msgs = bus->msgs; msgs_num = bus->msgs_num; @@ -723,23 +984,17 @@ static void npcm_i2c_callback(struct npcm_i2c *bus, msgs[1].flags & I2C_M_RD) msgs[1].len = info; } - if (completion_done(&bus->cmd_complete) == false) - complete(&bus->cmd_complete); - break; - + do_complete = true; + break; case I2C_NACK_IND: /* MASTER transmit got a NACK before tx all bytes */ bus->cmd_err = -ENXIO; - if (bus->master_or_slave == I2C_MASTER) - complete(&bus->cmd_complete); - + do_complete = true; break; case I2C_BUS_ERR_IND: /* Bus error */ bus->cmd_err = -EAGAIN; - if (bus->master_or_slave == I2C_MASTER) - complete(&bus->cmd_complete); - + do_complete = true; break; case I2C_WAKE_UP_IND: /* I2C wake up */ @@ -753,6 +1008,8 @@ static void npcm_i2c_callback(struct npcm_i2c *bus, if (bus->slave) bus->master_or_slave = I2C_SLAVE; #endif + if (do_complete) + complete(&bus->cmd_complete); } static u8 npcm_i2c_fifo_usage(struct npcm_i2c *bus) @@ -858,14 +1115,10 @@ static void npcm_i2c_master_abort(struct npcm_i2c *bus) #if IS_ENABLED(CONFIG_I2C_SLAVE) static u8 npcm_i2c_get_slave_addr(struct npcm_i2c *bus, enum i2c_addr addr_type) { - u8 slave_add; - if (addr_type > I2C_SLAVE_ADDR2 && addr_type <= I2C_SLAVE_ADDR10) dev_err(bus->dev, "get slave: try to use more than 2 SA not supported\n"); - slave_add = ioread8(bus->reg + npcm_i2caddr[(int)addr_type]); - - return slave_add; + return ioread8(bus->reg + npcm_i2caddr[addr_type]); } static int npcm_i2c_remove_slave_addr(struct npcm_i2c *bus, u8 slave_add) @@ -1269,9 +1522,6 @@ static int npcm_i2c_reg_slave(struct i2c_client *client) bus->slave = client; - if (!bus->slave) - return -EINVAL; - if (client->flags & I2C_CLIENT_TEN) return -EAFNOSUPPORT; @@ -1527,6 +1777,7 @@ static void npcm_i2c_irq_handle_ber(struct npcm_i2c *bus) if (npcm_i2c_is_master(bus)) { npcm_i2c_master_abort(bus); } else { + bus->ber_state = true; npcm_i2c_clear_master_status(bus); /* Clear BB (BUS BUSY) bit */ @@ -1634,13 +1885,10 @@ static void npcm_i2c_irq_handle_sda(struct npcm_i2c *bus, u8 i2cst) npcm_i2c_wr_byte(bus, bus->dest_addr | BIT(0)); /* SDA interrupt, after start\restart */ } else { - if (NPCM_I2CST_XMIT & i2cst) { - bus->operation = I2C_WRITE_OPER; + if (bus->operation == I2C_WRITE_OPER) npcm_i2c_irq_master_handler_write(bus); - } else { - bus->operation = I2C_READ_OPER; + else if (bus->operation == I2C_READ_OPER) npcm_i2c_irq_master_handler_read(bus); - } } } @@ -1673,6 +1921,12 @@ static int npcm_i2c_int_master_handler(struct npcm_i2c *bus) (FIELD_GET(NPCM_I2CCST3_EO_BUSY, ioread8(bus->reg + NPCM_I2CCST3)))) { npcm_i2c_irq_handle_eob(bus); +#if IS_ENABLED(CONFIG_I2C_SLAVE) + /* reenable slave if it was enabled */ + if (bus->slave) + iowrite8(bus->slave->addr | NPCM_I2CADDR_SAEN, + bus->reg + NPCM_I2CADDR1); +#endif return 0; } @@ -1708,6 +1962,7 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap) dev_dbg(bus->dev, "bus%d-0x%x recovery skipped, bus not stuck", bus->num, bus->dest_addr); npcm_i2c_reset(bus); + bus->ber_state = false; return 0; } @@ -1772,6 +2027,7 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap) if (bus->rec_succ_cnt < ULLONG_MAX) bus->rec_succ_cnt++; } + bus->ber_state = false; return status; } @@ -1810,102 +2066,45 @@ static void npcm_i2c_recovery_init(struct i2c_adapter *_adap) */ static int npcm_i2c_init_clk(struct npcm_i2c *bus, u32 bus_freq_hz) { - u32 k1 = 0; - u32 k2 = 0; - u8 dbnct = 0; - u32 sclfrq = 0; - u8 hldt = 7; + struct smb_timing_t *smb_timing; + u8 scl_table_cnt = 0, table_size = 0; u8 fast_mode = 0; - u32 src_clk_khz; - u32 bus_freq_khz; - src_clk_khz = bus->apb_clk / 1000; - bus_freq_khz = bus_freq_hz / 1000; bus->bus_freq = bus_freq_hz; - /* 100KHz and below: */ - if (bus_freq_hz <= I2C_MAX_STANDARD_MODE_FREQ) { - sclfrq = src_clk_khz / (bus_freq_khz * 4); - - if (sclfrq < SCLFRQ_MIN || sclfrq > SCLFRQ_MAX) - return -EDOM; - - if (src_clk_khz >= 40000) - hldt = 17; - else if (src_clk_khz >= 12500) - hldt = 15; - else - hldt = 7; - } - - /* 400KHz: */ - else if (bus_freq_hz <= I2C_MAX_FAST_MODE_FREQ) { - sclfrq = 0; + switch (bus_freq_hz) { + case I2C_MAX_STANDARD_MODE_FREQ: + smb_timing = smb_timing_100khz; + table_size = ARRAY_SIZE(smb_timing_100khz); + break; + case I2C_MAX_FAST_MODE_FREQ: + smb_timing = smb_timing_400khz; + table_size = ARRAY_SIZE(smb_timing_400khz); fast_mode = I2CCTL3_400K_MODE; - - if (src_clk_khz < 7500) - /* 400KHZ cannot be supported for core clock < 7.5MHz */ - return -EDOM; - - else if (src_clk_khz >= 50000) { - k1 = 80; - k2 = 48; - hldt = 12; - dbnct = 7; - } - - /* Master or Slave with frequency > 25MHz */ - else if (src_clk_khz > 25000) { - hldt = clk_coef(src_clk_khz, 300) + 7; - k1 = clk_coef(src_clk_khz, 1600); - k2 = clk_coef(src_clk_khz, 900); - } - } - - /* 1MHz: */ - else if (bus_freq_hz <= I2C_MAX_FAST_MODE_PLUS_FREQ) { - sclfrq = 0; + break; + case I2C_MAX_FAST_MODE_PLUS_FREQ: + smb_timing = smb_timing_1000khz; + table_size = ARRAY_SIZE(smb_timing_1000khz); fast_mode = I2CCTL3_400K_MODE; - - /* 1MHZ cannot be supported for core clock < 24 MHz */ - if (src_clk_khz < 24000) - return -EDOM; - - k1 = clk_coef(src_clk_khz, 620); - k2 = clk_coef(src_clk_khz, 380); - - /* Core clk > 40 MHz */ - if (src_clk_khz > 40000) { - /* - * Set HLDT: - * SDA hold time: (HLDT-7) * T(CLK) >= 120 - * HLDT = 120/T(CLK) + 7 = 120 * FREQ(CLK) + 7 - */ - hldt = clk_coef(src_clk_khz, 120) + 7; - } else { - hldt = 7; - dbnct = 2; - } + break; + default: + return -EINVAL; } - /* Frequency larger than 1 MHz is not supported */ - else - return -EINVAL; + for (scl_table_cnt = 0; scl_table_cnt < table_size; scl_table_cnt++) + if (bus->apb_clk >= smb_timing[scl_table_cnt].core_clk) + break; - if (bus_freq_hz >= I2C_MAX_FAST_MODE_FREQ) { - k1 = round_up(k1, 2); - k2 = round_up(k2 + 1, 2); - if (k1 < SCLFRQ_MIN || k1 > SCLFRQ_MAX || - k2 < SCLFRQ_MIN || k2 > SCLFRQ_MAX) - return -EDOM; - } + if (scl_table_cnt == table_size) + return -EINVAL; /* write sclfrq value. bits [6:0] are in I2CCTL2 reg */ - iowrite8(FIELD_PREP(I2CCTL2_SCLFRQ6_0, sclfrq & 0x7F), + iowrite8(FIELD_PREP(I2CCTL2_SCLFRQ6_0, smb_timing[scl_table_cnt].sclfrq & 0x7F), bus->reg + NPCM_I2CCTL2); /* bits [8:7] are in I2CCTL3 reg */ - iowrite8(fast_mode | FIELD_PREP(I2CCTL3_SCLFRQ8_7, (sclfrq >> 7) & 0x3), + iowrite8(FIELD_PREP(I2CCTL3_SCLFRQ8_7, (smb_timing[scl_table_cnt].sclfrq >> 7) & 0x3) | + fast_mode, bus->reg + NPCM_I2CCTL3); /* Select Bank 0 to access NPCM_I2CCTL4/NPCM_I2CCTL5 */ @@ -1917,13 +2116,13 @@ static int npcm_i2c_init_clk(struct npcm_i2c *bus, u32 bus_freq_hz) * k1 = 2 * SCLLT7-0 -> Low Time = k1 / 2 * k2 = 2 * SCLLT7-0 -> High Time = k2 / 2 */ - iowrite8(k1 / 2, bus->reg + NPCM_I2CSCLLT); - iowrite8(k2 / 2, bus->reg + NPCM_I2CSCLHT); + iowrite8(smb_timing[scl_table_cnt].scllt, bus->reg + NPCM_I2CSCLLT); + iowrite8(smb_timing[scl_table_cnt].sclht, bus->reg + NPCM_I2CSCLHT); - iowrite8(dbnct, bus->reg + NPCM_I2CCTL5); + iowrite8(smb_timing[scl_table_cnt].dbcnt, bus->reg + NPCM_I2CCTL5); } - iowrite8(hldt, bus->reg + NPCM_I2CCTL4); + iowrite8(smb_timing[scl_table_cnt].hldt, bus->reg + NPCM_I2CCTL4); /* Return to Bank 1, and stay there by default: */ npcm_i2c_select_bank(bus, I2C_BANK_1); @@ -1975,10 +2174,14 @@ static int npcm_i2c_init_module(struct npcm_i2c *bus, enum i2c_mode mode, /* Check HW is OK: SDA and SCL should be high at this point. */ if ((npcm_i2c_get_SDA(&bus->adap) == 0) || (npcm_i2c_get_SCL(&bus->adap) == 0)) { - dev_err(bus->dev, "I2C%d init fail: lines are low\n", bus->num); - dev_err(bus->dev, "SDA=%d SCL=%d\n", npcm_i2c_get_SDA(&bus->adap), - npcm_i2c_get_SCL(&bus->adap)); - return -ENXIO; + dev_warn(bus->dev, " I2C%d SDA=%d SCL=%d, attempting to recover\n", bus->num, + npcm_i2c_get_SDA(&bus->adap), npcm_i2c_get_SCL(&bus->adap)); + if (npcm_i2c_recovery_tgclk(&bus->adap)) { + dev_err(bus->dev, "I2C%d init fail: SDA=%d SCL=%d\n", + bus->num, npcm_i2c_get_SDA(&bus->adap), + npcm_i2c_get_SCL(&bus->adap)); + return -ENXIO; + } } npcm_i2c_int_enable(bus, true); @@ -2040,7 +2243,7 @@ static irqreturn_t npcm_i2c_bus_irq(int irq, void *dev_id) } static bool npcm_i2c_master_start_xmit(struct npcm_i2c *bus, - u8 slave_addr, u16 nwrite, u16 nread, + u16 nwrite, u16 nread, u8 *write_data, u8 *read_data, bool use_PEC, bool use_read_block) { @@ -2048,7 +2251,6 @@ static bool npcm_i2c_master_start_xmit(struct npcm_i2c *bus, bus->cmd_err = -EBUSY; return false; } - bus->dest_addr = slave_addr << 1; bus->wr_buf = write_data; bus->wr_size = nwrite; bus->wr_ind = 0; @@ -2091,7 +2293,6 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, unsigned long time_left, flags; u16 nwrite, nread; u8 *write_data, *read_data; - u8 slave_addr; unsigned long timeout; bool read_block = false; bool read_PEC = false; @@ -2104,7 +2305,6 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } msg0 = &msgs[0]; - slave_addr = msg0->addr; if (msg0->flags & I2C_M_RD) { /* read */ nwrite = 0; write_data = NULL; @@ -2137,19 +2337,12 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } } - /* - * Adaptive TimeOut: estimated time in usec + 100% margin: - * 2: double the timeout for clock stretching case - * 9: bits per transaction (including the ack/nack) - */ - timeout_usec = (2 * 9 * USEC_PER_SEC / bus->bus_freq) * (2 + nread + nwrite); - timeout = max_t(unsigned long, bus->adap.timeout, usecs_to_jiffies(timeout_usec)); if (nwrite >= 32 * 1024 || nread >= 32 * 1024) { dev_err(bus->dev, "i2c%d buffer too big\n", bus->num); return -EINVAL; } - time_left = jiffies + timeout + 1; + time_left = jiffies + bus->adap.timeout / bus->adap.retries + 1; do { /* * we must clear slave address immediately when the bus is not @@ -2167,7 +2360,31 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } while (time_is_after_jiffies(time_left) && bus_busy); - if (bus_busy) { + /* + * Store the address early in a global position to ensure it is + * accessible for a potential call to i2c_recover_bus(). + * + * Since the transfer might be a read operation, remove the I2C_M_RD flag + * from the bus->dest_addr for the i2c_recover_bus() call later. + * + * The i2c_recover_bus() uses the address in a write direction to recover + * the i2c bus if some error condition occurs. + * + * Remove the I2C_M_RD flag from the address since npcm_i2c_master_start_xmit() + * handles the read/write operation internally. + */ + bus->dest_addr = i2c_8bit_addr_from_msg(msg0) & ~I2C_M_RD; + + /* + * Check the BER (bus error) state, when ber_state is true, it means that the module + * detects the bus error which is caused by some factor like that the electricity + * noise occurs on the bus. Under this condition, the module is reset and the bus + * gets recovered. + * + * While ber_state is false, the module reset and bus recovery also get done as the + * bus is busy. + */ + if (bus_busy || bus->ber_state) { iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST); npcm_i2c_reset(bus); i2c_recover_bus(adap); @@ -2175,7 +2392,6 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } npcm_i2c_init_params(bus); - bus->dest_addr = slave_addr; bus->msgs = msgs; bus->msgs_num = num; bus->cmd_err = 0; @@ -2185,9 +2401,17 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, npcm_i2c_int_enable(bus, true); - if (npcm_i2c_master_start_xmit(bus, slave_addr, nwrite, nread, + if (npcm_i2c_master_start_xmit(bus, nwrite, nread, write_data, read_data, read_PEC, read_block)) { + /* + * Adaptive TimeOut: estimated time in usec + 100% margin: + * 2: double the timeout for clock stretching case + * 9: bits per transaction (including the ack/nack) + */ + timeout_usec = (2 * 9 * USEC_PER_SEC / bus->bus_freq) * (2 + nread + nwrite); + timeout = max_t(unsigned long, bus->adap.timeout / bus->adap.retries, + usecs_to_jiffies(timeout_usec)); time_left = wait_for_completion_timeout(&bus->cmd_complete, timeout); @@ -2246,35 +2470,23 @@ static const struct i2c_adapter_quirks npcm_i2c_quirks = { }; static const struct i2c_algorithm npcm_i2c_algo = { - .master_xfer = npcm_i2c_master_xfer, + .xfer = npcm_i2c_master_xfer, .functionality = npcm_i2c_functionality, #if IS_ENABLED(CONFIG_I2C_SLAVE) - .reg_slave = npcm_i2c_reg_slave, - .unreg_slave = npcm_i2c_unreg_slave, + .reg_slave = npcm_i2c_reg_slave, + .unreg_slave = npcm_i2c_unreg_slave, #endif }; -/* i2c debugfs directory: used to keep health monitor of i2c devices */ -static struct dentry *npcm_i2c_debugfs_dir; - static void npcm_i2c_init_debugfs(struct platform_device *pdev, struct npcm_i2c *bus) { - struct dentry *d; - - if (!npcm_i2c_debugfs_dir) - return; - d = debugfs_create_dir(dev_name(&pdev->dev), npcm_i2c_debugfs_dir); - if (IS_ERR_OR_NULL(d)) - return; - debugfs_create_u64("ber_cnt", 0444, d, &bus->ber_cnt); - debugfs_create_u64("nack_cnt", 0444, d, &bus->nack_cnt); - debugfs_create_u64("rec_succ_cnt", 0444, d, &bus->rec_succ_cnt); - debugfs_create_u64("rec_fail_cnt", 0444, d, &bus->rec_fail_cnt); - debugfs_create_u64("timeout_cnt", 0444, d, &bus->timeout_cnt); - debugfs_create_u64("tx_complete_cnt", 0444, d, &bus->tx_complete_cnt); - - bus->debugfs = d; + debugfs_create_u64("ber_cnt", 0444, bus->adap.debugfs, &bus->ber_cnt); + debugfs_create_u64("nack_cnt", 0444, bus->adap.debugfs, &bus->nack_cnt); + debugfs_create_u64("rec_succ_cnt", 0444, bus->adap.debugfs, &bus->rec_succ_cnt); + debugfs_create_u64("rec_fail_cnt", 0444, bus->adap.debugfs, &bus->rec_fail_cnt); + debugfs_create_u64("timeout_cnt", 0444, bus->adap.debugfs, &bus->timeout_cnt); + debugfs_create_u64("tx_complete_cnt", 0444, bus->adap.debugfs, &bus->tx_complete_cnt); } static int npcm_i2c_probe_bus(struct platform_device *pdev) @@ -2325,7 +2537,12 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev) adap = &bus->adap; adap->owner = THIS_MODULE; adap->retries = 3; - adap->timeout = msecs_to_jiffies(35); + /* + * The users want to connect a lot of masters on the same bus. + * This timeout is used to determine the time it takes to take bus ownership. + * The transactions are very long, so waiting 35ms is not enough. + */ + adap->timeout = 2 * HZ; adap->algo = &npcm_i2c_algo; adap->quirks = &npcm_i2c_quirks; adap->algo_data = bus; @@ -2337,6 +2554,13 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev) if (irq < 0) return irq; + /* + * Disable the interrupt to avoid the interrupt handler being triggered + * incorrectly by the asynchronous interrupt status since the machine + * might do a warm reset during the last smbus/i2c transfer session. + */ + npcm_i2c_int_enable(bus, false); + ret = devm_request_irq(bus->dev, irq, npcm_i2c_bus_irq, 0, dev_name(bus->dev), bus); if (ret) @@ -2361,17 +2585,15 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev) return 0; } -static int npcm_i2c_remove_bus(struct platform_device *pdev) +static void npcm_i2c_remove_bus(struct platform_device *pdev) { unsigned long lock_flags; struct npcm_i2c *bus = platform_get_drvdata(pdev); - debugfs_remove_recursive(bus->debugfs); spin_lock_irqsave(&bus->lock, lock_flags); npcm_i2c_disable(bus); spin_unlock_irqrestore(&bus->lock, lock_flags); i2c_del_adapter(&bus->adap); - return 0; } static const struct of_device_id npcm_i2c_bus_of_table[] = { @@ -2390,28 +2612,7 @@ static struct platform_driver npcm_i2c_bus_driver = { } }; -static int __init npcm_i2c_init(void) -{ - int ret; - - npcm_i2c_debugfs_dir = debugfs_create_dir("npcm_i2c", NULL); - - ret = platform_driver_register(&npcm_i2c_bus_driver); - if (ret) { - debugfs_remove_recursive(npcm_i2c_debugfs_dir); - return ret; - } - - return 0; -} -module_init(npcm_i2c_init); - -static void __exit npcm_i2c_exit(void) -{ - platform_driver_unregister(&npcm_i2c_bus_driver); - debugfs_remove_recursive(npcm_i2c_debugfs_dir); -} -module_exit(npcm_i2c_exit); +module_platform_driver(npcm_i2c_bus_driver); MODULE_AUTHOR("Avi Fishman <avi.fishman@gmail.com>"); MODULE_AUTHOR("Tali Perry <tali.perry@nuvoton.com>"); diff --git a/drivers/i2c/busses/i2c-nvidia-gpu.c b/drivers/i2c/busses/i2c-nvidia-gpu.c index 12e330cd7635..14c059b03945 100644 --- a/drivers/i2c/busses/i2c-nvidia-gpu.c +++ b/drivers/i2c/busses/i2c-nvidia-gpu.c @@ -14,8 +14,9 @@ #include <linux/platform_device.h> #include <linux/pm.h> #include <linux/pm_runtime.h> +#include <linux/power_supply.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include "i2c-ccgx-ucsi.h" @@ -162,8 +163,7 @@ static int gpu_i2c_write(struct gpu_i2c_dev *i2cd, u8 data) return gpu_i2c_check_status(i2cd); } -static int gpu_i2c_master_xfer(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) +static int gpu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct gpu_i2c_dev *i2cd = i2c_get_adapdata(adap); int status, status2; @@ -216,7 +216,6 @@ exit: if (status2 < 0) dev_err(i2cd->dev, "i2c stop failed %d\n", status2); } - pm_runtime_mark_last_busy(i2cd->dev); pm_runtime_put_autosuspend(i2cd->dev); return status; } @@ -233,8 +232,8 @@ static u32 gpu_i2c_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm gpu_i2c_algorithm = { - .master_xfer = gpu_i2c_master_xfer, - .functionality = gpu_i2c_functionality, + .xfer = gpu_i2c_xfer, + .functionality = gpu_i2c_functionality, }; /* @@ -259,8 +258,10 @@ static const struct pci_device_id gpu_i2c_ids[] = { MODULE_DEVICE_TABLE(pci, gpu_i2c_ids); static const struct property_entry ccgx_props[] = { - /* Use FW built for NVIDIA (nv) only */ - PROPERTY_ENTRY_U16("ccgx,firmware-build", ('n' << 8) | 'v'), + /* Use FW built for NVIDIA GPU only */ + PROPERTY_ENTRY_STRING("firmware-name", "nvidia,gpu"), + /* USB-C doesn't power the system */ + PROPERTY_ENTRY_U8("scope", POWER_SUPPLY_SCOPE_DEVICE), { } }; diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index a0af027db04c..0f67e57cdeff 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -32,7 +32,6 @@ */ struct ocores_i2c { void __iomem *base; - int iobase; u32 reg_shift; u32 reg_io_width; unsigned long flags; @@ -136,16 +135,6 @@ static inline u8 oc_getreg_32be(struct ocores_i2c *i2c, int reg) return ioread32be(i2c->base + (reg << i2c->reg_shift)); } -static void oc_setreg_io_8(struct ocores_i2c *i2c, int reg, u8 value) -{ - outb(value, i2c->iobase + reg); -} - -static inline u8 oc_getreg_io_8(struct ocores_i2c *i2c, int reg) -{ - return inb(i2c->iobase + reg); -} - static inline void oc_setreg(struct ocores_i2c *i2c, int reg, u8 value) { i2c->setreg(i2c, reg, value); @@ -342,18 +331,18 @@ static int ocores_poll_wait(struct ocores_i2c *i2c) * ocores_isr(), we just add our polling code around it. * * It can run in atomic context + * + * Return: 0 on success, -ETIMEDOUT on timeout */ -static void ocores_process_polling(struct ocores_i2c *i2c) +static int ocores_process_polling(struct ocores_i2c *i2c) { - while (1) { - irqreturn_t ret; - int err; + irqreturn_t ret; + int err = 0; + while (1) { err = ocores_poll_wait(i2c); - if (err) { - i2c->state = STATE_ERROR; + if (err) break; /* timeout */ - } ret = ocores_isr(-1, i2c); if (ret == IRQ_NONE) @@ -364,13 +353,15 @@ static void ocores_process_polling(struct ocores_i2c *i2c) break; } } + + return err; } static int ocores_xfer_core(struct ocores_i2c *i2c, struct i2c_msg *msgs, int num, bool polling) { - int ret; + int ret = 0; u8 ctrl; ctrl = oc_getreg(i2c, OCI2C_CONTROL); @@ -388,15 +379,16 @@ static int ocores_xfer_core(struct ocores_i2c *i2c, oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_START); if (polling) { - ocores_process_polling(i2c); + ret = ocores_process_polling(i2c); } else { - ret = wait_event_timeout(i2c->wait, - (i2c->state == STATE_ERROR) || - (i2c->state == STATE_DONE), HZ); - if (ret == 0) { - ocores_process_timeout(i2c); - return -ETIMEDOUT; - } + if (wait_event_timeout(i2c->wait, + (i2c->state == STATE_ERROR) || + (i2c->state == STATE_DONE), HZ) == 0) + ret = -ETIMEDOUT; + } + if (ret) { + ocores_process_timeout(i2c); + return ret; } return (i2c->state == STATE_DONE) ? num : -EIO; @@ -439,8 +431,8 @@ static int ocores_init(struct device *dev, struct ocores_i2c *i2c) oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8); /* Init the device */ - oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_EN); + oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK); return 0; } @@ -452,8 +444,8 @@ static u32 ocores_func(struct i2c_adapter *adap) } static struct i2c_algorithm ocores_algorithm = { - .master_xfer = ocores_xfer, - .master_xfer_atomic = ocores_xfer_polling, + .xfer = ocores_xfer, + .xfer_atomic = ocores_xfer_polling, .functionality = ocores_func, }; @@ -549,28 +541,20 @@ static int ocores_i2c_of_probe(struct platform_device *pdev, &clock_frequency); i2c->bus_clock_khz = 100; - i2c->clk = devm_clk_get(&pdev->dev, NULL); - - if (!IS_ERR(i2c->clk)) { - int ret = clk_prepare_enable(i2c->clk); - - if (ret) { - dev_err(&pdev->dev, - "clk_prepare_enable failed: %d\n", ret); - return ret; - } - i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000; - if (clock_frequency_present) - i2c->bus_clock_khz = clock_frequency / 1000; - } + i2c->clk = devm_clk_get_optional_enabled(&pdev->dev, NULL); + if (IS_ERR(i2c->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk), + "devm_clk_get_optional_enabled failed\n"); + i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000; + if (clock_frequency_present) + i2c->bus_clock_khz = clock_frequency / 1000; if (i2c->ip_clock_khz == 0) { if (of_property_read_u32(np, "opencores,ip-clock-frequency", &val)) { if (!clock_frequency_present) { dev_err(&pdev->dev, "Missing required parameter 'opencores,ip-clock-frequency'\n"); - clk_disable_unprepare(i2c->clk); return -ENODEV; } i2c->ip_clock_khz = clock_frequency / 1000; @@ -623,15 +607,19 @@ static int ocores_i2c_probe(struct platform_device *pdev) res = platform_get_resource(pdev, IORESOURCE_IO, 0); if (!res) return -EINVAL; - i2c->iobase = res->start; if (!devm_request_region(&pdev->dev, res->start, resource_size(res), pdev->name)) { dev_err(&pdev->dev, "Can't get I/O resource.\n"); return -EBUSY; } - i2c->setreg = oc_setreg_io_8; - i2c->getreg = oc_getreg_io_8; + i2c->base = devm_ioport_map(&pdev->dev, res->start, + resource_size(res)); + if (!i2c->base) { + dev_err(&pdev->dev, "Can't map I/O resource.\n"); + return -EBUSY; + } + i2c->reg_io_width = 1; } pdata = dev_get_platdata(&pdev->dev); @@ -675,8 +663,7 @@ static int ocores_i2c_probe(struct platform_device *pdev) default: dev_err(&pdev->dev, "Unsupported I/O width (%d)\n", i2c->reg_io_width); - ret = -EINVAL; - goto err_clk; + return -EINVAL; } } @@ -695,25 +682,25 @@ static int ocores_i2c_probe(struct platform_device *pdev) } if (irq == -ENXIO) { - ocores_algorithm.master_xfer = ocores_xfer_polling; + ocores_algorithm.xfer = ocores_xfer_polling; } else { if (irq < 0) return irq; } - if (ocores_algorithm.master_xfer != ocores_xfer_polling) { + if (ocores_algorithm.xfer != ocores_xfer_polling) { ret = devm_request_any_context_irq(&pdev->dev, irq, ocores_isr, 0, pdev->name, i2c); if (ret) { dev_err(&pdev->dev, "Cannot claim IRQ\n"); - goto err_clk; + return ret; } } ret = ocores_init(&pdev->dev, i2c); if (ret) - goto err_clk; + return ret; /* hook up driver to tree */ platform_set_drvdata(pdev, i2c); @@ -725,7 +712,7 @@ static int ocores_i2c_probe(struct platform_device *pdev) /* add i2c adapter to i2c tree */ ret = i2c_add_adapter(&i2c->adap); if (ret) - goto err_clk; + return ret; /* add in known devices to the bus */ if (pdata) { @@ -734,13 +721,9 @@ static int ocores_i2c_probe(struct platform_device *pdev) } return 0; - -err_clk: - clk_disable_unprepare(i2c->clk); - return ret; } -static int ocores_i2c_remove(struct platform_device *pdev) +static void ocores_i2c_remove(struct platform_device *pdev) { struct ocores_i2c *i2c = platform_get_drvdata(pdev); u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL); @@ -751,14 +734,8 @@ static int ocores_i2c_remove(struct platform_device *pdev) /* remove adapter & data */ i2c_del_adapter(&i2c->adap); - - if (!IS_ERR(i2c->clk)) - clk_disable_unprepare(i2c->clk); - - return 0; } -#ifdef CONFIG_PM_SLEEP static int ocores_i2c_suspend(struct device *dev) { struct ocores_i2c *i2c = dev_get_drvdata(dev); @@ -768,44 +745,35 @@ static int ocores_i2c_suspend(struct device *dev) ctrl &= ~(OCI2C_CTRL_EN | OCI2C_CTRL_IEN); oc_setreg(i2c, OCI2C_CONTROL, ctrl); - if (!IS_ERR(i2c->clk)) - clk_disable_unprepare(i2c->clk); + clk_disable_unprepare(i2c->clk); return 0; } static int ocores_i2c_resume(struct device *dev) { struct ocores_i2c *i2c = dev_get_drvdata(dev); + unsigned long rate; + int ret; - if (!IS_ERR(i2c->clk)) { - unsigned long rate; - int ret = clk_prepare_enable(i2c->clk); - - if (ret) { - dev_err(dev, - "clk_prepare_enable failed: %d\n", ret); - return ret; - } - rate = clk_get_rate(i2c->clk) / 1000; - if (rate) - i2c->ip_clock_khz = rate; - } + ret = clk_prepare_enable(i2c->clk); + if (ret) + return dev_err_probe(dev, ret, "clk_prepare_enable failed\n"); + rate = clk_get_rate(i2c->clk) / 1000; + if (rate) + i2c->ip_clock_khz = rate; return ocores_init(dev, i2c); } -static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume); -#define OCORES_I2C_PM (&ocores_i2c_pm) -#else -#define OCORES_I2C_PM NULL -#endif +static DEFINE_NOIRQ_DEV_PM_OPS(ocores_i2c_pm, + ocores_i2c_suspend, ocores_i2c_resume); static struct platform_driver ocores_i2c_driver = { .probe = ocores_i2c_probe, - .remove = ocores_i2c_remove, + .remove = ocores_i2c_remove, .driver = { .name = "ocores-i2c", .of_match_table = ocores_i2c_match, - .pm = OCORES_I2C_PM, + .pm = pm_sleep_ptr(&ocores_i2c_pm), }, }; diff --git a/drivers/i2c/busses/i2c-octeon-core.c b/drivers/i2c/busses/i2c-octeon-core.c index 845eda70b8ca..93a49e4637ec 100644 --- a/drivers/i2c/busses/i2c-octeon-core.c +++ b/drivers/i2c/busses/i2c-octeon-core.c @@ -17,9 +17,14 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/pci.h> #include "i2c-octeon-core.h" +#define INITIAL_DELTA_HZ 1000000 +#define TWSI_MASTER_CLK_REG_DEF_VAL 0x18 +#define TWSI_MASTER_CLK_REG_OTX2_VAL 0x3 + /* interrupt service routine */ irqreturn_t octeon_i2c_isr(int irq, void *dev_id) { @@ -40,7 +45,7 @@ static bool octeon_i2c_test_iflg(struct octeon_i2c *i2c) * octeon_i2c_wait - wait for the IFLG to be set * @i2c: The struct octeon_i2c * - * Returns 0 on success, otherwise a negative errno. + * Returns: 0 on success, otherwise a negative errno. */ static int octeon_i2c_wait(struct octeon_i2c *i2c) { @@ -80,7 +85,7 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c) static bool octeon_i2c_hlc_test_valid(struct octeon_i2c *i2c) { - return (__raw_readq(i2c->twsi_base + SW_TWSI(i2c)) & SW_TWSI_V) == 0; + return (__raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)) & SW_TWSI_V) == 0; } static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c) @@ -130,11 +135,37 @@ static void octeon_i2c_hlc_disable(struct octeon_i2c *i2c) octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); } +static void octeon_i2c_block_enable(struct octeon_i2c *i2c) +{ + u64 mode; + + if (i2c->block_enabled || !OCTEON_REG_BLOCK_CTL(i2c)) + return; + + i2c->block_enabled = true; + mode = __raw_readq(i2c->twsi_base + OCTEON_REG_MODE(i2c)); + mode |= TWSX_MODE_BLOCK_MODE; + octeon_i2c_writeq_flush(mode, i2c->twsi_base + OCTEON_REG_MODE(i2c)); +} + +static void octeon_i2c_block_disable(struct octeon_i2c *i2c) +{ + u64 mode; + + if (!i2c->block_enabled || !OCTEON_REG_BLOCK_CTL(i2c)) + return; + + i2c->block_enabled = false; + mode = __raw_readq(i2c->twsi_base + OCTEON_REG_MODE(i2c)); + mode &= ~TWSX_MODE_BLOCK_MODE; + octeon_i2c_writeq_flush(mode, i2c->twsi_base + OCTEON_REG_MODE(i2c)); +} + /** * octeon_i2c_hlc_wait - wait for an HLC operation to complete * @i2c: The struct octeon_i2c * - * Returns 0 on success, otherwise -ETIMEDOUT. + * Returns: 0 on success, otherwise -ETIMEDOUT. */ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c) { @@ -177,13 +208,14 @@ static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c) static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read) { u8 stat; + u64 mode; /* * This is ugly... in HLC mode the status is not in the status register - * but in the lower 8 bits of SW_TWSI. + * but in the lower 8 bits of OCTEON_REG_SW_TWSI. */ if (i2c->hlc_enabled) - stat = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + stat = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); else stat = octeon_i2c_stat_read(i2c); @@ -215,14 +247,14 @@ static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read) case STAT_LOST_ARB_B0: return -EAGAIN; - /* Being addressed as slave, should back off & listen */ + /* Being addressed as local target, should back off & listen */ case STAT_SLAVE_60: case STAT_SLAVE_70: case STAT_GENDATA_ACK: case STAT_GENDATA_NAK: return -EOPNOTSUPP; - /* Core busy as slave */ + /* Core busy as local target */ case STAT_SLAVE_80: case STAT_SLAVE_88: case STAT_SLAVE_A0: @@ -239,6 +271,13 @@ static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read) case STAT_RXADDR_NAK: case STAT_AD2W_NAK: return -ENXIO; + + case STAT_WDOG_TOUT: + mode = __raw_readq(i2c->twsi_base + OCTEON_REG_MODE(i2c)); + /* Set BUS_MON_RST to reset bus monitor */ + mode |= BUS_MON_RST_MASK; + octeon_i2c_writeq_flush(mode, i2c->twsi_base + OCTEON_REG_MODE(i2c)); + return -EIO; default: dev_err(i2c->dev, "unhandled state: %d\n", stat); return -EIO; @@ -260,7 +299,7 @@ static int octeon_i2c_recovery(struct octeon_i2c *i2c) * octeon_i2c_start - send START to the bus * @i2c: The struct octeon_i2c * - * Returns 0 on success, otherwise a negative errno. + * Returns: 0 on success, otherwise a negative errno. */ static int octeon_i2c_start(struct octeon_i2c *i2c) { @@ -268,6 +307,7 @@ static int octeon_i2c_start(struct octeon_i2c *i2c) u8 stat; octeon_i2c_hlc_disable(i2c); + octeon_i2c_block_disable(i2c); octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STA); ret = octeon_i2c_wait(i2c); @@ -301,7 +341,7 @@ static void octeon_i2c_stop(struct octeon_i2c *i2c) * * The address is sent over the bus, then the data is read. * - * Returns 0 on success, otherwise a negative errno. + * Returns: 0 on success, otherwise a negative errno. */ static int octeon_i2c_read(struct octeon_i2c *i2c, int target, u8 *data, u16 *rlength, bool recv_len) @@ -369,7 +409,7 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target, * * The address is sent over the bus, then the data. * - * Returns 0 on success, otherwise a negative errno. + * Returns: 0 on success, otherwise a negative errno. */ static int octeon_i2c_write(struct octeon_i2c *i2c, int target, const u8 *data, int length) @@ -408,23 +448,18 @@ static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs) octeon_i2c_hlc_enable(i2c); octeon_i2c_hlc_int_clear(i2c); - cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR; + cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR | SW_TWSI_OP_7; /* SIZE */ cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT; /* A */ cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT; - if (msgs[0].flags & I2C_M_TEN) - cmd |= SW_TWSI_OP_10; - else - cmd |= SW_TWSI_OP_7; - - octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c)); + octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); ret = octeon_i2c_hlc_wait(i2c); if (ret) goto err; - cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); if ((cmd & SW_TWSI_R) == 0) return octeon_i2c_check_status(i2c, false); @@ -432,7 +467,7 @@ static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs) msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff; if (msgs[0].len > 4) { - cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c)); + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c)); for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--) msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff; } @@ -450,17 +485,12 @@ static int octeon_i2c_hlc_write(struct octeon_i2c *i2c, struct i2c_msg *msgs) octeon_i2c_hlc_enable(i2c); octeon_i2c_hlc_int_clear(i2c); - cmd = SW_TWSI_V | SW_TWSI_SOVR; + cmd = SW_TWSI_V | SW_TWSI_SOVR | SW_TWSI_OP_7; /* SIZE */ cmd |= (u64)(msgs[0].len - 1) << SW_TWSI_SIZE_SHIFT; /* A */ cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT; - if (msgs[0].flags & I2C_M_TEN) - cmd |= SW_TWSI_OP_10; - else - cmd |= SW_TWSI_OP_7; - for (i = 0, j = msgs[0].len - 1; i < msgs[0].len && i < 4; i++, j--) cmd |= (u64)msgs[0].buf[j] << (8 * i); @@ -469,15 +499,15 @@ static int octeon_i2c_hlc_write(struct octeon_i2c *i2c, struct i2c_msg *msgs) for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--) ext |= (u64)msgs[0].buf[j] << (8 * i); - octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c)); + octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c)); } - octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c)); + octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); ret = octeon_i2c_hlc_wait(i2c); if (ret) goto err; - cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); if ((cmd & SW_TWSI_R) == 0) return octeon_i2c_check_status(i2c, false); @@ -485,6 +515,45 @@ err: return ret; } +/* Process hlc transaction */ +static int octeon_i2c_hlc_cmd_send(struct octeon_i2c *i2c, u64 cmd) +{ + octeon_i2c_hlc_int_clear(i2c); + octeon_i2c_writeq_flush(cmd, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); + + return octeon_i2c_hlc_wait(i2c); +} + +/* Generic consideration for extended internal addresses in i2c hlc r/w ops */ +static bool octeon_i2c_hlc_ext(struct octeon_i2c *i2c, struct i2c_msg msg, u64 *cmd_in, u64 *ext) +{ + bool set_ext = false; + u64 cmd = 0; + + if (msg.len == 2) { + cmd |= SW_TWSI_EIA; + *ext = (u64)msg.buf[0] << SW_TWSI_IA_SHIFT; + cmd |= (u64)msg.buf[1] << SW_TWSI_IA_SHIFT; + set_ext = true; + } else { + cmd |= (u64)msg.buf[0] << SW_TWSI_IA_SHIFT; + } + + *cmd_in |= cmd; + return set_ext; +} + +/* Construct and send i2c transaction core cmd for read ops */ +static int octeon_i2c_hlc_read_cmd(struct octeon_i2c *i2c, struct i2c_msg msg, u64 cmd) +{ + u64 ext = 0; + + if (octeon_i2c_hlc_ext(i2c, msg, &cmd, &ext)) + octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c)); + + return octeon_i2c_hlc_cmd_send(i2c, cmd); +} + /* high-level-controller composite write+read, msg0=addr, msg1=data */ static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs) { @@ -493,36 +562,18 @@ static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs octeon_i2c_hlc_enable(i2c); - cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR; + cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR | SW_TWSI_OP_7_IA; /* SIZE */ cmd |= (u64)(msgs[1].len - 1) << SW_TWSI_SIZE_SHIFT; /* A */ cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT; - if (msgs[0].flags & I2C_M_TEN) - cmd |= SW_TWSI_OP_10_IA; - else - cmd |= SW_TWSI_OP_7_IA; - - if (msgs[0].len == 2) { - u64 ext = 0; - - cmd |= SW_TWSI_EIA; - ext = (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT; - cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT; - octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c)); - } else { - cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT; - } - - octeon_i2c_hlc_int_clear(i2c); - octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c)); - - ret = octeon_i2c_hlc_wait(i2c); + /* Send core command */ + ret = octeon_i2c_hlc_read_cmd(i2c, msgs[0], cmd); if (ret) goto err; - cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); if ((cmd & SW_TWSI_R) == 0) return octeon_i2c_check_status(i2c, false); @@ -530,7 +581,7 @@ static int octeon_i2c_hlc_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff; if (msgs[1].len > 4) { - cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c)); + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c)); for (i = 0; i < msgs[1].len - 4 && i < 4; i++, j--) msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff; } @@ -548,25 +599,14 @@ static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msg octeon_i2c_hlc_enable(i2c); - cmd = SW_TWSI_V | SW_TWSI_SOVR; + cmd = SW_TWSI_V | SW_TWSI_SOVR | SW_TWSI_OP_7_IA; /* SIZE */ cmd |= (u64)(msgs[1].len - 1) << SW_TWSI_SIZE_SHIFT; /* A */ cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT; - if (msgs[0].flags & I2C_M_TEN) - cmd |= SW_TWSI_OP_10_IA; - else - cmd |= SW_TWSI_OP_7_IA; - - if (msgs[0].len == 2) { - cmd |= SW_TWSI_EIA; - ext |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT; - set_ext = true; - cmd |= (u64)msgs[0].buf[1] << SW_TWSI_IA_SHIFT; - } else { - cmd |= (u64)msgs[0].buf[0] << SW_TWSI_IA_SHIFT; - } + /* Set parameters for extended message (if required) */ + set_ext = octeon_i2c_hlc_ext(i2c, msgs[0], &cmd, &ext); for (i = 0, j = msgs[1].len - 1; i < msgs[1].len && i < 4; i++, j--) cmd |= (u64)msgs[1].buf[j] << (8 * i); @@ -577,16 +617,13 @@ static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msg set_ext = true; } if (set_ext) - octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT(i2c)); - - octeon_i2c_hlc_int_clear(i2c); - octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI(i2c)); + octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c)); - ret = octeon_i2c_hlc_wait(i2c); + ret = octeon_i2c_hlc_cmd_send(i2c, cmd); if (ret) goto err; - cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); if ((cmd & SW_TWSI_R) == 0) return octeon_i2c_check_status(i2c, false); @@ -595,37 +632,166 @@ err: } /** - * octeon_i2c_xfer - The driver's master_xfer function + * octeon_i2c_hlc_block_comp_read - high-level-controller composite block read + * @i2c: The struct octeon_i2c + * @msgs: msg[0] contains address, place read data into msg[1] + * + * i2c core command is constructed and written into the SW_TWSI register. + * The execution of the command will result in requested data being + * placed into a FIFO buffer, ready to be read. + * Used in the case where the i2c xfer is for greater than 8 bytes of read data. + * + * Returns: 0 on success, otherwise a negative errno. + */ +static int octeon_i2c_hlc_block_comp_read(struct octeon_i2c *i2c, struct i2c_msg *msgs) +{ + int ret; + u16 len, i; + u64 cmd; + + octeon_i2c_hlc_enable(i2c); + octeon_i2c_block_enable(i2c); + + /* Write (size - 1) into block control register */ + len = msgs[1].len - 1; + octeon_i2c_writeq_flush((u64)len, i2c->twsi_base + OCTEON_REG_BLOCK_CTL(i2c)); + + /* Prepare core command */ + cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR | SW_TWSI_OP_7_IA; + cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT; + + /* Send core command */ + ret = octeon_i2c_hlc_read_cmd(i2c, msgs[0], cmd); + if (ret) + goto err; + + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); + if ((cmd & SW_TWSI_R) == 0) { + octeon_i2c_block_disable(i2c); + return octeon_i2c_check_status(i2c, false); + } + + /* read data in FIFO */ + octeon_i2c_writeq_flush(TWSX_BLOCK_STS_RESET_PTR, + i2c->twsi_base + OCTEON_REG_BLOCK_STS(i2c)); + for (i = 0; i <= len; i += 8) { + /* Byte-swap FIFO data and copy into msg buffer */ + __be64 rd = cpu_to_be64(__raw_readq(i2c->twsi_base + OCTEON_REG_BLOCK_FIFO(i2c))); + + memcpy(&msgs[1].buf[i], &rd, min(8, msgs[1].len - i)); + } + +err: + octeon_i2c_block_disable(i2c); + return ret; +} + +/** + * octeon_i2c_hlc_block_comp_write - high-level-controller composite block write + * @i2c: The struct octeon_i2c + * @msgs: msg[0] contains address, msg[1] contains data to be written + * + * i2c core command is constructed and write data is written into the FIFO buffer. + * The execution of the command will result in HW write, using the data in FIFO. + * Used in the case where the i2c xfer is for greater than 8 bytes of write data. + * + * Returns: 0 on success, otherwise a negative errno. + */ +static int octeon_i2c_hlc_block_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msgs) +{ + bool set_ext; + int ret; + u16 len, i; + u64 cmd, ext = 0; + + octeon_i2c_hlc_enable(i2c); + octeon_i2c_block_enable(i2c); + + /* Write (size - 1) into block control register */ + len = msgs[1].len - 1; + octeon_i2c_writeq_flush((u64)len, i2c->twsi_base + OCTEON_REG_BLOCK_CTL(i2c)); + + /* Prepare core command */ + cmd = SW_TWSI_V | SW_TWSI_SOVR | SW_TWSI_OP_7_IA; + cmd |= (u64)(msgs[0].addr & 0x7full) << SW_TWSI_ADDR_SHIFT; + + /* Set parameters for extended message (if required) */ + set_ext = octeon_i2c_hlc_ext(i2c, msgs[0], &cmd, &ext); + + /* Write msg into FIFO buffer */ + octeon_i2c_writeq_flush(TWSX_BLOCK_STS_RESET_PTR, + i2c->twsi_base + OCTEON_REG_BLOCK_STS(i2c)); + for (i = 0; i <= len; i += 8) { + __be64 buf = 0; + + /* Copy 8 bytes or remaining bytes from message buffer */ + memcpy(&buf, &msgs[1].buf[i], min(8, msgs[1].len - i)); + + /* Byte-swap message data and write into FIFO */ + buf = cpu_to_be64(buf); + octeon_i2c_writeq_flush((u64)buf, i2c->twsi_base + OCTEON_REG_BLOCK_FIFO(i2c)); + } + if (set_ext) + octeon_i2c_writeq_flush(ext, i2c->twsi_base + OCTEON_REG_SW_TWSI_EXT(i2c)); + + /* Send command to core (send data in FIFO) */ + ret = octeon_i2c_hlc_cmd_send(i2c, cmd); + if (ret) + goto err; + + cmd = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); + if ((cmd & SW_TWSI_R) == 0) { + octeon_i2c_block_disable(i2c); + return octeon_i2c_check_status(i2c, false); + } + +err: + octeon_i2c_block_disable(i2c); + return ret; +} + +/** + * octeon_i2c_xfer - The driver's xfer function * @adap: Pointer to the i2c_adapter structure * @msgs: Pointer to the messages to be processed * @num: Length of the MSGS array * - * Returns the number of messages processed, or a negative errno on failure. + * Returns: the number of messages processed, or a negative errno on failure. */ int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct octeon_i2c *i2c = i2c_get_adapdata(adap); int i, ret = 0; - if (num == 1) { - if (msgs[0].len > 0 && msgs[0].len <= 8) { - if (msgs[0].flags & I2C_M_RD) - ret = octeon_i2c_hlc_read(i2c, msgs); - else - ret = octeon_i2c_hlc_write(i2c, msgs); - goto out; - } - } else if (num == 2) { - if ((msgs[0].flags & I2C_M_RD) == 0 && - (msgs[1].flags & I2C_M_RECV_LEN) == 0 && - msgs[0].len > 0 && msgs[0].len <= 2 && - msgs[1].len > 0 && msgs[1].len <= 8 && - msgs[0].addr == msgs[1].addr) { - if (msgs[1].flags & I2C_M_RD) - ret = octeon_i2c_hlc_comp_read(i2c, msgs); - else - ret = octeon_i2c_hlc_comp_write(i2c, msgs); - goto out; + if (IS_LS_FREQ(i2c->twsi_freq)) { + if (num == 1) { + if (msgs[0].len > 0 && msgs[0].len <= 8) { + if (msgs[0].flags & I2C_M_RD) + ret = octeon_i2c_hlc_read(i2c, msgs); + else + ret = octeon_i2c_hlc_write(i2c, msgs); + goto out; + } + } else if (num == 2) { + if ((msgs[0].flags & I2C_M_RD) == 0 && + (msgs[1].flags & I2C_M_RECV_LEN) == 0 && + msgs[0].len > 0 && msgs[0].len <= 2 && + msgs[1].len > 0 && + msgs[0].addr == msgs[1].addr) { + if (msgs[1].len <= 8) { + if (msgs[1].flags & I2C_M_RD) + ret = octeon_i2c_hlc_comp_read(i2c, msgs); + else + ret = octeon_i2c_hlc_comp_write(i2c, msgs); + goto out; + } else if (msgs[1].len <= 1024 && OCTEON_REG_BLOCK_CTL(i2c)) { + if (msgs[1].flags & I2C_M_RD) + ret = octeon_i2c_hlc_block_comp_read(i2c, msgs); + else + ret = octeon_i2c_hlc_block_comp_write(i2c, msgs); + goto out; + } + } } } @@ -658,31 +824,64 @@ out: void octeon_i2c_set_clock(struct octeon_i2c *i2c) { int tclk, thp_base, inc, thp_idx, mdiv_idx, ndiv_idx, foscl, diff; - int thp = 0x18, mdiv = 2, ndiv = 0, delta_hz = 1000000; + bool is_plat_otx2; + /* + * Find divisors to produce target frequency, start with large delta + * to cover wider range of divisors, note thp = TCLK half period and + * ds is OSCL output frequency divisor. + */ + unsigned int thp, mdiv_min, mdiv = 2, ndiv = 0, ds = 10; + unsigned int delta_hz = INITIAL_DELTA_HZ; + + is_plat_otx2 = octeon_i2c_is_otx2(to_pci_dev(i2c->dev)); + + if (is_plat_otx2) { + thp = TWSI_MASTER_CLK_REG_OTX2_VAL; + mdiv_min = 0; + if (!IS_LS_FREQ(i2c->twsi_freq)) + ds = 15; + } else { + thp = TWSI_MASTER_CLK_REG_DEF_VAL; + mdiv_min = 2; + } for (ndiv_idx = 0; ndiv_idx < 8 && delta_hz != 0; ndiv_idx++) { /* * An mdiv value of less than 2 seems to not work well * with ds1337 RTCs, so we constrain it to larger values. */ - for (mdiv_idx = 15; mdiv_idx >= 2 && delta_hz != 0; mdiv_idx--) { + for (mdiv_idx = 15; mdiv_idx >= mdiv_min && delta_hz != 0; mdiv_idx--) { /* * For given ndiv and mdiv values check the * two closest thp values. */ - tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10; + tclk = i2c->twsi_freq * (mdiv_idx + 1) * ds; tclk *= (1 << ndiv_idx); - thp_base = (i2c->sys_freq / (tclk * 2)) - 1; + if (is_plat_otx2) + thp_base = (i2c->sys_freq / tclk) - 2; + else + thp_base = (i2c->sys_freq / (tclk * 2)) - 1; for (inc = 0; inc <= 1; inc++) { thp_idx = thp_base + inc; if (thp_idx < 5 || thp_idx > 0xff) continue; - foscl = i2c->sys_freq / (2 * (thp_idx + 1)); + if (is_plat_otx2) + foscl = i2c->sys_freq / (thp_idx + 2); + else + foscl = i2c->sys_freq / + (2 * (thp_idx + 1)); foscl = foscl / (1 << ndiv_idx); - foscl = foscl / (mdiv_idx + 1) / 10; + foscl = foscl / (mdiv_idx + 1) / ds; + if (foscl > i2c->twsi_freq) + continue; diff = abs(foscl - i2c->twsi_freq); + /* + * Diff holds difference between calculated frequency + * value vs desired frequency. + * Delta_hz is updated with last minimum diff. + */ if (diff < delta_hz) { delta_hz = diff; thp = thp_idx; @@ -694,6 +893,17 @@ void octeon_i2c_set_clock(struct octeon_i2c *i2c) } octeon_i2c_reg_write(i2c, SW_TWSI_OP_TWSI_CLK, thp); octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv); + if (is_plat_otx2) { + u64 mode; + + mode = __raw_readq(i2c->twsi_base + OCTEON_REG_MODE(i2c)); + /* Set REFCLK_SRC and HS_MODE in TWSX_MODE register */ + if (!IS_LS_FREQ(i2c->twsi_freq)) + mode |= TWSX_MODE_HS_MASK; + else + mode &= ~TWSX_MODE_HS_MASK; + octeon_i2c_writeq_flush(mode, i2c->twsi_base + OCTEON_REG_MODE(i2c)); + } } int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c) diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h index 9bb9f64fdda0..32a44f2d6274 100644 --- a/drivers/i2c/busses/i2c-octeon-core.h +++ b/drivers/i2c/busses/i2c-octeon-core.h @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ #include <linux/atomic.h> +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/device.h> @@ -7,6 +8,7 @@ #include <linux/i2c-smbus.h> #include <linux/io.h> #include <linux/kernel.h> +#include <linux/pci.h> /* Controller command patterns */ #define SW_TWSI_V BIT_ULL(63) /* Valid bit */ @@ -37,8 +39,8 @@ /* Controller command and status bits */ #define TWSI_CTL_CE 0x80 /* High level controller enable */ #define TWSI_CTL_ENAB 0x40 /* Bus enable */ -#define TWSI_CTL_STA 0x20 /* Master-mode start, HW clears when done */ -#define TWSI_CTL_STP 0x10 /* Master-mode stop, HW clears when done */ +#define TWSI_CTL_STA 0x20 /* Controller-mode start, HW clears when done */ +#define TWSI_CTL_STP 0x10 /* Controller-mode stop, HW clears when done */ #define TWSI_CTL_IFLG 0x08 /* HW event, SW writes 0 to ACK */ #define TWSI_CTL_AAK 0x04 /* Assert ACK */ @@ -71,6 +73,7 @@ #define STAT_SLAVE_ACK 0xC8 #define STAT_AD2W_ACK 0xD0 #define STAT_AD2W_NAK 0xD8 +#define STAT_WDOG_TOUT 0xF0 #define STAT_IDLE 0xF8 /* TWSI_INT values */ @@ -92,11 +95,31 @@ struct octeon_i2c_reg_offset { unsigned int sw_twsi; unsigned int twsi_int; unsigned int sw_twsi_ext; + unsigned int mode; + unsigned int block_ctl; + unsigned int block_sts; + unsigned int block_fifo; }; -#define SW_TWSI(x) (x->roff.sw_twsi) -#define TWSI_INT(x) (x->roff.twsi_int) -#define SW_TWSI_EXT(x) (x->roff.sw_twsi_ext) +#define OCTEON_REG_SW_TWSI(x) ((x)->roff.sw_twsi) +#define OCTEON_REG_TWSI_INT(x) ((x)->roff.twsi_int) +#define OCTEON_REG_SW_TWSI_EXT(x) ((x)->roff.sw_twsi_ext) +#define OCTEON_REG_MODE(x) ((x)->roff.mode) +#define OCTEON_REG_BLOCK_CTL(x) ((x)->roff.block_ctl) +#define OCTEON_REG_BLOCK_STS(x) ((x)->roff.block_sts) +#define OCTEON_REG_BLOCK_FIFO(x) ((x)->roff.block_fifo) + +/* TWSX_MODE register */ +#define TWSX_MODE_REFCLK_SRC BIT(4) +#define TWSX_MODE_BLOCK_MODE BIT(2) +#define TWSX_MODE_HS_MODE BIT(0) +#define TWSX_MODE_HS_MASK (TWSX_MODE_REFCLK_SRC | TWSX_MODE_HS_MODE) + +/* TWSX_BLOCK_STS register */ +#define TWSX_BLOCK_STS_RESET_PTR BIT(0) + +/* Set BUS_MON_RST to reset bus monitor */ +#define BUS_MON_RST_MASK BIT(3) struct octeon_i2c { wait_queue_head_t queue; @@ -110,6 +133,7 @@ struct octeon_i2c { void __iomem *twsi_base; struct device *dev; bool hlc_enabled; + bool block_enabled; bool broken_irq_mode; bool broken_irq_check; void (*int_enable)(struct octeon_i2c *); @@ -134,16 +158,16 @@ static inline void octeon_i2c_writeq_flush(u64 val, void __iomem *addr) * @eop_reg: Register selector * @data: Value to be written * - * The I2C core registers are accessed indirectly via the SW_TWSI CSR. + * The I2C core registers are accessed indirectly via the OCTEON_REG_SW_TWSI CSR. */ static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data) { int tries = 1000; u64 tmp; - __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI(i2c)); + __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); do { - tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + tmp = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); if (--tries < 0) return; } while ((tmp & SW_TWSI_V) != 0); @@ -169,9 +193,9 @@ static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg, int tries = 1000; u64 tmp; - __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI(i2c)); + __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); do { - tmp = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + tmp = __raw_readq(i2c->twsi_base + OCTEON_REG_SW_TWSI(i2c)); if (--tries < 0) { /* signal that the returned data is invalid */ if (error) @@ -191,24 +215,40 @@ static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg, octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT, NULL) /** - * octeon_i2c_read_int - read the TWSI_INT register + * octeon_i2c_read_int - read the OCTEON_REG_TWSI_INT register * @i2c: The struct octeon_i2c * * Returns the value of the register. */ static inline u64 octeon_i2c_read_int(struct octeon_i2c *i2c) { - return __raw_readq(i2c->twsi_base + TWSI_INT(i2c)); + return __raw_readq(i2c->twsi_base + OCTEON_REG_TWSI_INT(i2c)); } /** - * octeon_i2c_write_int - write the TWSI_INT register + * octeon_i2c_write_int - write the OCTEON_REG_TWSI_INT register * @i2c: The struct octeon_i2c * @data: Value to be written */ static inline void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data) { - octeon_i2c_writeq_flush(data, i2c->twsi_base + TWSI_INT(i2c)); + octeon_i2c_writeq_flush(data, i2c->twsi_base + OCTEON_REG_TWSI_INT(i2c)); +} + +#define IS_LS_FREQ(twsi_freq) ((twsi_freq) <= 400000) +#define PCI_SUBSYS_DEVID_9XXX 0xB +#define PCI_SUBSYS_MASK GENMASK(15, 12) +/** + * octeon_i2c_is_otx2 - check for chip ID + * @pdev: PCI dev structure + * + * Returns true if the device is an OcteonTX2, false otherwise. + */ +static inline bool octeon_i2c_is_otx2(struct pci_dev *pdev) +{ + u32 chip_id = FIELD_GET(PCI_SUBSYS_MASK, pdev->subsystem_device); + + return (chip_id == PCI_SUBSYS_DEVID_9XXX); } /* Prototypes */ diff --git a/drivers/i2c/busses/i2c-octeon-platdrv.c b/drivers/i2c/busses/i2c-octeon-platdrv.c index 0c227963c8d6..edfca7b20f29 100644 --- a/drivers/i2c/busses/i2c-octeon-platdrv.c +++ b/drivers/i2c/busses/i2c-octeon-platdrv.c @@ -122,7 +122,7 @@ static u32 octeon_i2c_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm octeon_i2c_algo = { - .master_xfer = octeon_i2c_xfer, + .xfer = octeon_i2c_xfer, .functionality = octeon_i2c_functionality, }; @@ -253,12 +253,11 @@ out: return result; }; -static int octeon_i2c_remove(struct platform_device *pdev) +static void octeon_i2c_remove(struct platform_device *pdev) { struct octeon_i2c *i2c = platform_get_drvdata(pdev); i2c_del_adapter(&i2c->adap); - return 0; }; static const struct of_device_id octeon_i2c_match[] = { diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index f9ae520aed22..d9f590f0c384 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -24,12 +24,13 @@ #include <linux/platform_device.h> #include <linux/clk.h> #include <linux/io.h> +#include <linux/mux/consumer.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/slab.h> #include <linux/platform_data/i2c-omap.h> #include <linux/pm_runtime.h> #include <linux/pinctrl/consumer.h> +#include <linux/property.h> /* I2C controller revisions */ #define OMAP_I2C_OMAP1_REV_2 0x20 @@ -211,6 +212,7 @@ struct omap_i2c_dev { u16 syscstate; u16 westate; u16 errata; + struct mux_state *mux_state; }; static const u8 reg_map_ip_v1[] = { @@ -660,7 +662,7 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop, bool polling) { struct omap_i2c_dev *omap = i2c_get_adapdata(adap); - unsigned long timeout; + unsigned long time_left; u16 w; int ret; @@ -740,19 +742,18 @@ static int omap_i2c_xfer_msg(struct i2c_adapter *adap, * into arbitration and we're currently unable to recover from it. */ if (!polling) { - timeout = wait_for_completion_timeout(&omap->cmd_complete, - OMAP_I2C_TIMEOUT); + time_left = wait_for_completion_timeout(&omap->cmd_complete, + OMAP_I2C_TIMEOUT); } else { do { omap_i2c_wait(omap); ret = omap_i2c_xfer_data(omap); } while (ret == -EAGAIN); - timeout = !ret; + time_left = !ret; } - if (timeout == 0) { - dev_err(omap->dev, "controller timed out\n"); + if (time_left == 0) { omap_i2c_reset(omap); __omap_i2c_init(omap); return -ETIMEDOUT; @@ -827,7 +828,6 @@ omap_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg msgs[], int num, omap->set_mpu_wkup_lat(omap->dev, -1); out: - pm_runtime_mark_last_busy(omap->dev); pm_runtime_put_autosuspend(omap->dev); return r; } @@ -1049,23 +1049,6 @@ static int omap_i2c_transmit_data(struct omap_i2c_dev *omap, u8 num_bytes, return 0; } -static irqreturn_t -omap_i2c_isr(int irq, void *dev_id) -{ - struct omap_i2c_dev *omap = dev_id; - irqreturn_t ret = IRQ_HANDLED; - u16 mask; - u16 stat; - - stat = omap_i2c_read_reg(omap, OMAP_I2C_STAT_REG); - mask = omap_i2c_read_reg(omap, OMAP_I2C_IE_REG); - - if (stat & mask) - ret = IRQ_WAKE_THREAD; - - return ret; -} - static int omap_i2c_xfer_data(struct omap_i2c_dev *omap) { u16 bits; @@ -1096,8 +1079,13 @@ static int omap_i2c_xfer_data(struct omap_i2c_dev *omap) } if (stat & OMAP_I2C_STAT_NACK) { - err |= OMAP_I2C_STAT_NACK; + omap->cmd_err |= OMAP_I2C_STAT_NACK; omap_i2c_ack_stat(omap, OMAP_I2C_STAT_NACK); + + if (!(stat & ~OMAP_I2C_STAT_NACK)) { + err = -EAGAIN; + break; + } } if (stat & OMAP_I2C_STAT_AL) { @@ -1212,9 +1200,9 @@ omap_i2c_isr_thread(int this_irq, void *dev_id) } static const struct i2c_algorithm omap_i2c_algo = { - .master_xfer = omap_i2c_xfer_irq, - .master_xfer_atomic = omap_i2c_xfer_polling, - .functionality = omap_i2c_func, + .xfer = omap_i2c_xfer_irq, + .xfer_atomic = omap_i2c_xfer_polling, + .functionality = omap_i2c_func, }; static const struct i2c_adapter_quirks omap_i2c_quirks = { @@ -1262,7 +1250,7 @@ static const struct of_device_id omap_i2c_of_match[] = { .compatible = "ti,omap2420-i2c", .data = &omap2420_pdata, }, - { }, + { } }; MODULE_DEVICE_TABLE(of, omap_i2c_of_match); #endif @@ -1358,7 +1346,6 @@ omap_i2c_probe(struct platform_device *pdev) const struct omap_i2c_bus_platform_data *pdata = dev_get_platdata(&pdev->dev); struct device_node *node = pdev->dev.of_node; - const struct of_device_id *match; int irq; int r; u32 rev; @@ -1376,11 +1363,10 @@ omap_i2c_probe(struct platform_device *pdev) if (IS_ERR(omap->base)) return PTR_ERR(omap->base); - match = of_match_device(of_match_ptr(omap_i2c_of_match), &pdev->dev); - if (match) { + if (pdev->dev.of_node) { u32 freq = I2C_MAX_STANDARD_MODE_FREQ; - pdata = match->data; + pdata = device_get_match_data(&pdev->dev); omap->flags = pdata->flags; of_property_read_u32(node, "clock-frequency", &freq); @@ -1467,15 +1453,34 @@ omap_i2c_probe(struct platform_device *pdev) (1000 * omap->speed / 8); } + if (of_property_present(node, "mux-states")) { + struct mux_state *mux_state; + + mux_state = devm_mux_state_get(&pdev->dev, NULL); + if (IS_ERR(mux_state)) { + r = PTR_ERR(mux_state); + dev_dbg(&pdev->dev, "failed to get I2C mux: %d\n", r); + goto err_put_pm; + } + omap->mux_state = mux_state; + r = mux_state_select(omap->mux_state); + if (r) { + dev_err(&pdev->dev, "failed to select I2C mux: %d\n", r); + goto err_put_pm; + } + } + /* reset ASAP, clearing any IRQs */ - omap_i2c_init(omap); + r = omap_i2c_init(omap); + if (r) + goto err_mux_state_deselect; if (omap->rev < OMAP_I2C_OMAP1_REV_2) r = devm_request_irq(&pdev->dev, omap->irq, omap_i2c_omap1_isr, IRQF_NO_SUSPEND, pdev->name, omap); else r = devm_request_threaded_irq(&pdev->dev, omap->irq, - omap_i2c_isr, omap_i2c_isr_thread, + NULL, omap_i2c_isr_thread, IRQF_NO_SUSPEND | IRQF_ONESHOT, pdev->name, omap); @@ -1504,39 +1509,46 @@ omap_i2c_probe(struct platform_device *pdev) dev_info(omap->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr, major, minor, omap->speed); - pm_runtime_mark_last_busy(omap->dev); pm_runtime_put_autosuspend(omap->dev); return 0; err_unuse_clocks: omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0); - pm_runtime_dont_use_autosuspend(omap->dev); +err_mux_state_deselect: + if (omap->mux_state) + mux_state_deselect(omap->mux_state); +err_put_pm: pm_runtime_put_sync(omap->dev); err_disable_pm: + pm_runtime_dont_use_autosuspend(omap->dev); pm_runtime_disable(&pdev->dev); return r; } -static int omap_i2c_remove(struct platform_device *pdev) +static void omap_i2c_remove(struct platform_device *pdev) { struct omap_i2c_dev *omap = platform_get_drvdata(pdev); int ret; i2c_del_adapter(&omap->adapter); - ret = pm_runtime_resume_and_get(&pdev->dev); + + if (omap->mux_state) + mux_state_deselect(omap->mux_state); + + ret = pm_runtime_get_sync(&pdev->dev); if (ret < 0) - return ret; + dev_err(omap->dev, "Failed to resume hardware, skip disable\n"); + else + omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0); - omap_i2c_write_reg(omap, OMAP_I2C_CON_REG, 0); pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - return 0; } -static int __maybe_unused omap_i2c_runtime_suspend(struct device *dev) +static int omap_i2c_runtime_suspend(struct device *dev) { struct omap_i2c_dev *omap = dev_get_drvdata(dev); @@ -1562,7 +1574,7 @@ static int __maybe_unused omap_i2c_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused omap_i2c_runtime_resume(struct device *dev) +static int omap_i2c_runtime_resume(struct device *dev) { struct omap_i2c_dev *omap = dev_get_drvdata(dev); @@ -1576,11 +1588,32 @@ static int __maybe_unused omap_i2c_runtime_resume(struct device *dev) return 0; } +static int omap_i2c_suspend(struct device *dev) +{ + /* + * If the controller is autosuspended, there is no way to wakeup it once + * runtime pm is disabled (in suspend_late()). + * But a device may need the controller up during suspend_noirq() or + * resume_noirq(). + * Wakeup the controller while runtime pm is enabled, so it is available + * until its suspend_noirq(), and from resume_noirq(). + */ + return pm_runtime_resume_and_get(dev); +} + +static int omap_i2c_resume(struct device *dev) +{ + pm_runtime_put_autosuspend(dev); + + return 0; +} + static const struct dev_pm_ops omap_i2c_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend, - omap_i2c_runtime_resume, NULL) + NOIRQ_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) + SYSTEM_SLEEP_PM_OPS(omap_i2c_suspend, omap_i2c_resume) + RUNTIME_PM_OPS(omap_i2c_runtime_suspend, + omap_i2c_runtime_resume, NULL) }; static struct platform_driver omap_i2c_driver = { @@ -1588,7 +1621,7 @@ static struct platform_driver omap_i2c_driver = { .remove = omap_i2c_remove, .driver = { .name = "omap_i2c", - .pm = &omap_i2c_pm_ops, + .pm = pm_ptr(&omap_i2c_pm_ops), .of_match_table = of_match_ptr(omap_i2c_of_match), }, }; diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c index 9f773b4f5ed8..c9b62892397a 100644 --- a/drivers/i2c/busses/i2c-opal.c +++ b/drivers/i2c/busses/i2c-opal.c @@ -70,8 +70,8 @@ exit: return rc; } -static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num) +static int i2c_opal_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) { unsigned long opal_id = (unsigned long)adap->algo_data; struct opal_i2c_request req; @@ -179,9 +179,9 @@ static u32 i2c_opal_func(struct i2c_adapter *adapter) } static const struct i2c_algorithm i2c_opal_algo = { - .master_xfer = i2c_opal_master_xfer, - .smbus_xfer = i2c_opal_smbus_xfer, - .functionality = i2c_opal_func, + .xfer = i2c_opal_xfer, + .smbus_xfer = i2c_opal_smbus_xfer, + .functionality = i2c_opal_func, }; /* @@ -232,13 +232,11 @@ static int i2c_opal_probe(struct platform_device *pdev) return rc; } -static int i2c_opal_remove(struct platform_device *pdev) +static void i2c_opal_remove(struct platform_device *pdev) { struct i2c_adapter *adapter = platform_get_drvdata(pdev); i2c_del_adapter(adapter); - - return 0; } static const struct of_device_id i2c_opal_of_match[] = { @@ -251,7 +249,7 @@ MODULE_DEVICE_TABLE(of, i2c_opal_of_match); static struct platform_driver i2c_opal_driver = { .probe = i2c_opal_probe, - .remove = i2c_opal_remove, + .remove = i2c_opal_remove, .driver = { .name = "i2c-opal", .of_match_table = i2c_opal_of_match, diff --git a/drivers/i2c/busses/i2c-owl.c b/drivers/i2c/busses/i2c-owl.c index 98882fe4e965..84a195e35886 100644 --- a/drivers/i2c/busses/i2c-owl.c +++ b/drivers/i2c/busses/i2c-owl.c @@ -16,7 +16,8 @@ #include <linux/io.h> #include <linux/iopoll.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> +#include <linux/platform_device.h> /* I2C registers */ #define OWL_I2C_REG_CTL 0x0000 @@ -171,7 +172,7 @@ static void owl_i2c_xfer_data(struct owl_i2c_dev *i2c_dev) i2c_dev->err = 0; - /* Handle NACK from slave */ + /* Handle NACK from target */ fifostat = readl(i2c_dev->base + OWL_I2C_REG_FIFOSTAT); if (fifostat & OWL_I2C_FIFOSTAT_RNB) { i2c_dev->err = -ENXIO; @@ -301,7 +302,7 @@ static int owl_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs, OWL_I2C_CTL_IRQE, !atomic); /* - * Select: FIFO enable, Master mode, Stop enable, Data count enable, + * Select: FIFO enable, controller mode, Stop enable, Data count enable, * Send start bit */ i2c_cmd = OWL_I2C_CMD_SECL | OWL_I2C_CMD_MSS | OWL_I2C_CMD_SE | @@ -313,7 +314,7 @@ static int owl_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs, i2c_cmd |= OWL_I2C_CMD_AS(msgs[0].len + 1) | OWL_I2C_CMD_SAS(1) | OWL_I2C_CMD_RBE; - /* Write slave address */ + /* Write target address */ addr = i2c_8bit_addr_from_msg(&msgs[0]); writel(addr, i2c_dev->base + OWL_I2C_REG_TXDAT); @@ -419,9 +420,9 @@ static int owl_i2c_xfer_atomic(struct i2c_adapter *adap, } static const struct i2c_algorithm owl_i2c_algorithm = { - .master_xfer = owl_i2c_xfer, - .master_xfer_atomic = owl_i2c_xfer_atomic, - .functionality = owl_i2c_func, + .xfer = owl_i2c_xfer, + .xfer_atomic = owl_i2c_xfer_atomic, + .functionality = owl_i2c_func, }; static const struct i2c_adapter_quirks owl_i2c_quirks = { @@ -461,21 +462,16 @@ static int owl_i2c_probe(struct platform_device *pdev) return -EINVAL; } - i2c_dev->clk = devm_clk_get(dev, NULL); + i2c_dev->clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(i2c_dev->clk)) { - dev_err(dev, "failed to get clock\n"); + dev_err(dev, "failed to enable clock\n"); return PTR_ERR(i2c_dev->clk); } - ret = clk_prepare_enable(i2c_dev->clk); - if (ret) - return ret; - i2c_dev->clk_rate = clk_get_rate(i2c_dev->clk); if (!i2c_dev->clk_rate) { dev_err(dev, "input clock rate should not be zero\n"); - ret = -EINVAL; - goto disable_clk; + return -EINVAL; } init_completion(&i2c_dev->msg_complete); @@ -496,15 +492,10 @@ static int owl_i2c_probe(struct platform_device *pdev) i2c_dev); if (ret) { dev_err(dev, "failed to request irq %d\n", irq); - goto disable_clk; + return ret; } return i2c_add_adapter(&i2c_dev->adap); - -disable_clk: - clk_disable_unprepare(i2c_dev->clk); - - return ret; } static const struct of_device_id owl_i2c_of_match[] = { @@ -519,7 +510,7 @@ static struct platform_driver owl_i2c_driver = { .probe = owl_i2c_probe, .driver = { .name = "owl-i2c", - .of_match_table = of_match_ptr(owl_i2c_of_match), + .of_match_table = owl_i2c_of_match, .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; diff --git a/drivers/i2c/busses/i2c-parport.c b/drivers/i2c/busses/i2c-parport.c index 0af86a542568..3249bbd5eb43 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -400,7 +400,6 @@ static struct parport_driver i2c_parport_driver = { .name = "i2c-parport", .match_port = i2c_parport_attach, .detach = i2c_parport_detach, - .devmodel = true, }; module_parport_driver(i2c_parport_driver); diff --git a/drivers/i2c/busses/i2c-pasemi-core.c b/drivers/i2c/busses/i2c-pasemi-core.c index 7d54a9f34c74..f4eca44ed183 100644 --- a/drivers/i2c/busses/i2c-pasemi-core.c +++ b/drivers/i2c/busses/i2c-pasemi-core.c @@ -5,42 +5,60 @@ * SMBus host driver for PA Semi PWRficient */ +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/kernel.h> -#include <linux/stddef.h> #include <linux/sched.h> -#include <linux/i2c.h> -#include <linux/delay.h> #include <linux/slab.h> -#include <linux/io.h> +#include <linux/stddef.h> #include "i2c-pasemi-core.h" /* Register offsets */ #define REG_MTXFIFO 0x00 #define REG_MRXFIFO 0x04 +#define REG_XFSTA 0x0c #define REG_SMSTA 0x14 #define REG_IMASK 0x18 #define REG_CTL 0x1c #define REG_REV 0x28 /* Register defs */ -#define MTXFIFO_READ 0x00000400 -#define MTXFIFO_STOP 0x00000200 -#define MTXFIFO_START 0x00000100 -#define MTXFIFO_DATA_M 0x000000ff +#define MTXFIFO_READ BIT(10) +#define MTXFIFO_STOP BIT(9) +#define MTXFIFO_START BIT(8) +#define MTXFIFO_DATA_M GENMASK(7, 0) + +#define MRXFIFO_EMPTY BIT(8) +#define MRXFIFO_DATA_M GENMASK(7, 0) + +#define SMSTA_XIP BIT(28) +#define SMSTA_XEN BIT(27) +#define SMSTA_JMD BIT(25) +#define SMSTA_JAM BIT(24) +#define SMSTA_MTO BIT(23) +#define SMSTA_MTA BIT(22) +#define SMSTA_MTN BIT(21) +#define SMSTA_MRNE BIT(19) +#define SMSTA_MTE BIT(16) +#define SMSTA_TOM BIT(6) + +#define CTL_EN BIT(11) +#define CTL_MRR BIT(10) +#define CTL_MTR BIT(9) +#define CTL_UJM BIT(8) +#define CTL_CLK_M GENMASK(7, 0) -#define MRXFIFO_EMPTY 0x00000100 -#define MRXFIFO_DATA_M 0x000000ff - -#define SMSTA_XEN 0x08000000 -#define SMSTA_MTN 0x00200000 - -#define CTL_MRR 0x00000400 -#define CTL_MTR 0x00000200 -#define CTL_EN 0x00000800 -#define CTL_CLK_M 0x000000ff +/* + * The hardware (supposedly) has a 25ms timeout for clock stretching, thus + * use 100ms here which should be plenty. + */ +#define PASEMI_TRANSFER_TIMEOUT_MS 100 static inline void reg_write(struct pasemi_smbus *smbus, int reg, int val) { @@ -61,7 +79,7 @@ static inline int reg_read(struct pasemi_smbus *smbus, int reg) static void pasemi_reset(struct pasemi_smbus *smbus) { - u32 val = (CTL_MTR | CTL_MRR | (smbus->clk_div & CTL_CLK_M)); + u32 val = (CTL_MTR | CTL_MRR | CTL_UJM | (smbus->clk_div & CTL_CLK_M)); if (smbus->hw_rev >= 6) val |= CTL_EN; @@ -70,43 +88,102 @@ static void pasemi_reset(struct pasemi_smbus *smbus) reinit_completion(&smbus->irq_completion); } -static void pasemi_smb_clear(struct pasemi_smbus *smbus) +static int pasemi_smb_clear(struct pasemi_smbus *smbus) { unsigned int status; + int ret; + + /* First wait for the bus to go idle */ + ret = readx_poll_timeout(ioread32, smbus->ioaddr + REG_SMSTA, + status, !(status & (SMSTA_XIP | SMSTA_JAM)), + USEC_PER_MSEC, + USEC_PER_MSEC * PASEMI_TRANSFER_TIMEOUT_MS); + + if (ret < 0) { + dev_err(smbus->dev, "Bus is still stuck (status 0x%08x xfstatus 0x%08x)\n", + status, reg_read(smbus, REG_XFSTA)); + return -EIO; + } + + /* If any badness happened or there is data in the FIFOs, reset the FIFOs */ + if ((status & (SMSTA_MRNE | SMSTA_JMD | SMSTA_MTO | SMSTA_TOM | SMSTA_MTN | SMSTA_MTA)) || + !(status & SMSTA_MTE)) { + dev_warn(smbus->dev, "Issuing reset due to status 0x%08x (xfstatus 0x%08x)\n", + status, reg_read(smbus, REG_XFSTA)); + pasemi_reset(smbus); + } - status = reg_read(smbus, REG_SMSTA); + /* Clear the flags */ reg_write(smbus, REG_SMSTA, status); + + return 0; } static int pasemi_smb_waitready(struct pasemi_smbus *smbus) { - int timeout = 100; unsigned int status; if (smbus->use_irq) { reinit_completion(&smbus->irq_completion); reg_write(smbus, REG_IMASK, SMSTA_XEN | SMSTA_MTN); - wait_for_completion_timeout(&smbus->irq_completion, msecs_to_jiffies(100)); + int ret = wait_for_completion_timeout( + &smbus->irq_completion, + msecs_to_jiffies(PASEMI_TRANSFER_TIMEOUT_MS)); reg_write(smbus, REG_IMASK, 0); status = reg_read(smbus, REG_SMSTA); + + if (ret < 0) { + dev_err(smbus->dev, + "Completion wait failed with %d, status 0x%08x\n", + ret, status); + return ret; + } else if (ret == 0) { + dev_err(smbus->dev, "Timeout, status 0x%08x\n", status); + return -ETIME; + } } else { - status = reg_read(smbus, REG_SMSTA); - while (!(status & SMSTA_XEN) && timeout--) { - msleep(1); - status = reg_read(smbus, REG_SMSTA); + int ret = readx_poll_timeout( + ioread32, smbus->ioaddr + REG_SMSTA, + status, status & SMSTA_XEN, + USEC_PER_MSEC, + USEC_PER_MSEC * PASEMI_TRANSFER_TIMEOUT_MS); + + if (ret < 0) { + dev_err(smbus->dev, "Timeout, status 0x%08x\n", status); + return -ETIME; } } - /* Got NACK? */ - if (status & SMSTA_MTN) - return -ENXIO; + /* Controller timeout? */ + if (status & SMSTA_TOM) { + dev_err(smbus->dev, "Controller timeout, status 0x%08x\n", status); + return -EIO; + } - if (timeout < 0) { - dev_warn(smbus->dev, "Timeout, status 0x%08x\n", status); - reg_write(smbus, REG_SMSTA, status); + /* Peripheral timeout? */ + if (status & SMSTA_MTO) { + dev_err(smbus->dev, "Peripheral timeout, status 0x%08x\n", status); return -ETIME; } + /* Still stuck in a transaction? */ + if (status & SMSTA_XIP) { + dev_err(smbus->dev, "Bus stuck, status 0x%08x\n", status); + return -EIO; + } + + /* Arbitration loss? */ + if (status & SMSTA_MTA) { + dev_err(smbus->dev, "Arbitration loss, status 0x%08x\n", status); + return -EBUSY; + } + + /* Got NACK? */ + if (status & SMSTA_MTN) { + dev_err(smbus->dev, "NACK, status 0x%08x\n", status); + return -ENXIO; + } + /* Clear XEN */ reg_write(smbus, REG_SMSTA, SMSTA_XEN); @@ -167,9 +244,9 @@ static int pasemi_i2c_xfer(struct i2c_adapter *adapter, struct pasemi_smbus *smbus = adapter->algo_data; int ret, i; - pasemi_smb_clear(smbus); - - ret = 0; + ret = pasemi_smb_clear(smbus); + if (ret) + return ret; for (i = 0; i < num && !ret; i++) ret = pasemi_i2c_xfer_msg(adapter, &msgs[i], (i == (num - 1))); @@ -190,7 +267,9 @@ static int pasemi_smb_xfer(struct i2c_adapter *adapter, addr <<= 1; read_flag = read_write == I2C_SMBUS_READ; - pasemi_smb_clear(smbus); + err = pasemi_smb_clear(smbus); + if (err) + return err; switch (size) { case I2C_SMBUS_QUICK: @@ -336,9 +415,9 @@ static u32 pasemi_smb_func(struct i2c_adapter *adapter) } static const struct i2c_algorithm smbus_algorithm = { - .master_xfer = pasemi_i2c_xfer, - .smbus_xfer = pasemi_smb_xfer, - .functionality = pasemi_smb_func, + .xfer = pasemi_i2c_xfer, + .smbus_xfer = pasemi_smb_xfer, + .functionality = pasemi_smb_func, }; int pasemi_i2c_common_probe(struct pasemi_smbus *smbus) @@ -369,6 +448,7 @@ int pasemi_i2c_common_probe(struct pasemi_smbus *smbus) return 0; } +EXPORT_SYMBOL_GPL(pasemi_i2c_common_probe); irqreturn_t pasemi_irq_handler(int irq, void *dev_id) { @@ -378,3 +458,8 @@ irqreturn_t pasemi_irq_handler(int irq, void *dev_id) complete(&smbus->irq_completion); return IRQ_HANDLED; } +EXPORT_SYMBOL_GPL(pasemi_irq_handler); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Olof Johansson <olof@lixom.net>"); +MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver"); diff --git a/drivers/i2c/busses/i2c-pasemi-pci.c b/drivers/i2c/busses/i2c-pasemi-pci.c index cfc89e04eb94..b9ccb54ec77e 100644 --- a/drivers/i2c/busses/i2c-pasemi-pci.c +++ b/drivers/i2c/busses/i2c-pasemi-pci.c @@ -5,15 +5,15 @@ * SMBus host driver for PA Semi PWRficient */ +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/kernel.h> #include <linux/module.h> #include <linux/pci.h> -#include <linux/kernel.h> -#include <linux/stddef.h> #include <linux/sched.h> -#include <linux/i2c.h> -#include <linux/delay.h> #include <linux/slab.h> -#include <linux/io.h> +#include <linux/stddef.h> #include "i2c-pasemi-core.h" @@ -56,7 +56,7 @@ static int pasemi_smb_pci_probe(struct pci_dev *dev, if (!smbus->ioaddr) return -EBUSY; - smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + smbus->adapter.class = I2C_CLASS_HWMON; error = pasemi_i2c_common_probe(smbus); if (error) return error; diff --git a/drivers/i2c/busses/i2c-pasemi-platform.c b/drivers/i2c/busses/i2c-pasemi-platform.c index e35945a91dbe..a486a37d3863 100644 --- a/drivers/i2c/busses/i2c-pasemi-platform.c +++ b/drivers/i2c/busses/i2c-pasemi-platform.c @@ -66,22 +66,18 @@ static int pasemi_platform_i2c_probe(struct platform_device *pdev) if (of_property_read_u32(dev->of_node, "clock-frequency", &frequency)) frequency = I2C_MAX_STANDARD_MODE_FREQ; - data->clk_ref = devm_clk_get(dev, NULL); + data->clk_ref = devm_clk_get_enabled(dev, NULL); if (IS_ERR(data->clk_ref)) return PTR_ERR(data->clk_ref); - error = clk_prepare_enable(data->clk_ref); - if (error) - return error; - error = pasemi_platform_i2c_calc_clk_div(data, frequency); if (error) - goto out_clk_disable; + return error; smbus->adapter.dev.of_node = pdev->dev.of_node; error = pasemi_i2c_common_probe(smbus); if (error) - goto out_clk_disable; + return error; irq_num = platform_get_irq(pdev, 0); error = devm_request_irq(smbus->dev, irq_num, pasemi_irq_handler, 0, "pasemi_apple_i2c", (void *)smbus); @@ -91,20 +87,9 @@ static int pasemi_platform_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, data); return 0; - -out_clk_disable: - clk_disable_unprepare(data->clk_ref); - - return error; } -static int pasemi_platform_i2c_remove(struct platform_device *pdev) -{ - struct pasemi_platform_i2c_data *data = platform_get_drvdata(pdev); - - clk_disable_unprepare(data->clk_ref); - return 0; -} +static void pasemi_platform_i2c_remove(struct platform_device *pdev) { } static const struct of_device_id pasemi_platform_i2c_of_match[] = { { .compatible = "apple,t8103-i2c" }, @@ -119,7 +104,7 @@ static struct platform_driver pasemi_platform_i2c_driver = { .of_match_table = pasemi_platform_i2c_of_match, }, .probe = pasemi_platform_i2c_probe, - .remove = pasemi_platform_i2c_remove, + .remove = pasemi_platform_i2c_remove, }; module_platform_driver(pasemi_platform_i2c_driver); diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c index 85e8cf58e8bf..0cbf2f509527 100644 --- a/drivers/i2c/busses/i2c-pca-isa.c +++ b/drivers/i2c/busses/i2c-pca-isa.c @@ -95,7 +95,7 @@ static struct i2c_algo_pca_data pca_isa_data = { /* .data intentionally left NULL, not needed with ISA */ .write_byte = pca_isa_writebyte, .read_byte = pca_isa_readbyte, - .wait_for_completion = pca_isa_waitforcompletion, + .wait_for_completion_cb = pca_isa_waitforcompletion, .reset_chip = pca_isa_resetchip, }; diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c index 86d4f75ef8d3..c0f35ebbe37d 100644 --- a/drivers/i2c/busses/i2c-pca-platform.c +++ b/drivers/i2c/busses/i2c-pca-platform.c @@ -22,7 +22,6 @@ #include <linux/gpio/consumer.h> #include <linux/io.h> #include <linux/of.h> -#include <linux/of_device.h> #include <asm/irq.h> @@ -181,7 +180,7 @@ static int i2c_pca_pf_probe(struct platform_device *pdev) } i2c->algo_data.data = i2c; - i2c->algo_data.wait_for_completion = i2c_pca_pf_waitforcompletion; + i2c->algo_data.wait_for_completion_cb = i2c_pca_pf_waitforcompletion; if (i2c->gpio) i2c->algo_data.reset_chip = i2c_pca_pf_resetchip; else @@ -221,13 +220,11 @@ static int i2c_pca_pf_probe(struct platform_device *pdev) return 0; } -static int i2c_pca_pf_remove(struct platform_device *pdev) +static void i2c_pca_pf_remove(struct platform_device *pdev) { struct i2c_pca_pf_data *i2c = platform_get_drvdata(pdev); i2c_del_adapter(&i2c->adap); - - return 0; } #ifdef CONFIG_OF diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 809fbd014cd6..ac3bb550303f 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -29,25 +29,14 @@ #include <linux/stddef.h> #include <linux/ioport.h> #include <linux/i2c.h> +#include <linux/i2c-smbus.h> #include <linux/slab.h> #include <linux/dmi.h> #include <linux/acpi.h> #include <linux/io.h> +#include <linux/platform_data/x86/amd-fch.h> - -/* PIIX4 SMBus address offsets */ -#define SMBHSTSTS (0 + piix4_smba) -#define SMBHSLVSTS (1 + piix4_smba) -#define SMBHSTCNT (2 + piix4_smba) -#define SMBHSTCMD (3 + piix4_smba) -#define SMBHSTADD (4 + piix4_smba) -#define SMBHSTDAT0 (5 + piix4_smba) -#define SMBHSTDAT1 (6 + piix4_smba) -#define SMBBLKDAT (7 + piix4_smba) -#define SMBSLVCNT (8 + piix4_smba) -#define SMBSHDWCMD (9 + piix4_smba) -#define SMBSLVEVT (0xA + piix4_smba) -#define SMBSLVDAT (0xC + piix4_smba) +#include "i2c-piix4.h" /* count for request_region */ #define SMBIOSIZE 9 @@ -69,7 +58,6 @@ #define PIIX4_BYTE 0x04 #define PIIX4_BYTE_DATA 0x08 #define PIIX4_WORD_DATA 0x0C -#define PIIX4_BLOCK_DATA 0x14 /* Multi-port constants */ #define PIIX4_MAX_ADAPTERS 4 @@ -93,13 +81,13 @@ #define SB800_PIIX4_PORT_IDX_MASK 0x06 #define SB800_PIIX4_PORT_IDX_SHIFT 1 -/* On kerncz and Hudson2, SmBus0Sel is at bit 20:19 of PMx00 DecodeEn */ -#define SB800_PIIX4_PORT_IDX_KERNCZ 0x02 -#define SB800_PIIX4_PORT_IDX_MASK_KERNCZ 0x18 +/* SmBus0Sel is at bit 20:19 of PMx00 DecodeEn */ +#define SB800_PIIX4_PORT_IDX_KERNCZ (FCH_PM_DECODEEN + 0x02) +#define SB800_PIIX4_PORT_IDX_MASK_KERNCZ (FCH_PM_DECODEEN_SMBUS0SEL >> 16) #define SB800_PIIX4_PORT_IDX_SHIFT_KERNCZ 3 -#define SB800_PIIX4_FCH_PM_ADDR 0xFED80300 #define SB800_PIIX4_FCH_PM_SIZE 8 +#define SB800_ASF_ACPI_PATH "\\_SB.ASFC" /* insmod parameters */ @@ -145,7 +133,7 @@ static const struct dmi_system_id piix4_dmi_ibm[] = { .ident = "IBM", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), }, }, - { }, + { } }; /* @@ -159,11 +147,6 @@ static const char *piix4_main_port_names_sb800[PIIX4_MAX_ADAPTERS] = { }; static const char *piix4_aux_port_name_sb800 = " port 1"; -struct sb800_mmio_cfg { - void __iomem *addr; - bool use_mmio; -}; - struct i2c_piix4_adapdata { unsigned short smba; @@ -174,25 +157,24 @@ struct i2c_piix4_adapdata { struct sb800_mmio_cfg mmio_cfg; }; -static int piix4_sb800_region_request(struct device *dev, - struct sb800_mmio_cfg *mmio_cfg) +int piix4_sb800_region_request(struct device *dev, struct sb800_mmio_cfg *mmio_cfg) { if (mmio_cfg->use_mmio) { void __iomem *addr; - if (!request_mem_region_muxed(SB800_PIIX4_FCH_PM_ADDR, + if (!request_mem_region_muxed(FCH_PM_BASE, SB800_PIIX4_FCH_PM_SIZE, "sb800_piix4_smb")) { dev_err(dev, "SMBus base address memory region 0x%x already in use.\n", - SB800_PIIX4_FCH_PM_ADDR); + FCH_PM_BASE); return -EBUSY; } - addr = ioremap(SB800_PIIX4_FCH_PM_ADDR, + addr = ioremap(FCH_PM_BASE, SB800_PIIX4_FCH_PM_SIZE); if (!addr) { - release_mem_region(SB800_PIIX4_FCH_PM_ADDR, + release_mem_region(FCH_PM_BASE, SB800_PIIX4_FCH_PM_SIZE); dev_err(dev, "SMBus base address mapping failed.\n"); return -ENOMEM; @@ -213,19 +195,20 @@ static int piix4_sb800_region_request(struct device *dev, return 0; } +EXPORT_SYMBOL_NS_GPL(piix4_sb800_region_request, "PIIX4_SMBUS"); -static void piix4_sb800_region_release(struct device *dev, - struct sb800_mmio_cfg *mmio_cfg) +void piix4_sb800_region_release(struct device *dev, struct sb800_mmio_cfg *mmio_cfg) { if (mmio_cfg->use_mmio) { iounmap(mmio_cfg->addr); - release_mem_region(SB800_PIIX4_FCH_PM_ADDR, + release_mem_region(FCH_PM_BASE, SB800_PIIX4_FCH_PM_SIZE); return; } release_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE); } +EXPORT_SYMBOL_NS_GPL(piix4_sb800_region_release, "PIIX4_SMBUS"); static bool piix4_sb800_use_mmio(struct pci_dev *PIIX4_dev) { @@ -535,10 +518,8 @@ static int piix4_setup_aux(struct pci_dev *PIIX4_dev, return piix4_smba; } -static int piix4_transaction(struct i2c_adapter *piix4_adapter) +int piix4_transaction(struct i2c_adapter *piix4_adapter, unsigned short piix4_smba) { - struct i2c_piix4_adapdata *adapdata = i2c_get_adapdata(piix4_adapter); - unsigned short piix4_smba = adapdata->smba; int temp; int result = 0; int timeout = 0; @@ -589,7 +570,7 @@ static int piix4_transaction(struct i2c_adapter *piix4_adapter) result = -EIO; dev_dbg(&piix4_adapter->dev, "Bus collision! SMBus may be " "locked until next hard reset. (sorry!)\n"); - /* Clock stops and slave is stuck in mid-transmission */ + /* Clock stops and target is stuck in mid-transmission */ } if (temp & 0x04) { @@ -610,6 +591,7 @@ static int piix4_transaction(struct i2c_adapter *piix4_adapter) inb_p(SMBHSTDAT1)); return result; } +EXPORT_SYMBOL_NS_GPL(piix4_transaction, "PIIX4_SMBUS"); /* Return negative errno on error. */ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, @@ -674,7 +656,7 @@ static s32 piix4_access(struct i2c_adapter * adap, u16 addr, outb_p((size & 0x1C) + (ENABLE_INT9 & 1), SMBHSTCNT); - status = piix4_transaction(adap); + status = piix4_transaction(adap, piix4_smba); if (status) return status; @@ -763,7 +745,7 @@ static void piix4_imc_wakeup(void) release_region(KERNCZ_IMC_IDX, 2); } -static int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg) +int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg) { u8 smba_en_lo, val; @@ -785,6 +767,7 @@ static int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg) return (smba_en_lo & piix4_port_mask_sb800); } +EXPORT_SYMBOL_NS_GPL(piix4_sb800_port_sel, "PIIX4_SMBUS"); /* * Handles access to multiple SMBus ports on the SB800. @@ -943,7 +926,7 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba, } adap->owner = THIS_MODULE; - adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + adap->class = I2C_CLASS_HWMON; adap->algo = sb800_main ? &piix4_smbus_algorithm_sb800 : &smbus_algorithm; @@ -982,6 +965,14 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba, return retval; } + /* + * The AUX bus can not be probed as on some platforms it reports all + * devices present and all reads return "0". + * This would allow the ee1004 to be probed incorrectly. + */ + if (port == 0) + i2c_register_spd_write_enable(adap); + *padap = adap; return 0; } @@ -1034,6 +1025,9 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) { int retval; bool is_sb800 = false; + bool is_asf = false; + acpi_status status; + acpi_handle handle; if ((dev->vendor == PCI_VENDOR_ID_ATI && dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS && @@ -1096,10 +1090,16 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) } } + status = acpi_get_handle(NULL, (acpi_string)SB800_ASF_ACPI_PATH, &handle); + if (ACPI_SUCCESS(status)) + is_asf = true; + if (dev->vendor == PCI_VENDOR_ID_AMD && (dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS || dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS)) { - retval = piix4_setup_sb800(dev, id, 1); + /* Do not setup AUX port if ASF is enabled */ + if (!is_asf) + retval = piix4_setup_sb800(dev, id, 1); } if (retval > 0) { diff --git a/drivers/i2c/busses/i2c-piix4.h b/drivers/i2c/busses/i2c-piix4.h new file mode 100644 index 000000000000..36bc6ce82a27 --- /dev/null +++ b/drivers/i2c/busses/i2c-piix4.h @@ -0,0 +1,44 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * PIIX4/SB800 SMBus Interfaces + * + * Copyright (c) 2024, Advanced Micro Devices, Inc. + * All Rights Reserved. + * + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> + * Sanket Goswami <Sanket.Goswami@amd.com> + */ + +#ifndef I2C_PIIX4_H +#define I2C_PIIX4_H + +#include <linux/types.h> + +/* PIIX4 SMBus address offsets */ +#define SMBHSTSTS (0x00 + piix4_smba) +#define SMBHSLVSTS (0x01 + piix4_smba) +#define SMBHSTCNT (0x02 + piix4_smba) +#define SMBHSTCMD (0x03 + piix4_smba) +#define SMBHSTADD (0x04 + piix4_smba) +#define SMBHSTDAT0 (0x05 + piix4_smba) +#define SMBHSTDAT1 (0x06 + piix4_smba) +#define SMBBLKDAT (0x07 + piix4_smba) +#define SMBSLVCNT (0x08 + piix4_smba) +#define SMBSHDWCMD (0x09 + piix4_smba) +#define SMBSLVEVT (0x0A + piix4_smba) +#define SMBSLVDAT (0x0C + piix4_smba) + +/* PIIX4 constants */ +#define PIIX4_BLOCK_DATA 0x14 + +struct sb800_mmio_cfg { + void __iomem *addr; + bool use_mmio; +}; + +int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg); +int piix4_transaction(struct i2c_adapter *piix4_adapter, unsigned short piix4_smba); +int piix4_sb800_region_request(struct device *dev, struct sb800_mmio_cfg *mmio_cfg); +void piix4_sb800_region_release(struct device *dev, struct sb800_mmio_cfg *mmio_cfg); + +#endif /* I2C_PIIX4_H */ diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 50f21cdbe90d..8daa0008bd05 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -15,7 +15,6 @@ #include <linux/ioport.h> #include <linux/delay.h> #include <linux/i2c.h> -#include <linux/timer.h> #include <linux/completion.h> #include <linux/platform_device.h> #include <linux/io.h> @@ -32,7 +31,6 @@ struct i2c_pnx_mif { int ret; /* Return value */ int mode; /* Interface mode */ struct completion complete; /* I/O completion */ - struct timer_list timer; /* Timeout */ u8 * buf; /* Data buffer */ int len; /* Length of data buffer */ int order; /* RX Bytes to order via TX */ @@ -97,7 +95,7 @@ enum { static inline int wait_timeout(struct i2c_pnx_algo_data *data) { - long timeout = data->timeout; + long timeout = jiffies_to_msecs(data->timeout); while (timeout > 0 && (ioread32(I2C_REG_STS(data)) & mstatus_active)) { mdelay(1); @@ -108,7 +106,7 @@ static inline int wait_timeout(struct i2c_pnx_algo_data *data) static inline int wait_reset(struct i2c_pnx_algo_data *data) { - long timeout = data->timeout; + long timeout = jiffies_to_msecs(data->timeout); while (timeout > 0 && (ioread32(I2C_REG_CTL(data)) & mcntrl_reset)) { mdelay(1); @@ -117,24 +115,6 @@ static inline int wait_reset(struct i2c_pnx_algo_data *data) return (timeout <= 0); } -static inline void i2c_pnx_arm_timer(struct i2c_pnx_algo_data *alg_data) -{ - struct timer_list *timer = &alg_data->mif.timer; - unsigned long expires = msecs_to_jiffies(alg_data->timeout); - - if (expires <= 1) - expires = 2; - - del_timer_sync(timer); - - dev_dbg(&alg_data->adapter.dev, "Timer armed at %lu plus %lu jiffies.\n", - jiffies, expires); - - timer->expires = jiffies + expires; - - add_timer(timer); -} - /** * i2c_pnx_start - start a device * @slave_addr: slave address @@ -259,8 +239,6 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data) ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie), I2C_REG_CTL(alg_data)); - del_timer_sync(&alg_data->mif.timer); - dev_dbg(&alg_data->adapter.dev, "%s(): Waking up xfer routine.\n", __func__); @@ -276,8 +254,6 @@ static int i2c_pnx_master_xmit(struct i2c_pnx_algo_data *alg_data) ~(mcntrl_afie | mcntrl_naie | mcntrl_drmie), I2C_REG_CTL(alg_data)); - /* Stop timer. */ - del_timer_sync(&alg_data->mif.timer); dev_dbg(&alg_data->adapter.dev, "%s(): Waking up xfer routine after zero-xfer.\n", __func__); @@ -364,8 +340,6 @@ static int i2c_pnx_master_rcv(struct i2c_pnx_algo_data *alg_data) mcntrl_drmie | mcntrl_daie); iowrite32(ctl, I2C_REG_CTL(alg_data)); - /* Kill timer. */ - del_timer_sync(&alg_data->mif.timer); complete(&alg_data->mif.complete); } } @@ -400,8 +374,6 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) mcntrl_drmie); iowrite32(ctl, I2C_REG_CTL(alg_data)); - /* Stop timer, to prevent timeout. */ - del_timer_sync(&alg_data->mif.timer); complete(&alg_data->mif.complete); } else if (stat & mstatus_nai) { /* Slave did not acknowledge, generate a STOP */ @@ -419,8 +391,6 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) /* Our return value. */ alg_data->mif.ret = -EIO; - /* Stop timer, to prevent timeout. */ - del_timer_sync(&alg_data->mif.timer); complete(&alg_data->mif.complete); } else { /* @@ -453,9 +423,8 @@ static irqreturn_t i2c_pnx_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void i2c_pnx_timeout(struct timer_list *t) +static void i2c_pnx_timeout(struct i2c_pnx_algo_data *alg_data) { - struct i2c_pnx_algo_data *alg_data = from_timer(alg_data, t, mif.timer); u32 ctl; dev_err(&alg_data->adapter.dev, @@ -472,7 +441,6 @@ static void i2c_pnx_timeout(struct timer_list *t) iowrite32(ctl, I2C_REG_CTL(alg_data)); wait_reset(alg_data); alg_data->mif.ret = -EIO; - complete(&alg_data->mif.complete); } static inline void bus_reset_if_active(struct i2c_pnx_algo_data *alg_data) @@ -514,6 +482,7 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) struct i2c_msg *pmsg; int rc = 0, completed = 0, i; struct i2c_pnx_algo_data *alg_data = adap->algo_data; + unsigned long time_left; u32 stat; dev_dbg(&alg_data->adapter.dev, @@ -548,7 +517,6 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) dev_dbg(&alg_data->adapter.dev, "%s(): mode %d, %d bytes\n", __func__, alg_data->mif.mode, alg_data->mif.len); - i2c_pnx_arm_timer(alg_data); /* initialize the completion var */ init_completion(&alg_data->mif.complete); @@ -564,7 +532,10 @@ i2c_pnx_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) break; /* Wait for completion */ - wait_for_completion(&alg_data->mif.complete); + time_left = wait_for_completion_timeout(&alg_data->mif.complete, + alg_data->timeout); + if (time_left == 0) + i2c_pnx_timeout(alg_data); if (!(rc = alg_data->mif.ret)) completed++; @@ -609,11 +580,10 @@ static u32 i2c_pnx_func(struct i2c_adapter *adapter) } static const struct i2c_algorithm pnx_algorithm = { - .master_xfer = i2c_pnx_xfer, + .xfer = i2c_pnx_xfer, .functionality = i2c_pnx_func, }; -#ifdef CONFIG_PM_SLEEP static int i2c_pnx_controller_suspend(struct device *dev) { struct i2c_pnx_algo_data *alg_data = dev_get_drvdata(dev); @@ -630,12 +600,9 @@ static int i2c_pnx_controller_resume(struct device *dev) return clk_prepare_enable(alg_data->clk); } -static SIMPLE_DEV_PM_OPS(i2c_pnx_pm, - i2c_pnx_controller_suspend, i2c_pnx_controller_resume); -#define PNX_I2C_PM (&i2c_pnx_pm) -#else -#define PNX_I2C_PM NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(i2c_pnx_pm, + i2c_pnx_controller_suspend, + i2c_pnx_controller_resume); static int i2c_pnx_probe(struct platform_device *pdev) { @@ -657,7 +624,10 @@ static int i2c_pnx_probe(struct platform_device *pdev) alg_data->adapter.algo_data = alg_data; alg_data->adapter.nr = pdev->id; - alg_data->timeout = I2C_PNX_TIMEOUT_DEFAULT; + alg_data->timeout = msecs_to_jiffies(I2C_PNX_TIMEOUT_DEFAULT); + if (alg_data->timeout <= 1) + alg_data->timeout = 2; + #ifdef CONFIG_OF alg_data->adapter.dev.of_node = of_node_get(pdev->dev.of_node); if (pdev->dev.of_node) { @@ -677,14 +647,11 @@ static int i2c_pnx_probe(struct platform_device *pdev) if (IS_ERR(alg_data->clk)) return PTR_ERR(alg_data->clk); - timer_setup(&alg_data->mif.timer, i2c_pnx_timeout, 0); - snprintf(alg_data->adapter.name, sizeof(alg_data->adapter.name), "%s", pdev->name); /* Register I/O resource */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - alg_data->ioaddr = devm_ioremap_resource(&pdev->dev, res); + alg_data->ioaddr = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(alg_data->ioaddr)) return PTR_ERR(alg_data->ioaddr); @@ -743,20 +710,18 @@ out_clock: return ret; } -static int i2c_pnx_remove(struct platform_device *pdev) +static void i2c_pnx_remove(struct platform_device *pdev) { struct i2c_pnx_algo_data *alg_data = platform_get_drvdata(pdev); i2c_del_adapter(&alg_data->adapter); clk_disable_unprepare(alg_data->clk); - - return 0; } #ifdef CONFIG_OF static const struct of_device_id i2c_pnx_of_match[] = { { .compatible = "nxp,pnx-i2c" }, - { }, + { } }; MODULE_DEVICE_TABLE(of, i2c_pnx_of_match); #endif @@ -765,7 +730,7 @@ static struct platform_driver i2c_pnx_driver = { .driver = { .name = "pnx-i2c", .of_match_table = of_match_ptr(i2c_pnx_of_match), - .pm = PNX_I2C_PM, + .pm = pm_sleep_ptr(&i2c_pnx_pm), }, .probe = i2c_pnx_probe, .remove = i2c_pnx_remove, diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c index 2e74747eec9c..f99a2cc721a8 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -127,13 +127,13 @@ static s32 i2c_powermac_smbus_xfer( struct i2c_adapter* adap, } /* - * Generic i2c master transfer entrypoint. This driver only support single + * Generic i2c transfer entrypoint. This driver only supports single * messages (for "lame i2c" transfers). Anything else should use the smbus * entry point */ -static int i2c_powermac_master_xfer( struct i2c_adapter *adap, - struct i2c_msg *msgs, - int num) +static int i2c_powermac_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, + int num) { struct pmac_i2c_bus *bus = i2c_get_adapdata(adap); int rc = 0; @@ -179,23 +179,21 @@ static u32 i2c_powermac_func(struct i2c_adapter * adapter) /* For now, we only handle smbus */ static const struct i2c_algorithm i2c_powermac_algorithm = { - .smbus_xfer = i2c_powermac_smbus_xfer, - .master_xfer = i2c_powermac_master_xfer, - .functionality = i2c_powermac_func, + .smbus_xfer = i2c_powermac_smbus_xfer, + .xfer = i2c_powermac_xfer, + .functionality = i2c_powermac_func, }; static const struct i2c_adapter_quirks i2c_powermac_quirks = { .max_num_msgs = 1, }; -static int i2c_powermac_remove(struct platform_device *dev) +static void i2c_powermac_remove(struct platform_device *dev) { struct i2c_adapter *adapter = platform_get_drvdata(dev); i2c_del_adapter(adapter); memset(adapter, 0, sizeof(*adapter)); - - return 0; } static u32 i2c_powermac_get_addr(struct i2c_adapter *adap, @@ -233,7 +231,7 @@ static void i2c_powermac_create_one(struct i2c_adapter *adap, struct i2c_board_info info = {}; struct i2c_client *newdev; - strncpy(info.type, type, sizeof(info.type)); + strscpy(info.type, type, sizeof(info.type)); info.addr = addr; newdev = i2c_new_client_device(adap, &info); if (IS_ERR(newdev)) @@ -284,7 +282,7 @@ static bool i2c_powermac_get_type(struct i2c_adapter *adap, */ /* First try proper modalias */ - if (of_modalias_node(node, tmp, sizeof(tmp)) >= 0) { + if (of_alias_from_compatible(node, tmp, sizeof(tmp)) >= 0) { snprintf(type, type_size, "MAC,%s", tmp); return true; } @@ -351,7 +349,7 @@ static void i2c_powermac_register_devices(struct i2c_adapter *adap, /* Fill out the rest of the info structure */ info.addr = addr; info.irq = irq_of_parse_and_map(node, 0); - info.of_node = of_node_get(node); + info.fwnode = of_fwnode_handle(of_node_get(node)); newdev = i2c_new_client_device(adap, &info); if (IS_ERR(newdev)) { diff --git a/drivers/i2c/busses/i2c-pxa-pci.c b/drivers/i2c/busses/i2c-pxa-pci.c index 30e38bc8b6db..af2094720a4d 100644 --- a/drivers/i2c/busses/i2c-pxa-pci.c +++ b/drivers/i2c/busses/i2c-pxa-pci.c @@ -4,7 +4,7 @@ * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de> * * The CE4100's I2C device is more or less the same one as found on PXA. - * It does not support slave mode, the register slightly moved. This PCI + * It does not support target mode, the register slightly moved. This PCI * device provides three bars, every contains a single I2C controller. */ #include <linux/init.h> @@ -12,7 +12,6 @@ #include <linux/platform_device.h> #include <linux/platform_data/i2c-pxa.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/of_address.h> #define CE4100_PCI_I2C_DEVS 3 @@ -136,7 +135,7 @@ err_dev_add: static const struct pci_device_id ce4100_i2c_devices[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x2e68)}, - { }, + { } }; static struct pci_driver ce4100_i2c_driver = { diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index b605b6e43cb9..968a8b8794da 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -32,6 +32,7 @@ #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/platform_data/i2c-pxa.h> +#include <linux/property.h> #include <linux/slab.h> /* I2C register field definitions */ @@ -217,7 +218,7 @@ static const struct platform_device_id i2c_pxa_id_table[] = { { "ce4100-i2c", REGS_CE4100 }, { "pxa910-i2c", REGS_PXA910 }, { "armada-3700-i2c", REGS_A3700 }, - { }, + { } }; MODULE_DEVICE_TABLE(platform, i2c_pxa_id_table); @@ -264,6 +265,9 @@ struct pxa_i2c { u32 hs_mask; struct i2c_bus_recovery_info recovery; + struct pinctrl *pinctrl; + struct pinctrl_state *pinctrl_default; + struct pinctrl_state *pinctrl_recovery; }; #define _IBMR(i2c) ((i2c)->reg_ibmr) @@ -320,6 +324,7 @@ static void decode_ISR(unsigned int val) decode_bits(KERN_DEBUG "ISR", isr_bits, ARRAY_SIZE(isr_bits), val); } +#ifdef CONFIG_I2C_PXA_SLAVE static const struct bits icr_bits[] = { PXA_BIT(ICR_START, "START", NULL), PXA_BIT(ICR_STOP, "STOP", NULL), @@ -338,7 +343,6 @@ static const struct bits icr_bits[] = { PXA_BIT(ICR_UR, "UR", "ur"), }; -#ifdef CONFIG_I2C_PXA_SLAVE static void decode_ICR(unsigned int val) { decode_bits(KERN_DEBUG "ICR", icr_bits, ARRAY_SIZE(icr_bits), val); @@ -822,7 +826,7 @@ static inline void i2c_pxa_stop_message(struct pxa_i2c *i2c) static int i2c_pxa_send_mastercode(struct pxa_i2c *i2c) { u32 icr; - long timeout; + long time_left; spin_lock_irq(&i2c->lock); i2c->highmode_enter = true; @@ -833,12 +837,12 @@ static int i2c_pxa_send_mastercode(struct pxa_i2c *i2c) writel(icr, _ICR(i2c)); spin_unlock_irq(&i2c->lock); - timeout = wait_event_timeout(i2c->wait, - i2c->highmode_enter == false, HZ * 1); + time_left = wait_event_timeout(i2c->wait, + i2c->highmode_enter == false, HZ * 1); i2c->highmode_enter = false; - return (timeout == 0) ? I2C_RETRY : 0; + return (time_left == 0) ? I2C_RETRY : 0; } /* @@ -1046,7 +1050,7 @@ static irqreturn_t i2c_pxa_handler(int this_irq, void *dev_id) */ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) { - long timeout; + long time_left; int ret; /* @@ -1091,7 +1095,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) /* * The rest of the processing occurs in the interrupt handler. */ - timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); + time_left = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); i2c_pxa_stop_message(i2c); /* @@ -1099,7 +1103,7 @@ static int i2c_pxa_do_xfer(struct pxa_i2c *i2c, struct i2c_msg *msg, int num) */ ret = i2c->msg_idx; - if (!timeout && i2c->msg_num) { + if (!time_left && i2c->msg_num) { i2c_pxa_scream_blue_murder(i2c, "timeout with active message"); i2c_recover_bus(&i2c->adap); ret = I2C_RETRY; @@ -1150,11 +1154,11 @@ static u32 i2c_pxa_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm i2c_pxa_algorithm = { - .master_xfer = i2c_pxa_xfer, - .functionality = i2c_pxa_functionality, + .xfer = i2c_pxa_xfer, + .functionality = i2c_pxa_functionality, #ifdef CONFIG_I2C_PXA_SLAVE - .reg_slave = i2c_pxa_slave_reg, - .unreg_slave = i2c_pxa_slave_unreg, + .reg_slave = i2c_pxa_slave_reg, + .unreg_slave = i2c_pxa_slave_unreg, #endif }; @@ -1240,11 +1244,11 @@ static int i2c_pxa_pio_xfer(struct i2c_adapter *adap, } static const struct i2c_algorithm i2c_pxa_pio_algorithm = { - .master_xfer = i2c_pxa_pio_xfer, - .functionality = i2c_pxa_functionality, + .xfer = i2c_pxa_pio_xfer, + .functionality = i2c_pxa_functionality, #ifdef CONFIG_I2C_PXA_SLAVE - .reg_slave = i2c_pxa_slave_reg, - .unreg_slave = i2c_pxa_slave_unreg, + .reg_slave = i2c_pxa_slave_reg, + .unreg_slave = i2c_pxa_slave_unreg, #endif }; @@ -1252,21 +1256,17 @@ static int i2c_pxa_probe_dt(struct platform_device *pdev, struct pxa_i2c *i2c, enum pxa_i2c_types *i2c_types) { struct device_node *np = pdev->dev.of_node; - const struct of_device_id *of_id = - of_match_device(i2c_pxa_dt_ids, &pdev->dev); - if (!of_id) + if (!pdev->dev.of_node) return 1; /* For device tree we always use the dynamic or alias-assigned ID */ i2c->adap.nr = -1; - if (of_get_property(np, "mrvl,i2c-polling", NULL)) - i2c->use_pio = 1; - if (of_get_property(np, "mrvl,i2c-fast-mode", NULL)) - i2c->fast_mode = 1; + i2c->use_pio = of_property_read_bool(np, "mrvl,i2c-polling"); + i2c->fast_mode = of_property_read_bool(np, "mrvl,i2c-fast-mode"); - *i2c_types = (enum pxa_i2c_types)(of_id->data); + *i2c_types = (enum pxa_i2c_types)device_get_match_data(&pdev->dev); return 0; } @@ -1302,12 +1302,13 @@ static void i2c_pxa_prepare_recovery(struct i2c_adapter *adap) */ gpiod_set_value(i2c->recovery.scl_gpiod, ibmr & IBMR_SCLS); gpiod_set_value(i2c->recovery.sda_gpiod, ibmr & IBMR_SDAS); + + WARN_ON(pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_recovery)); } static void i2c_pxa_unprepare_recovery(struct i2c_adapter *adap) { struct pxa_i2c *i2c = adap->algo_data; - struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; u32 isr; /* @@ -1321,7 +1322,7 @@ static void i2c_pxa_unprepare_recovery(struct i2c_adapter *adap) i2c_pxa_do_reset(i2c); } - WARN_ON(pinctrl_select_state(bri->pinctrl, bri->pins_default)); + WARN_ON(pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_default)); dev_dbg(&i2c->adap.dev, "recovery: IBMR 0x%08x ISR 0x%08x\n", readl(_IBMR(i2c)), readl(_ISR(i2c))); @@ -1343,20 +1344,76 @@ static int i2c_pxa_init_recovery(struct pxa_i2c *i2c) if (IS_ENABLED(CONFIG_I2C_PXA_SLAVE)) return 0; - bri->pinctrl = devm_pinctrl_get(dev); - if (PTR_ERR(bri->pinctrl) == -ENODEV) { - bri->pinctrl = NULL; + i2c->pinctrl = devm_pinctrl_get(dev); + if (PTR_ERR(i2c->pinctrl) == -ENODEV) + i2c->pinctrl = NULL; + if (IS_ERR(i2c->pinctrl)) + return PTR_ERR(i2c->pinctrl); + + if (!i2c->pinctrl) + return 0; + + i2c->pinctrl_default = pinctrl_lookup_state(i2c->pinctrl, + PINCTRL_STATE_DEFAULT); + i2c->pinctrl_recovery = pinctrl_lookup_state(i2c->pinctrl, "recovery"); + + if (IS_ERR(i2c->pinctrl_default) || IS_ERR(i2c->pinctrl_recovery)) { + dev_info(dev, "missing pinmux recovery information: %ld %ld\n", + PTR_ERR(i2c->pinctrl_default), + PTR_ERR(i2c->pinctrl_recovery)); + return 0; + } + + /* + * Claiming GPIOs can influence the pinmux state, and may glitch the + * I2C bus. Do this carefully. + */ + bri->scl_gpiod = devm_gpiod_get(dev, "scl", GPIOD_OUT_HIGH_OPEN_DRAIN); + if (bri->scl_gpiod == ERR_PTR(-EPROBE_DEFER)) + return -EPROBE_DEFER; + if (IS_ERR(bri->scl_gpiod)) { + dev_info(dev, "missing scl gpio recovery information: %pe\n", + bri->scl_gpiod); + return 0; + } + + /* + * We have SCL. Pull SCL low and wait a bit so that SDA glitches + * have no effect. + */ + gpiod_direction_output(bri->scl_gpiod, 0); + udelay(10); + bri->sda_gpiod = devm_gpiod_get(dev, "sda", GPIOD_OUT_HIGH_OPEN_DRAIN); + + /* Wait a bit in case of a SDA glitch, and then release SCL. */ + udelay(10); + gpiod_direction_output(bri->scl_gpiod, 1); + + if (bri->sda_gpiod == ERR_PTR(-EPROBE_DEFER)) + return -EPROBE_DEFER; + + if (IS_ERR(bri->sda_gpiod)) { + dev_info(dev, "missing sda gpio recovery information: %pe\n", + bri->sda_gpiod); return 0; } - if (IS_ERR(bri->pinctrl)) - return PTR_ERR(bri->pinctrl); bri->prepare_recovery = i2c_pxa_prepare_recovery; bri->unprepare_recovery = i2c_pxa_unprepare_recovery; + bri->recover_bus = i2c_generic_scl_recovery; i2c->adap.bus_recovery_info = bri; - return 0; + /* + * Claiming GPIOs can change the pinmux state, which confuses the + * pinctrl since pinctrl's idea of the current setting is unaffected + * by the pinmux change caused by claiming the GPIO. Work around that + * by switching pinctrl to the GPIO state here. We do it this way to + * avoid glitching the I2C bus. + */ + pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_recovery); + + return pinctrl_select_state(i2c->pinctrl, i2c->pinctrl_default); } static int i2c_pxa_probe(struct platform_device *dev) @@ -1364,7 +1421,7 @@ static int i2c_pxa_probe(struct platform_device *dev) struct i2c_pxa_platform_data *plat = dev_get_platdata(&dev->dev); enum pxa_i2c_types i2c_type; struct pxa_i2c *i2c; - struct resource *res = NULL; + struct resource *res; int ret, irq; i2c = devm_kzalloc(&dev->dev, sizeof(struct pxa_i2c), GFP_KERNEL); @@ -1381,8 +1438,7 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.dev.of_node = dev->dev.of_node; #endif - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - i2c->reg_base = devm_ioremap_resource(&dev->dev, res); + i2c->reg_base = devm_platform_get_and_ioremap_resource(dev, 0, &res); if (IS_ERR(i2c->reg_base)) return PTR_ERR(i2c->reg_base); @@ -1406,10 +1462,9 @@ static int i2c_pxa_probe(struct platform_device *dev) strscpy(i2c->adap.name, "pxa_i2c-i2c", sizeof(i2c->adap.name)); i2c->clk = devm_clk_get(&dev->dev, NULL); - if (IS_ERR(i2c->clk)) { - dev_err(&dev->dev, "failed to get the clk: %ld\n", PTR_ERR(i2c->clk)); - return PTR_ERR(i2c->clk); - } + if (IS_ERR(i2c->clk)) + return dev_err_probe(&dev->dev, PTR_ERR(i2c->clk), + "failed to get the clk\n"); i2c->reg_ibmr = i2c->reg_base + pxa_reg_layout[i2c_type].ibmr; i2c->reg_idbr = i2c->reg_base + pxa_reg_layout[i2c_type].idbr; @@ -1448,7 +1503,10 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.name); } - clk_prepare_enable(i2c->clk); + ret = clk_prepare_enable(i2c->clk); + if (ret) + return dev_err_probe(&dev->dev, ret, + "failed to enable clock\n"); if (i2c->use_pio) { i2c->adap.algo = &i2c_pxa_pio_algorithm; @@ -1484,18 +1542,15 @@ ereqirq: return ret; } -static int i2c_pxa_remove(struct platform_device *dev) +static void i2c_pxa_remove(struct platform_device *dev) { struct pxa_i2c *i2c = platform_get_drvdata(dev); i2c_del_adapter(&i2c->adap); clk_disable_unprepare(i2c->clk); - - return 0; } -#ifdef CONFIG_PM static int i2c_pxa_suspend_noirq(struct device *dev) { struct pxa_i2c *i2c = dev_get_drvdata(dev); @@ -1520,17 +1575,12 @@ static const struct dev_pm_ops i2c_pxa_dev_pm_ops = { .resume_noirq = i2c_pxa_resume_noirq, }; -#define I2C_PXA_DEV_PM_OPS (&i2c_pxa_dev_pm_ops) -#else -#define I2C_PXA_DEV_PM_OPS NULL -#endif - static struct platform_driver i2c_pxa_driver = { .probe = i2c_pxa_probe, .remove = i2c_pxa_remove, .driver = { .name = "pxa2xx-i2c", - .pm = I2C_PXA_DEV_PM_OPS, + .pm = pm_sleep_ptr(&i2c_pxa_dev_pm_ops), .of_match_table = i2c_pxa_dt_ids, }, .id_table = i2c_pxa_id_table, @@ -1546,6 +1596,7 @@ static void __exit i2c_adap_pxa_exit(void) platform_driver_unregister(&i2c_pxa_driver); } +MODULE_DESCRIPTION("Intel PXA2XX I2C adapter"); MODULE_LICENSE("GPL"); subsys_initcall(i2c_adap_pxa_init); diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c index a4b97fe3c3a5..884055df1560 100644 --- a/drivers/i2c/busses/i2c-qcom-cci.c +++ b/drivers/i2c/busses/i2c-qcom-cci.c @@ -120,7 +120,6 @@ struct cci_data { unsigned int num_masters; struct i2c_adapter_quirks quirks; u16 queue_size[NUM_QUEUES]; - unsigned long cci_clk_rate; struct hw_params params[3]; }; @@ -451,7 +450,6 @@ static int cci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ret = num; err: - pm_runtime_mark_last_busy(cci->dev); pm_runtime_put_autosuspend(cci->dev); return ret; @@ -463,8 +461,8 @@ static u32 cci_func(struct i2c_adapter *adap) } static const struct i2c_algorithm cci_algo = { - .master_xfer = cci_xfer, - .functionality = cci_func, + .xfer = cci_xfer, + .functionality = cci_func, }; static int cci_enable_clocks(struct cci *cci) @@ -509,7 +507,6 @@ static int __maybe_unused cci_suspend(struct device *dev) static int __maybe_unused cci_resume(struct device *dev) { cci_resume_runtime(dev); - pm_runtime_mark_last_busy(dev); pm_request_autosuspend(dev); return 0; @@ -523,7 +520,6 @@ static const struct dev_pm_ops qcom_cci_pm = { static int cci_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - unsigned long cci_clk_rate = 0; struct device_node *child; struct resource *r; struct cci *cci; @@ -581,36 +577,19 @@ static int cci_probe(struct platform_device *pdev) /* Memory */ - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - cci->base = devm_ioremap_resource(dev, r); + cci->base = devm_platform_get_and_ioremap_resource(pdev, 0, &r); if (IS_ERR(cci->base)) return PTR_ERR(cci->base); /* Clocks */ ret = devm_clk_bulk_get_all(dev, &cci->clocks); - if (ret < 1) { - dev_err(dev, "failed to get clocks %d\n", ret); - return ret; - } + if (ret < 0) + return dev_err_probe(dev, ret, "failed to get clocks\n"); + else if (!ret) + return dev_err_probe(dev, -EINVAL, "not enough clocks in DT\n"); cci->nclocks = ret; - /* Retrieve CCI clock rate */ - for (i = 0; i < cci->nclocks; i++) { - if (!strcmp(cci->clocks[i].id, "cci")) { - cci_clk_rate = clk_get_rate(cci->clocks[i].clk); - break; - } - } - - if (cci_clk_rate != cci->data->cci_clk_rate) { - /* cci clock set by the bootloader or via assigned clock rate - * in DT. - */ - dev_warn(dev, "Found %lu cci clk rate while %lu was expected\n", - cci_clk_rate, cci->data->cci_clk_rate); - } - ret = cci_enable_clocks(cci); if (ret < 0) return ret; @@ -675,7 +654,7 @@ disable_clocks: return ret; } -static int cci_remove(struct platform_device *pdev) +static void cci_remove(struct platform_device *pdev) { struct cci *cci = platform_get_drvdata(pdev); int i; @@ -691,8 +670,6 @@ static int cci_remove(struct platform_device *pdev) disable_irq(cci->irq); pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); - - return 0; } static const struct cci_data cci_v1_data = { @@ -702,7 +679,6 @@ static const struct cci_data cci_v1_data = { .max_write_len = 10, .max_read_len = 12, }, - .cci_clk_rate = 19200000, .params[I2C_MODE_STANDARD] = { .thigh = 78, .tlow = 114, @@ -736,7 +712,6 @@ static const struct cci_data cci_v1_5_data = { .max_write_len = 10, .max_read_len = 12, }, - .cci_clk_rate = 19200000, .params[I2C_MODE_STANDARD] = { .thigh = 78, .tlow = 114, @@ -770,7 +745,6 @@ static const struct cci_data cci_v2_data = { .max_write_len = 11, .max_read_len = 12, }, - .cci_clk_rate = 37500000, .params[I2C_MODE_STANDARD] = { .thigh = 201, .tlow = 174, @@ -809,11 +783,63 @@ static const struct cci_data cci_v2_data = { }, }; +static const struct cci_data cci_msm8953_data = { + .num_masters = 2, + .queue_size = { 64, 16 }, + .quirks = { + .max_write_len = 11, + .max_read_len = 12, + }, + .params[I2C_MODE_STANDARD] = { + .thigh = 78, + .tlow = 114, + .tsu_sto = 28, + .tsu_sta = 28, + .thd_dat = 10, + .thd_sta = 77, + .tbuf = 118, + .scl_stretch_en = 0, + .trdhld = 6, + .tsp = 1 + }, + .params[I2C_MODE_FAST] = { + .thigh = 20, + .tlow = 28, + .tsu_sto = 21, + .tsu_sta = 21, + .thd_dat = 13, + .thd_sta = 18, + .tbuf = 32, + .scl_stretch_en = 0, + .trdhld = 6, + .tsp = 3 + }, + .params[I2C_MODE_FAST_PLUS] = { + .thigh = 16, + .tlow = 22, + .tsu_sto = 17, + .tsu_sta = 18, + .thd_dat = 16, + .thd_sta = 15, + .tbuf = 19, + .scl_stretch_en = 1, + .trdhld = 3, + .tsp = 3 + }, +}; + static const struct of_device_id cci_dt_match[] = { { .compatible = "qcom,msm8226-cci", .data = &cci_v1_data}, - { .compatible = "qcom,msm8916-cci", .data = &cci_v1_data}, + { .compatible = "qcom,msm8953-cci", .data = &cci_msm8953_data}, { .compatible = "qcom,msm8974-cci", .data = &cci_v1_5_data}, { .compatible = "qcom,msm8996-cci", .data = &cci_v2_data}, + + + /* + * Legacy compatibles kept for backwards compatibility. + * Do not add any new ones unless they introduce a new config + */ + { .compatible = "qcom,msm8916-cci", .data = &cci_v1_data}, { .compatible = "qcom,sdm845-cci", .data = &cci_v2_data}, { .compatible = "qcom,sm8250-cci", .data = &cci_v2_data}, { .compatible = "qcom,sm8450-cci", .data = &cci_v2_data}, diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index fd70794bfcee..3a04016db2c3 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -14,8 +14,9 @@ #include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/qcom-geni-se.h> +#include <linux/soc/qcom/geni-se.h> #include <linux/spinlock.h> +#include <linux/units.h> #define SE_I2C_TX_TRANS_LEN 0x26c #define SE_I2C_RX_TRANS_LEN 0x270 @@ -70,13 +71,31 @@ enum geni_i2c_err_code { << 5) #define I2C_AUTO_SUSPEND_DELAY 250 -#define KHZ(freq) (1000 * freq) #define PACKING_BYTES_PW 4 #define ABORT_TIMEOUT HZ #define XFER_TIMEOUT HZ #define RST_TIMEOUT HZ +#define QCOM_I2C_MIN_NUM_OF_MSGS_MULTI_DESC 2 + +/** + * struct geni_i2c_gpi_multi_desc_xfer - Structure for multi transfer support + * + * @msg_idx_cnt: Current message index being processed in the transfer + * @unmap_msg_cnt: Number of messages that have been unmapped + * @irq_cnt: Number of transfer completion interrupts received + * @dma_buf: Array of virtual addresses for DMA-safe buffers + * @dma_addr: Array of DMA addresses corresponding to the buffers + */ +struct geni_i2c_gpi_multi_desc_xfer { + u32 msg_idx_cnt; + u32 unmap_msg_cnt; + u32 irq_cnt; + void **dma_buf; + dma_addr_t *dma_addr; +}; + struct geni_i2c_dev { struct geni_se se; u32 tx_wm; @@ -99,6 +118,9 @@ struct geni_i2c_dev { struct dma_chan *rx_c; bool gpi_mode; bool abort_done; + bool is_tx_multi_desc_xfer; + u32 num_msgs; + struct geni_i2c_gpi_multi_desc_xfer i2c_multi_desc_config; }; struct geni_i2c_desc { @@ -146,22 +168,36 @@ struct geni_i2c_clk_fld { * clk_freq_out = t / t_cycle * source_clock = 19.2 MHz */ -static const struct geni_i2c_clk_fld geni_i2c_clk_map[] = { - {KHZ(100), 7, 10, 11, 26}, - {KHZ(400), 2, 5, 12, 24}, - {KHZ(1000), 1, 3, 9, 18}, +static const struct geni_i2c_clk_fld geni_i2c_clk_map_19p2mhz[] = { + { I2C_MAX_STANDARD_MODE_FREQ, 7, 10, 12, 26 }, + { I2C_MAX_FAST_MODE_FREQ, 2, 5, 11, 22 }, + { I2C_MAX_FAST_MODE_PLUS_FREQ, 1, 2, 8, 18 }, + {} +}; + +/* source_clock = 32 MHz */ +static const struct geni_i2c_clk_fld geni_i2c_clk_map_32mhz[] = { + { I2C_MAX_STANDARD_MODE_FREQ, 8, 14, 18, 38 }, + { I2C_MAX_FAST_MODE_FREQ, 4, 3, 9, 19 }, + { I2C_MAX_FAST_MODE_PLUS_FREQ, 2, 3, 5, 15 }, + {} }; static int geni_i2c_clk_map_idx(struct geni_i2c_dev *gi2c) { - int i; - const struct geni_i2c_clk_fld *itr = geni_i2c_clk_map; + const struct geni_i2c_clk_fld *itr; + + if (clk_get_rate(gi2c->se.clk) == 32 * HZ_PER_MHZ) + itr = geni_i2c_clk_map_32mhz; + else + itr = geni_i2c_clk_map_19p2mhz; - for (i = 0; i < ARRAY_SIZE(geni_i2c_clk_map); i++, itr++) { + while (itr->clk_freq_out != 0) { if (itr->clk_freq_out == gi2c->clk_freq_out) { gi2c->clk_fld = itr; return 0; } + itr++; } return -EINVAL; } @@ -485,6 +521,7 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, static void i2c_gpi_cb_result(void *cb, const struct dmaengine_result *result) { struct geni_i2c_dev *gi2c = cb; + struct geni_i2c_gpi_multi_desc_xfer *tx_multi_xfer; if (result->result != DMA_TRANS_NOERROR) { dev_err(gi2c->se.dev, "DMA txn failed:%d\n", result->result); @@ -493,6 +530,11 @@ static void i2c_gpi_cb_result(void *cb, const struct dmaengine_result *result) dev_dbg(gi2c->se.dev, "DMA xfer has pending: %d\n", result->residue); } + if (gi2c->is_tx_multi_desc_xfer) { + tx_multi_xfer = &gi2c->i2c_multi_desc_config; + tx_multi_xfer->irq_cnt++; + } + complete(&gi2c->done); } @@ -511,7 +553,72 @@ static void geni_i2c_gpi_unmap(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, } } -static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, +/** + * geni_i2c_gpi_multi_desc_unmap() - Unmaps DMA buffers post multi message TX transfers + * @gi2c: I2C dev handle + * @msgs: Array of I2C messages + * @peripheral: Pointer to gpi_i2c_config + */ +static void geni_i2c_gpi_multi_desc_unmap(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], + struct gpi_i2c_config *peripheral) +{ + u32 msg_xfer_cnt, wr_idx = 0; + struct geni_i2c_gpi_multi_desc_xfer *tx_multi_xfer = &gi2c->i2c_multi_desc_config; + + msg_xfer_cnt = gi2c->err ? tx_multi_xfer->msg_idx_cnt : tx_multi_xfer->irq_cnt; + + /* Unmap the processed DMA buffers based on the received interrupt count */ + for (; tx_multi_xfer->unmap_msg_cnt < msg_xfer_cnt; tx_multi_xfer->unmap_msg_cnt++) { + wr_idx = tx_multi_xfer->unmap_msg_cnt; + geni_i2c_gpi_unmap(gi2c, &msgs[wr_idx], + tx_multi_xfer->dma_buf[wr_idx], + tx_multi_xfer->dma_addr[wr_idx], + NULL, 0); + + if (tx_multi_xfer->unmap_msg_cnt == gi2c->num_msgs - 1) { + kfree(tx_multi_xfer->dma_buf); + kfree(tx_multi_xfer->dma_addr); + break; + } + } +} + +/** + * geni_i2c_gpi_multi_xfer_timeout_handler() - Handles multi message transfer timeout + * @dev: Pointer to the corresponding dev node + * @multi_xfer: Pointer to the geni_i2c_gpi_multi_desc_xfer + * @transfer_timeout_msecs: Timeout value in milliseconds + * @transfer_comp: Completion object of the transfer + * + * This function waits for the completion of each processed transfer messages + * based on the interrupts generated upon transfer completion. + * + * Return: On success returns 0, -ETIMEDOUT on timeout. + */ +static int geni_i2c_gpi_multi_xfer_timeout_handler(struct device *dev, + struct geni_i2c_gpi_multi_desc_xfer *multi_xfer, + u32 transfer_timeout_msecs, + struct completion *transfer_comp) +{ + int i; + u32 time_left; + + for (i = 0; i < multi_xfer->msg_idx_cnt - 1; i++) { + reinit_completion(transfer_comp); + + if (multi_xfer->msg_idx_cnt != multi_xfer->irq_cnt) { + time_left = wait_for_completion_timeout(transfer_comp, + transfer_timeout_msecs); + if (!time_left) { + dev_err(dev, "%s: Transfer timeout\n", __func__); + return -ETIMEDOUT; + } + } + } + return 0; +} + +static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], struct dma_slave_config *config, dma_addr_t *dma_addr_p, void **buf, unsigned int op, struct dma_chan *dma_chan) { @@ -523,26 +630,45 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, enum dma_transfer_direction dma_dirn; struct dma_async_tx_descriptor *desc; int ret; + struct geni_i2c_gpi_multi_desc_xfer *gi2c_gpi_xfer; + dma_cookie_t cookie; + u32 msg_idx; peripheral = config->peripheral_config; + gi2c_gpi_xfer = &gi2c->i2c_multi_desc_config; + msg_idx = gi2c_gpi_xfer->msg_idx_cnt; - dma_buf = i2c_get_dma_safe_msg_buf(msg, 1); - if (!dma_buf) - return -ENOMEM; + dma_buf = i2c_get_dma_safe_msg_buf(&msgs[msg_idx], 1); + if (!dma_buf) { + ret = -ENOMEM; + goto out; + } if (op == I2C_WRITE) map_dirn = DMA_TO_DEVICE; else map_dirn = DMA_FROM_DEVICE; - addr = dma_map_single(gi2c->se.dev->parent, dma_buf, msg->len, map_dirn); + addr = dma_map_single(gi2c->se.dev->parent, dma_buf, + msgs[msg_idx].len, map_dirn); if (dma_mapping_error(gi2c->se.dev->parent, addr)) { - i2c_put_dma_safe_msg_buf(dma_buf, msg, false); - return -ENOMEM; + i2c_put_dma_safe_msg_buf(dma_buf, &msgs[msg_idx], false); + ret = -ENOMEM; + goto out; + } + + if (gi2c->is_tx_multi_desc_xfer) { + flags = DMA_CTRL_ACK; + + /* BEI bit to be cleared for last TRE */ + if (msg_idx == gi2c->num_msgs - 1) + flags |= DMA_PREP_INTERRUPT; + } else { + flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; } /* set the length as message for rx txn */ - peripheral->rx_len = msg->len; + peripheral->rx_len = msgs[msg_idx].len; peripheral->op = op; ret = dmaengine_slave_config(dma_chan, config); @@ -553,14 +679,21 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, peripheral->set_config = 0; peripheral->multi_msg = true; - flags = DMA_PREP_INTERRUPT | DMA_CTRL_ACK; if (op == I2C_WRITE) dma_dirn = DMA_MEM_TO_DEV; else dma_dirn = DMA_DEV_TO_MEM; - desc = dmaengine_prep_slave_single(dma_chan, addr, msg->len, dma_dirn, flags); + desc = dmaengine_prep_slave_single(dma_chan, addr, msgs[msg_idx].len, + dma_dirn, flags); + if (!desc && !(flags & DMA_PREP_INTERRUPT)) { + /* Retry with interrupt if not enough TREs */ + flags |= DMA_PREP_INTERRUPT; + desc = dmaengine_prep_slave_single(dma_chan, addr, msgs[msg_idx].len, + dma_dirn, flags); + } + if (!desc) { dev_err(gi2c->se.dev, "prep_slave_sg failed\n"); ret = -EIO; @@ -570,15 +703,48 @@ static int geni_i2c_gpi(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, desc->callback_result = i2c_gpi_cb_result; desc->callback_param = gi2c; - dmaengine_submit(desc); - *buf = dma_buf; - *dma_addr_p = addr; + if (!((msgs[msg_idx].flags & I2C_M_RD) && op == I2C_WRITE)) + gi2c_gpi_xfer->msg_idx_cnt++; + cookie = dmaengine_submit(desc); + if (dma_submit_error(cookie)) { + dev_err(gi2c->se.dev, + "%s: dmaengine_submit failed (%d)\n", __func__, cookie); + ret = -EINVAL; + goto err_config; + } + + if (gi2c->is_tx_multi_desc_xfer) { + gi2c_gpi_xfer->dma_buf[msg_idx] = dma_buf; + gi2c_gpi_xfer->dma_addr[msg_idx] = addr; + + dma_async_issue_pending(gi2c->tx_c); + + if ((msg_idx == (gi2c->num_msgs - 1)) || flags & DMA_PREP_INTERRUPT) { + ret = geni_i2c_gpi_multi_xfer_timeout_handler(gi2c->se.dev, gi2c_gpi_xfer, + XFER_TIMEOUT, &gi2c->done); + if (ret) { + dev_err(gi2c->se.dev, + "I2C multi write msg transfer timeout: %d\n", + ret); + gi2c->err = ret; + return ret; + } + } + } else { + /* Non multi descriptor message transfer */ + *buf = dma_buf; + *dma_addr_p = addr; + } return 0; err_config: - dma_unmap_single(gi2c->se.dev->parent, addr, msg->len, map_dirn); - i2c_put_dma_safe_msg_buf(dma_buf, msg, false); + dma_unmap_single(gi2c->se.dev->parent, addr, + msgs[msg_idx].len, map_dirn); + i2c_put_dma_safe_msg_buf(dma_buf, &msgs[msg_idx], false); + +out: + gi2c->err = ret; return ret; } @@ -586,9 +752,11 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i { struct dma_slave_config config = {}; struct gpi_i2c_config peripheral = {}; - int i, ret = 0, timeout; + int i, ret = 0; + unsigned long time_left; dma_addr_t tx_addr, rx_addr; void *tx_buf = NULL, *rx_buf = NULL; + struct geni_i2c_gpi_multi_desc_xfer *tx_multi_xfer; const struct geni_i2c_clk_fld *itr = gi2c->clk_fld; config.peripheral_config = &peripheral; @@ -602,6 +770,41 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i peripheral.set_config = 1; peripheral.multi_msg = false; + gi2c->num_msgs = num; + gi2c->is_tx_multi_desc_xfer = false; + + tx_multi_xfer = &gi2c->i2c_multi_desc_config; + memset(tx_multi_xfer, 0, sizeof(struct geni_i2c_gpi_multi_desc_xfer)); + + /* + * If number of write messages are two and higher then + * configure hardware for multi descriptor transfers with BEI. + */ + if (num >= QCOM_I2C_MIN_NUM_OF_MSGS_MULTI_DESC) { + gi2c->is_tx_multi_desc_xfer = true; + for (i = 0; i < num; i++) { + if (msgs[i].flags & I2C_M_RD) { + /* + * Multi descriptor transfer with BEI + * support is enabled for write transfers. + * TODO: Add BEI optimization support for + * read transfers later. + */ + gi2c->is_tx_multi_desc_xfer = false; + break; + } + } + } + + if (gi2c->is_tx_multi_desc_xfer) { + tx_multi_xfer->dma_buf = kcalloc(num, sizeof(void *), GFP_KERNEL); + tx_multi_xfer->dma_addr = kcalloc(num, sizeof(dma_addr_t), GFP_KERNEL); + if (!tx_multi_xfer->dma_buf || !tx_multi_xfer->dma_addr) { + ret = -ENOMEM; + goto err; + } + } + for (i = 0; i < num; i++) { gi2c->cur = &msgs[i]; gi2c->err = 0; @@ -612,28 +815,30 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i peripheral.stretch = 1; peripheral.addr = msgs[i].addr; + if (i > 0 && (!(msgs[i].flags & I2C_M_RD))) + peripheral.multi_msg = false; + + ret = geni_i2c_gpi(gi2c, msgs, &config, + &tx_addr, &tx_buf, I2C_WRITE, gi2c->tx_c); + if (ret) + goto err; if (msgs[i].flags & I2C_M_RD) { - ret = geni_i2c_gpi(gi2c, &msgs[i], &config, + ret = geni_i2c_gpi(gi2c, msgs, &config, &rx_addr, &rx_buf, I2C_READ, gi2c->rx_c); if (ret) goto err; - } - ret = geni_i2c_gpi(gi2c, &msgs[i], &config, - &tx_addr, &tx_buf, I2C_WRITE, gi2c->tx_c); - if (ret) - goto err; - - if (msgs[i].flags & I2C_M_RD) dma_async_issue_pending(gi2c->rx_c); - dma_async_issue_pending(gi2c->tx_c); + } - timeout = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); - if (!timeout) { - dev_err(gi2c->se.dev, "I2C timeout gpi flags:%d addr:0x%x\n", - gi2c->cur->flags, gi2c->cur->addr); - gi2c->err = -ETIMEDOUT; + if (!gi2c->is_tx_multi_desc_xfer) { + dma_async_issue_pending(gi2c->tx_c); + time_left = wait_for_completion_timeout(&gi2c->done, XFER_TIMEOUT); + if (!time_left) { + dev_err(gi2c->se.dev, "%s:I2C timeout\n", __func__); + gi2c->err = -ETIMEDOUT; + } } if (gi2c->err) { @@ -641,7 +846,10 @@ static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], i goto err; } - geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr); + if (!gi2c->is_tx_multi_desc_xfer) + geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr); + else if (tx_multi_xfer->unmap_msg_cnt != tx_multi_xfer->irq_cnt) + geni_i2c_gpi_multi_desc_unmap(gi2c, msgs, &peripheral); } return num; @@ -650,7 +858,11 @@ err: dev_err(gi2c->se.dev, "GPI transfer failed: %d\n", ret); dmaengine_terminate_sync(gi2c->rx_c); dmaengine_terminate_sync(gi2c->tx_c); - geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr); + if (gi2c->is_tx_multi_desc_xfer) + geni_i2c_gpi_multi_desc_unmap(gi2c, msgs, &peripheral); + else + geni_i2c_gpi_unmap(gi2c, &msgs[i], tx_buf, tx_addr, rx_buf, rx_addr); + return ret; } @@ -702,7 +914,6 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, else ret = geni_i2c_fifo_xfer(gi2c, msgs, num); - pm_runtime_mark_last_busy(gi2c->se.dev); pm_runtime_put_autosuspend(gi2c->se.dev); gi2c->cur = NULL; gi2c->err = 0; @@ -715,14 +926,15 @@ static u32 geni_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm geni_i2c_algo = { - .master_xfer = geni_i2c_xfer, - .functionality = geni_i2c_func, + .xfer = geni_i2c_xfer, + .functionality = geni_i2c_func, }; #ifdef CONFIG_ACPI static const struct acpi_device_id geni_i2c_acpi_match[] = { { "QCOM0220"}, - { }, + { "QCOM0411" }, + { } }; MODULE_DEVICE_TABLE(acpi, geni_i2c_acpi_match); #endif @@ -767,7 +979,6 @@ err_tx: static int geni_i2c_probe(struct platform_device *pdev) { struct geni_i2c_dev *gi2c; - struct resource *res; u32 proto, tx_depth, fifo_disable; int ret; struct device *dev = &pdev->dev; @@ -779,8 +990,7 @@ static int geni_i2c_probe(struct platform_device *pdev) gi2c->se.dev = dev; gi2c->se.wrapper = dev_get_drvdata(dev->parent); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - gi2c->se.base = devm_ioremap_resource(dev, res); + gi2c->se.base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(gi2c->se.base)) return PTR_ERR(gi2c->se.base); @@ -800,7 +1010,7 @@ static int geni_i2c_probe(struct platform_device *pdev) &gi2c->clk_freq_out); if (ret) { dev_info(dev, "Bus frequency not specified, default to 100kHz.\n"); - gi2c->clk_freq_out = KHZ(100); + gi2c->clk_freq_out = I2C_MAX_STANDARD_MODE_FREQ; } if (has_acpi_companion(dev)) @@ -811,25 +1021,22 @@ static int geni_i2c_probe(struct platform_device *pdev) return gi2c->irq; ret = geni_i2c_clk_map_idx(gi2c); - if (ret) { - dev_err(dev, "Invalid clk frequency %d Hz: %d\n", - gi2c->clk_freq_out, ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Invalid clk frequency %d Hz\n", + gi2c->clk_freq_out); gi2c->adap.algo = &geni_i2c_algo; init_completion(&gi2c->done); spin_lock_init(&gi2c->lock); platform_set_drvdata(pdev, gi2c); - ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, 0, + + /* Keep interrupts disabled initially to allow for low-power modes */ + ret = devm_request_irq(dev, gi2c->irq, geni_i2c_irq, IRQF_NO_AUTOEN, dev_name(dev), gi2c); - if (ret) { - dev_err(dev, "Request_irq failed:%d: err:%d\n", - gi2c->irq, ret); - return ret; - } - /* Disable the interrupt so that the system can enter low-power mode */ - disable_irq(gi2c->irq); + if (ret) + return dev_err_probe(dev, ret, + "Request_irq failed: %d\n", gi2c->irq); + i2c_set_adapdata(&gi2c->adap, gi2c); gi2c->adap.dev.parent = dev; gi2c->adap.dev.of_node = dev->of_node; @@ -858,15 +1065,19 @@ static int geni_i2c_probe(struct platform_device *pdev) ret = geni_se_resources_on(&gi2c->se); if (ret) { - dev_err(dev, "Error turning on resources %d\n", ret); - return ret; + dev_err_probe(dev, ret, "Error turning on resources\n"); + goto err_clk; } proto = geni_se_read_proto(&gi2c->se); - if (proto != GENI_SE_I2C) { - dev_err(dev, "Invalid proto %d\n", proto); - geni_se_resources_off(&gi2c->se); - clk_disable_unprepare(gi2c->core_clk); - return -ENXIO; + if (proto == GENI_SE_INVALID_PROTO) { + ret = geni_load_se_firmware(&gi2c->se, GENI_SE_I2C); + if (ret) { + dev_err_probe(dev, ret, "i2c firmware load failed ret: %d\n", ret); + goto err_resources; + } + } else if (proto != GENI_SE_I2C) { + ret = dev_err_probe(dev, -ENXIO, "Invalid proto %d\n", proto); + goto err_resources; } if (desc && desc->no_dma_support) @@ -879,7 +1090,7 @@ static int geni_i2c_probe(struct platform_device *pdev) gi2c->gpi_mode = true; ret = setup_gpi_dma(gi2c); if (ret) - return dev_err_probe(dev, ret, "Failed to setup GPI DMA mode\n"); + goto err_resources; dev_dbg(dev, "Using GPI DMA mode for I2C\n"); } else { @@ -891,8 +1102,9 @@ static int geni_i2c_probe(struct platform_device *pdev) tx_depth = desc->tx_fifo_depth; if (!tx_depth) { - dev_err(dev, "Invalid TX FIFO depth\n"); - return -EINVAL; + ret = dev_err_probe(dev, -EINVAL, + "Invalid TX FIFO depth\n"); + goto err_resources; } gi2c->tx_wm = tx_depth - 1; @@ -906,7 +1118,7 @@ static int geni_i2c_probe(struct platform_device *pdev) clk_disable_unprepare(gi2c->core_clk); ret = geni_se_resources_off(&gi2c->se); if (ret) { - dev_err(dev, "Error turning off resources %d\n", ret); + dev_err_probe(dev, ret, "Error turning off resources\n"); goto err_dma; } @@ -922,28 +1134,35 @@ static int geni_i2c_probe(struct platform_device *pdev) ret = i2c_add_adapter(&gi2c->adap); if (ret) { - dev_err(dev, "Error adding i2c adapter %d\n", ret); + dev_err_probe(dev, ret, "Error adding i2c adapter\n"); pm_runtime_disable(gi2c->se.dev); goto err_dma; } dev_dbg(dev, "Geni-I2C adaptor successfully added\n"); - return 0; + return ret; + +err_resources: + geni_se_resources_off(&gi2c->se); +err_clk: + clk_disable_unprepare(gi2c->core_clk); + + return ret; err_dma: release_gpi_dma(gi2c); + return ret; } -static int geni_i2c_remove(struct platform_device *pdev) +static void geni_i2c_remove(struct platform_device *pdev) { struct geni_i2c_dev *gi2c = platform_get_drvdata(pdev); i2c_del_adapter(&gi2c->adap); release_gpi_dma(gi2c); pm_runtime_disable(gi2c->se.dev); - return 0; } static void geni_i2c_shutdown(struct platform_device *pdev) @@ -985,15 +1204,23 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev) ret = clk_prepare_enable(gi2c->core_clk); if (ret) - return ret; + goto out_icc_disable; ret = geni_se_resources_on(&gi2c->se); if (ret) - return ret; + goto out_clk_disable; enable_irq(gi2c->irq); gi2c->suspended = 0; + return 0; + +out_clk_disable: + clk_disable_unprepare(gi2c->core_clk); +out_icc_disable: + geni_icc_disable(&gi2c->se); + + return ret; } static int __maybe_unused geni_i2c_suspend_noirq(struct device *dev) @@ -1025,7 +1252,7 @@ static const struct dev_pm_ops geni_i2c_pm_ops = { NULL) }; -const struct geni_i2c_desc i2c_master_hub = { +static const struct geni_i2c_desc i2c_master_hub = { .has_core_clk = true, .icc_ddr = NULL, .no_dma_support = true, diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 2e153f2f71b6..a0e076fc5f36 100644 --- a/drivers/i2c/busses/i2c-qup.c +++ b/drivers/i2c/busses/i2c-qup.c @@ -14,12 +14,13 @@ #include <linux/dma-mapping.h> #include <linux/err.h> #include <linux/i2c.h> +#include <linux/interconnect.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/module.h> -#include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> +#include <linux/property.h> #include <linux/scatterlist.h> /* QUP Registers */ @@ -150,6 +151,8 @@ /* TAG length for DATA READ in RX FIFO */ #define READ_RX_TAGS_LEN 2 +#define QUP_BUS_WIDTH 8 + static unsigned int scl_freq; module_param_named(scl_freq, scl_freq, uint, 0444); MODULE_PARM_DESC(scl_freq, "SCL frequency override"); @@ -227,6 +230,7 @@ struct qup_i2c_dev { int irq; struct clk *clk; struct clk *pclk; + struct icc_path *icc_path; struct i2c_adapter adap; int clk_ctl; @@ -255,6 +259,10 @@ struct qup_i2c_dev { /* To configure when bus is in run state */ u32 config_run; + /* bandwidth votes */ + u32 src_clk_freq; + u32 cur_bw_clk_freq; + /* dma parameters */ bool is_dma; /* To check if the current transfer is using DMA */ @@ -444,8 +452,10 @@ static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len) if (!(status & I2C_STATUS_BUS_ACTIVE)) break; - if (time_after(jiffies, timeout)) + if (time_after(jiffies, timeout)) { ret = -ETIMEDOUT; + break; + } usleep_range(len, len * 2); } @@ -453,6 +463,23 @@ static int qup_i2c_bus_active(struct qup_i2c_dev *qup, int len) return ret; } +static int qup_i2c_vote_bw(struct qup_i2c_dev *qup, u32 clk_freq) +{ + u32 needed_peak_bw; + int ret; + + if (qup->cur_bw_clk_freq == clk_freq) + return 0; + + needed_peak_bw = Bps_to_icc(clk_freq * QUP_BUS_WIDTH); + ret = icc_set_bw(qup->icc_path, 0, needed_peak_bw); + if (ret) + return ret; + + qup->cur_bw_clk_freq = clk_freq; + return 0; +} + static void qup_i2c_write_tx_fifo_v1(struct qup_i2c_dev *qup) { struct qup_i2c_block *blk = &qup->blk; @@ -793,10 +820,8 @@ static int qup_i2c_bam_schedule_desc(struct qup_i2c_dev *qup) dma_async_issue_pending(qup->brx.dma); } - if (!wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout)) { - dev_err(qup->dev, "normal trans timed out\n"); + if (!wait_for_completion_timeout(&qup->xfer, qup->xfer_timeout)) ret = -ETIMEDOUT; - } if (ret || qup->bus_err || qup->qup_err) { reinit_completion(&qup->xfer); @@ -840,6 +865,10 @@ static int qup_i2c_bam_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int ret = 0; int idx = 0; + ret = qup_i2c_vote_bw(qup, qup->src_clk_freq); + if (ret) + return ret; + enable_irq(qup->irq); ret = qup_i2c_req_dma(qup); @@ -1110,7 +1139,6 @@ static int qup_i2c_xfer(struct i2c_adapter *adap, ret = num; out: - pm_runtime_mark_last_busy(qup->dev); pm_runtime_put_autosuspend(qup->dev); return ret; @@ -1595,7 +1623,6 @@ static int qup_i2c_xfer_v2(struct i2c_adapter *adap, if (ret == 0) ret = num; out: - pm_runtime_mark_last_busy(qup->dev); pm_runtime_put_autosuspend(qup->dev); return ret; @@ -1607,13 +1634,13 @@ static u32 qup_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm qup_i2c_algo = { - .master_xfer = qup_i2c_xfer, - .functionality = qup_i2c_func, + .xfer = qup_i2c_xfer, + .functionality = qup_i2c_func, }; static const struct i2c_algorithm qup_i2c_algo_v2 = { - .master_xfer = qup_i2c_xfer_v2, - .functionality = qup_i2c_func, + .xfer = qup_i2c_xfer_v2, + .functionality = qup_i2c_func, }; /* @@ -1645,12 +1672,13 @@ static void qup_i2c_disable_clocks(struct qup_i2c_dev *qup) config = readl(qup->base + QUP_CONFIG); config |= QUP_CLOCK_AUTO_GATE; writel(config, qup->base + QUP_CONFIG); + qup_i2c_vote_bw(qup, 0); clk_disable_unprepare(qup->pclk); } static const struct acpi_device_id qup_i2c_acpi_match[] = { { "QCOM8010"}, - { }, + { } }; MODULE_DEVICE_TABLE(acpi, qup_i2c_acpi_match); @@ -1685,7 +1713,7 @@ static int qup_i2c_probe(struct platform_device *pdev) } } - if (of_device_is_compatible(pdev->dev.of_node, "qcom,i2c-qup-v1.1.1")) { + if (device_is_compatible(&pdev->dev, "qcom,i2c-qup-v1.1.1")) { qup->adap.algo = &qup_i2c_algo; qup->adap.quirks = &qup_i2c_quirks; is_qup_v1 = true; @@ -1745,6 +1773,11 @@ static int qup_i2c_probe(struct platform_device *pdev) goto fail_dma; } qup->is_dma = true; + + qup->icc_path = devm_of_icc_get(&pdev->dev, NULL); + if (IS_ERR(qup->icc_path)) + return dev_err_probe(&pdev->dev, PTR_ERR(qup->icc_path), + "failed to get interconnect path\n"); } nodma: @@ -1752,16 +1785,21 @@ nodma: if (!clk_freq || clk_freq > I2C_MAX_FAST_MODE_PLUS_FREQ) { dev_err(qup->dev, "clock frequency not supported %d\n", clk_freq); - return -EINVAL; + ret = -EINVAL; + goto fail_dma; } qup->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(qup->base)) - return PTR_ERR(qup->base); + if (IS_ERR(qup->base)) { + ret = PTR_ERR(qup->base); + goto fail_dma; + } qup->irq = platform_get_irq(pdev, 0); - if (qup->irq < 0) - return qup->irq; + if (qup->irq < 0) { + ret = qup->irq; + goto fail_dma; + } if (has_acpi_companion(qup->dev)) { ret = device_property_read_u32(qup->dev, @@ -1775,17 +1813,20 @@ nodma: qup->clk = devm_clk_get(qup->dev, "core"); if (IS_ERR(qup->clk)) { dev_err(qup->dev, "Could not get core clock\n"); - return PTR_ERR(qup->clk); + ret = PTR_ERR(qup->clk); + goto fail_dma; } qup->pclk = devm_clk_get(qup->dev, "iface"); if (IS_ERR(qup->pclk)) { dev_err(qup->dev, "Could not get iface clock\n"); - return PTR_ERR(qup->pclk); + ret = PTR_ERR(qup->pclk); + goto fail_dma; } qup_i2c_enable_clocks(qup); src_clk_freq = clk_get_rate(qup->clk); } + qup->src_clk_freq = src_clk_freq; /* * Bootloaders might leave a pending interrupt on certain QUP's, @@ -1904,7 +1945,7 @@ fail_dma: return ret; } -static int qup_i2c_remove(struct platform_device *pdev) +static void qup_i2c_remove(struct platform_device *pdev) { struct qup_i2c_dev *qup = platform_get_drvdata(pdev); @@ -1918,10 +1959,8 @@ static int qup_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&qup->adap); pm_runtime_disable(qup->dev); pm_runtime_set_suspended(qup->dev); - return 0; } -#ifdef CONFIG_PM static int qup_i2c_pm_suspend_runtime(struct device *device) { struct qup_i2c_dev *qup = dev_get_drvdata(device); @@ -1939,9 +1978,7 @@ static int qup_i2c_pm_resume_runtime(struct device *device) qup_i2c_enable_clocks(qup); return 0; } -#endif -#ifdef CONFIG_PM_SLEEP static int qup_i2c_suspend(struct device *device) { if (!pm_runtime_suspended(device)) @@ -1952,20 +1989,14 @@ static int qup_i2c_suspend(struct device *device) static int qup_i2c_resume(struct device *device) { qup_i2c_pm_resume_runtime(device); - pm_runtime_mark_last_busy(device); pm_request_autosuspend(device); return 0; } -#endif static const struct dev_pm_ops qup_i2c_qup_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS( - qup_i2c_suspend, - qup_i2c_resume) - SET_RUNTIME_PM_OPS( - qup_i2c_pm_suspend_runtime, - qup_i2c_pm_resume_runtime, - NULL) + SYSTEM_SLEEP_PM_OPS(qup_i2c_suspend, qup_i2c_resume) + RUNTIME_PM_OPS(qup_i2c_pm_suspend_runtime, + qup_i2c_pm_resume_runtime, NULL) }; static const struct of_device_id qup_i2c_dt_match[] = { @@ -1981,7 +2012,7 @@ static struct platform_driver qup_i2c_driver = { .remove = qup_i2c_remove, .driver = { .name = "i2c_qup", - .pm = &qup_i2c_qup_pm_ops, + .pm = pm_ptr(&qup_i2c_qup_pm_ops), .of_match_table = qup_i2c_dt_match, .acpi_match_table = ACPI_PTR(qup_i2c_acpi_match), }, @@ -1989,5 +2020,6 @@ static struct platform_driver qup_i2c_driver = { module_platform_driver(qup_i2c_driver); +MODULE_DESCRIPTION("Qualcomm QUP based I2C controller"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:i2c_qup"); diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index cef82b205c26..d51884ab99f4 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -24,7 +24,7 @@ #include <linux/i2c-smbus.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/reset.h> @@ -41,6 +41,10 @@ #define ICSAR 0x1C /* slave address */ #define ICMAR 0x20 /* master address */ #define ICRXTX 0x24 /* data port */ +#define ICCCR2 0x28 /* Clock control 2 */ +#define ICMPR 0x2C /* SCL mask control */ +#define ICHPR 0x30 /* SCL HIGH control */ +#define ICLPR 0x34 /* SCL LOW control */ #define ICFBSCR 0x38 /* first bit setup cycle (Gen3) */ #define ICDMAER 0x3c /* DMA enable (Gen3) */ @@ -84,11 +88,26 @@ #define RMDMAE BIT(1) /* DMA Master Received Enable */ #define TMDMAE BIT(0) /* DMA Master Transmitted Enable */ +/* ICCCR2 */ +#define FMPE BIT(7) /* Fast Mode Plus Enable */ +#define CDFD BIT(2) /* CDF Disable */ +#define HLSE BIT(1) /* HIGH/LOW Separate Control Enable */ +#define SME BIT(0) /* SCL Mask Enable */ + /* ICFBSCR */ #define TCYC17 0x0f /* 17*Tcyc delay 1st bit between SDA and SCL */ #define RCAR_MIN_DMA_LEN 8 +/* SCL low/high ratio 5:4 to meet all I2C timing specs (incl safety margin) */ +#define RCAR_SCLD_RATIO 5 +#define RCAR_SCHD_RATIO 4 +/* + * SMD should be smaller than SCLD/SCHD and is always around 20 in the docs. + * Thus, we simply use 20 which works for low and high speeds. + */ +#define RCAR_DEFAULT_SMD 20 + #define RCAR_BUS_PHASE_START (MDBS | MIE | ESG) #define RCAR_BUS_PHASE_DATA (MDBS | MIE) #define RCAR_BUS_PHASE_STOP (MDBS | MIE | FSB) @@ -104,16 +123,20 @@ #define ID_NACK BIT(4) #define ID_EPROTO BIT(5) /* persistent flags */ +#define ID_P_FMPLUS BIT(27) #define ID_P_NOT_ATOMIC BIT(28) #define ID_P_HOST_NOTIFY BIT(29) #define ID_P_NO_RXDMA BIT(30) /* HW forbids RXDMA sometimes */ #define ID_P_PM_BLOCKED BIT(31) -#define ID_P_MASK GENMASK(31, 28) +#define ID_P_MASK GENMASK(31, 27) + +#define ID_SLAVE_NACK BIT(0) enum rcar_i2c_type { I2C_RCAR_GEN1, I2C_RCAR_GEN2, I2C_RCAR_GEN3, + I2C_RCAR_GEN4, }; struct rcar_i2c_priv { @@ -128,6 +151,9 @@ struct rcar_i2c_priv { int pos; u32 icccr; + u16 schd; + u16 scld; + u8 smd; u8 recovery_icmcr; /* protected by adapter lock */ enum rcar_i2c_type devtype; struct i2c_client *slave; @@ -142,6 +168,7 @@ struct rcar_i2c_priv { int irq; struct i2c_client *host_notify_client; + u8 slave_flags; }; #define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent) @@ -167,8 +194,7 @@ static int rcar_i2c_get_scl(struct i2c_adapter *adap) struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); return !!(rcar_i2c_read(priv, ICMCR) & FSCL); - -}; +} static void rcar_i2c_set_scl(struct i2c_adapter *adap, int val) { @@ -180,7 +206,7 @@ static void rcar_i2c_set_scl(struct i2c_adapter *adap, int val) priv->recovery_icmcr &= ~FSCL; rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr); -}; +} static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val) { @@ -192,15 +218,14 @@ static void rcar_i2c_set_sda(struct i2c_adapter *adap, int val) priv->recovery_icmcr &= ~FSDA; rcar_i2c_write(priv, ICMCR, priv->recovery_icmcr); -}; +} static int rcar_i2c_get_bus_free(struct i2c_adapter *adap) { struct rcar_i2c_priv *priv = i2c_get_adapdata(adap); return !(rcar_i2c_read(priv, ICMCR) & FSDA); - -}; +} static struct i2c_bus_recovery_info rcar_i2c_bri = { .get_scl = rcar_i2c_get_scl, @@ -209,6 +234,7 @@ static struct i2c_bus_recovery_info rcar_i2c_bri = { .get_bus_free = rcar_i2c_get_bus_free, .recover_bus = i2c_generic_scl_recovery, }; + static void rcar_i2c_init(struct rcar_i2c_priv *priv) { /* reset master mode */ @@ -216,11 +242,29 @@ static void rcar_i2c_init(struct rcar_i2c_priv *priv) rcar_i2c_write(priv, ICMCR, MDBS); rcar_i2c_write(priv, ICMSR, 0); /* start clock */ - rcar_i2c_write(priv, ICCCR, priv->icccr); + if (priv->devtype < I2C_RCAR_GEN3) { + rcar_i2c_write(priv, ICCCR, priv->icccr); + } else { + u32 icccr2 = CDFD | HLSE | SME; - if (priv->devtype == I2C_RCAR_GEN3) + if (priv->flags & ID_P_FMPLUS) + icccr2 |= FMPE; + + rcar_i2c_write(priv, ICCCR2, icccr2); + rcar_i2c_write(priv, ICCCR, priv->icccr); + rcar_i2c_write(priv, ICMPR, priv->smd); + rcar_i2c_write(priv, ICHPR, priv->schd); + rcar_i2c_write(priv, ICLPR, priv->scld); rcar_i2c_write(priv, ICFBSCR, TCYC17); + } +} +static void rcar_i2c_reset_slave(struct rcar_i2c_priv *priv) +{ + rcar_i2c_write(priv, ICSIER, 0); + rcar_i2c_write(priv, ICSSR, 0); + rcar_i2c_write(priv, ICSCR, SDBS); + rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */ } static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) @@ -241,7 +285,7 @@ static int rcar_i2c_bus_barrier(struct rcar_i2c_priv *priv) static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv) { - u32 scgd, cdf, round, ick, sum, scl, cdf_width; + u32 cdf, round, ick, sum, scl, cdf_width; unsigned long rate; struct device *dev = rcar_i2c_priv_to_dev(priv); struct i2c_timings t = { @@ -253,28 +297,19 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv) /* Fall back to previously used values if not supplied */ i2c_parse_fw_timings(dev, &t, false); - - switch (priv->devtype) { - case I2C_RCAR_GEN1: - cdf_width = 2; - break; - case I2C_RCAR_GEN2: - case I2C_RCAR_GEN3: - cdf_width = 3; - break; - default: - dev_err(dev, "device type error\n"); - return -EIO; - } + priv->smd = RCAR_DEFAULT_SMD; /* * calculate SCL clock * see - * ICCCR + * ICCCR (and ICCCR2 for Gen3+) * * ick = clkp / (1 + CDF) * SCL = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick]) * + * for Gen3+: + * SCL = clkp / (8 + SMD * 2 + SCLD + SCHD +F[(ticf + tr + intd) * clkp]) + * * ick : I2C internal clock < 20 MHz * ticf : I2C SCL falling time * tr : I2C SCL rising time @@ -284,52 +319,87 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv) */ rate = clk_get_rate(priv->clk); cdf = rate / 20000000; - if (cdf >= 1U << cdf_width) { - dev_err(dev, "Input clock %lu too high\n", rate); - return -EIO; - } - ick = rate / (cdf + 1); + cdf_width = (priv->devtype == I2C_RCAR_GEN1) ? 2 : 3; + if (cdf >= 1U << cdf_width) + goto err_no_val; + + if (t.bus_freq_hz > I2C_MAX_FAST_MODE_FREQ && priv->devtype >= I2C_RCAR_GEN4) + priv->flags |= ID_P_FMPLUS; + else + priv->flags &= ~ID_P_FMPLUS; + + /* On Gen3+, we use cdf only for the filters, not as a SCL divider */ + ick = rate / (priv->devtype < I2C_RCAR_GEN3 ? (cdf + 1) : 1); /* - * it is impossible to calculate large scale - * number on u32. separate it + * It is impossible to calculate a large scale number on u32. Separate it. * * F[(ticf + tr + intd) * ick] with sum = (ticf + tr + intd) * = F[sum * ick / 1000000000] * = F[(ick / 1000000) * sum / 1000] */ sum = t.scl_fall_ns + t.scl_rise_ns + t.scl_int_delay_ns; - round = (ick + 500000) / 1000000 * sum; - round = (round + 500) / 1000; + round = DIV_ROUND_CLOSEST(ick, 1000000); + round = DIV_ROUND_CLOSEST(round * sum, 1000); - /* - * SCL = ick / (20 + SCGD * 8 + F[(ticf + tr + intd) * ick]) - * - * Calculation result (= SCL) should be less than - * bus_speed for hardware safety - * - * We could use something along the lines of - * div = ick / (bus_speed + 1) + 1; - * scgd = (div - 20 - round + 7) / 8; - * scl = ick / (20 + (scgd * 8) + round); - * (not fully verified) but that would get pretty involved - */ - for (scgd = 0; scgd < 0x40; scgd++) { - scl = ick / (20 + (scgd * 8) + round); - if (scl <= t.bus_freq_hz) - goto scgd_find; - } - dev_err(dev, "it is impossible to calculate best SCL\n"); - return -EIO; + if (priv->devtype < I2C_RCAR_GEN3) { + u32 scgd; + /* + * SCL = ick / (20 + 8 * SCGD + F[(ticf + tr + intd) * ick]) + * 20 + 8 * SCGD + F[...] = ick / SCL + * SCGD = ((ick / SCL) - 20 - F[...]) / 8 + * Result (= SCL) should be less than bus_speed for hardware safety + */ + scgd = DIV_ROUND_UP(ick, t.bus_freq_hz ?: 1); + scgd = DIV_ROUND_UP(scgd - 20 - round, 8); + scl = ick / (20 + 8 * scgd + round); + + if (scgd > 0x3f) + goto err_no_val; + + dev_dbg(dev, "clk %u/%u(%lu), round %u, CDF: %u, SCGD: %u\n", + scl, t.bus_freq_hz, rate, round, cdf, scgd); + + priv->icccr = scgd << cdf_width | cdf; + } else { + u32 x, sum_ratio = RCAR_SCHD_RATIO + RCAR_SCLD_RATIO; + /* + * SCLD/SCHD ratio and SMD default value are explained above + * where they are defined. With these definitions, we can compute + * x as a base value for the SCLD/SCHD ratio: + * + * SCL = clkp / (8 + 2 * SMD + SCLD + SCHD + F[(ticf + tr + intd) * clkp]) + * SCL = clkp / (8 + 2 * SMD + RCAR_SCLD_RATIO * x + * + RCAR_SCHD_RATIO * x + F[...]) + * + * with: sum_ratio = RCAR_SCLD_RATIO + RCAR_SCHD_RATIO + * + * SCL = clkp / (8 + 2 * smd + sum_ratio * x + F[...]) + * 8 + 2 * smd + sum_ratio * x + F[...] = clkp / SCL + * x = ((clkp / SCL) - 8 - 2 * smd - F[...]) / sum_ratio + */ + x = DIV_ROUND_UP(rate, t.bus_freq_hz ?: 1); + x = DIV_ROUND_UP(x - 8 - 2 * priv->smd - round, sum_ratio); + scl = rate / (8 + 2 * priv->smd + sum_ratio * x + round); -scgd_find: - dev_dbg(dev, "clk %d/%d(%lu), round %u, CDF:0x%x, SCGD: 0x%x\n", - scl, t.bus_freq_hz, rate, round, cdf, scgd); + if (x == 0 || x * RCAR_SCLD_RATIO > 0xffff) + goto err_no_val; - /* keep icccr value */ - priv->icccr = scgd << cdf_width | cdf; + priv->icccr = cdf; + priv->schd = RCAR_SCHD_RATIO * x; + priv->scld = RCAR_SCLD_RATIO * x; + if (priv->smd >= priv->schd) + priv->smd = priv->schd - 1; + + dev_dbg(dev, "clk %u/%u(%lu), round %u, CDF: %u SCHD %u SCLD %u SMD %u\n", + scl, t.bus_freq_hz, rate, round, cdf, priv->schd, priv->scld, priv->smd); + } return 0; + +err_no_val: + dev_err(dev, "it is impossible to calculate best SCL\n"); + return -EINVAL; } /* @@ -386,8 +456,8 @@ static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv, bool terminate) dma_unmap_single(chan->device->dev, sg_dma_address(&priv->sg), sg_dma_len(&priv->sg), priv->dma_direction); - /* Gen3 can only do one RXDMA per transfer and we just completed it */ - if (priv->devtype == I2C_RCAR_GEN3 && + /* Gen3+ can only do one RXDMA per transfer and we just completed it */ + if (priv->devtype >= I2C_RCAR_GEN3 && priv->dma_direction == DMA_FROM_DEVICE) priv->flags |= ID_P_NO_RXDMA; @@ -485,7 +555,7 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) u32 irqs_to_clear = MDE; /* FIXME: sometimes, unknown interrupt happened. Do nothing */ - if (!(msr & MDE)) + if (WARN(!(msr & MDE), "spurious irq")) return; if (msr & MAT) @@ -588,6 +658,7 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv) { u32 ssr_raw, ssr_filtered; u8 value; + int ret; ssr_raw = rcar_i2c_read(priv, ICSSR) & 0xff; ssr_filtered = ssr_raw & rcar_i2c_read(priv, ICSIER); @@ -603,7 +674,10 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv) rcar_i2c_write(priv, ICRXTX, value); rcar_i2c_write(priv, ICSIER, SDE | SSR | SAR); } else { - i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value); + ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value); + if (ret) + priv->slave_flags |= ID_SLAVE_NACK; + rcar_i2c_read(priv, ICRXTX); /* dummy read */ rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR); } @@ -616,18 +690,21 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv) if (ssr_filtered & SSR) { i2c_slave_event(priv->slave, I2C_SLAVE_STOP, &value); rcar_i2c_write(priv, ICSCR, SIE | SDBS); /* clear our NACK */ + priv->slave_flags &= ~ID_SLAVE_NACK; rcar_i2c_write(priv, ICSIER, SAR); rcar_i2c_write(priv, ICSSR, ~SSR & 0xff); } /* master wants to write to us */ if (ssr_filtered & SDR) { - int ret; - value = rcar_i2c_read(priv, ICRXTX); ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_RECEIVED, &value); - /* Send NACK in case of error */ - rcar_i2c_write(priv, ICSCR, SIE | SDBS | (ret < 0 ? FNA : 0)); + if (ret) + priv->slave_flags |= ID_SLAVE_NACK; + + /* Send NACK in case of error, but it will come 1 byte late :( */ + rcar_i2c_write(priv, ICSCR, SIE | SDBS | + (priv->slave_flags & ID_SLAVE_NACK ? FNA : 0)); rcar_i2c_write(priv, ICSSR, ~SDR & 0xff); } @@ -815,6 +892,10 @@ static int rcar_i2c_do_reset(struct rcar_i2c_priv *priv) { int ret; + /* Don't reset if a slave instance is currently running */ + if (priv->slave) + return -EISCONN; + ret = reset_control_reset(priv->rstc); if (ret) return ret; @@ -841,14 +922,12 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, if (ret < 0) goto out; - /* Gen3 needs a reset before allowing RXDMA once */ - if (priv->devtype == I2C_RCAR_GEN3) { - priv->flags |= ID_P_NO_RXDMA; - if (!IS_ERR(priv->rstc)) { - ret = rcar_i2c_do_reset(priv); - if (ret == 0) - priv->flags &= ~ID_P_NO_RXDMA; - } + /* Gen3+ needs a reset. That also allows RXDMA once */ + if (priv->devtype >= I2C_RCAR_GEN3) { + ret = rcar_i2c_do_reset(priv); + if (ret) + goto out; + priv->flags &= ~ID_P_NO_RXDMA; } rcar_i2c_init(priv); @@ -975,11 +1054,8 @@ static int rcar_unreg_slave(struct i2c_client *slave) /* ensure no irq is running before clearing ptr */ disable_irq(priv->irq); - rcar_i2c_write(priv, ICSIER, 0); - rcar_i2c_write(priv, ICSSR, 0); + rcar_i2c_reset_slave(priv); enable_irq(priv->irq); - rcar_i2c_write(priv, ICSCR, SDBS); - rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */ priv->slave = NULL; @@ -1008,11 +1084,11 @@ static u32 rcar_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm rcar_i2c_algo = { - .master_xfer = rcar_i2c_master_xfer, - .master_xfer_atomic = rcar_i2c_master_xfer_atomic, - .functionality = rcar_i2c_func, - .reg_slave = rcar_reg_slave, - .unreg_slave = rcar_unreg_slave, + .xfer = rcar_i2c_master_xfer, + .xfer_atomic = rcar_i2c_master_xfer_atomic, + .functionality = rcar_i2c_func, + .reg_slave = rcar_reg_slave, + .unreg_slave = rcar_unreg_slave, }; static const struct i2c_adapter_quirks rcar_i2c_quirks = { @@ -1029,10 +1105,12 @@ static const struct of_device_id rcar_i2c_dt_ids[] = { { .compatible = "renesas,i2c-r8a7794", .data = (void *)I2C_RCAR_GEN2 }, { .compatible = "renesas,i2c-r8a7795", .data = (void *)I2C_RCAR_GEN3 }, { .compatible = "renesas,i2c-r8a7796", .data = (void *)I2C_RCAR_GEN3 }, + /* S4 has no FM+ bit */ + { .compatible = "renesas,i2c-r8a779f0", .data = (void *)I2C_RCAR_GEN3 }, { .compatible = "renesas,rcar-gen1-i2c", .data = (void *)I2C_RCAR_GEN1 }, { .compatible = "renesas,rcar-gen2-i2c", .data = (void *)I2C_RCAR_GEN2 }, { .compatible = "renesas,rcar-gen3-i2c", .data = (void *)I2C_RCAR_GEN3 }, - { .compatible = "renesas,rcar-gen4-i2c", .data = (void *)I2C_RCAR_GEN3 }, + { .compatible = "renesas,rcar-gen4-i2c", .data = (void *)I2C_RCAR_GEN4 }, {}, }; MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids); @@ -1092,21 +1170,9 @@ static int rcar_i2c_probe(struct platform_device *pdev) goto out_pm_disable; } - rcar_i2c_write(priv, ICSAR, 0); /* Gen2: must be 0 if not using slave */ - - if (priv->devtype < I2C_RCAR_GEN3) { - irqflags |= IRQF_NO_THREAD; - irqhandler = rcar_i2c_gen2_irq; - } - - if (priv->devtype == I2C_RCAR_GEN3) { - priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); - if (!IS_ERR(priv->rstc)) { - ret = reset_control_status(priv->rstc); - if (ret < 0) - priv->rstc = ERR_PTR(-ENOTSUPP); - } - } + /* Bring hardware to known state */ + rcar_i2c_init(priv); + rcar_i2c_reset_slave(priv); /* Stay always active when multi-master to keep arbitration working */ if (of_property_read_bool(dev->of_node, "multi-master")) @@ -1117,6 +1183,25 @@ static int rcar_i2c_probe(struct platform_device *pdev) if (of_property_read_bool(dev->of_node, "smbus")) priv->flags |= ID_P_HOST_NOTIFY; + if (priv->devtype < I2C_RCAR_GEN3) { + irqflags |= IRQF_NO_THREAD; + irqhandler = rcar_i2c_gen2_irq; + } else { + /* R-Car Gen3+ needs a reset before every transfer */ + priv->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); + if (IS_ERR(priv->rstc)) { + ret = PTR_ERR(priv->rstc); + goto out_pm_put; + } + + ret = reset_control_status(priv->rstc); + if (ret < 0) + goto out_pm_put; + + /* hard reset disturbs HostNotify local target, so disable it */ + priv->flags &= ~ID_P_HOST_NOTIFY; + } + ret = platform_get_irq(pdev, 0); if (ret < 0) goto out_pm_put; @@ -1155,7 +1240,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) return ret; } -static int rcar_i2c_remove(struct platform_device *pdev) +static void rcar_i2c_remove(struct platform_device *pdev) { struct rcar_i2c_priv *priv = platform_get_drvdata(pdev); struct device *dev = &pdev->dev; @@ -1167,11 +1252,8 @@ static int rcar_i2c_remove(struct platform_device *pdev) if (priv->flags & ID_P_PM_BLOCKED) pm_runtime_put(dev); pm_runtime_disable(dev); - - return 0; } -#ifdef CONFIG_PM_SLEEP static int rcar_i2c_suspend(struct device *dev) { struct rcar_i2c_priv *priv = dev_get_drvdata(dev); @@ -1189,19 +1271,14 @@ static int rcar_i2c_resume(struct device *dev) } static const struct dev_pm_ops rcar_i2c_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(rcar_i2c_suspend, rcar_i2c_resume) + NOIRQ_SYSTEM_SLEEP_PM_OPS(rcar_i2c_suspend, rcar_i2c_resume) }; -#define DEV_PM_OPS (&rcar_i2c_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ - static struct platform_driver rcar_i2c_driver = { .driver = { .name = "i2c-rcar", .of_match_table = rcar_i2c_dt_ids, - .pm = DEV_PM_OPS, + .pm = pm_sleep_ptr(&rcar_i2c_pm_ops), }, .probe = rcar_i2c_probe, .remove = rcar_i2c_remove, diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 849848ccb080..3e8f126cb7f7 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -12,9 +12,9 @@ * * 1) The main xfer routine kicks off a transmission by putting the start bit * (or repeated start) on the bus and enabling the transmit interrupt (TIE) - * since we need to send the slave address + RW bit in every case. + * since we need to send the target address + RW bit in every case. * - * 2) TIE sends slave address + RW bit and selects how to continue. + * 2) TIE sends target address + RW bit and selects how to continue. * * 3a) Write case: We keep utilizing TIE as long as we have data to send. If we * are done, we switch over to the transmission done interrupt (TEIE) and mark @@ -34,60 +34,80 @@ * Also check the comments in the interrupt routines for some gory details. */ +#include <linux/bits.h> #include <linux/clk.h> #include <linux/completion.h> #include <linux/err.h> #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/reset.h> - -#define RIIC_ICCR1 0x00 -#define RIIC_ICCR2 0x04 -#define RIIC_ICMR1 0x08 -#define RIIC_ICMR3 0x10 -#define RIIC_ICSER 0x18 -#define RIIC_ICIER 0x1c -#define RIIC_ICSR2 0x24 -#define RIIC_ICBRL 0x34 -#define RIIC_ICBRH 0x38 -#define RIIC_ICDRT 0x3c -#define RIIC_ICDRR 0x40 - -#define ICCR1_ICE 0x80 -#define ICCR1_IICRST 0x40 -#define ICCR1_SOWP 0x10 - -#define ICCR2_BBSY 0x80 -#define ICCR2_SP 0x08 -#define ICCR2_RS 0x04 -#define ICCR2_ST 0x02 - -#define ICMR1_CKS_MASK 0x70 -#define ICMR1_BCWP 0x08 +#include <linux/time.h> + +#define ICCR1_ICE BIT(7) +#define ICCR1_IICRST BIT(6) +#define ICCR1_SOWP BIT(4) +#define ICCR1_SCLO BIT(3) +#define ICCR1_SDAO BIT(2) +#define ICCR1_SCLI BIT(1) +#define ICCR1_SDAI BIT(0) + +#define ICCR2_BBSY BIT(7) +#define ICCR2_SP BIT(3) +#define ICCR2_RS BIT(2) +#define ICCR2_ST BIT(1) + +#define ICMR1_CKS_MASK GENMASK(6, 4) +#define ICMR1_BCWP BIT(3) #define ICMR1_CKS(_x) ((((_x) << 4) & ICMR1_CKS_MASK) | ICMR1_BCWP) -#define ICMR3_RDRFS 0x20 -#define ICMR3_ACKWP 0x10 -#define ICMR3_ACKBT 0x08 +#define ICMR3_RDRFS BIT(5) +#define ICMR3_ACKWP BIT(4) +#define ICMR3_ACKBT BIT(3) + +#define ICFER_FMPE BIT(7) -#define ICIER_TIE 0x80 -#define ICIER_TEIE 0x40 -#define ICIER_RIE 0x20 -#define ICIER_NAKIE 0x10 -#define ICIER_SPIE 0x08 +#define ICIER_TIE BIT(7) +#define ICIER_TEIE BIT(6) +#define ICIER_RIE BIT(5) +#define ICIER_NAKIE BIT(4) +#define ICIER_SPIE BIT(3) -#define ICSR2_NACKF 0x10 +#define ICSR2_NACKF BIT(4) +#define ICSR2_STOP BIT(3) -#define ICBR_RESERVED 0xe0 /* Should be 1 on writes */ +#define ICBR_RESERVED GENMASK(7, 5) /* Should be 1 on writes */ #define RIIC_INIT_MSG -1 +enum riic_reg_list { + RIIC_ICCR1 = 0, + RIIC_ICCR2, + RIIC_ICMR1, + RIIC_ICMR3, + RIIC_ICFER, + RIIC_ICSER, + RIIC_ICIER, + RIIC_ICSR2, + RIIC_ICBRL, + RIIC_ICBRH, + RIIC_ICDRT, + RIIC_ICDRR, + RIIC_REG_END, +}; + +struct riic_of_data { + const u8 *regs; + const struct riic_irq_desc *irqs; + u8 num_irqs; + bool fast_mode_plus; +}; + struct riic_dev { void __iomem *base; u8 *buf; @@ -95,9 +115,12 @@ struct riic_dev { int bytes_left; int err; int is_last; + const struct riic_of_data *info; struct completion msg_done; struct i2c_adapter adapter; struct clk *clk; + struct reset_control *rstc; + struct i2c_timings i2c_t; }; struct riic_irq_desc { @@ -106,29 +129,61 @@ struct riic_irq_desc { char *name; }; +static inline void riic_writeb(struct riic_dev *riic, u8 val, u8 offset) +{ + writeb(val, riic->base + riic->info->regs[offset]); +} + +static inline u8 riic_readb(struct riic_dev *riic, u8 offset) +{ + return readb(riic->base + riic->info->regs[offset]); +} + static inline void riic_clear_set_bit(struct riic_dev *riic, u8 clear, u8 set, u8 reg) { - writeb((readb(riic->base + reg) & ~clear) | set, riic->base + reg); + riic_writeb(riic, (riic_readb(riic, reg) & ~clear) | set, reg); +} + +static int riic_bus_barrier(struct riic_dev *riic) +{ + int ret; + u8 val; + + /* + * The SDA line can still be low even when BBSY = 0. Therefore, after checking + * the BBSY flag, also verify that the SDA and SCL lines are not being held low. + */ + ret = readb_poll_timeout(riic->base + riic->info->regs[RIIC_ICCR2], val, + !(val & ICCR2_BBSY), 10, riic->adapter.timeout); + if (ret) + return i2c_recover_bus(&riic->adapter); + + if ((riic_readb(riic, RIIC_ICCR1) & (ICCR1_SDAI | ICCR1_SCLI)) != + (ICCR1_SDAI | ICCR1_SCLI)) + return i2c_recover_bus(&riic->adapter); + + return 0; } static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct riic_dev *riic = i2c_get_adapdata(adap); + struct device *dev = adap->dev.parent; unsigned long time_left; - int i; + int i, ret; u8 start_bit; - pm_runtime_get_sync(adap->dev.parent); + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; - if (readb(riic->base + RIIC_ICCR2) & ICCR2_BBSY) { - riic->err = -EBUSY; + riic->err = riic_bus_barrier(riic); + if (riic->err) goto out; - } reinit_completion(&riic->msg_done); - riic->err = 0; - writeb(0, riic->base + RIIC_ICSR2); + riic_writeb(riic, 0, RIIC_ICSR2); for (i = 0, start_bit = ICCR2_ST; i < num; i++) { riic->bytes_left = RIIC_INIT_MSG; @@ -136,9 +191,9 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) riic->msg = &msgs[i]; riic->is_last = (i == num - 1); - writeb(ICIER_NAKIE | ICIER_TIE, riic->base + RIIC_ICIER); + riic_writeb(riic, ICIER_NAKIE | ICIER_TIE, RIIC_ICIER); - writeb(start_bit, riic->base + RIIC_ICCR2); + riic_writeb(riic, start_bit, RIIC_ICCR2); time_left = wait_for_completion_timeout(&riic->msg_done, riic->adapter.timeout); if (time_left == 0) @@ -151,7 +206,7 @@ static int riic_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) } out: - pm_runtime_put(adap->dev.parent); + pm_runtime_put_autosuspend(dev); return riic->err ?: num; } @@ -192,7 +247,7 @@ static irqreturn_t riic_tdre_isr(int irq, void *data) * value could be moved to the shadow shift register right away. So * this must be after updates to ICIER (where we want to disable TIE)! */ - writeb(val, riic->base + RIIC_ICDRT); + riic_writeb(riic, val, RIIC_ICDRT); return IRQ_HANDLED; } @@ -201,9 +256,9 @@ static irqreturn_t riic_tend_isr(int irq, void *data) { struct riic_dev *riic = data; - if (readb(riic->base + RIIC_ICSR2) & ICSR2_NACKF) { + if (riic_readb(riic, RIIC_ICSR2) & ICSR2_NACKF) { /* We got a NACKIE */ - readb(riic->base + RIIC_ICDRR); /* dummy read */ + riic_readb(riic, RIIC_ICDRR); /* dummy read */ riic_clear_set_bit(riic, ICSR2_NACKF, 0, RIIC_ICSR2); riic->err = -ENXIO; } else if (riic->bytes_left) { @@ -212,7 +267,7 @@ static irqreturn_t riic_tend_isr(int irq, void *data) if (riic->is_last || riic->err) { riic_clear_set_bit(riic, ICIER_TEIE, ICIER_SPIE, RIIC_ICIER); - writeb(ICCR2_SP, riic->base + RIIC_ICCR2); + riic_writeb(riic, ICCR2_SP, RIIC_ICCR2); } else { /* Transfer is complete, but do not send STOP */ riic_clear_set_bit(riic, ICIER_TEIE, 0, RIIC_ICIER); @@ -231,7 +286,7 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data) if (riic->bytes_left == RIIC_INIT_MSG) { riic->bytes_left = riic->msg->len; - readb(riic->base + RIIC_ICDRR); /* dummy read */ + riic_readb(riic, RIIC_ICDRR); /* dummy read */ return IRQ_HANDLED; } @@ -239,7 +294,7 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data) /* STOP must come before we set ACKBT! */ if (riic->is_last) { riic_clear_set_bit(riic, 0, ICIER_SPIE, RIIC_ICIER); - writeb(ICCR2_SP, riic->base + RIIC_ICCR2); + riic_writeb(riic, ICCR2_SP, RIIC_ICCR2); } riic_clear_set_bit(riic, 0, ICMR3_ACKBT, RIIC_ICMR3); @@ -249,7 +304,7 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data) } /* Reading acks the RIE interrupt */ - *riic->buf = readb(riic->base + RIIC_ICDRR); + *riic->buf = riic_readb(riic, RIIC_ICDRR); riic->buf++; riic->bytes_left--; @@ -261,41 +316,55 @@ static irqreturn_t riic_stop_isr(int irq, void *data) struct riic_dev *riic = data; /* read back registers to confirm writes have fully propagated */ - writeb(0, riic->base + RIIC_ICSR2); - readb(riic->base + RIIC_ICSR2); - writeb(0, riic->base + RIIC_ICIER); - readb(riic->base + RIIC_ICIER); + riic_writeb(riic, 0, RIIC_ICSR2); + riic_readb(riic, RIIC_ICSR2); + riic_writeb(riic, 0, RIIC_ICIER); + riic_readb(riic, RIIC_ICIER); complete(&riic->msg_done); return IRQ_HANDLED; } +static irqreturn_t riic_eei_isr(int irq, void *data) +{ + u8 icsr2 = riic_readb(data, RIIC_ICSR2); + + if (icsr2 & ICSR2_NACKF) + return riic_tend_isr(irq, data); + + if (icsr2 & ICSR2_STOP) + return riic_stop_isr(irq, data); + + return IRQ_NONE; +} + static u32 riic_func(struct i2c_adapter *adap) { return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } static const struct i2c_algorithm riic_algo = { - .master_xfer = riic_xfer, - .functionality = riic_func, + .xfer = riic_xfer, + .functionality = riic_func, }; -static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t) +static int riic_init_hw(struct riic_dev *riic) { - int ret = 0; + int ret; unsigned long rate; + unsigned long ns_per_tick; int total_ticks, cks, brl, brh; + struct i2c_timings *t = &riic->i2c_t; + struct device *dev = riic->adapter.dev.parent; + bool fast_mode_plus = riic->info->fast_mode_plus; + u32 max_freq = fast_mode_plus ? I2C_MAX_FAST_MODE_PLUS_FREQ + : I2C_MAX_FAST_MODE_FREQ; - pm_runtime_get_sync(riic->adapter.dev.parent); - - if (t->bus_freq_hz > I2C_MAX_FAST_MODE_FREQ) { - dev_err(&riic->adapter.dev, - "unsupported bus speed (%dHz). %d max\n", - t->bus_freq_hz, I2C_MAX_FAST_MODE_FREQ); - ret = -EINVAL; - goto out; - } + if (t->bus_freq_hz > max_freq) + return dev_err_probe(dev, -EINVAL, + "unsupported bus speed %uHz (%u max)\n", + t->bus_freq_hz, max_freq); rate = clk_get_rate(riic->clk); @@ -314,9 +383,9 @@ static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t) * frequency with only 62 clock ticks max (31 high, 31 low). * Aim for a duty of 60% LOW, 40% HIGH. */ - total_ticks = DIV_ROUND_UP(rate, t->bus_freq_hz); + total_ticks = DIV_ROUND_UP(rate, t->bus_freq_hz ?: 1); - for (cks = 0; cks < 7; cks++) { + for (cks = 0; cks <= 7; cks++) { /* * 60% low time must be less than BRL + 2 + 1 * BRL max register value is 0x1F. @@ -325,16 +394,13 @@ static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t) if (brl <= (0x1F + 3)) break; - total_ticks /= 2; + total_ticks = DIV_ROUND_UP(total_ticks, 2); rate /= 2; } - if (brl > (0x1F + 3)) { - dev_err(&riic->adapter.dev, "invalid speed (%lu). Too slow.\n", - (unsigned long)t->bus_freq_hz); - ret = -EINVAL; - goto out; - } + if (brl > (0x1F + 3)) + return dev_err_probe(dev, -EINVAL, "invalid speed (%uHz). Too slow.\n", + t->bus_freq_hz); brh = total_ticks - brl; @@ -351,8 +417,9 @@ static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t) * Remove clock ticks for rise and fall times. Convert ns to clock * ticks. */ - brl -= t->scl_fall_ns / (1000000000 / rate); - brh -= t->scl_rise_ns / (1000000000 / rate); + ns_per_tick = NSEC_PER_SEC / rate; + brl -= t->scl_fall_ns / ns_per_tick; + brh -= t->scl_rise_ns / ns_per_tick; /* Adjust for min register values for when SCLE=1 and NFE=1 */ if (brl < 1) @@ -362,28 +429,79 @@ static int riic_init_hw(struct riic_dev *riic, struct i2c_timings *t) pr_debug("i2c-riic: freq=%lu, duty=%d, fall=%lu, rise=%lu, cks=%d, brl=%d, brh=%d\n", rate / total_ticks, ((brl + 3) * 100) / (brl + brh + 6), - t->scl_fall_ns / (1000000000 / rate), - t->scl_rise_ns / (1000000000 / rate), cks, brl, brh); + t->scl_fall_ns / ns_per_tick, t->scl_rise_ns / ns_per_tick, cks, brl, brh); + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; /* Changing the order of accessing IICRST and ICE may break things! */ - writeb(ICCR1_IICRST | ICCR1_SOWP, riic->base + RIIC_ICCR1); + riic_writeb(riic, ICCR1_IICRST | ICCR1_SOWP, RIIC_ICCR1); riic_clear_set_bit(riic, 0, ICCR1_ICE, RIIC_ICCR1); - writeb(ICMR1_CKS(cks), riic->base + RIIC_ICMR1); - writeb(brh | ICBR_RESERVED, riic->base + RIIC_ICBRH); - writeb(brl | ICBR_RESERVED, riic->base + RIIC_ICBRL); + riic_writeb(riic, ICMR1_CKS(cks), RIIC_ICMR1); + riic_writeb(riic, brh | ICBR_RESERVED, RIIC_ICBRH); + riic_writeb(riic, brl | ICBR_RESERVED, RIIC_ICBRL); + + riic_writeb(riic, 0, RIIC_ICSER); + riic_writeb(riic, ICMR3_ACKWP | ICMR3_RDRFS, RIIC_ICMR3); - writeb(0, riic->base + RIIC_ICSER); - writeb(ICMR3_ACKWP | ICMR3_RDRFS, riic->base + RIIC_ICMR3); + if (fast_mode_plus && t->bus_freq_hz > I2C_MAX_FAST_MODE_FREQ) + riic_clear_set_bit(riic, 0, ICFER_FMPE, RIIC_ICFER); riic_clear_set_bit(riic, ICCR1_IICRST, 0, RIIC_ICCR1); -out: - pm_runtime_put(riic->adapter.dev.parent); - return ret; + pm_runtime_put_autosuspend(dev); + return 0; +} + +static int riic_get_scl(struct i2c_adapter *adap) +{ + struct riic_dev *riic = i2c_get_adapdata(adap); + + return !!(riic_readb(riic, RIIC_ICCR1) & ICCR1_SCLI); +} + +static int riic_get_sda(struct i2c_adapter *adap) +{ + struct riic_dev *riic = i2c_get_adapdata(adap); + + return !!(riic_readb(riic, RIIC_ICCR1) & ICCR1_SDAI); +} + +static void riic_set_scl(struct i2c_adapter *adap, int val) +{ + struct riic_dev *riic = i2c_get_adapdata(adap); + + if (val) + riic_clear_set_bit(riic, ICCR1_SOWP, ICCR1_SCLO, RIIC_ICCR1); + else + riic_clear_set_bit(riic, ICCR1_SOWP | ICCR1_SCLO, 0, RIIC_ICCR1); + + riic_clear_set_bit(riic, 0, ICCR1_SOWP, RIIC_ICCR1); } -static struct riic_irq_desc riic_irqs[] = { +static void riic_set_sda(struct i2c_adapter *adap, int val) +{ + struct riic_dev *riic = i2c_get_adapdata(adap); + + if (val) + riic_clear_set_bit(riic, ICCR1_SOWP, ICCR1_SDAO, RIIC_ICCR1); + else + riic_clear_set_bit(riic, ICCR1_SOWP | ICCR1_SDAO, 0, RIIC_ICCR1); + + riic_clear_set_bit(riic, 0, ICCR1_SOWP, RIIC_ICCR1); +} + +static struct i2c_bus_recovery_info riic_bri = { + .recover_bus = i2c_generic_scl_recovery, + .get_scl = riic_get_scl, + .set_scl = riic_set_scl, + .get_sda = riic_get_sda, + .set_sda = riic_set_sda, +}; + +static const struct riic_irq_desc riic_irqs[] = { { .res_num = 0, .isr = riic_tend_isr, .name = "riic-tend" }, { .res_num = 1, .isr = riic_rdrf_isr, .name = "riic-rdrf" }, { .res_num = 2, .isr = riic_tdre_isr, .name = "riic-tdre" }, @@ -391,20 +509,21 @@ static struct riic_irq_desc riic_irqs[] = { { .res_num = 5, .isr = riic_tend_isr, .name = "riic-nack" }, }; -static void riic_reset_control_assert(void *data) -{ - reset_control_assert(data); -} +static const struct riic_irq_desc riic_rzt2h_irqs[] = { + { .res_num = 0, .isr = riic_eei_isr, .name = "riic-eei" }, + { .res_num = 1, .isr = riic_rdrf_isr, .name = "riic-rxi" }, + { .res_num = 2, .isr = riic_tdre_isr, .name = "riic-txi" }, + { .res_num = 3, .isr = riic_tend_isr, .name = "riic-tei" }, +}; static int riic_i2c_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; struct riic_dev *riic; struct i2c_adapter *adap; - struct i2c_timings i2c_t; - struct reset_control *rstc; int i, ret; - riic = devm_kzalloc(&pdev->dev, sizeof(*riic), GFP_KERNEL); + riic = devm_kzalloc(dev, sizeof(*riic), GFP_KERNEL); if (!riic) return -ENOMEM; @@ -412,53 +531,53 @@ static int riic_i2c_probe(struct platform_device *pdev) if (IS_ERR(riic->base)) return PTR_ERR(riic->base); - riic->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(riic->clk)) { - dev_err(&pdev->dev, "missing controller clock"); - return PTR_ERR(riic->clk); - } + riic->clk = devm_clk_get(dev, NULL); + if (IS_ERR(riic->clk)) + return dev_err_probe(dev, PTR_ERR(riic->clk), + "missing controller clock"); - rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); - if (IS_ERR(rstc)) - return dev_err_probe(&pdev->dev, PTR_ERR(rstc), - "Error: missing reset ctrl\n"); + riic->rstc = devm_reset_control_get_optional_exclusive_deasserted(dev, NULL); + if (IS_ERR(riic->rstc)) + return dev_err_probe(dev, PTR_ERR(riic->rstc), + "failed to acquire deasserted reset\n"); - ret = reset_control_deassert(rstc); - if (ret) - return ret; + riic->info = of_device_get_match_data(dev); - ret = devm_add_action_or_reset(&pdev->dev, riic_reset_control_assert, rstc); - if (ret) - return ret; + for (i = 0; i < riic->info->num_irqs; i++) { + const struct riic_irq_desc *irq_desc; + int irq; - for (i = 0; i < ARRAY_SIZE(riic_irqs); i++) { - ret = platform_get_irq(pdev, riic_irqs[i].res_num); - if (ret < 0) - return ret; + irq_desc = &riic->info->irqs[i]; + irq = platform_get_irq(pdev, irq_desc->res_num); + if (irq < 0) + return irq; - ret = devm_request_irq(&pdev->dev, ret, riic_irqs[i].isr, - 0, riic_irqs[i].name, riic); - if (ret) { - dev_err(&pdev->dev, "failed to request irq %s\n", riic_irqs[i].name); - return ret; - } + ret = devm_request_irq(dev, irq, irq_desc->isr, 0, irq_desc->name, riic); + if (ret) + return dev_err_probe(dev, ret, "failed to request irq %s\n", + irq_desc->name); } + adap = &riic->adapter; i2c_set_adapdata(adap, riic); strscpy(adap->name, "Renesas RIIC adapter", sizeof(adap->name)); adap->owner = THIS_MODULE; adap->algo = &riic_algo; - adap->dev.parent = &pdev->dev; - adap->dev.of_node = pdev->dev.of_node; + adap->dev.parent = dev; + adap->dev.of_node = dev->of_node; + adap->bus_recovery_info = &riic_bri; init_completion(&riic->msg_done); - i2c_parse_fw_timings(&pdev->dev, &i2c_t, true); + i2c_parse_fw_timings(dev, &riic->i2c_t, true); - pm_runtime_enable(&pdev->dev); + /* Default 0 to save power. Can be overridden via sysfs for lower latency. */ + pm_runtime_set_autosuspend_delay(dev, 0); + pm_runtime_use_autosuspend(dev); + pm_runtime_enable(dev); - ret = riic_init_hw(riic, &i2c_t); + ret = riic_init_hw(riic); if (ret) goto out; @@ -468,31 +587,142 @@ static int riic_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, riic); - dev_info(&pdev->dev, "registered with %dHz bus speed\n", - i2c_t.bus_freq_hz); + dev_info(dev, "registered with %dHz bus speed\n", riic->i2c_t.bus_freq_hz); return 0; out: - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); + pm_runtime_dont_use_autosuspend(dev); return ret; } -static int riic_i2c_remove(struct platform_device *pdev) +static void riic_i2c_remove(struct platform_device *pdev) { struct riic_dev *riic = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + int ret; - pm_runtime_get_sync(&pdev->dev); - writeb(0, riic->base + RIIC_ICIER); - pm_runtime_put(&pdev->dev); + ret = pm_runtime_resume_and_get(dev); + if (!ret) { + riic_writeb(riic, 0, RIIC_ICIER); + pm_runtime_put(dev); + } i2c_del_adapter(&riic->adapter); - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); + pm_runtime_dont_use_autosuspend(dev); +} + +static const u8 riic_rz_a_regs[RIIC_REG_END] = { + [RIIC_ICCR1] = 0x00, + [RIIC_ICCR2] = 0x04, + [RIIC_ICMR1] = 0x08, + [RIIC_ICMR3] = 0x10, + [RIIC_ICFER] = 0x14, + [RIIC_ICSER] = 0x18, + [RIIC_ICIER] = 0x1c, + [RIIC_ICSR2] = 0x24, + [RIIC_ICBRL] = 0x34, + [RIIC_ICBRH] = 0x38, + [RIIC_ICDRT] = 0x3c, + [RIIC_ICDRR] = 0x40, +}; + +static const struct riic_of_data riic_rz_a_info = { + .regs = riic_rz_a_regs, + .irqs = riic_irqs, + .num_irqs = ARRAY_SIZE(riic_irqs), + .fast_mode_plus = true, +}; + +static const struct riic_of_data riic_rz_a1h_info = { + .regs = riic_rz_a_regs, + .irqs = riic_irqs, + .num_irqs = ARRAY_SIZE(riic_irqs), +}; + +static const u8 riic_rz_v2h_regs[RIIC_REG_END] = { + [RIIC_ICCR1] = 0x00, + [RIIC_ICCR2] = 0x01, + [RIIC_ICMR1] = 0x02, + [RIIC_ICMR3] = 0x04, + [RIIC_ICFER] = 0x05, + [RIIC_ICSER] = 0x06, + [RIIC_ICIER] = 0x07, + [RIIC_ICSR2] = 0x09, + [RIIC_ICBRL] = 0x10, + [RIIC_ICBRH] = 0x11, + [RIIC_ICDRT] = 0x12, + [RIIC_ICDRR] = 0x13, +}; + +static const struct riic_of_data riic_rz_v2h_info = { + .regs = riic_rz_v2h_regs, + .irqs = riic_irqs, + .num_irqs = ARRAY_SIZE(riic_irqs), + .fast_mode_plus = true, +}; + +static const struct riic_of_data riic_rz_t2h_info = { + .regs = riic_rz_v2h_regs, + .irqs = riic_rzt2h_irqs, + .num_irqs = ARRAY_SIZE(riic_rzt2h_irqs), +}; + +static int riic_i2c_suspend(struct device *dev) +{ + struct riic_dev *riic = dev_get_drvdata(dev); + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret) + return ret; + + i2c_mark_adapter_suspended(&riic->adapter); + + /* Disable output on SDA, SCL pins. */ + riic_clear_set_bit(riic, ICCR1_ICE, 0, RIIC_ICCR1); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_sync(dev); + + return reset_control_assert(riic->rstc); +} + +static int riic_i2c_resume(struct device *dev) +{ + struct riic_dev *riic = dev_get_drvdata(dev); + int ret; + + ret = reset_control_deassert(riic->rstc); + if (ret) + return ret; + + ret = riic_init_hw(riic); + if (ret) { + /* + * In case this happens there is no way to recover from this + * state. The driver will remain loaded. We want to avoid + * keeping the reset line de-asserted for no reason. + */ + reset_control_assert(riic->rstc); + return ret; + } + + i2c_mark_adapter_resumed(&riic->adapter); return 0; } +static const struct dev_pm_ops riic_i2c_pm_ops = { + SYSTEM_SLEEP_PM_OPS(riic_i2c_suspend, riic_i2c_resume) +}; + static const struct of_device_id riic_i2c_dt_ids[] = { - { .compatible = "renesas,riic-rz", }, - { /* Sentinel */ }, + { .compatible = "renesas,riic-r7s72100", .data = &riic_rz_a1h_info, }, + { .compatible = "renesas,riic-r9a09g057", .data = &riic_rz_v2h_info }, + { .compatible = "renesas,riic-r9a09g077", .data = &riic_rz_t2h_info }, + { .compatible = "renesas,riic-rz", .data = &riic_rz_a_info }, + { /* Sentinel */ } }; static struct platform_driver riic_i2c_driver = { @@ -501,6 +731,7 @@ static struct platform_driver riic_i2c_driver = { .driver = { .name = "i2c-riic", .of_match_table = riic_i2c_dt_ids, + .pm = pm_ptr(&riic_i2c_pm_ops), }, }; diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index b31cf4f18f85..d4e9196445c0 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -28,8 +28,8 @@ /* Register Map */ #define REG_CON 0x00 /* control register */ #define REG_CLKDIV 0x04 /* clock divisor register */ -#define REG_MRXADDR 0x08 /* slave address for REGISTER_TX */ -#define REG_MRXRADDR 0x0c /* slave register address for REGISTER_TX */ +#define REG_MRXADDR 0x08 /* target address for REGISTER_TX */ +#define REG_MRXRADDR 0x0c /* target register address for REGISTER_TX */ #define REG_MTXCNT 0x10 /* number of bytes to be transmitted */ #define REG_MRXCNT 0x14 /* number of bytes to be received */ #define REG_IEN 0x18 /* interrupt enable */ @@ -68,8 +68,8 @@ enum { /* REG_IEN/REG_IPD bits */ #define REG_INT_BTF BIT(0) /* a byte was transmitted */ #define REG_INT_BRF BIT(1) /* a byte was received */ -#define REG_INT_MBTF BIT(2) /* master data transmit finished */ -#define REG_INT_MBRF BIT(3) /* master data receive finished */ +#define REG_INT_MBTF BIT(2) /* controller data transmit finished */ +#define REG_INT_MBRF BIT(3) /* controller data receive finished */ #define REG_INT_START BIT(4) /* START condition generated */ #define REG_INT_STOP BIT(5) /* STOP condition generated */ #define REG_INT_NAKRCV BIT(6) /* NACK received */ @@ -178,12 +178,13 @@ struct rk3x_i2c_soc_data { * @clk: function clk for rk3399 or function & Bus clks for others * @pclk: Bus clk for rk3399 * @clk_rate_nb: i2c clk rate change notify + * @irq: irq number * @t: I2C known timing information * @lock: spinlock for the i2c bus * @wait: the waitqueue to wait for i2c transfer * @busy: the condition for the event to wait for * @msg: current i2c message - * @addr: addr of i2c slave device + * @addr: addr of i2c target device * @mode: mode of i2c transfer * @is_last_msg: flag determines whether it is the last msg in this transfer * @state: state of i2c transfer @@ -200,6 +201,7 @@ struct rk3x_i2c { struct clk *clk; struct clk *pclk; struct notifier_block clk_rate_nb; + int irq; /* Settings */ struct i2c_timings t; @@ -977,7 +979,7 @@ static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num) /* * The I2C adapter can issue a small (len < 4) write packet before * reading. This speeds up SMBus-style register reads. - * The MRXADDR/MRXRADDR hold the slave address and the slave register + * The MRXADDR/MRXRADDR hold the target address and the target register * address in this case. */ @@ -1014,7 +1016,7 @@ static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num) addr |= 1; /* set read bit */ /* - * We have to transmit the slave addr first. Use + * We have to transmit the target addr first. Use * MOD_REGISTER_TX for that purpose. */ i2c->mode = REG_CON_MOD_REGISTER_TX; @@ -1058,7 +1060,8 @@ static int rk3x_i2c_xfer_common(struct i2c_adapter *adap, struct i2c_msg *msgs, int num, bool polling) { struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data; - unsigned long timeout, flags; + unsigned long flags; + long time_left; u32 val; int ret = 0; int i; @@ -1087,21 +1090,23 @@ static int rk3x_i2c_xfer_common(struct i2c_adapter *adap, spin_unlock_irqrestore(&i2c->lock, flags); - rk3x_i2c_start(i2c); - if (!polling) { - timeout = wait_event_timeout(i2c->wait, !i2c->busy, - msecs_to_jiffies(WAIT_TIMEOUT)); + rk3x_i2c_start(i2c); + + time_left = wait_event_timeout(i2c->wait, !i2c->busy, + msecs_to_jiffies(WAIT_TIMEOUT)); } else { - timeout = rk3x_i2c_wait_xfer_poll(i2c); + disable_irq(i2c->irq); + rk3x_i2c_start(i2c); + + time_left = rk3x_i2c_wait_xfer_poll(i2c); + + enable_irq(i2c->irq); } spin_lock_irqsave(&i2c->lock, flags); - if (timeout == 0) { - dev_err(i2c->dev, "timeout, ipd: 0x%02x, state: %d\n", - i2c_readl(i2c, REG_IPD), i2c->state); - + if (time_left == 0) { /* Force a STOP condition without interrupt */ i2c_writel(i2c, 0, REG_IEN); val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK; @@ -1155,9 +1160,9 @@ static u32 rk3x_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm rk3x_i2c_algorithm = { - .master_xfer = rk3x_i2c_xfer, - .master_xfer_atomic = rk3x_i2c_xfer_polling, - .functionality = rk3x_i2c_func, + .xfer = rk3x_i2c_xfer, + .xfer_atomic = rk3x_i2c_xfer_polling, + .functionality = rk3x_i2c_func, }; static const struct rk3x_i2c_soc_data rv1108_soc_data = { @@ -1288,8 +1293,12 @@ static int rk3x_i2c_probe(struct platform_device *pdev) return -EINVAL; } - /* 27+i: write mask, 11+i: value */ - value = BIT(27 + bus_nr) | BIT(11 + bus_nr); + /* rv1126 i2c2 uses non-sequential write mask 20, value 4 */ + if (i2c->soc_data == &rv1126_soc_data && bus_nr == 2) + value = BIT(20) | BIT(4); + else + /* 27+i: write mask, 11+i: value */ + value = BIT(27 + bus_nr) | BIT(11 + bus_nr); ret = regmap_write(grf, i2c->soc_data->grf_offset, value); if (ret != 0) { @@ -1310,6 +1319,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev) return ret; } + i2c->irq = irq; + platform_set_drvdata(pdev, i2c); if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) { @@ -1372,7 +1383,7 @@ err_clk: return ret; } -static int rk3x_i2c_remove(struct platform_device *pdev) +static void rk3x_i2c_remove(struct platform_device *pdev) { struct rk3x_i2c *i2c = platform_get_drvdata(pdev); @@ -1381,15 +1392,13 @@ static int rk3x_i2c_remove(struct platform_device *pdev) clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb); clk_unprepare(i2c->pclk); clk_unprepare(i2c->clk); - - return 0; } static SIMPLE_DEV_PM_OPS(rk3x_i2c_pm_ops, NULL, rk3x_i2c_resume); static struct platform_driver rk3x_i2c_driver = { .probe = rk3x_i2c_probe, - .remove = rk3x_i2c_remove, + .remove = rk3x_i2c_remove, .driver = { .name = "rk3x-i2c", .of_match_table = rk3x_i2c_match, diff --git a/drivers/i2c/busses/i2c-robotfuzz-osif.c b/drivers/i2c/busses/i2c-robotfuzz-osif.c index 66dfa211e736..e0a76fb5bc31 100644 --- a/drivers/i2c/busses/i2c-robotfuzz-osif.c +++ b/drivers/i2c/busses/i2c-robotfuzz-osif.c @@ -111,9 +111,14 @@ static u32 osif_func(struct i2c_adapter *adapter) return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } +/* prevent invalid 0-length usb_control_msg */ +static const struct i2c_adapter_quirks osif_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN_READ, +}; + static const struct i2c_algorithm osif_algorithm = { - .master_xfer = osif_xfer, - .functionality = osif_func, + .xfer = osif_xfer, + .functionality = osif_func, }; #define USB_OSIF_VENDOR_ID 0x1964 @@ -143,6 +148,7 @@ static int osif_probe(struct usb_interface *interface, priv->adapter.owner = THIS_MODULE; priv->adapter.class = I2C_CLASS_HWMON; + priv->adapter.quirks = &osif_quirks; priv->adapter.algo = &osif_algorithm; priv->adapter.algo_data = priv; snprintf(priv->adapter.name, sizeof(priv->adapter.name), diff --git a/drivers/i2c/busses/i2c-rtl9300.c b/drivers/i2c/busses/i2c-rtl9300.c new file mode 100644 index 000000000000..4723e48cfe18 --- /dev/null +++ b/drivers/i2c/busses/i2c-rtl9300.c @@ -0,0 +1,539 @@ +// SPDX-License-Identifier: GPL-2.0-only + +#include <linux/bits.h> +#include <linux/i2c.h> +#include <linux/i2c-mux.h> +#include <linux/mod_devicetable.h> +#include <linux/mfd/syscon.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/regmap.h> +#include <linux/unaligned.h> + +enum rtl9300_bus_freq { + RTL9300_I2C_STD_FREQ, + RTL9300_I2C_FAST_FREQ, +}; + +struct rtl9300_i2c; + +struct rtl9300_i2c_chan { + struct i2c_adapter adap; + struct rtl9300_i2c *i2c; + enum rtl9300_bus_freq bus_freq; + u8 sda_num; +}; + +enum rtl9300_i2c_reg_scope { + REG_SCOPE_GLOBAL, + REG_SCOPE_MASTER, +}; + +struct rtl9300_i2c_reg_field { + struct reg_field field; + enum rtl9300_i2c_reg_scope scope; +}; + +enum rtl9300_i2c_reg_fields { + F_DATA_WIDTH = 0, + F_DEV_ADDR, + F_I2C_FAIL, + F_I2C_TRIG, + F_MEM_ADDR, + F_MEM_ADDR_WIDTH, + F_RD_MODE, + F_RWOP, + F_SCL_FREQ, + F_SCL_SEL, + F_SDA_OUT_SEL, + F_SDA_SEL, + + /* keep last */ + F_NUM_FIELDS +}; + +struct rtl9300_i2c_drv_data { + struct rtl9300_i2c_reg_field field_desc[F_NUM_FIELDS]; + int (*select_scl)(struct rtl9300_i2c *i2c, u8 scl); + u32 data_reg; + u8 max_nchan; +}; + +#define RTL9300_I2C_MUX_NCHAN 8 +#define RTL9310_I2C_MUX_NCHAN 12 + +struct rtl9300_i2c { + struct regmap *regmap; + struct device *dev; + struct rtl9300_i2c_chan chans[RTL9310_I2C_MUX_NCHAN]; + struct regmap_field *fields[F_NUM_FIELDS]; + u32 reg_base; + u32 data_reg; + u8 scl_num; + u8 sda_num; + struct mutex lock; +}; + +DEFINE_GUARD(rtl9300_i2c, struct rtl9300_i2c *, mutex_lock(&_T->lock), mutex_unlock(&_T->lock)) + +enum rtl9300_i2c_xfer_type { + RTL9300_I2C_XFER_BYTE, + RTL9300_I2C_XFER_WORD, + RTL9300_I2C_XFER_BLOCK, +}; + +struct rtl9300_i2c_xfer { + enum rtl9300_i2c_xfer_type type; + u16 dev_addr; + u8 reg_addr; + u8 reg_addr_len; + u8 *data; + u8 data_len; + bool write; +}; + +#define RTL9300_I2C_MST_CTRL1 0x0 +#define RTL9300_I2C_MST_CTRL2 0x4 +#define RTL9300_I2C_MST_DATA_WORD0 0x8 +#define RTL9300_I2C_MST_DATA_WORD1 0xc +#define RTL9300_I2C_MST_DATA_WORD2 0x10 +#define RTL9300_I2C_MST_DATA_WORD3 0x14 +#define RTL9300_I2C_MST_GLB_CTRL 0x384 + +#define RTL9310_I2C_MST_IF_CTRL 0x1004 +#define RTL9310_I2C_MST_IF_SEL 0x1008 +#define RTL9310_I2C_MST_CTRL 0x0 +#define RTL9310_I2C_MST_MEMADDR_CTRL 0x4 +#define RTL9310_I2C_MST_DATA_CTRL 0x8 + +static int rtl9300_i2c_reg_addr_set(struct rtl9300_i2c *i2c, u32 reg, u16 len) +{ + int ret; + + ret = regmap_field_write(i2c->fields[F_MEM_ADDR_WIDTH], len); + if (ret) + return ret; + + return regmap_field_write(i2c->fields[F_MEM_ADDR], reg); +} + +static int rtl9300_i2c_select_scl(struct rtl9300_i2c *i2c, u8 scl) +{ + return regmap_field_write(i2c->fields[F_SCL_SEL], 1); +} + +static int rtl9310_i2c_select_scl(struct rtl9300_i2c *i2c, u8 scl) +{ + return regmap_field_update_bits(i2c->fields[F_SCL_SEL], BIT(scl), BIT(scl)); +} + +static int rtl9300_i2c_config_chan(struct rtl9300_i2c *i2c, struct rtl9300_i2c_chan *chan) +{ + struct rtl9300_i2c_drv_data *drv_data; + int ret; + + if (i2c->sda_num == chan->sda_num) + return 0; + + ret = regmap_field_write(i2c->fields[F_SCL_FREQ], chan->bus_freq); + if (ret) + return ret; + + drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev); + ret = drv_data->select_scl(i2c, i2c->scl_num); + if (ret) + return ret; + + ret = regmap_field_update_bits(i2c->fields[F_SDA_SEL], BIT(chan->sda_num), + BIT(chan->sda_num)); + if (ret) + return ret; + + ret = regmap_field_write(i2c->fields[F_SDA_OUT_SEL], chan->sda_num); + if (ret) + return ret; + + i2c->sda_num = chan->sda_num; + return 0; +} + +static int rtl9300_i2c_read(struct rtl9300_i2c *i2c, u8 *buf, u8 len) +{ + u32 vals[4] = {}; + int i, ret; + + if (len > 16) + return -EIO; + + ret = regmap_bulk_read(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals)); + if (ret) + return ret; + + for (i = 0; i < len; i++) { + buf[i] = vals[i/4] & 0xff; + vals[i/4] >>= 8; + } + + return 0; +} + +static int rtl9300_i2c_write(struct rtl9300_i2c *i2c, u8 *buf, u8 len) +{ + u32 vals[4] = {}; + int i; + + if (len > 16) + return -EIO; + + for (i = 0; i < len; i++) { + unsigned int shift = (i % 4) * 8; + unsigned int reg = i / 4; + + vals[reg] |= buf[i] << shift; + } + + return regmap_bulk_write(i2c->regmap, i2c->data_reg, vals, ARRAY_SIZE(vals)); +} + +static int rtl9300_i2c_writel(struct rtl9300_i2c *i2c, u32 data) +{ + return regmap_write(i2c->regmap, i2c->data_reg, data); +} + +static int rtl9300_i2c_prepare_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer) +{ + int ret; + + if (xfer->data_len < 1 || xfer->data_len > 16) + return -EINVAL; + + ret = regmap_field_write(i2c->fields[F_DEV_ADDR], xfer->dev_addr); + if (ret) + return ret; + + ret = rtl9300_i2c_reg_addr_set(i2c, xfer->reg_addr, xfer->reg_addr_len); + if (ret) + return ret; + + ret = regmap_field_write(i2c->fields[F_RWOP], xfer->write); + if (ret) + return ret; + + ret = regmap_field_write(i2c->fields[F_DATA_WIDTH], (xfer->data_len - 1) & 0xf); + if (ret) + return ret; + + if (xfer->write) { + switch (xfer->type) { + case RTL9300_I2C_XFER_BYTE: + ret = rtl9300_i2c_writel(i2c, *xfer->data); + break; + case RTL9300_I2C_XFER_WORD: + ret = rtl9300_i2c_writel(i2c, get_unaligned((const u16 *)xfer->data)); + break; + default: + ret = rtl9300_i2c_write(i2c, xfer->data, xfer->data_len); + break; + } + } + + return ret; +} + +static int rtl9300_i2c_do_xfer(struct rtl9300_i2c *i2c, struct rtl9300_i2c_xfer *xfer) +{ + u32 val; + int ret; + + ret = regmap_field_write(i2c->fields[F_I2C_TRIG], 1); + if (ret) + return ret; + + ret = regmap_field_read_poll_timeout(i2c->fields[F_I2C_TRIG], val, !val, 100, 100000); + if (ret) + return ret; + + ret = regmap_field_read(i2c->fields[F_I2C_FAIL], &val); + if (ret) + return ret; + if (val) + return -EIO; + + if (!xfer->write) { + switch (xfer->type) { + case RTL9300_I2C_XFER_BYTE: + ret = regmap_read(i2c->regmap, i2c->data_reg, &val); + if (ret) + return ret; + + *xfer->data = val & 0xff; + break; + case RTL9300_I2C_XFER_WORD: + ret = regmap_read(i2c->regmap, i2c->data_reg, &val); + if (ret) + return ret; + + put_unaligned(val & 0xffff, (u16*)xfer->data); + break; + default: + ret = rtl9300_i2c_read(i2c, xfer->data, xfer->data_len); + if (ret) + return ret; + break; + } + } + + return 0; +} + +static int rtl9300_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, unsigned short flags, + char read_write, u8 command, int size, + union i2c_smbus_data *data) +{ + struct rtl9300_i2c_chan *chan = i2c_get_adapdata(adap); + struct rtl9300_i2c *i2c = chan->i2c; + struct rtl9300_i2c_xfer xfer = {0}; + int ret; + + if (addr > 0x7f) + return -EINVAL; + + guard(rtl9300_i2c)(i2c); + + ret = rtl9300_i2c_config_chan(i2c, chan); + if (ret) + return ret; + + xfer.dev_addr = addr & 0x7f; + xfer.write = (read_write == I2C_SMBUS_WRITE); + xfer.reg_addr = command; + xfer.reg_addr_len = 1; + + switch (size) { + case I2C_SMBUS_BYTE: + xfer.data = (read_write == I2C_SMBUS_READ) ? &data->byte : &command; + xfer.data_len = 1; + xfer.reg_addr = 0; + xfer.reg_addr_len = 0; + xfer.type = RTL9300_I2C_XFER_BYTE; + break; + case I2C_SMBUS_BYTE_DATA: + xfer.data = &data->byte; + xfer.data_len = 1; + xfer.type = RTL9300_I2C_XFER_BYTE; + break; + case I2C_SMBUS_WORD_DATA: + xfer.data = (u8 *)&data->word; + xfer.data_len = 2; + xfer.type = RTL9300_I2C_XFER_WORD; + break; + case I2C_SMBUS_BLOCK_DATA: + xfer.data = &data->block[0]; + xfer.data_len = data->block[0] + 1; + xfer.type = RTL9300_I2C_XFER_BLOCK; + break; + case I2C_SMBUS_I2C_BLOCK_DATA: + xfer.data = &data->block[1]; + xfer.data_len = data->block[0]; + xfer.type = RTL9300_I2C_XFER_BLOCK; + break; + default: + dev_err(&adap->dev, "Unsupported transaction %d\n", size); + return -EOPNOTSUPP; + } + + ret = rtl9300_i2c_prepare_xfer(i2c, &xfer); + if (ret) + return ret; + + return rtl9300_i2c_do_xfer(i2c, &xfer); +} + +static u32 rtl9300_i2c_func(struct i2c_adapter *a) +{ + return I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK; +} + +static const struct i2c_algorithm rtl9300_i2c_algo = { + .smbus_xfer = rtl9300_i2c_smbus_xfer, + .functionality = rtl9300_i2c_func, +}; + +static struct i2c_adapter_quirks rtl9300_i2c_quirks = { + .flags = I2C_AQ_NO_CLK_STRETCH | I2C_AQ_NO_ZERO_LEN, + .max_read_len = 16, + .max_write_len = 16, +}; + +static int rtl9300_i2c_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rtl9300_i2c *i2c; + struct fwnode_handle *child; + struct rtl9300_i2c_drv_data *drv_data; + struct reg_field fields[F_NUM_FIELDS]; + u32 clock_freq, scl_num, sda_num; + int ret, i = 0; + + i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + i2c->regmap = syscon_node_to_regmap(dev->parent->of_node); + if (IS_ERR(i2c->regmap)) + return PTR_ERR(i2c->regmap); + i2c->dev = dev; + + mutex_init(&i2c->lock); + + ret = device_property_read_u32(dev, "reg", &i2c->reg_base); + if (ret) + return ret; + + ret = device_property_read_u32(dev, "realtek,scl", &scl_num); + if (ret || scl_num != 1) + scl_num = 0; + i2c->scl_num = (u8)scl_num; + + platform_set_drvdata(pdev, i2c); + + drv_data = (struct rtl9300_i2c_drv_data *)device_get_match_data(i2c->dev); + if (device_get_child_node_count(dev) > drv_data->max_nchan) + return dev_err_probe(dev, -EINVAL, "Too many channels\n"); + + i2c->data_reg = i2c->reg_base + drv_data->data_reg; + for (i = 0; i < F_NUM_FIELDS; i++) { + fields[i] = drv_data->field_desc[i].field; + if (drv_data->field_desc[i].scope == REG_SCOPE_MASTER) + fields[i].reg += i2c->reg_base; + } + ret = devm_regmap_field_bulk_alloc(dev, i2c->regmap, i2c->fields, + fields, F_NUM_FIELDS); + if (ret) + return ret; + + i = 0; + device_for_each_child_node(dev, child) { + struct rtl9300_i2c_chan *chan = &i2c->chans[i]; + struct i2c_adapter *adap = &chan->adap; + + ret = fwnode_property_read_u32(child, "reg", &sda_num); + if (ret) + return ret; + + ret = fwnode_property_read_u32(child, "clock-frequency", &clock_freq); + if (ret) + clock_freq = I2C_MAX_STANDARD_MODE_FREQ; + + switch (clock_freq) { + case I2C_MAX_STANDARD_MODE_FREQ: + chan->bus_freq = RTL9300_I2C_STD_FREQ; + break; + case I2C_MAX_FAST_MODE_FREQ: + chan->bus_freq = RTL9300_I2C_FAST_FREQ; + break; + default: + dev_warn(i2c->dev, "SDA%d clock-frequency %d not supported using default\n", + sda_num, clock_freq); + break; + } + + chan->sda_num = sda_num; + chan->i2c = i2c; + adap = &i2c->chans[i].adap; + adap->owner = THIS_MODULE; + adap->algo = &rtl9300_i2c_algo; + adap->quirks = &rtl9300_i2c_quirks; + adap->retries = 3; + adap->dev.parent = dev; + i2c_set_adapdata(adap, chan); + adap->dev.of_node = to_of_node(child); + snprintf(adap->name, sizeof(adap->name), "%s SDA%d\n", dev_name(dev), sda_num); + i++; + + ret = devm_i2c_add_adapter(dev, adap); + if (ret) + return ret; + } + i2c->sda_num = 0xff; + + /* only use standard read format */ + ret = regmap_field_write(i2c->fields[F_RD_MODE], 0); + if (ret) + return ret; + + return 0; +} + +#define GLB_REG_FIELD(reg, msb, lsb) \ + { .field = REG_FIELD(reg, msb, lsb), .scope = REG_SCOPE_GLOBAL } +#define MST_REG_FIELD(reg, msb, lsb) \ + { .field = REG_FIELD(reg, msb, lsb), .scope = REG_SCOPE_MASTER } + +static const struct rtl9300_i2c_drv_data rtl9300_i2c_drv_data = { + .field_desc = { + [F_MEM_ADDR] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 8, 31), + [F_SDA_OUT_SEL] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 4, 6), + [F_SCL_SEL] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 3, 3), + [F_RWOP] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 2, 2), + [F_I2C_FAIL] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 1, 1), + [F_I2C_TRIG] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL1, 0, 0), + [F_RD_MODE] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 15, 15), + [F_DEV_ADDR] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 8, 14), + [F_DATA_WIDTH] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 4, 7), + [F_MEM_ADDR_WIDTH] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 2, 3), + [F_SCL_FREQ] = MST_REG_FIELD(RTL9300_I2C_MST_CTRL2, 0, 1), + [F_SDA_SEL] = GLB_REG_FIELD(RTL9300_I2C_MST_GLB_CTRL, 0, 7), + }, + .select_scl = rtl9300_i2c_select_scl, + .data_reg = RTL9300_I2C_MST_DATA_WORD0, + .max_nchan = RTL9300_I2C_MUX_NCHAN, +}; + +static const struct rtl9300_i2c_drv_data rtl9310_i2c_drv_data = { + .field_desc = { + [F_SCL_SEL] = GLB_REG_FIELD(RTL9310_I2C_MST_IF_SEL, 12, 13), + [F_SDA_SEL] = GLB_REG_FIELD(RTL9310_I2C_MST_IF_SEL, 0, 11), + [F_SCL_FREQ] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 30, 31), + [F_DEV_ADDR] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 11, 17), + [F_SDA_OUT_SEL] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 18, 21), + [F_MEM_ADDR_WIDTH] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 9, 10), + [F_DATA_WIDTH] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 5, 8), + [F_RD_MODE] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 4, 4), + [F_RWOP] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 2, 2), + [F_I2C_FAIL] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 1, 1), + [F_I2C_TRIG] = MST_REG_FIELD(RTL9310_I2C_MST_CTRL, 0, 0), + [F_MEM_ADDR] = MST_REG_FIELD(RTL9310_I2C_MST_MEMADDR_CTRL, 0, 23), + }, + .select_scl = rtl9310_i2c_select_scl, + .data_reg = RTL9310_I2C_MST_DATA_CTRL, + .max_nchan = RTL9310_I2C_MUX_NCHAN, +}; + +static const struct of_device_id i2c_rtl9300_dt_ids[] = { + { .compatible = "realtek,rtl9301-i2c", .data = (void *) &rtl9300_i2c_drv_data }, + { .compatible = "realtek,rtl9302b-i2c", .data = (void *) &rtl9300_i2c_drv_data }, + { .compatible = "realtek,rtl9302c-i2c", .data = (void *) &rtl9300_i2c_drv_data }, + { .compatible = "realtek,rtl9303-i2c", .data = (void *) &rtl9300_i2c_drv_data }, + { .compatible = "realtek,rtl9310-i2c", .data = (void *) &rtl9310_i2c_drv_data }, + { .compatible = "realtek,rtl9311-i2c", .data = (void *) &rtl9310_i2c_drv_data }, + { .compatible = "realtek,rtl9312-i2c", .data = (void *) &rtl9310_i2c_drv_data }, + { .compatible = "realtek,rtl9313-i2c", .data = (void *) &rtl9310_i2c_drv_data }, + {} +}; +MODULE_DEVICE_TABLE(of, i2c_rtl9300_dt_ids); + +static struct platform_driver rtl9300_i2c_driver = { + .probe = rtl9300_i2c_probe, + .driver = { + .name = "i2c-rtl9300", + .of_match_table = i2c_rtl9300_dt_ids, + }, +}; + +module_platform_driver(rtl9300_i2c_driver); + +MODULE_DESCRIPTION("RTL9300 I2C controller driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-rzv2m.c b/drivers/i2c/busses/i2c-rzv2m.c index 56d0faee5c46..238714850673 100644 --- a/drivers/i2c/busses/i2c-rzv2m.c +++ b/drivers/i2c/busses/i2c-rzv2m.c @@ -50,9 +50,6 @@ #define IICB0MDSC BIT(7) /* Bus Mode */ #define IICB0SLSE BIT(1) /* Start condition output */ -#define bit_setl(addr, val) writel(readl(addr) | (val), (addr)) -#define bit_clrl(addr, val) writel(readl(addr) & ~(val), (addr)) - struct rzv2m_i2c_priv { void __iomem *base; struct i2c_adapter adap; @@ -78,6 +75,16 @@ static const struct bitrate_config bitrate_configs[] = { [RZV2M_I2C_400K] = { 52, 900 }, }; +static inline void bit_setl(void __iomem *addr, u32 val) +{ + writel(readl(addr) | val, addr); +} + +static inline void bit_clrl(void __iomem *addr, u32 val) +{ + writel(readl(addr) & ~val, addr); +} + static irqreturn_t rzv2m_i2c_tia_irq_handler(int this_irq, void *dev_id) { struct rzv2m_i2c_priv *priv = dev_id; @@ -280,20 +287,15 @@ static int rzv2m_i2c_send_address(struct rzv2m_i2c_priv *priv, int ret; if (msg->flags & I2C_M_TEN) { - /* - * 10-bit address - * addr_1: 5'b11110 | addr[9:8] | (R/nW) - * addr_2: addr[7:0] - */ - addr = 0xf0 | ((msg->addr & GENMASK(9, 8)) >> 7); - addr |= !!(msg->flags & I2C_M_RD); - /* Send 1st address(extend code) */ + /* 10-bit address: Send 1st address(extend code) */ + addr = i2c_10bit_addr_hi_from_msg(msg); ret = rzv2m_i2c_write_with_ack(priv, addr); if (ret) return ret; - /* Send 2nd address */ - ret = rzv2m_i2c_write_with_ack(priv, msg->addr & 0xff); + /* 10-bit address: Send 2nd address */ + addr = i2c_10bit_addr_lo_from_msg(msg); + ret = rzv2m_i2c_write_with_ack(priv, addr); } else { /* 7-bit address */ addr = i2c_8bit_addr_from_msg(msg); @@ -314,8 +316,8 @@ static int rzv2m_i2c_stop_condition(struct rzv2m_i2c_priv *priv) 100, jiffies_to_usecs(priv->adap.timeout)); } -static int rzv2m_i2c_master_xfer_msg(struct rzv2m_i2c_priv *priv, - struct i2c_msg *msg, int stop) +static int rzv2m_i2c_xfer_msg(struct rzv2m_i2c_priv *priv, + struct i2c_msg *msg, int stop) { unsigned int count = 0; int ret, read = !!(msg->flags & I2C_M_RD); @@ -344,8 +346,8 @@ static int rzv2m_i2c_master_xfer_msg(struct rzv2m_i2c_priv *priv, return ret; } -static int rzv2m_i2c_master_xfer(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) +static int rzv2m_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) { struct rzv2m_i2c_priv *priv = i2c_get_adapdata(adap); struct device *dev = priv->adap.dev.parent; @@ -363,14 +365,13 @@ static int rzv2m_i2c_master_xfer(struct i2c_adapter *adap, /* I2C main transfer */ for (i = 0; i < num; i++) { - ret = rzv2m_i2c_master_xfer_msg(priv, &msgs[i], i == (num - 1)); + ret = rzv2m_i2c_xfer_msg(priv, &msgs[i], i == (num - 1)); if (ret < 0) goto out; } ret = num; out: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -382,12 +383,26 @@ static u32 rzv2m_i2c_func(struct i2c_adapter *adap) I2C_FUNC_10BIT_ADDR; } +static int rzv2m_i2c_disable(struct device *dev, struct rzv2m_i2c_priv *priv) +{ + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + bit_clrl(priv->base + IICB0CTL0, IICB0IICE); + pm_runtime_put(dev); + + return 0; +} + static const struct i2c_adapter_quirks rzv2m_i2c_quirks = { .flags = I2C_AQ_NO_ZERO_LEN, }; -static struct i2c_algorithm rzv2m_i2c_algo = { - .master_xfer = rzv2m_i2c_master_xfer, +static const struct i2c_algorithm rzv2m_i2c_algo = { + .xfer = rzv2m_i2c_xfer, .functionality = rzv2m_i2c_func, }; @@ -454,37 +469,29 @@ static int rzv2m_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); ret = i2c_add_numbered_adapter(adap); - if (ret < 0) + if (ret < 0) { + rzv2m_i2c_disable(dev, priv); pm_runtime_disable(dev); + } return ret; } -static int rzv2m_i2c_remove(struct platform_device *pdev) +static void rzv2m_i2c_remove(struct platform_device *pdev) { struct rzv2m_i2c_priv *priv = platform_get_drvdata(pdev); struct device *dev = priv->adap.dev.parent; i2c_del_adapter(&priv->adap); - bit_clrl(priv->base + IICB0CTL0, IICB0IICE); + rzv2m_i2c_disable(dev, priv); pm_runtime_disable(dev); - - return 0; } static int rzv2m_i2c_suspend(struct device *dev) { struct rzv2m_i2c_priv *priv = dev_get_drvdata(dev); - int ret; - ret = pm_runtime_resume_and_get(dev); - if (ret < 0) - return ret; - - bit_clrl(priv->base + IICB0CTL0, IICB0IICE); - pm_runtime_put(dev); - - return 0; + return rzv2m_i2c_disable(dev, priv); } static int rzv2m_i2c_resume(struct device *dev) @@ -523,7 +530,7 @@ static struct platform_driver rzv2m_i2c_driver = { .pm = pm_sleep_ptr(&rzv2m_i2c_pm_ops), }, .probe = rzv2m_i2c_probe, - .remove = rzv2m_i2c_remove, + .remove = rzv2m_i2c_remove, }; module_platform_driver(rzv2m_i2c_driver); diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 36dab9cd208c..8138f5ef40f0 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -24,7 +24,6 @@ #include <linux/slab.h> #include <linux/io.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/gpio/consumer.h> #include <linux/pinctrl/consumer.h> #include <linux/mfd/syscon.h> @@ -77,6 +76,7 @@ #define QUIRK_HDMIPHY (1 << 1) #define QUIRK_NO_GPIO (1 << 2) #define QUIRK_POLL (1 << 3) +#define QUIRK_ATOMIC (1 << 4) /* Max time to wait for bus to become idle after a xfer (in us) */ #define S3C2410_IDLE_TIMEOUT 5000 @@ -116,9 +116,6 @@ struct s3c24xx_i2c { struct s3c2410_platform_i2c *pdata; struct gpio_desc *gpios[2]; struct pinctrl *pctrl; -#if defined(CONFIG_ARM_S3C24XX_CPUFREQ) - struct notifier_block freq_transition; -#endif struct regmap *sysreg; unsigned int sys_i2c_cfg; }; @@ -133,15 +130,14 @@ static const struct platform_device_id s3c24xx_driver_ids[] = { }, { .name = "s3c2440-hdmiphy-i2c", .driver_data = QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO, - }, { }, + }, { } }; MODULE_DEVICE_TABLE(platform, s3c24xx_driver_ids); -static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat); +static void i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat); #ifdef CONFIG_OF static const struct of_device_id s3c24xx_i2c_match[] = { - { .compatible = "samsung,s3c2410-i2c", .data = (void *)0 }, { .compatible = "samsung,s3c2440-i2c", .data = (void *)QUIRK_S3C2440 }, { .compatible = "samsung,s3c2440-hdmiphy-i2c", .data = (void *)(QUIRK_S3C2440 | QUIRK_HDMIPHY | QUIRK_NO_GPIO) }, @@ -178,7 +174,7 @@ static inline void s3c24xx_i2c_master_complete(struct s3c24xx_i2c *i2c, int ret) if (ret) i2c->msg_idx = ret; - if (!(i2c->quirks & QUIRK_POLL)) + if (!(i2c->quirks & (QUIRK_POLL | QUIRK_ATOMIC))) wake_up(&i2c->wait); } @@ -220,8 +216,17 @@ static bool is_ack(struct s3c24xx_i2c *i2c) int tries; for (tries = 50; tries; --tries) { - if (readl(i2c->regs + S3C2410_IICCON) - & S3C2410_IICCON_IRQPEND) { + unsigned long tmp = readl(i2c->regs + S3C2410_IICCON); + + if (!(tmp & S3C2410_IICCON_ACKEN)) { + /* + * Wait a bit for the bus to stabilize, + * delay estimated experimentally. + */ + usleep_range(100, 200); + return true; + } + if (tmp & S3C2410_IICCON_IRQPEND) { if (!(readl(i2c->regs + S3C2410_IICSTAT) & S3C2410_IICSTAT_LASTBIT)) return true; @@ -274,16 +279,6 @@ static void s3c24xx_i2c_message_start(struct s3c24xx_i2c *i2c, stat |= S3C2410_IICSTAT_START; writel(stat, i2c->regs + S3C2410_IICSTAT); - - if (i2c->quirks & QUIRK_POLL) { - while ((i2c->msg_num != 0) && is_ack(i2c)) { - i2c_s3c_irq_nextbyte(i2c, stat); - stat = readl(i2c->regs + S3C2410_IICSTAT); - - if (stat & S3C2410_IICSTAT_ARBITR) - dev_err(i2c->dev, "deal with arbitration loss\n"); - } - } } static inline void s3c24xx_i2c_stop(struct s3c24xx_i2c *i2c, int ret) @@ -381,11 +376,10 @@ static inline int is_msgend(struct s3c24xx_i2c *i2c) /* * process an interrupt and work out what to do */ -static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) +static void i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) { unsigned long tmp; unsigned char byte; - int ret = 0; switch (i2c->state) { @@ -548,7 +542,7 @@ static int i2c_s3c_irq_nextbyte(struct s3c24xx_i2c *i2c, unsigned long iicstat) tmp &= ~S3C2410_IICCON_IRQPEND; writel(tmp, i2c->regs + S3C2410_IICCON); out: - return ret; + return; } /* @@ -690,7 +684,7 @@ static void s3c24xx_i2c_wait_idle(struct s3c24xx_i2c *i2c) static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, struct i2c_msg *msgs, int num) { - unsigned long timeout; + long time_left = 0; int ret; ret = s3c24xx_i2c_set_master(i2c); @@ -709,24 +703,27 @@ static int s3c24xx_i2c_doxfer(struct s3c24xx_i2c *i2c, s3c24xx_i2c_enable_irq(i2c); s3c24xx_i2c_message_start(i2c, msgs); - if (i2c->quirks & QUIRK_POLL) { - ret = i2c->msg_idx; + if (i2c->quirks & (QUIRK_POLL | QUIRK_ATOMIC)) { + while ((i2c->msg_num != 0) && is_ack(i2c)) { + unsigned long stat = readl(i2c->regs + S3C2410_IICSTAT); - if (ret != num) - dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); + i2c_s3c_irq_nextbyte(i2c, stat); - goto out; + stat = readl(i2c->regs + S3C2410_IICSTAT); + if (stat & S3C2410_IICSTAT_ARBITR) + dev_err(i2c->dev, "deal with arbitration loss\n"); + } + } else { + time_left = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); } - timeout = wait_event_timeout(i2c->wait, i2c->msg_num == 0, HZ * 5); - ret = i2c->msg_idx; /* * Having these next two as dev_err() makes life very * noisy when doing an i2cdetect */ - if (timeout == 0) + if (time_left == 0) dev_dbg(i2c->dev, "timeout\n"); else if (ret != num) dev_dbg(i2c->dev, "incomplete xfer (%d)\n", ret); @@ -778,6 +775,21 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap, return -EREMOTEIO; } +static int s3c24xx_i2c_xfer_atomic(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct s3c24xx_i2c *i2c = (struct s3c24xx_i2c *)adap->algo_data; + int ret; + + disable_irq(i2c->irq); + i2c->quirks |= QUIRK_ATOMIC; + ret = s3c24xx_i2c_xfer(adap, msgs, num); + i2c->quirks &= ~QUIRK_ATOMIC; + enable_irq(i2c->irq); + + return ret; +} + /* declare our i2c functionality */ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap) { @@ -787,8 +799,9 @@ static u32 s3c24xx_i2c_func(struct i2c_adapter *adap) /* i2c bus registration info */ static const struct i2c_algorithm s3c24xx_i2c_algorithm = { - .master_xfer = s3c24xx_i2c_xfer, - .functionality = s3c24xx_i2c_func, + .xfer = s3c24xx_i2c_xfer, + .xfer_atomic = s3c24xx_i2c_xfer_atomic, + .functionality = s3c24xx_i2c_func, }; /* @@ -885,65 +898,6 @@ static int s3c24xx_i2c_clockrate(struct s3c24xx_i2c *i2c, unsigned int *got) return 0; } -#if defined(CONFIG_ARM_S3C24XX_CPUFREQ) - -#define freq_to_i2c(_n) container_of(_n, struct s3c24xx_i2c, freq_transition) - -static int s3c24xx_i2c_cpufreq_transition(struct notifier_block *nb, - unsigned long val, void *data) -{ - struct s3c24xx_i2c *i2c = freq_to_i2c(nb); - unsigned int got; - int delta_f; - int ret; - - delta_f = clk_get_rate(i2c->clk) - i2c->clkrate; - - /* if we're post-change and the input clock has slowed down - * or at pre-change and the clock is about to speed up, then - * adjust our clock rate. <0 is slow, >0 speedup. - */ - - if ((val == CPUFREQ_POSTCHANGE && delta_f < 0) || - (val == CPUFREQ_PRECHANGE && delta_f > 0)) { - i2c_lock_bus(&i2c->adap, I2C_LOCK_ROOT_ADAPTER); - ret = s3c24xx_i2c_clockrate(i2c, &got); - i2c_unlock_bus(&i2c->adap, I2C_LOCK_ROOT_ADAPTER); - - if (ret < 0) - dev_err(i2c->dev, "cannot find frequency (%d)\n", ret); - else - dev_info(i2c->dev, "setting freq %d\n", got); - } - - return 0; -} - -static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c) -{ - i2c->freq_transition.notifier_call = s3c24xx_i2c_cpufreq_transition; - - return cpufreq_register_notifier(&i2c->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c) -{ - cpufreq_unregister_notifier(&i2c->freq_transition, - CPUFREQ_TRANSITION_NOTIFIER); -} - -#else -static inline int s3c24xx_i2c_register_cpufreq(struct s3c24xx_i2c *i2c) -{ - return 0; -} - -static inline void s3c24xx_i2c_deregister_cpufreq(struct s3c24xx_i2c *i2c) -{ -} -#endif - #ifdef CONFIG_OF static int s3c24xx_i2c_parse_dt_gpio(struct s3c24xx_i2c *i2c) { @@ -1096,9 +1050,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "clock source %p\n", i2c->clk); /* map the registers */ - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2c->regs = devm_ioremap_resource(&pdev->dev, res); - + i2c->regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(i2c->regs)) return PTR_ERR(i2c->regs); @@ -1138,7 +1090,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) if (!(i2c->quirks & QUIRK_POLL)) { i2c->irq = ret = platform_get_irq(pdev, 0); if (ret < 0) { - dev_err(&pdev->dev, "cannot find IRQ\n"); clk_unprepare(i2c->clk); return ret; } @@ -1152,13 +1103,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) } } - ret = s3c24xx_i2c_register_cpufreq(i2c); - if (ret < 0) { - dev_err(&pdev->dev, "failed to register cpufreq notifier\n"); - clk_unprepare(i2c->clk); - return ret; - } - /* * Note, previous versions of the driver used i2c_add_adapter() * to add the bus at any number. We now pass the bus number via @@ -1175,7 +1119,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { pm_runtime_disable(&pdev->dev); - s3c24xx_i2c_deregister_cpufreq(i2c); clk_unprepare(i2c->clk); return ret; } @@ -1184,7 +1127,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) return 0; } -static int s3c24xx_i2c_remove(struct platform_device *pdev) +static void s3c24xx_i2c_remove(struct platform_device *pdev) { struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev); @@ -1192,14 +1135,9 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); - s3c24xx_i2c_deregister_cpufreq(i2c); - i2c_del_adapter(&i2c->adap); - - return 0; } -#ifdef CONFIG_PM_SLEEP static int s3c24xx_i2c_suspend_noirq(struct device *dev) { struct s3c24xx_i2c *i2c = dev_get_drvdata(dev); @@ -1229,26 +1167,19 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev) return 0; } -#endif -#ifdef CONFIG_PM static const struct dev_pm_ops s3c24xx_i2c_dev_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(s3c24xx_i2c_suspend_noirq, - s3c24xx_i2c_resume_noirq) + NOIRQ_SYSTEM_SLEEP_PM_OPS(s3c24xx_i2c_suspend_noirq, + s3c24xx_i2c_resume_noirq) }; -#define S3C24XX_DEV_PM_OPS (&s3c24xx_i2c_dev_pm_ops) -#else -#define S3C24XX_DEV_PM_OPS NULL -#endif - static struct platform_driver s3c24xx_i2c_driver = { .probe = s3c24xx_i2c_probe, .remove = s3c24xx_i2c_remove, .id_table = s3c24xx_driver_ids, .driver = { .name = "s3c-i2c", - .pm = S3C24XX_DEV_PM_OPS, + .pm = pm_sleep_ptr(&s3c24xx_i2c_dev_pm_ops), .of_match_table = of_match_ptr(s3c24xx_i2c_match), }, }; diff --git a/drivers/i2c/busses/i2c-scmi.c b/drivers/i2c/busses/i2c-scmi.c index 0239e134b90f..10a5146b3aa5 100644 --- a/drivers/i2c/busses/i2c-scmi.c +++ b/drivers/i2c/busses/i2c-scmi.c @@ -13,9 +13,6 @@ #include <linux/i2c.h> #include <linux/acpi.h> -/* SMBUS HID definition as supported by Microsoft Windows */ -#define ACPI_SMBUS_MS_HID "SMB0001" - struct smbus_methods_t { char *mt_info; char *mt_sbr; @@ -388,7 +385,7 @@ static int smbus_cmi_probe(struct platform_device *device) smbus_cmi->adapter.owner = THIS_MODULE; smbus_cmi->adapter.algo = &acpi_smbus_cmi_algorithm; smbus_cmi->adapter.algo_data = smbus_cmi; - smbus_cmi->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + smbus_cmi->adapter.class = I2C_CLASS_HWMON; smbus_cmi->adapter.dev.parent = &device->dev; ret = i2c_add_adapter(&smbus_cmi->adapter); @@ -404,14 +401,12 @@ err: return ret; } -static int smbus_cmi_remove(struct platform_device *device) +static void smbus_cmi_remove(struct platform_device *device) { struct acpi_smbus_cmi *smbus_cmi = platform_get_drvdata(device); i2c_del_adapter(&smbus_cmi->adapter); kfree(smbus_cmi); - - return 0; } static struct platform_driver smbus_cmi_driver = { diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c index 319d1fa617c8..43f33988b98f 100644 --- a/drivers/i2c/busses/i2c-sh7760.c +++ b/drivers/i2c/busses/i2c-sh7760.c @@ -379,8 +379,8 @@ static u32 sh7760_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm sh7760_i2c_algo = { - .master_xfer = sh7760_i2c_master_xfer, - .functionality = sh7760_i2c_func, + .xfer = sh7760_i2c_master_xfer, + .functionality = sh7760_i2c_func, }; /* calculate CCR register setting for a desired scl clock. SCL clock is @@ -443,9 +443,8 @@ static int sh7760_i2c_probe(struct platform_device *pdev) goto out0; } - id = kzalloc(sizeof(struct cami2c), GFP_KERNEL); + id = kzalloc(sizeof(*id), GFP_KERNEL); if (!id) { - dev_err(&pdev->dev, "no mem for private data\n"); ret = -ENOMEM; goto out0; } @@ -478,7 +477,7 @@ static int sh7760_i2c_probe(struct platform_device *pdev) id->adap.nr = pdev->id; id->adap.algo = &sh7760_i2c_algo; - id->adap.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + id->adap.class = I2C_CLASS_HWMON; id->adap.retries = 3; id->adap.algo_data = id; id->adap.dev.parent = &pdev->dev; @@ -536,7 +535,7 @@ out0: return ret; } -static int sh7760_i2c_remove(struct platform_device *pdev) +static void sh7760_i2c_remove(struct platform_device *pdev) { struct cami2c *id = platform_get_drvdata(pdev); @@ -546,8 +545,6 @@ static int sh7760_i2c_remove(struct platform_device *pdev) release_resource(id->ioarea); kfree(id->ioarea); kfree(id); - - return 0; } static struct platform_driver sh7760_i2c_drv = { diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 29330ee64c9c..dae8967f8749 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -20,10 +20,11 @@ #include <linux/io.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/slab.h> +#include <linux/string_choices.h> /* Transmit operation: */ /* */ @@ -409,7 +410,7 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) pd->sr |= sr; /* remember state */ dev_dbg(pd->dev, "i2c_isr 0x%02x 0x%02x %s %d %d!\n", sr, pd->sr, - (pd->msg->flags & I2C_M_RD) ? "read" : "write", + str_read_write(pd->msg->flags & I2C_M_RD), pd->pos, pd->msg->len); /* Kick off TxDMA after preface was done */ @@ -688,7 +689,6 @@ static int sh_mobile_xfer(struct sh_mobile_i2c_data *pd, } if (!time_left) { - dev_err(pd->dev, "Transfer request timed out\n"); if (pd->dma_direction != DMA_NONE) sh_mobile_i2c_cleanup_dma(pd, true); @@ -740,8 +740,8 @@ static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter) static const struct i2c_algorithm sh_mobile_i2c_algorithm = { .functionality = sh_mobile_i2c_func, - .master_xfer = sh_mobile_i2c_xfer, - .master_xfer_atomic = sh_mobile_i2c_xfer_atomic, + .xfer = sh_mobile_i2c_xfer, + .xfer_atomic = sh_mobile_i2c_xfer_atomic, }; static const struct i2c_adapter_quirks sh_mobile_i2c_quirks = { @@ -773,7 +773,7 @@ static int sh_mobile_i2c_r8a7740_workaround(struct sh_mobile_i2c_data *pd) iic_wr(pd, ICCR, ICCR_TRS); udelay(10); - return sh_mobile_i2c_init(pd); + return sh_mobile_i2c_v2_init(pd); } static const struct sh_mobile_dt_config default_dt_config = { @@ -783,11 +783,6 @@ static const struct sh_mobile_dt_config default_dt_config = { static const struct sh_mobile_dt_config fast_clock_dt_config = { .clks_per_count = 2, - .setup = sh_mobile_i2c_init, -}; - -static const struct sh_mobile_dt_config v2_freq_calc_dt_config = { - .clks_per_count = 2, .setup = sh_mobile_i2c_v2_init, }; @@ -799,17 +794,17 @@ static const struct sh_mobile_dt_config r8a7740_dt_config = { static const struct of_device_id sh_mobile_i2c_dt_ids[] = { { .compatible = "renesas,iic-r8a73a4", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-r8a7740", .data = &r8a7740_dt_config }, - { .compatible = "renesas,iic-r8a774c0", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,iic-r8a7790", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,iic-r8a7791", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,iic-r8a7792", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,iic-r8a7793", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,iic-r8a7794", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,iic-r8a7795", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,iic-r8a77990", .data = &v2_freq_calc_dt_config }, + { .compatible = "renesas,iic-r8a774c0", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7790", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7791", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7792", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7793", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7794", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a7795", .data = &fast_clock_dt_config }, + { .compatible = "renesas,iic-r8a77990", .data = &fast_clock_dt_config }, { .compatible = "renesas,iic-sh73a0", .data = &fast_clock_dt_config }, - { .compatible = "renesas,rcar-gen2-iic", .data = &v2_freq_calc_dt_config }, - { .compatible = "renesas,rcar-gen3-iic", .data = &v2_freq_calc_dt_config }, + { .compatible = "renesas,rcar-gen2-iic", .data = &fast_clock_dt_config }, + { .compatible = "renesas,rcar-gen3-iic", .data = &fast_clock_dt_config }, { .compatible = "renesas,rmobile-iic", .data = &default_dt_config }, {}, }; @@ -871,7 +866,6 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) { struct sh_mobile_i2c_data *pd; struct i2c_adapter *adap; - struct resource *res; const struct sh_mobile_dt_config *config; int ret; u32 bus_speed; @@ -893,10 +887,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) pd->dev = &dev->dev; platform_set_drvdata(dev, pd); - res = platform_get_resource(dev, IORESOURCE_MEM, 0); - - pd->res = res; - pd->reg = devm_ioremap_resource(&dev->dev, res); + pd->reg = devm_platform_get_and_ioremap_resource(dev, 0, &pd->res); if (IS_ERR(pd->reg)) return PTR_ERR(pd->reg); @@ -905,7 +896,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) pd->clks_per_count = 1; /* Newer variants come with two new bits in ICIC */ - if (resource_size(res) > 0x17) + if (resource_size(pd->res) > 0x17) pd->flags |= IIC_FLAG_HAS_ICIC67; pm_runtime_enable(&dev->dev); @@ -956,17 +947,15 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) return 0; } -static int sh_mobile_i2c_remove(struct platform_device *dev) +static void sh_mobile_i2c_remove(struct platform_device *dev) { struct sh_mobile_i2c_data *pd = platform_get_drvdata(dev); i2c_del_adapter(&pd->adap); sh_mobile_i2c_release_dma(pd); pm_runtime_disable(&dev->dev); - return 0; } -#ifdef CONFIG_PM_SLEEP static int sh_mobile_i2c_suspend(struct device *dev) { struct sh_mobile_i2c_data *pd = dev_get_drvdata(dev); @@ -984,20 +973,15 @@ static int sh_mobile_i2c_resume(struct device *dev) } static const struct dev_pm_ops sh_mobile_i2c_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(sh_mobile_i2c_suspend, - sh_mobile_i2c_resume) + NOIRQ_SYSTEM_SLEEP_PM_OPS(sh_mobile_i2c_suspend, + sh_mobile_i2c_resume) }; -#define DEV_PM_OPS (&sh_mobile_i2c_pm_ops) -#else -#define DEV_PM_OPS NULL -#endif /* CONFIG_PM_SLEEP */ - static struct platform_driver sh_mobile_i2c_driver = { .driver = { .name = "i2c-sh_mobile", .of_match_table = sh_mobile_i2c_dt_ids, - .pm = DEV_PM_OPS, + .pm = pm_sleep_ptr(&sh_mobile_i2c_pm_ops), }, .probe = sh_mobile_i2c_probe, .remove = sh_mobile_i2c_remove, diff --git a/drivers/i2c/busses/i2c-sibyte.c b/drivers/i2c/busses/i2c-sibyte.c index 8f71f01cb169..49f8f4f1b0f0 100644 --- a/drivers/i2c/busses/i2c-sibyte.c +++ b/drivers/i2c/busses/i2c-sibyte.c @@ -142,7 +142,7 @@ static struct i2c_algo_sibyte_data sibyte_board_data[2] = { static struct i2c_adapter sibyte_board_adapter[2] = { { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = NULL, .algo_data = &sibyte_board_data[0], .nr = 0, @@ -150,7 +150,7 @@ static struct i2c_adapter sibyte_board_adapter[2] = { }, { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = NULL, .algo_data = &sibyte_board_data[1], .nr = 1, diff --git a/drivers/i2c/busses/i2c-simtec.c b/drivers/i2c/busses/i2c-simtec.c index 87701744752f..d90606048611 100644 --- a/drivers/i2c/busses/i2c-simtec.c +++ b/drivers/i2c/busses/i2c-simtec.c @@ -126,7 +126,7 @@ static int simtec_i2c_probe(struct platform_device *dev) return ret; } -static int simtec_i2c_remove(struct platform_device *dev) +static void simtec_i2c_remove(struct platform_device *dev) { struct simtec_i2c_data *pd = platform_get_drvdata(dev); @@ -135,8 +135,6 @@ static int simtec_i2c_remove(struct platform_device *dev) iounmap(pd->reg); release_mem_region(pd->ioarea->start, resource_size(pd->ioarea)); kfree(pd); - - return 0; } /* device driver */ diff --git a/drivers/i2c/busses/i2c-sis5595.c b/drivers/i2c/busses/i2c-sis5595.c index c793a5c14cda..ca06fffb8f61 100644 --- a/drivers/i2c/busses/i2c-sis5595.c +++ b/drivers/i2c/busses/i2c-sis5595.c @@ -175,11 +175,11 @@ static int sis5595_setup(struct pci_dev *SIS5595_dev) if (force_addr) { dev_info(&SIS5595_dev->dev, "forcing ISA address 0x%04X\n", sis5595_base); - if (pci_write_config_word(SIS5595_dev, ACPI_BASE, sis5595_base) - != PCIBIOS_SUCCESSFUL) + retval = pci_write_config_word(SIS5595_dev, ACPI_BASE, sis5595_base); + if (retval != PCIBIOS_SUCCESSFUL) goto error; - if (pci_read_config_word(SIS5595_dev, ACPI_BASE, &a) - != PCIBIOS_SUCCESSFUL) + retval = pci_read_config_word(SIS5595_dev, ACPI_BASE, &a); + if (retval != PCIBIOS_SUCCESSFUL) goto error; if ((a & ~(SIS5595_EXTENT - 1)) != sis5595_base) { /* doesn't work for some chips! */ @@ -188,16 +188,16 @@ static int sis5595_setup(struct pci_dev *SIS5595_dev) } } - if (pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val) - != PCIBIOS_SUCCESSFUL) + retval = pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val); + if (retval != PCIBIOS_SUCCESSFUL) goto error; if ((val & 0x80) == 0) { dev_info(&SIS5595_dev->dev, "enabling ACPI\n"); - if (pci_write_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, val | 0x80) - != PCIBIOS_SUCCESSFUL) + retval = pci_write_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, val | 0x80); + if (retval != PCIBIOS_SUCCESSFUL) goto error; - if (pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val) - != PCIBIOS_SUCCESSFUL) + retval = pci_read_config_byte(SIS5595_dev, SIS5595_ENABLE_REG, &val); + if (retval != PCIBIOS_SUCCESSFUL) goto error; if ((val & 0x80) == 0) { /* doesn't work for some chips? */ @@ -257,7 +257,7 @@ static int sis5595_transaction(struct i2c_adapter *adap) if (temp & 0x20) { dev_err(&adap->dev, "Bus collision! SMBus may be locked until " "next hard reset (or not...)\n"); - /* Clock stops and slave is stuck in mid-transmission */ + /* Clock stops and target is stuck in mid-transmission */ result = -EIO; } @@ -353,7 +353,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter sis5595_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-sis630.c b/drivers/i2c/busses/i2c-sis630.c index 87d56250d78a..a19c3d251804 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -493,7 +493,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter sis630_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, .retries = 3 }; @@ -509,6 +509,8 @@ MODULE_DEVICE_TABLE(pci, sis630_ids); static int sis630_probe(struct pci_dev *dev, const struct pci_device_id *id) { + int ret; + if (sis630_setup(dev)) { dev_err(&dev->dev, "SIS630 compatible bus not detected, " @@ -522,7 +524,15 @@ static int sis630_probe(struct pci_dev *dev, const struct pci_device_id *id) snprintf(sis630_adapter.name, sizeof(sis630_adapter.name), "SMBus SIS630 adapter at %04x", smbus_base + SMB_STS); - return i2c_add_adapter(&sis630_adapter); + ret = i2c_add_adapter(&sis630_adapter); + if (ret) + goto release_region; + + return 0; + +release_region: + release_region(smbus_base + SMB_STS, SIS630_SMB_IOREGION); + return ret; } static void sis630_remove(struct pci_dev *dev) diff --git a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c index cde8003985a5..77529dda6fcd 100644 --- a/drivers/i2c/busses/i2c-sis96x.c +++ b/drivers/i2c/busses/i2c-sis96x.c @@ -228,7 +228,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter sis96x_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; diff --git a/drivers/i2c/busses/i2c-sprd.c b/drivers/i2c/busses/i2c-sprd.c index 4fe15cd78907..1b490525d8dd 100644 --- a/drivers/i2c/busses/i2c-sprd.c +++ b/drivers/i2c/busses/i2c-sprd.c @@ -14,7 +14,6 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -284,8 +283,8 @@ static int sprd_i2c_handle_msg(struct i2c_adapter *i2c_adap, return i2c_dev->err; } -static int sprd_i2c_master_xfer(struct i2c_adapter *i2c_adap, - struct i2c_msg *msgs, int num) +static int sprd_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) { struct sprd_i2c *i2c_dev = i2c_adap->algo_data; int im, ret; @@ -303,7 +302,6 @@ static int sprd_i2c_master_xfer(struct i2c_adapter *i2c_adap, ret = sprd_i2c_handle_msg(i2c_adap, &msgs[im++], 1); err_msg: - pm_runtime_mark_last_busy(i2c_dev->dev); pm_runtime_put_autosuspend(i2c_dev->dev); return ret < 0 ? ret : im; @@ -315,7 +313,7 @@ static u32 sprd_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm sprd_i2c_algo = { - .master_xfer = sprd_i2c_master_xfer, + .xfer = sprd_i2c_xfer, .functionality = sprd_i2c_func, }; @@ -379,12 +377,12 @@ static irqreturn_t sprd_i2c_isr_thread(int irq, void *dev_id) i2c_tran = i2c_dev->count; /* - * If we got one ACK from slave when writing data, and we did not + * If we got one ACK from target when writing data, and we did not * finish this transmission (i2c_tran is not zero), then we should * continue to write data. * * For reading data, ack is always true, if i2c_tran is not 0 which - * means we still need to contine to read data from slave. + * means we still need to contine to read data from target. */ if (i2c_tran && ack) { sprd_i2c_data_transfer(i2c_dev); @@ -394,7 +392,7 @@ static irqreturn_t sprd_i2c_isr_thread(int irq, void *dev_id) i2c_dev->err = 0; /* - * If we did not get one ACK from slave when writing data, we should + * If we did not get one ACK from target when writing data, we should * return -EIO to notify users. */ if (!ack) @@ -423,10 +421,10 @@ static irqreturn_t sprd_i2c_isr(int irq, void *dev_id) i2c_tran = i2c_dev->count; /* - * If we did not get one ACK from slave when writing data, then we + * If we did not get one ACK from target when writing data, then we * should finish this transmission since we got some errors. * - * When writing data, if i2c_tran == 0 which means we have writen + * When writing data, if i2c_tran == 0 which means we have written * done all data, then we can finish this transmission. * * When reading data, if conut < rx fifo full threshold, which @@ -560,7 +558,6 @@ static int sprd_i2c_probe(struct platform_device *pdev) goto err_rpm_put; } - pm_runtime_mark_last_busy(i2c_dev->dev); pm_runtime_put_autosuspend(i2c_dev->dev); return 0; @@ -571,22 +568,22 @@ err_rpm_put: return ret; } -static int sprd_i2c_remove(struct platform_device *pdev) +static void sprd_i2c_remove(struct platform_device *pdev) { struct sprd_i2c *i2c_dev = platform_get_drvdata(pdev); int ret; - ret = pm_runtime_resume_and_get(i2c_dev->dev); + ret = pm_runtime_get_sync(i2c_dev->dev); if (ret < 0) - return ret; + dev_err(&pdev->dev, "Failed to resume device (%pe)\n", ERR_PTR(ret)); i2c_del_adapter(&i2c_dev->adap); - clk_disable_unprepare(i2c_dev->clk); + + if (ret >= 0) + clk_disable_unprepare(i2c_dev->clk); pm_runtime_put_noidle(i2c_dev->dev); pm_runtime_disable(i2c_dev->dev); - - return 0; } static int __maybe_unused sprd_i2c_suspend_noirq(struct device *dev) @@ -654,5 +651,5 @@ static struct platform_driver sprd_i2c_driver = { module_platform_driver(sprd_i2c_driver); -MODULE_DESCRIPTION("Spreadtrum I2C master controller driver"); +MODULE_DESCRIPTION("Spreadtrum I2C controller driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 88482316d22a..97d70e667227 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2013 STMicroelectronics * - * I2C master mode controller driver, used in STMicroelectronics devices. + * I2C controller driver, used in STMicroelectronics devices. * * Author: Maxime Coquelin <maxime.coquelin@st.com> */ @@ -13,6 +13,7 @@ #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/minmax.h> #include <linux/module.h> #include <linux/of_address.h> #include <linux/of_irq.h> @@ -150,8 +151,8 @@ struct st_i2c_timings { /** * struct st_i2c_client - client specific data - * @addr: 8-bit slave addr, including r/w bit - * @count: number of bytes to be transfered + * @addr: 8-bit target addr, including r/w bit + * @count: number of bytes to be transferred * @xfered: number of bytes already transferred * @buf: data buffer * @result: result of the transfer @@ -422,12 +423,8 @@ static void st_i2c_wr_fill_tx_fifo(struct st_i2c_dev *i2c_dev) tx_fstat = readl_relaxed(i2c_dev->base + SSC_TX_FSTAT); tx_fstat &= SSC_TX_FSTAT_STATUS; - if (c->count < (SSC_TXFIFO_SIZE - tx_fstat)) - i = c->count; - else - i = SSC_TXFIFO_SIZE - tx_fstat; - - for (; i > 0; i--, c->count--, c->buf++) + for (i = min(c->count, SSC_TXFIFO_SIZE - tx_fstat); + i > 0; i--, c->count--, c->buf++) st_i2c_write_tx_fifo(i2c_dev, *c->buf); } @@ -439,7 +436,7 @@ static void st_i2c_wr_fill_tx_fifo(struct st_i2c_dev *i2c_dev) * This functions fills the Tx FIFO with fixed pattern when * in read mode to trigger clock. */ -static void st_i2c_rd_fill_tx_fifo(struct st_i2c_dev *i2c_dev, int max) +static void st_i2c_rd_fill_tx_fifo(struct st_i2c_dev *i2c_dev, u32 max) { struct st_i2c_client *c = &i2c_dev->client; u32 tx_fstat, sta; @@ -452,12 +449,8 @@ static void st_i2c_rd_fill_tx_fifo(struct st_i2c_dev *i2c_dev, int max) tx_fstat = readl_relaxed(i2c_dev->base + SSC_TX_FSTAT); tx_fstat &= SSC_TX_FSTAT_STATUS; - if (max < (SSC_TXFIFO_SIZE - tx_fstat)) - i = max; - else - i = SSC_TXFIFO_SIZE - tx_fstat; - - for (; i > 0; i--, c->xfered++) + for (i = min(max, SSC_TXFIFO_SIZE - tx_fstat); + i > 0; i--, c->xfered++) st_i2c_write_tx_fifo(i2c_dev, 0xff); } @@ -647,7 +640,7 @@ static int st_i2c_xfer_msg(struct st_i2c_dev *i2c_dev, struct i2c_msg *msg, { struct st_i2c_client *c = &i2c_dev->client; u32 ctl, i2c, it; - unsigned long timeout; + unsigned long time_left; int ret; c->addr = i2c_8bit_addr_from_msg(msg); @@ -667,7 +660,7 @@ static int st_i2c_xfer_msg(struct st_i2c_dev *i2c_dev, struct i2c_msg *msg, i2c |= SSC_I2C_ACKG; st_i2c_set_bits(i2c_dev->base + SSC_I2C, i2c); - /* Write slave address */ + /* Write target address */ st_i2c_write_tx_fifo(i2c_dev, c->addr); /* Pre-fill Tx fifo with data in case of write */ @@ -685,15 +678,12 @@ static int st_i2c_xfer_msg(struct st_i2c_dev *i2c_dev, struct i2c_msg *msg, st_i2c_set_bits(i2c_dev->base + SSC_I2C, SSC_I2C_STRTG); } - timeout = wait_for_completion_timeout(&i2c_dev->complete, - i2c_dev->adap.timeout); + time_left = wait_for_completion_timeout(&i2c_dev->complete, + i2c_dev->adap.timeout); ret = c->result; - if (!timeout) { - dev_err(i2c_dev->dev, "Write to slave 0x%x timed out\n", - c->addr); + if (!time_left) ret = -ETIMEDOUT; - } i2c = SSC_I2C_STOPG | SSC_I2C_REPSTRTG; st_i2c_clr_bits(i2c_dev->base + SSC_I2C, i2c); @@ -740,7 +730,6 @@ static int st_i2c_xfer(struct i2c_adapter *i2c_adap, return (ret < 0) ? ret : i; } -#ifdef CONFIG_PM_SLEEP static int st_i2c_suspend(struct device *dev) { struct st_i2c_dev *i2c_dev = dev_get_drvdata(dev); @@ -762,11 +751,7 @@ static int st_i2c_resume(struct device *dev) return 0; } -static SIMPLE_DEV_PM_OPS(st_i2c_pm, st_i2c_suspend, st_i2c_resume); -#define ST_I2C_PM (&st_i2c_pm) -#else -#define ST_I2C_PM NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(st_i2c_pm, st_i2c_suspend, st_i2c_resume); static u32 st_i2c_func(struct i2c_adapter *adap) { @@ -774,7 +759,7 @@ static u32 st_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm st_i2c_algo = { - .master_xfer = st_i2c_xfer, + .xfer = st_i2c_xfer, .functionality = st_i2c_func, }; @@ -817,8 +802,7 @@ static int st_i2c_probe(struct platform_device *pdev) if (!i2c_dev) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2c_dev->base = devm_ioremap_resource(&pdev->dev, res); + i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(i2c_dev->base)) return PTR_ERR(i2c_dev->base); @@ -881,13 +865,11 @@ static int st_i2c_probe(struct platform_device *pdev) return 0; } -static int st_i2c_remove(struct platform_device *pdev) +static void st_i2c_remove(struct platform_device *pdev) { struct st_i2c_dev *i2c_dev = platform_get_drvdata(pdev); i2c_del_adapter(&i2c_dev->adap); - - return 0; } static const struct of_device_id st_i2c_match[] = { @@ -901,7 +883,7 @@ static struct platform_driver st_i2c_driver = { .driver = { .name = "st-i2c", .of_match_table = st_i2c_match, - .pm = ST_I2C_PM, + .pm = pm_sleep_ptr(&st_i2c_pm), }, .probe = st_i2c_probe, .remove = st_i2c_remove, diff --git a/drivers/i2c/busses/i2c-stm32.c b/drivers/i2c/busses/i2c-stm32.c index 157c64e27d0b..becf8977979f 100644 --- a/drivers/i2c/busses/i2c-stm32.c +++ b/drivers/i2c/busses/i2c-stm32.c @@ -27,8 +27,8 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev, if (IS_ERR(dma->chan_tx)) { ret = PTR_ERR(dma->chan_tx); if (ret != -ENODEV) - ret = dev_err_probe(dev, ret, - "can't request DMA tx channel\n"); + dev_err_probe(dev, ret, "can't request DMA tx channel\n"); + goto fail_al; } @@ -48,8 +48,7 @@ struct stm32_i2c_dma *stm32_i2c_dma_request(struct device *dev, if (IS_ERR(dma->chan_rx)) { ret = PTR_ERR(dma->chan_rx); if (ret != -ENODEV) - ret = dev_err_probe(dev, ret, - "can't request DMA rx channel\n"); + dev_err_probe(dev, ret, "can't request DMA rx channel\n"); goto fail_tx; } @@ -102,7 +101,6 @@ int stm32_i2c_prep_dma_xfer(struct device *dev, struct stm32_i2c_dma *dma, void *dma_async_param) { struct dma_async_tx_descriptor *txdesc; - struct device *chan_dev; int ret; if (rd_wr) { @@ -116,11 +114,10 @@ int stm32_i2c_prep_dma_xfer(struct device *dev, struct stm32_i2c_dma *dma, } dma->dma_len = len; - chan_dev = dma->chan_using->device->dev; - dma->dma_buf = dma_map_single(chan_dev, buf, dma->dma_len, + dma->dma_buf = dma_map_single(dev, buf, dma->dma_len, dma->dma_data_dir); - if (dma_mapping_error(chan_dev, dma->dma_buf)) { + if (dma_mapping_error(dev, dma->dma_buf)) { dev_err(dev, "DMA mapping failed\n"); return -EINVAL; } @@ -150,7 +147,7 @@ int stm32_i2c_prep_dma_xfer(struct device *dev, struct stm32_i2c_dma *dma, return 0; err: - dma_unmap_single(chan_dev, dma->dma_buf, dma->dma_len, + dma_unmap_single(dev, dma->dma_buf, dma->dma_len, dma->dma_data_dir); return ret; } diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c index eebce7ecef25..b3d56d0aa9d0 100644 --- a/drivers/i2c/busses/i2c-stm32f4.c +++ b/drivers/i2c/busses/i2c-stm32f4.c @@ -95,7 +95,7 @@ /** * struct stm32f4_i2c_msg - client specific data - * @addr: 8-bit slave addr, including r/w bit + * @addr: 8-bit target addr, including r/w bit * @count: number of bytes to be transferred * @buf: data buffer * @result: result of the transfer @@ -480,7 +480,7 @@ static void stm32f4_i2c_handle_rx_done(struct stm32f4_i2c_dev *i2c_dev) /** * stm32f4_i2c_handle_rx_addr() - Handle address matched interrupt in case of - * master receiver + * controller receiver * @i2c_dev: Controller's private data */ static void stm32f4_i2c_handle_rx_addr(struct stm32f4_i2c_dev *i2c_dev) @@ -643,7 +643,7 @@ static irqreturn_t stm32f4_i2c_isr_error(int irq, void *data) /* * Acknowledge failure: - * In master transmitter mode a Stop must be generated by software + * In controller transmitter mode a Stop must be generated by software */ if (status & STM32F4_I2C_SR1_AF) { if (!(msg->addr & I2C_M_RD)) { @@ -681,7 +681,7 @@ static int stm32f4_i2c_xfer_msg(struct stm32f4_i2c_dev *i2c_dev, { struct stm32f4_i2c_msg *f4_msg = &i2c_dev->msg; void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR1; - unsigned long timeout; + unsigned long time_left; u32 mask; int ret; @@ -706,11 +706,11 @@ static int stm32f4_i2c_xfer_msg(struct stm32f4_i2c_dev *i2c_dev, stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START); } - timeout = wait_for_completion_timeout(&i2c_dev->complete, - i2c_dev->adap.timeout); + time_left = wait_for_completion_timeout(&i2c_dev->complete, + i2c_dev->adap.timeout); ret = f4_msg->result; - if (!timeout) + if (!time_left) ret = -ETIMEDOUT; return ret; @@ -749,7 +749,7 @@ static u32 stm32f4_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm stm32f4_i2c_algo = { - .master_xfer = stm32f4_i2c_xfer, + .xfer = stm32f4_i2c_xfer, .functionality = stm32f4_i2c_func, }; @@ -767,8 +767,7 @@ static int stm32f4_i2c_probe(struct platform_device *pdev) if (!i2c_dev) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2c_dev->base = devm_ioremap_resource(&pdev->dev, res); + i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(i2c_dev->base)) return PTR_ERR(i2c_dev->base); @@ -784,23 +783,17 @@ static int stm32f4_i2c_probe(struct platform_device *pdev) return -EINVAL; } - i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); + i2c_dev->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(i2c_dev->clk)) { - dev_err(&pdev->dev, "Error: Missing controller clock\n"); + dev_err(&pdev->dev, "Failed to enable clock\n"); return PTR_ERR(i2c_dev->clk); } - ret = clk_prepare_enable(i2c_dev->clk); - if (ret) { - dev_err(i2c_dev->dev, "Failed to prepare_enable clock\n"); - return ret; - } rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); - if (IS_ERR(rst)) { - ret = dev_err_probe(&pdev->dev, PTR_ERR(rst), - "Error: Missing reset ctrl\n"); - goto clk_free; - } + if (IS_ERR(rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(rst), + "Error: Missing reset ctrl\n"); + reset_control_assert(rst); udelay(2); reset_control_deassert(rst); @@ -817,7 +810,7 @@ static int stm32f4_i2c_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Failed to request irq event %i\n", irq_event); - goto clk_free; + return ret; } ret = devm_request_irq(&pdev->dev, irq_error, stm32f4_i2c_isr_error, 0, @@ -825,12 +818,12 @@ static int stm32f4_i2c_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Failed to request irq error %i\n", irq_error); - goto clk_free; + return ret; } ret = stm32f4_i2c_hw_config(i2c_dev); if (ret) - goto clk_free; + return ret; adap = &i2c_dev->adap; i2c_set_adapdata(adap, i2c_dev); @@ -846,7 +839,7 @@ static int stm32f4_i2c_probe(struct platform_device *pdev) ret = i2c_add_adapter(adap); if (ret) - goto clk_free; + return ret; platform_set_drvdata(pdev, i2c_dev); @@ -855,21 +848,13 @@ static int stm32f4_i2c_probe(struct platform_device *pdev) dev_info(i2c_dev->dev, "STM32F4 I2C driver registered\n"); return 0; - -clk_free: - clk_disable_unprepare(i2c_dev->clk); - return ret; } -static int stm32f4_i2c_remove(struct platform_device *pdev) +static void stm32f4_i2c_remove(struct platform_device *pdev) { struct stm32f4_i2c_dev *i2c_dev = platform_get_drvdata(pdev); i2c_del_adapter(&i2c_dev->adap); - - clk_unprepare(i2c_dev->clk); - - return 0; } static const struct of_device_id stm32f4_i2c_match[] = { diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c index d1c59d83a65b..dc69ed934ec8 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c @@ -34,6 +34,7 @@ #include <linux/regmap.h> #include <linux/reset.h> #include <linux/slab.h> +#include <linux/string_choices.h> #include "i2c-stm32.h" @@ -50,6 +51,7 @@ #define STM32F7_I2C_TXDR 0x28 /* STM32F7 I2C control 1 */ +#define STM32_I2C_CR1_FMP BIT(24) #define STM32F7_I2C_CR1_PECEN BIT(23) #define STM32F7_I2C_CR1_ALERTEN BIT(22) #define STM32F7_I2C_CR1_SMBHEN BIT(20) @@ -226,6 +228,8 @@ struct stm32f7_i2c_spec { * @rise_time: Rise time (ns) * @fall_time: Fall time (ns) * @fmp_clr_offset: Fast Mode Plus clear register offset from set register + * @single_it_line: Only a single IT line is used for both events/errors + * @fmp_cr1_bit: Fast Mode Plus control is done via a bit in CR1 */ struct stm32f7_i2c_setup { u32 speed_freq; @@ -233,6 +237,8 @@ struct stm32f7_i2c_setup { u32 rise_time; u32 fall_time; u32 fmp_clr_offset; + bool single_it_line; + bool fmp_cr1_bit; }; /** @@ -325,6 +331,7 @@ struct stm32f7_i2c_alert { * @dnf_dt: value of digital filter requested via dt * @dnf: value of digital filter to apply * @alert: SMBus alert specific data + * @atomic: boolean indicating that current transfer is atomic */ struct stm32f7_i2c_dev { struct i2c_adapter adap; @@ -357,6 +364,7 @@ struct stm32f7_i2c_dev { u32 dnf_dt; u32 dnf; struct stm32f7_i2c_alert *alert; + bool atomic; }; /* @@ -416,6 +424,13 @@ static const struct stm32f7_i2c_setup stm32mp13_setup = { .fmp_clr_offset = 0x4, }; +static const struct stm32f7_i2c_setup stm32mp25_setup = { + .rise_time = STM32F7_I2C_RISE_TIME_DEFAULT, + .fall_time = STM32F7_I2C_FALL_TIME_DEFAULT, + .single_it_line = true, + .fmp_cr1_bit = true, +}; + static inline void stm32f7_i2c_set_bits(void __iomem *reg, u32 mask) { writel_relaxed(readl_relaxed(reg) | mask, reg); @@ -708,7 +723,7 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, dev_dbg(i2c_dev->dev, "I2C Rise(%i) and Fall(%i) Time\n", setup->rise_time, setup->fall_time); dev_dbg(i2c_dev->dev, "I2C Analog Filter(%s), DNF(%i)\n", - (i2c_dev->analog_filter ? "On" : "Off"), i2c_dev->dnf); + str_on_off(i2c_dev->analog_filter), i2c_dev->dnf); i2c_dev->bus_rate = setup->speed_freq; @@ -725,12 +740,16 @@ static void stm32f7_i2c_disable_dma_req(struct stm32f7_i2c_dev *i2c_dev) static void stm32f7_i2c_dma_callback(void *arg) { - struct stm32f7_i2c_dev *i2c_dev = (struct stm32f7_i2c_dev *)arg; + struct stm32f7_i2c_dev *i2c_dev = arg; struct stm32_i2c_dma *dma = i2c_dev->dma; - struct device *dev = dma->chan_using->device->dev; + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; stm32f7_i2c_disable_dma_req(i2c_dev); - dma_unmap_single(dev, dma->dma_buf, dma->dma_len, dma->dma_data_dir); + dmaengine_terminate_async(dma->chan_using); + dma_unmap_single(i2c_dev->dev, dma->dma_buf, dma->dma_len, + dma->dma_data_dir); + if (!f7_msg->smbus) + i2c_put_dma_safe_msg_buf(f7_msg->buf, i2c_dev->msg, true); complete(&dma->dma_complete); } @@ -866,6 +885,7 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, { struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; void __iomem *base = i2c_dev->base; + u8 *dma_buf; u32 cr1, cr2; int ret; @@ -915,16 +935,23 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, /* Configure DMA or enable RX/TX interrupt */ i2c_dev->use_dma = false; - if (i2c_dev->dma && f7_msg->count >= STM32F7_I2C_DMA_LEN_MIN) { - ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma, - msg->flags & I2C_M_RD, - f7_msg->count, f7_msg->buf, - stm32f7_i2c_dma_callback, - i2c_dev); - if (!ret) - i2c_dev->use_dma = true; - else - dev_warn(i2c_dev->dev, "can't use DMA\n"); + if (i2c_dev->dma && !i2c_dev->atomic) { + dma_buf = i2c_get_dma_safe_msg_buf(msg, STM32F7_I2C_DMA_LEN_MIN); + if (dma_buf) { + f7_msg->buf = dma_buf; + ret = stm32_i2c_prep_dma_xfer(i2c_dev->dev, i2c_dev->dma, + msg->flags & I2C_M_RD, + f7_msg->count, f7_msg->buf, + stm32f7_i2c_dma_callback, + i2c_dev); + if (ret) { + dev_warn(i2c_dev->dev, "can't use DMA\n"); + i2c_put_dma_safe_msg_buf(f7_msg->buf, msg, false); + f7_msg->buf = msg->buf; + } else { + i2c_dev->use_dma = true; + } + } } if (!i2c_dev->use_dma) { @@ -939,6 +966,9 @@ static void stm32f7_i2c_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, cr1 |= STM32F7_I2C_CR1_TXDMAEN; } + if (i2c_dev->atomic) + cr1 &= ~STM32F7_I2C_ALL_IRQ_MASK; /* Disable all interrupts */ + /* Configure Start/Repeated Start */ cr2 |= STM32F7_I2C_CR2_START; @@ -1059,9 +1089,10 @@ static int stm32f7_i2c_smbus_xfer_msg(struct stm32f7_i2c_dev *i2c_dev, /* Configure PEC */ if ((flags & I2C_CLIENT_PEC) && f7_msg->size != I2C_SMBUS_QUICK) { cr1 |= STM32F7_I2C_CR1_PECEN; - cr2 |= STM32F7_I2C_CR2_PECBYTE; - if (!f7_msg->read_write) + if (!f7_msg->read_write) { + cr2 |= STM32F7_I2C_CR2_PECBYTE; f7_msg->count++; + } } else { cr1 &= ~STM32F7_I2C_CR1_PECEN; cr2 &= ~STM32F7_I2C_CR2_PECBYTE; @@ -1149,8 +1180,10 @@ static void stm32f7_i2c_smbus_rep_start(struct stm32f7_i2c_dev *i2c_dev) f7_msg->stop = true; /* Add one byte for PEC if needed */ - if (cr1 & STM32F7_I2C_CR1_PECEN) + if (cr1 & STM32F7_I2C_CR1_PECEN) { + cr2 |= STM32F7_I2C_CR2_PECBYTE; f7_msg->count++; + } /* Set number of bytes to be transferred */ cr2 &= ~(STM32F7_I2C_CR2_NBYTES_MASK); @@ -1410,15 +1443,13 @@ static bool stm32f7_i2c_is_slave_busy(struct stm32f7_i2c_dev *i2c_dev) return i == busy; } -static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev) +static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev, u32 status) { void __iomem *base = i2c_dev->base; - u32 cr2, status, mask; + u32 cr2, mask; u8 val; int ret; - status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); - /* Slave transmitter mode */ if (status & STM32F7_I2C_ISR_TXIS) { i2c_slave_event(i2c_dev->slave_running, @@ -1485,23 +1516,78 @@ static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev) return IRQ_HANDLED; } -static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) +static irqreturn_t stm32f7_i2c_handle_isr_errs(struct stm32f7_i2c_dev *i2c_dev, u32 status) { - struct stm32f7_i2c_dev *i2c_dev = data; struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; - struct stm32_i2c_dma *dma = i2c_dev->dma; + u16 addr = f7_msg->addr; void __iomem *base = i2c_dev->base; - u32 status, mask; - int ret = IRQ_HANDLED; + struct device *dev = i2c_dev->dev; - /* Check if the interrupt if for a slave device */ - if (!i2c_dev->master_mode) { - ret = stm32f7_i2c_slave_isr_event(i2c_dev); - return ret; + /* Bus error */ + if (status & STM32F7_I2C_ISR_BERR) { + dev_err(dev, "Bus error accessing addr 0x%x\n", addr); + writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR); + stm32f7_i2c_release_bus(&i2c_dev->adap); + f7_msg->result = -EIO; } + /* Arbitration loss */ + if (status & STM32F7_I2C_ISR_ARLO) { + dev_dbg(dev, "Arbitration loss accessing addr 0x%x\n", addr); + writel_relaxed(STM32F7_I2C_ICR_ARLOCF, base + STM32F7_I2C_ICR); + f7_msg->result = -EAGAIN; + } + + if (status & STM32F7_I2C_ISR_PECERR) { + dev_err(dev, "PEC error in reception accessing addr 0x%x\n", addr); + writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR); + f7_msg->result = -EINVAL; + } + + if (status & STM32F7_I2C_ISR_ALERT) { + dev_dbg(dev, "SMBus alert received\n"); + writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR); + i2c_handle_smbus_alert(i2c_dev->alert->ara); + return IRQ_HANDLED; + } + + if (!i2c_dev->slave_running) { + u32 mask; + /* Disable interrupts */ + if (stm32f7_i2c_is_slave_registered(i2c_dev)) + mask = STM32F7_I2C_XFER_IRQ_MASK; + else + mask = STM32F7_I2C_ALL_IRQ_MASK; + stm32f7_i2c_disable_irq(i2c_dev, mask); + } + + /* Disable dma */ + if (i2c_dev->use_dma) + stm32f7_i2c_dma_callback(i2c_dev); + + i2c_dev->master_mode = false; + complete(&i2c_dev->complete); + + return IRQ_HANDLED; +} + +#define STM32F7_ERR_EVENTS (STM32F7_I2C_ISR_BERR | STM32F7_I2C_ISR_ARLO |\ + STM32F7_I2C_ISR_PECERR | STM32F7_I2C_ISR_ALERT) +static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) +{ + struct stm32f7_i2c_dev *i2c_dev = data; + u32 status; + status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); + /* + * Check if the interrupt is for a slave device or related + * to errors flags (in case of single it line mode) + */ + if (!i2c_dev->master_mode || + (i2c_dev->setup.single_it_line && (status & STM32F7_ERR_EVENTS))) + return IRQ_WAKE_THREAD; + /* Tx empty */ if (status & STM32F7_I2C_ISR_TXIS) stm32f7_i2c_write_tx_data(i2c_dev); @@ -1510,45 +1596,63 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) if (status & STM32F7_I2C_ISR_RXNE) stm32f7_i2c_read_rx_data(i2c_dev); + /* Wake up the thread if other flags are raised */ + if (status & + (STM32F7_I2C_ISR_NACKF | STM32F7_I2C_ISR_STOPF | + STM32F7_I2C_ISR_TC | STM32F7_I2C_ISR_TCR)) + return IRQ_WAKE_THREAD; + + return IRQ_HANDLED; +} + +static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data) +{ + struct stm32f7_i2c_dev *i2c_dev = data; + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; + void __iomem *base = i2c_dev->base; + u32 status, mask; + int ret; + + status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); + + if (!i2c_dev->master_mode) + return stm32f7_i2c_slave_isr_event(i2c_dev, status); + + /* Handle errors in case of this handler is used for events/errors */ + if (i2c_dev->setup.single_it_line && (status & STM32F7_ERR_EVENTS)) + return stm32f7_i2c_handle_isr_errs(i2c_dev, status); + /* NACK received */ if (status & STM32F7_I2C_ISR_NACKF) { dev_dbg(i2c_dev->dev, "<%s>: Receive NACK (addr %x)\n", __func__, f7_msg->addr); writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR); - if (i2c_dev->use_dma) { - stm32f7_i2c_disable_dma_req(i2c_dev); - dmaengine_terminate_async(dma->chan_using); - } + if (i2c_dev->use_dma) + stm32f7_i2c_dma_callback(i2c_dev); f7_msg->result = -ENXIO; } - /* STOP detection flag */ - if (status & STM32F7_I2C_ISR_STOPF) { - /* Disable interrupts */ - if (stm32f7_i2c_is_slave_registered(i2c_dev)) - mask = STM32F7_I2C_XFER_IRQ_MASK; + if (status & STM32F7_I2C_ISR_TCR) { + if (f7_msg->smbus) + stm32f7_i2c_smbus_reload(i2c_dev); else - mask = STM32F7_I2C_ALL_IRQ_MASK; - stm32f7_i2c_disable_irq(i2c_dev, mask); - - /* Clear STOP flag */ - writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR); - - if (i2c_dev->use_dma && !f7_msg->result) { - ret = IRQ_WAKE_THREAD; - } else { - i2c_dev->master_mode = false; - complete(&i2c_dev->complete); - } + stm32f7_i2c_reload(i2c_dev); } /* Transfer complete */ if (status & STM32F7_I2C_ISR_TC) { + /* Wait for dma transfer completion before sending next message */ + if (i2c_dev->use_dma && !f7_msg->result) { + ret = wait_for_completion_timeout(&i2c_dev->dma->dma_complete, HZ); + if (!ret) { + dev_dbg(i2c_dev->dev, "<%s>: Timed out\n", __func__); + stm32f7_i2c_dma_callback(i2c_dev); + f7_msg->result = -ETIMEDOUT; + } + } if (f7_msg->stop) { mask = STM32F7_I2C_CR2_STOP; stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask); - } else if (i2c_dev->use_dma && !f7_msg->result) { - ret = IRQ_WAKE_THREAD; } else if (f7_msg->smbus) { stm32f7_i2c_smbus_rep_start(i2c_dev); } else { @@ -1558,47 +1662,18 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) } } - if (status & STM32F7_I2C_ISR_TCR) { - if (f7_msg->smbus) - stm32f7_i2c_smbus_reload(i2c_dev); + /* STOP detection flag */ + if (status & STM32F7_I2C_ISR_STOPF) { + /* Disable interrupts */ + if (stm32f7_i2c_is_slave_registered(i2c_dev)) + mask = STM32F7_I2C_XFER_IRQ_MASK; else - stm32f7_i2c_reload(i2c_dev); - } - - return ret; -} - -static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data) -{ - struct stm32f7_i2c_dev *i2c_dev = data; - struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; - struct stm32_i2c_dma *dma = i2c_dev->dma; - u32 status; - int ret; - - /* - * Wait for dma transfer completion before sending next message or - * notity the end of xfer to the client - */ - ret = wait_for_completion_timeout(&i2c_dev->dma->dma_complete, HZ); - if (!ret) { - dev_dbg(i2c_dev->dev, "<%s>: Timed out\n", __func__); - stm32f7_i2c_disable_dma_req(i2c_dev); - dmaengine_terminate_async(dma->chan_using); - f7_msg->result = -ETIMEDOUT; - } + mask = STM32F7_I2C_ALL_IRQ_MASK; + stm32f7_i2c_disable_irq(i2c_dev, mask); - status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); + /* Clear STOP flag */ + writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR); - if (status & STM32F7_I2C_ISR_TC) { - if (f7_msg->smbus) { - stm32f7_i2c_smbus_rep_start(i2c_dev); - } else { - i2c_dev->msg_id++; - i2c_dev->msg++; - stm32f7_i2c_xfer_msg(i2c_dev, i2c_dev->msg); - } - } else { i2c_dev->master_mode = false; complete(&i2c_dev->complete); } @@ -1606,71 +1681,32 @@ static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) +static irqreturn_t stm32f7_i2c_isr_error_thread(int irq, void *data) { struct stm32f7_i2c_dev *i2c_dev = data; - struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; - void __iomem *base = i2c_dev->base; - struct device *dev = i2c_dev->dev; - struct stm32_i2c_dma *dma = i2c_dev->dma; u32 status; status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); - /* Bus error */ - if (status & STM32F7_I2C_ISR_BERR) { - dev_err(dev, "<%s>: Bus error accessing addr 0x%x\n", - __func__, f7_msg->addr); - writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR); - stm32f7_i2c_release_bus(&i2c_dev->adap); - f7_msg->result = -EIO; - } - - /* Arbitration loss */ - if (status & STM32F7_I2C_ISR_ARLO) { - dev_dbg(dev, "<%s>: Arbitration loss accessing addr 0x%x\n", - __func__, f7_msg->addr); - writel_relaxed(STM32F7_I2C_ICR_ARLOCF, base + STM32F7_I2C_ICR); - f7_msg->result = -EAGAIN; - } - - if (status & STM32F7_I2C_ISR_PECERR) { - dev_err(dev, "<%s>: PEC error in reception accessing addr 0x%x\n", - __func__, f7_msg->addr); - writel_relaxed(STM32F7_I2C_ICR_PECCF, base + STM32F7_I2C_ICR); - f7_msg->result = -EINVAL; - } + return stm32f7_i2c_handle_isr_errs(i2c_dev, status); +} - if (status & STM32F7_I2C_ISR_ALERT) { - dev_dbg(dev, "<%s>: SMBus alert received\n", __func__); - writel_relaxed(STM32F7_I2C_ICR_ALERTCF, base + STM32F7_I2C_ICR); - i2c_handle_smbus_alert(i2c_dev->alert->ara); - return IRQ_HANDLED; - } +static int stm32f7_i2c_wait_polling(struct stm32f7_i2c_dev *i2c_dev) +{ + ktime_t timeout = ktime_add_ms(ktime_get(), i2c_dev->adap.timeout); - if (!i2c_dev->slave_running) { - u32 mask; - /* Disable interrupts */ - if (stm32f7_i2c_is_slave_registered(i2c_dev)) - mask = STM32F7_I2C_XFER_IRQ_MASK; - else - mask = STM32F7_I2C_ALL_IRQ_MASK; - stm32f7_i2c_disable_irq(i2c_dev, mask); - } + while (ktime_compare(ktime_get(), timeout) < 0) { + udelay(5); + stm32f7_i2c_isr_event(0, i2c_dev); - /* Disable dma */ - if (i2c_dev->use_dma) { - stm32f7_i2c_disable_dma_req(i2c_dev); - dmaengine_terminate_async(dma->chan_using); + if (completion_done(&i2c_dev->complete)) + return 1; } - i2c_dev->master_mode = false; - complete(&i2c_dev->complete); - - return IRQ_HANDLED; + return 0; } -static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, +static int stm32f7_i2c_xfer_core(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num) { struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap); @@ -1694,8 +1730,12 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, stm32f7_i2c_xfer_msg(i2c_dev, msgs); - time_left = wait_for_completion_timeout(&i2c_dev->complete, - i2c_dev->adap.timeout); + if (!i2c_dev->atomic) + time_left = wait_for_completion_timeout(&i2c_dev->complete, + i2c_dev->adap.timeout); + else + time_left = stm32f7_i2c_wait_polling(i2c_dev); + ret = f7_msg->result; if (ret) { if (i2c_dev->use_dma) @@ -1721,12 +1761,29 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, } pm_free: - pm_runtime_mark_last_busy(i2c_dev->dev); pm_runtime_put_autosuspend(i2c_dev->dev); return (ret < 0) ? ret : num; } +static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], int num) +{ + struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap); + + i2c_dev->atomic = false; + return stm32f7_i2c_xfer_core(i2c_adap, msgs, num); +} + +static int stm32f7_i2c_xfer_atomic(struct i2c_adapter *i2c_adap, + struct i2c_msg msgs[], int num) +{ + struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap); + + i2c_dev->atomic = true; + return stm32f7_i2c_xfer_core(i2c_adap, msgs, num); +} + static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, unsigned short flags, char read_write, u8 command, int size, @@ -1736,7 +1793,7 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; struct stm32_i2c_dma *dma = i2c_dev->dma; struct device *dev = i2c_dev->dev; - unsigned long timeout; + unsigned long time_left; int i, ret; f7_msg->addr = addr; @@ -1756,8 +1813,8 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, if (ret) goto pm_free; - timeout = wait_for_completion_timeout(&i2c_dev->complete, - i2c_dev->adap.timeout); + time_left = wait_for_completion_timeout(&i2c_dev->complete, + i2c_dev->adap.timeout); ret = f7_msg->result; if (ret) { if (i2c_dev->use_dma) @@ -1773,7 +1830,7 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, goto pm_free; } - if (!timeout) { + if (!time_left) { dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr); if (i2c_dev->use_dma) dmaengine_terminate_sync(dma->chan_using); @@ -1812,7 +1869,6 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, } pm_free: - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; } @@ -1919,7 +1975,6 @@ pm_free: if (!stm32f7_i2c_is_slave_registered(i2c_dev)) stm32f7_i2c_enable_wakeup(i2c_dev, false); - pm_runtime_mark_last_busy(dev); pm_runtime_put_autosuspend(dev); return ret; @@ -1957,7 +2012,6 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) stm32f7_i2c_enable_wakeup(i2c_dev, false); } - pm_runtime_mark_last_busy(i2c_dev->dev); pm_runtime_put_autosuspend(i2c_dev->dev); return 0; @@ -1966,23 +2020,27 @@ static int stm32f7_i2c_unreg_slave(struct i2c_client *slave) static int stm32f7_i2c_write_fm_plus_bits(struct stm32f7_i2c_dev *i2c_dev, bool enable) { - int ret; + int ret = 0; if (i2c_dev->bus_rate <= I2C_MAX_FAST_MODE_FREQ || - IS_ERR_OR_NULL(i2c_dev->regmap)) + (!i2c_dev->setup.fmp_cr1_bit && IS_ERR_OR_NULL(i2c_dev->regmap))) /* Optional */ return 0; - if (i2c_dev->fmp_sreg == i2c_dev->fmp_creg) - ret = regmap_update_bits(i2c_dev->regmap, - i2c_dev->fmp_sreg, - i2c_dev->fmp_mask, - enable ? i2c_dev->fmp_mask : 0); - else - ret = regmap_write(i2c_dev->regmap, - enable ? i2c_dev->fmp_sreg : - i2c_dev->fmp_creg, - i2c_dev->fmp_mask); + if (i2c_dev->setup.fmp_cr1_bit) { + if (enable) + stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1, STM32_I2C_CR1_FMP); + else + stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, STM32_I2C_CR1_FMP); + } else { + if (i2c_dev->fmp_sreg == i2c_dev->fmp_creg) + ret = regmap_update_bits(i2c_dev->regmap, i2c_dev->fmp_sreg, + i2c_dev->fmp_mask, enable ? i2c_dev->fmp_mask : 0); + else + ret = regmap_write(i2c_dev->regmap, + enable ? i2c_dev->fmp_sreg : i2c_dev->fmp_creg, + i2c_dev->fmp_mask); + } return ret; } @@ -2094,7 +2152,8 @@ static u32 stm32f7_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm stm32f7_i2c_algo = { - .master_xfer = stm32f7_i2c_xfer, + .xfer = stm32f7_i2c_xfer, + .xfer_atomic = stm32f7_i2c_xfer_atomic, .smbus_xfer = stm32f7_i2c_smbus_xfer, .functionality = stm32f7_i2c_func, .reg_slave = stm32f7_i2c_reg_slave, @@ -2115,39 +2174,35 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) if (!i2c_dev) return -ENOMEM; + setup = of_device_get_match_data(&pdev->dev); + if (!setup) { + dev_err(&pdev->dev, "Can't get device data\n"); + return -ENODEV; + } + i2c_dev->setup = *setup; + i2c_dev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(i2c_dev->base)) return PTR_ERR(i2c_dev->base); phy_addr = (dma_addr_t)res->start; irq_event = platform_get_irq(pdev, 0); - if (irq_event <= 0) - return irq_event ? : -ENOENT; - - irq_error = platform_get_irq(pdev, 1); - if (irq_error <= 0) - return irq_error ? : -ENOENT; + if (irq_event < 0) + return irq_event; i2c_dev->wakeup_src = of_property_read_bool(pdev->dev.of_node, "wakeup-source"); - i2c_dev->clk = devm_clk_get(&pdev->dev, NULL); + i2c_dev->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(i2c_dev->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(i2c_dev->clk), - "Failed to get controller clock\n"); - - ret = clk_prepare_enable(i2c_dev->clk); - if (ret) { - dev_err(&pdev->dev, "Failed to prepare_enable clock\n"); - return ret; - } + "Failed to enable controller clock\n"); rst = devm_reset_control_get(&pdev->dev, NULL); - if (IS_ERR(rst)) { - ret = dev_err_probe(&pdev->dev, PTR_ERR(rst), - "Error: Missing reset ctrl\n"); - goto clk_free; - } + if (IS_ERR(rst)) + return dev_err_probe(&pdev->dev, PTR_ERR(rst), + "Error: Missing reset ctrl\n"); + reset_control_assert(rst); udelay(2); reset_control_deassert(rst); @@ -2159,40 +2214,38 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) stm32f7_i2c_isr_event_thread, IRQF_ONESHOT, pdev->name, i2c_dev); - if (ret) { - dev_err(&pdev->dev, "Failed to request irq event %i\n", - irq_event); - goto clk_free; - } - - ret = devm_request_irq(&pdev->dev, irq_error, stm32f7_i2c_isr_error, 0, - pdev->name, i2c_dev); - if (ret) { - dev_err(&pdev->dev, "Failed to request irq error %i\n", - irq_error); - goto clk_free; - } - - setup = of_device_get_match_data(&pdev->dev); - if (!setup) { - dev_err(&pdev->dev, "Can't get device data\n"); - ret = -ENODEV; - goto clk_free; + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to request irq event\n"); + + if (!i2c_dev->setup.single_it_line) { + irq_error = platform_get_irq(pdev, 1); + if (irq_error < 0) + return irq_error; + + ret = devm_request_threaded_irq(&pdev->dev, irq_error, + NULL, + stm32f7_i2c_isr_error_thread, + IRQF_ONESHOT, + pdev->name, i2c_dev); + if (ret) + return dev_err_probe(&pdev->dev, ret, "Failed to request irq error\n"); } - i2c_dev->setup = *setup; ret = stm32f7_i2c_setup_timing(i2c_dev, &i2c_dev->setup); if (ret) - goto clk_free; + return ret; /* Setup Fast mode plus if necessary */ if (i2c_dev->bus_rate > I2C_MAX_FAST_MODE_FREQ) { - ret = stm32f7_i2c_setup_fm_plus_bits(pdev, i2c_dev); - if (ret) - goto clk_free; + if (!i2c_dev->setup.fmp_cr1_bit) { + ret = stm32f7_i2c_setup_fm_plus_bits(pdev, i2c_dev); + if (ret) + return ret; + } + ret = stm32f7_i2c_write_fm_plus_bits(i2c_dev, true); if (ret) - goto clk_free; + return ret; } adap = &i2c_dev->adap; @@ -2271,7 +2324,6 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr); - pm_runtime_mark_last_busy(i2c_dev->dev); pm_runtime_put_autosuspend(i2c_dev->dev); return 0; @@ -2303,13 +2355,10 @@ clr_wakeup_capable: fmp_clear: stm32f7_i2c_write_fm_plus_bits(i2c_dev, false); -clk_free: - clk_disable_unprepare(i2c_dev->clk); - return ret; } -static int stm32f7_i2c_remove(struct platform_device *pdev) +static void stm32f7_i2c_remove(struct platform_device *pdev) { struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev); @@ -2339,10 +2388,6 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) } stm32f7_i2c_write_fm_plus_bits(i2c_dev, false); - - clk_disable_unprepare(i2c_dev->clk); - - return 0; } static int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev) @@ -2350,7 +2395,7 @@ static int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev) struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); if (!stm32f7_i2c_is_slave_registered(i2c_dev)) - clk_disable_unprepare(i2c_dev->clk); + clk_disable(i2c_dev->clk); return 0; } @@ -2361,9 +2406,9 @@ static int __maybe_unused stm32f7_i2c_runtime_resume(struct device *dev) int ret; if (!stm32f7_i2c_is_slave_registered(i2c_dev)) { - ret = clk_prepare_enable(i2c_dev->clk); + ret = clk_enable(i2c_dev->clk); if (ret) { - dev_err(dev, "failed to prepare_enable clock\n"); + dev_err(dev, "failed to enable clock\n"); return ret; } } @@ -2475,6 +2520,7 @@ static const struct of_device_id stm32f7_i2c_match[] = { { .compatible = "st,stm32f7-i2c", .data = &stm32f7_setup}, { .compatible = "st,stm32mp15-i2c", .data = &stm32mp15_setup}, { .compatible = "st,stm32mp13-i2c", .data = &stm32mp13_setup}, + { .compatible = "st,stm32mp25-i2c", .data = &stm32mp25_setup}, {}, }; MODULE_DEVICE_TABLE(of, stm32f7_i2c_match); diff --git a/drivers/i2c/busses/i2c-sun6i-p2wi.c b/drivers/i2c/busses/i2c-sun6i-p2wi.c index 9e3483f507ff..fb5280b8cf7f 100644 --- a/drivers/i2c/busses/i2c-sun6i-p2wi.c +++ b/drivers/i2c/busses/i2c-sun6i-p2wi.c @@ -10,7 +10,7 @@ * The P2WI controller looks like an SMBus controller which only supports byte * data transfers. But, it differs from standard SMBus protocol on several * aspects: - * - it supports only one slave device, and thus drop the address field + * - it supports only one target device, and thus drop the address field * - it adds a parity bit every 8bits of data * - only one read access is required to read a byte (instead of a write * followed by a read access in standard SMBus protocol) @@ -88,7 +88,7 @@ struct p2wi { void __iomem *regs; struct clk *clk; struct reset_control *rstc; - int slave_addr; + int target_addr; }; static irqreturn_t p2wi_interrupt(int irq, void *dev_id) @@ -121,7 +121,7 @@ static int p2wi_smbus_xfer(struct i2c_adapter *adap, u16 addr, struct p2wi *p2wi = i2c_get_adapdata(adap); unsigned long dlen = P2WI_DLEN_DATA_LENGTH(1); - if (p2wi->slave_addr >= 0 && addr != p2wi->slave_addr) { + if (p2wi->target_addr >= 0 && addr != p2wi->target_addr) { dev_err(&adap->dev, "invalid P2WI address\n"); return -EINVAL; } @@ -188,7 +188,7 @@ static int p2wi_probe(struct platform_device *pdev) unsigned long parent_clk_freq; u32 clk_freq = I2C_MAX_STANDARD_MODE_FREQ; struct p2wi *p2wi; - u32 slave_addr; + u32 target_addr; int clk_div; int irq; int ret; @@ -201,8 +201,13 @@ static int p2wi_probe(struct platform_device *pdev) return -EINVAL; } + if (clk_freq == 0) { + dev_err(dev, "clock-frequency is set to 0 in DT\n"); + return -EINVAL; + } + if (of_get_child_count(np) > 1) { - dev_err(dev, "P2WI only supports one slave device\n"); + dev_err(dev, "P2WI only supports one target device\n"); return -EINVAL; } @@ -210,24 +215,24 @@ static int p2wi_probe(struct platform_device *pdev) if (!p2wi) return -ENOMEM; - p2wi->slave_addr = -1; + p2wi->target_addr = -1; /* * Authorize a p2wi node without any children to be able to use an * i2c-dev from userpace. - * In this case the slave_addr is set to -1 and won't be checked when + * In this case the target_addr is set to -1 and won't be checked when * launching a P2WI transfer. */ childnp = of_get_next_available_child(np, NULL); if (childnp) { - ret = of_property_read_u32(childnp, "reg", &slave_addr); + ret = of_property_read_u32(childnp, "reg", &target_addr); if (ret) { - dev_err(dev, "invalid slave address on node %pOF\n", + dev_err(dev, "invalid target address on node %pOF\n", childnp); return -EINVAL; } - p2wi->slave_addr = slave_addr; + p2wi->target_addr = target_addr; } p2wi->regs = devm_platform_ioremap_resource(pdev, 0); @@ -239,15 +244,9 @@ static int p2wi_probe(struct platform_device *pdev) if (irq < 0) return irq; - p2wi->clk = devm_clk_get(dev, NULL); + p2wi->clk = devm_clk_get_enabled(dev, NULL); if (IS_ERR(p2wi->clk)) { ret = PTR_ERR(p2wi->clk); - dev_err(dev, "failed to retrieve clk: %d\n", ret); - return ret; - } - - ret = clk_prepare_enable(p2wi->clk); - if (ret) { dev_err(dev, "failed to enable clk: %d\n", ret); return ret; } @@ -256,15 +255,15 @@ static int p2wi_probe(struct platform_device *pdev) p2wi->rstc = devm_reset_control_get_exclusive(dev, NULL); if (IS_ERR(p2wi->rstc)) { - ret = PTR_ERR(p2wi->rstc); - dev_err(dev, "failed to retrieve reset controller: %d\n", ret); - goto err_clk_disable; + dev_err(dev, "failed to retrieve reset controller: %pe\n", + p2wi->rstc); + return PTR_ERR(p2wi->rstc); } ret = reset_control_deassert(p2wi->rstc); if (ret) { dev_err(dev, "failed to deassert reset line: %d\n", ret); - goto err_clk_disable; + return ret; } init_completion(&p2wi->complete); @@ -307,26 +306,20 @@ static int p2wi_probe(struct platform_device *pdev) err_reset_assert: reset_control_assert(p2wi->rstc); -err_clk_disable: - clk_disable_unprepare(p2wi->clk); - return ret; } -static int p2wi_remove(struct platform_device *dev) +static void p2wi_remove(struct platform_device *dev) { struct p2wi *p2wi = platform_get_drvdata(dev); reset_control_assert(p2wi->rstc); - clk_disable_unprepare(p2wi->clk); i2c_del_adapter(&p2wi->adapter); - - return 0; } static struct platform_driver p2wi_driver = { .probe = p2wi_probe, - .remove = p2wi_remove, + .remove = p2wi_remove, .driver = { .name = "i2c-sunxi-p2wi", .of_match_table = p2wi_of_match_table, diff --git a/drivers/i2c/busses/i2c-synquacer.c b/drivers/i2c/busses/i2c-synquacer.c index e4026c5416b1..1230f51e1624 100644 --- a/drivers/i2c/busses/i2c-synquacer.c +++ b/drivers/i2c/busses/i2c-synquacer.c @@ -138,7 +138,6 @@ struct synquacer_i2c { int irq; struct device *dev; void __iomem *base; - struct clk *pclk; u32 pclkrate; u32 speed_khz; u32 timeout_ms; @@ -311,7 +310,7 @@ static int synquacer_i2c_doxfer(struct synquacer_i2c *i2c, struct i2c_msg *msgs, int num) { unsigned char bsr; - unsigned long timeout; + unsigned long time_left; int ret; synquacer_i2c_hw_init(i2c); @@ -335,9 +334,9 @@ static int synquacer_i2c_doxfer(struct synquacer_i2c *i2c, return ret; } - timeout = wait_for_completion_timeout(&i2c->completion, - msecs_to_jiffies(i2c->timeout_ms)); - if (timeout == 0) { + time_left = wait_for_completion_timeout(&i2c->completion, + msecs_to_jiffies(i2c->timeout_ms)); + if (time_left == 0) { dev_dbg(i2c->dev, "timeout\n"); return -EAGAIN; } @@ -521,8 +520,8 @@ static u32 synquacer_i2c_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm synquacer_i2c_algo = { - .master_xfer = synquacer_i2c_xfer, - .functionality = synquacer_i2c_functionality, + .xfer = synquacer_i2c_xfer, + .functionality = synquacer_i2c_functionality, }; static const struct i2c_adapter synquacer_i2c_ops = { @@ -535,6 +534,7 @@ static const struct i2c_adapter synquacer_i2c_ops = { static int synquacer_i2c_probe(struct platform_device *pdev) { struct synquacer_i2c *i2c; + struct clk *pclk; u32 bus_speed; int ret; @@ -550,27 +550,19 @@ static int synquacer_i2c_probe(struct platform_device *pdev) device_property_read_u32(&pdev->dev, "socionext,pclk-rate", &i2c->pclkrate); - i2c->pclk = devm_clk_get(&pdev->dev, "pclk"); - if (PTR_ERR(i2c->pclk) == -EPROBE_DEFER) - return -EPROBE_DEFER; - if (!IS_ERR_OR_NULL(i2c->pclk)) { - dev_dbg(&pdev->dev, "clock source %p\n", i2c->pclk); + pclk = devm_clk_get_optional_enabled(&pdev->dev, "pclk"); + if (IS_ERR(pclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(pclk), + "failed to get and enable clock\n"); - ret = clk_prepare_enable(i2c->pclk); - if (ret) { - dev_err(&pdev->dev, "failed to enable clock (%d)\n", - ret); - return ret; - } - i2c->pclkrate = clk_get_rate(i2c->pclk); - } + if (pclk) + i2c->pclkrate = clk_get_rate(pclk); if (i2c->pclkrate < SYNQUACER_I2C_MIN_CLK_RATE || - i2c->pclkrate > SYNQUACER_I2C_MAX_CLK_RATE) { - dev_err(&pdev->dev, "PCLK missing or out of range (%d)\n", - i2c->pclkrate); - return -EINVAL; - } + i2c->pclkrate > SYNQUACER_I2C_MAX_CLK_RATE) + return dev_err_probe(&pdev->dev, -EINVAL, + "PCLK missing or out of range (%d)\n", + i2c->pclkrate); i2c->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(i2c->base)) @@ -582,10 +574,8 @@ static int synquacer_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(&pdev->dev, i2c->irq, synquacer_i2c_isr, 0, dev_name(&pdev->dev), i2c); - if (ret < 0) { - dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq); - return ret; - } + if (ret < 0) + return dev_err_probe(&pdev->dev, ret, "cannot claim IRQ %d\n", i2c->irq); i2c->state = STATE_IDLE; i2c->dev = &pdev->dev; @@ -605,10 +595,8 @@ static int synquacer_i2c_probe(struct platform_device *pdev) synquacer_i2c_hw_init(i2c); ret = i2c_add_numbered_adapter(&i2c->adapter); - if (ret) { - dev_err(&pdev->dev, "failed to add bus to i2c core\n"); - return ret; - } + if (ret) + return dev_err_probe(&pdev->dev, ret, "failed to add bus to i2c core\n"); platform_set_drvdata(pdev, i2c); @@ -618,18 +606,14 @@ static int synquacer_i2c_probe(struct platform_device *pdev) return 0; } -static int synquacer_i2c_remove(struct platform_device *pdev) +static void synquacer_i2c_remove(struct platform_device *pdev) { struct synquacer_i2c *i2c = platform_get_drvdata(pdev); i2c_del_adapter(&i2c->adapter); - if (!IS_ERR(i2c->pclk)) - clk_disable_unprepare(i2c->pclk); - - return 0; }; -static const struct of_device_id synquacer_i2c_dt_ids[] = { +static const struct of_device_id synquacer_i2c_dt_ids[] __maybe_unused = { { .compatible = "socionext,synquacer-i2c" }, { /* sentinel */ } }; @@ -645,7 +629,7 @@ MODULE_DEVICE_TABLE(acpi, synquacer_i2c_acpi_ids); static struct platform_driver synquacer_i2c_driver = { .probe = synquacer_i2c_probe, - .remove = synquacer_i2c_remove, + .remove = synquacer_i2c_remove, .driver = { .name = "synquacer_i2c", .of_match_table = of_match_ptr(synquacer_i2c_dt_ids), diff --git a/drivers/i2c/busses/i2c-taos-evm.c b/drivers/i2c/busses/i2c-taos-evm.c index b0f0120793e1..cb97f72291bc 100644 --- a/drivers/i2c/busses/i2c-taos-evm.c +++ b/drivers/i2c/busses/i2c-taos-evm.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Driver for the TAOS evaluation modules - * These devices include an I2C master which can be controlled over the + * These devices include an I2C controller which can be controlled over the * serial port. * * Copyright (C) 2007 Jean Delvare <jdelvare@suse.de> diff --git a/drivers/i2c/busses/i2c-tegra-bpmp.c b/drivers/i2c/busses/i2c-tegra-bpmp.c index 95139985b2d5..bb0de6db6391 100644 --- a/drivers/i2c/busses/i2c-tegra-bpmp.c +++ b/drivers/i2c/busses/i2c-tegra-bpmp.c @@ -12,7 +12,7 @@ #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -275,8 +275,8 @@ static u32 tegra_bpmp_i2c_func(struct i2c_adapter *adapter) } static const struct i2c_algorithm tegra_bpmp_i2c_algo = { - .master_xfer = tegra_bpmp_i2c_xfer, - .master_xfer_atomic = tegra_bpmp_i2c_xfer_atomic, + .xfer = tegra_bpmp_i2c_xfer, + .xfer_atomic = tegra_bpmp_i2c_xfer_atomic, .functionality = tegra_bpmp_i2c_func, }; @@ -316,13 +316,11 @@ static int tegra_bpmp_i2c_probe(struct platform_device *pdev) return i2c_add_adapter(&i2c->adapter); } -static int tegra_bpmp_i2c_remove(struct platform_device *pdev) +static void tegra_bpmp_i2c_remove(struct platform_device *pdev) { struct tegra_bpmp_i2c *i2c = platform_get_drvdata(pdev); i2c_del_adapter(&i2c->adapter); - - return 0; } static const struct of_device_id tegra_bpmp_i2c_of_match[] = { diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index 6aab84c8d22b..e533460bccc3 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -22,7 +22,7 @@ #include <linux/kernel.h> #include <linux/ktime.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/pinctrl/consumer.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> @@ -134,6 +134,8 @@ #define I2C_MST_FIFO_STATUS_TX GENMASK(23, 16) #define I2C_MST_FIFO_STATUS_RX GENMASK(7, 0) +#define I2C_MASTER_RESET_CNTRL 0x0a8 + /* configuration load timeout in microseconds */ #define I2C_CONFIG_LOAD_TIMEOUT 1000000 @@ -184,6 +186,9 @@ enum msg_end_type { * @has_mst_fifo: The I2C controller contains the new MST FIFO interface that * provides additional features and allows for longer messages to * be transferred in one go. + * @has_mst_reset: The I2C controller contains MASTER_RESET_CTRL register which + * provides an alternative to controller reset when configured as + * I2C master * @quirks: I2C adapter quirks for limiting write/read transfer size and not * allowing 0 length transfers. * @supports_bus_clear: Bus Clear support to recover from bus hang during @@ -213,6 +218,7 @@ struct tegra_i2c_hw_feature { bool has_multi_master_mode; bool has_slcg_override_reg; bool has_mst_fifo; + bool has_mst_reset; const struct i2c_adapter_quirks *quirks; bool supports_bus_clear; bool has_apb_dma; @@ -242,17 +248,18 @@ struct tegra_i2c_hw_feature { * @is_dvc: identifies the DVC I2C controller, has a different register layout * @is_vi: identifies the VI I2C controller, has a different register layout * @msg_complete: transfer completion notifier + * @msg_buf_remaining: size of unsent data in the message buffer + * @msg_len: length of message in current transfer * @msg_err: error code for completed message * @msg_buf: pointer to current message data - * @msg_buf_remaining: size of unsent data in the message buffer * @msg_read: indicates that the transfer is a read access * @timings: i2c timings information like bus frequency * @multimaster_mode: indicates that I2C controller is in multi-master mode - * @tx_dma_chan: DMA transmit channel - * @rx_dma_chan: DMA receive channel + * @dma_chan: DMA channel * @dma_phys: handle to DMA resources * @dma_buf: pointer to allocated DMA buffer * @dma_buf_size: DMA buffer size + * @dma_dev: DMA device used for transfers * @dma_mode: indicates active DMA transfer * @dma_complete: DMA completion notifier * @atomic_mode: indicates active atomic transfer @@ -277,12 +284,12 @@ struct tegra_i2c_dev { struct completion msg_complete; size_t msg_buf_remaining; + unsigned int msg_len; int msg_err; u8 *msg_buf; struct completion dma_complete; - struct dma_chan *tx_dma_chan; - struct dma_chan *rx_dma_chan; + struct dma_chan *dma_chan; unsigned int dma_buf_size; struct device *dma_dev; dma_addr_t dma_phys; @@ -296,6 +303,9 @@ struct tegra_i2c_dev { bool is_vi; }; +#define IS_DVC(dev) (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && (dev)->is_dvc) +#define IS_VI(dev) (IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) && (dev)->is_vi) + static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned int reg) { @@ -313,9 +323,9 @@ static u32 dvc_readl(struct tegra_i2c_dev *i2c_dev, unsigned int reg) */ static u32 tegra_i2c_reg_addr(struct tegra_i2c_dev *i2c_dev, unsigned int reg) { - if (i2c_dev->is_dvc) + if (IS_DVC(i2c_dev)) reg += (reg >= I2C_TX_FIFO) ? 0x10 : 0x40; - else if (i2c_dev->is_vi) + else if (IS_VI(i2c_dev)) reg = 0xc00 + (reg << 2); return reg; @@ -328,7 +338,7 @@ static void i2c_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned int reg) /* read back register to make sure that register writes completed */ if (reg != I2C_TX_FIFO) readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, reg)); - else if (i2c_dev->is_vi) + else if (IS_VI(i2c_dev)) readl_relaxed(i2c_dev->base + tegra_i2c_reg_addr(i2c_dev, I2C_INT_STATUS)); } @@ -391,16 +401,14 @@ static int tegra_i2c_dma_submit(struct tegra_i2c_dev *i2c_dev, size_t len) { struct dma_async_tx_descriptor *dma_desc; enum dma_transfer_direction dir; - struct dma_chan *chan; dev_dbg(i2c_dev->dev, "starting DMA for length: %zu\n", len); reinit_completion(&i2c_dev->dma_complete); dir = i2c_dev->msg_read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV; - chan = i2c_dev->msg_read ? i2c_dev->rx_dma_chan : i2c_dev->tx_dma_chan; - dma_desc = dmaengine_prep_slave_single(chan, i2c_dev->dma_phys, + dma_desc = dmaengine_prep_slave_single(i2c_dev->dma_chan, i2c_dev->dma_phys, len, dir, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!dma_desc) { @@ -413,7 +421,7 @@ static int tegra_i2c_dma_submit(struct tegra_i2c_dev *i2c_dev, size_t len) dma_desc->callback_param = i2c_dev; dmaengine_submit(dma_desc); - dma_async_issue_pending(chan); + dma_async_issue_pending(i2c_dev->dma_chan); return 0; } @@ -426,28 +434,22 @@ static void tegra_i2c_release_dma(struct tegra_i2c_dev *i2c_dev) i2c_dev->dma_buf = NULL; } - if (i2c_dev->tx_dma_chan) { - dma_release_channel(i2c_dev->tx_dma_chan); - i2c_dev->tx_dma_chan = NULL; - } - - if (i2c_dev->rx_dma_chan) { - dma_release_channel(i2c_dev->rx_dma_chan); - i2c_dev->rx_dma_chan = NULL; + if (i2c_dev->dma_chan) { + dma_release_channel(i2c_dev->dma_chan); + i2c_dev->dma_chan = NULL; } } static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev) { - struct dma_chan *chan; dma_addr_t dma_phys; u32 *dma_buf; int err; - if (i2c_dev->is_vi) + if (IS_VI(i2c_dev)) return 0; - if (!i2c_dev->hw->has_apb_dma) { + if (i2c_dev->hw->has_apb_dma) { if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA)) { dev_dbg(i2c_dev->dev, "APB DMA support not enabled\n"); return 0; @@ -457,25 +459,19 @@ static int tegra_i2c_init_dma(struct tegra_i2c_dev *i2c_dev) return 0; } - chan = dma_request_chan(i2c_dev->dev, "rx"); - if (IS_ERR(chan)) { - err = PTR_ERR(chan); - goto err_out; - } - - i2c_dev->rx_dma_chan = chan; - - chan = dma_request_chan(i2c_dev->dev, "tx"); - if (IS_ERR(chan)) { - err = PTR_ERR(chan); + /* + * The same channel will be used for both RX and TX. + * Keeping the name as "tx" for backward compatibility + * with existing devicetrees. + */ + i2c_dev->dma_chan = dma_request_chan(i2c_dev->dev, "tx"); + if (IS_ERR(i2c_dev->dma_chan)) { + err = PTR_ERR(i2c_dev->dma_chan); + i2c_dev->dma_chan = NULL; goto err_out; } - i2c_dev->tx_dma_chan = chan; - - WARN_ON(i2c_dev->tx_dma_chan->device != i2c_dev->rx_dma_chan->device); - i2c_dev->dma_dev = chan->device->dev; - + i2c_dev->dma_dev = i2c_dev->dma_chan->device->dev; i2c_dev->dma_buf_size = i2c_dev->hw->quirks->max_write_len + I2C_PACKET_HEADER_SIZE; @@ -615,14 +611,43 @@ static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev) return 0; } +static int tegra_i2c_master_reset(struct tegra_i2c_dev *i2c_dev) +{ + if (!i2c_dev->hw->has_mst_reset) + return -EOPNOTSUPP; + + /* + * Writing 1 to I2C_MASTER_RESET_CNTRL will reset all internal state of + * Master logic including FIFOs. Clear this bit to 0 for normal operation. + * SW needs to wait for 2us after assertion and de-assertion of this soft + * reset. + */ + i2c_writel(i2c_dev, 0x1, I2C_MASTER_RESET_CNTRL); + fsleep(2); + + i2c_writel(i2c_dev, 0x0, I2C_MASTER_RESET_CNTRL); + fsleep(2); + + return 0; +} + static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) { u32 val, clk_divisor, clk_multiplier, tsu_thd, tlow, thigh, non_hs_mode; - acpi_handle handle = ACPI_HANDLE(i2c_dev->dev); struct i2c_timings *t = &i2c_dev->timings; int err; /* + * Reset the controller before initializing it. + * In case if device_reset() returns -ENOENT, i.e. when the reset is + * not available, the internal software reset will be used if it is + * supported by the controller. + */ + err = device_reset(i2c_dev->dev); + if (err == -ENOENT) + err = tegra_i2c_master_reset(i2c_dev); + + /* * The reset shouldn't ever fail in practice. The failure will be a * sign of a severe problem that needs to be resolved. Still we don't * want to fail the initialization completely because this may break @@ -630,14 +655,9 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) * emit a noisy warning on error, which won't stay unnoticed and * won't hose machine entirely. */ - if (handle) - err = acpi_evaluate_object(handle, "_RST", NULL, NULL); - else - err = reset_control_reset(i2c_dev->rst); - WARN_ON_ONCE(err); - if (i2c_dev->is_dvc) + if (IS_DVC(i2c_dev)) tegra_dvc_init(i2c_dev); val = I2C_CNFG_NEW_MASTER_FSM | I2C_CNFG_PACKET_MODE_EN | @@ -649,7 +669,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) i2c_writel(i2c_dev, val, I2C_CNFG); i2c_writel(i2c_dev, 0, I2C_INT_MASK); - if (i2c_dev->is_vi) + if (IS_VI(i2c_dev)) tegra_i2c_vi_init(i2c_dev); switch (t->bus_freq_hz) { @@ -701,7 +721,7 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) return err; } - if (!i2c_dev->is_dvc && !i2c_dev->is_vi) { + if (!IS_DVC(i2c_dev) && !IS_VI(i2c_dev)) { u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL; @@ -844,7 +864,7 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev) i2c_dev->msg_buf_remaining = buf_remaining; i2c_dev->msg_buf = buf + words_to_transfer * BYTES_PER_FIFO_WORD; - if (i2c_dev->is_vi) + if (IS_VI(i2c_dev)) i2c_writesl_vi(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer); else i2c_writesl(i2c_dev, buf, I2C_TX_FIFO, words_to_transfer); @@ -931,7 +951,7 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) } i2c_writel(i2c_dev, status, I2C_INT_STATUS); - if (i2c_dev->is_dvc) + if (IS_DVC(i2c_dev)) dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); /* @@ -970,15 +990,11 @@ err: i2c_writel(i2c_dev, status, I2C_INT_STATUS); - if (i2c_dev->is_dvc) + if (IS_DVC(i2c_dev)) dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); if (i2c_dev->dma_mode) { - if (i2c_dev->msg_read) - dmaengine_terminate_async(i2c_dev->rx_dma_chan); - else - dmaengine_terminate_async(i2c_dev->tx_dma_chan); - + dmaengine_terminate_async(i2c_dev->dma_chan); complete(&i2c_dev->dma_complete); } @@ -992,7 +1008,6 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev, { struct dma_slave_config slv_config = {0}; u32 val, reg, dma_burst, reg_offset; - struct dma_chan *chan; int err; if (i2c_dev->hw->has_mst_fifo) @@ -1009,7 +1024,6 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev, dma_burst = 8; if (i2c_dev->msg_read) { - chan = i2c_dev->rx_dma_chan; reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_RX_FIFO); slv_config.src_addr = i2c_dev->base_phys + reg_offset; @@ -1021,7 +1035,6 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev, else val = I2C_FIFO_CONTROL_RX_TRIG(dma_burst); } else { - chan = i2c_dev->tx_dma_chan; reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_TX_FIFO); slv_config.dst_addr = i2c_dev->base_phys + reg_offset; @@ -1035,7 +1048,7 @@ static void tegra_i2c_config_fifo_trig(struct tegra_i2c_dev *i2c_dev, } slv_config.device_fc = true; - err = dmaengine_slave_config(chan, &slv_config); + err = dmaengine_slave_config(i2c_dev->dma_chan, &slv_config); if (err) { dev_err(i2c_dev->dev, "DMA config failed: %d\n", err); dev_err(i2c_dev->dev, "falling back to PIO\n"); @@ -1169,7 +1182,7 @@ static void tegra_i2c_push_packet_header(struct tegra_i2c_dev *i2c_dev, else i2c_writel(i2c_dev, packet_header, I2C_TX_FIFO); - packet_header = msg->len - 1; + packet_header = i2c_dev->msg_len - 1; if (i2c_dev->dma_mode && !i2c_dev->msg_read) *dma_buf++ = packet_header; @@ -1242,20 +1255,32 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, return err; i2c_dev->msg_buf = msg->buf; + i2c_dev->msg_len = msg->len; - /* The condition true implies smbus block read and len is already read */ - if (msg->flags & I2C_M_RECV_LEN && end_state != MSG_END_CONTINUE) - i2c_dev->msg_buf = msg->buf + 1; - - i2c_dev->msg_buf_remaining = msg->len; i2c_dev->msg_err = I2C_ERR_NONE; i2c_dev->msg_read = !!(msg->flags & I2C_M_RD); reinit_completion(&i2c_dev->msg_complete); + /* + * For SMBUS block read command, read only 1 byte in the first transfer. + * Adjust that 1 byte for the next transfer in the msg buffer and msg + * length. + */ + if (msg->flags & I2C_M_RECV_LEN) { + if (end_state == MSG_END_CONTINUE) { + i2c_dev->msg_len = 1; + } else { + i2c_dev->msg_buf += 1; + i2c_dev->msg_len -= 1; + } + } + + i2c_dev->msg_buf_remaining = i2c_dev->msg_len; + if (i2c_dev->msg_read) - xfer_size = msg->len; + xfer_size = i2c_dev->msg_len; else - xfer_size = msg->len + I2C_PACKET_HEADER_SIZE; + xfer_size = i2c_dev->msg_len + I2C_PACKET_HEADER_SIZE; xfer_size = ALIGN(xfer_size, BYTES_PER_FIFO_WORD); @@ -1276,17 +1301,9 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, if (i2c_dev->dma_mode) { if (i2c_dev->msg_read) { - dma_sync_single_for_device(i2c_dev->dma_dev, - i2c_dev->dma_phys, - xfer_size, DMA_FROM_DEVICE); - err = tegra_i2c_dma_submit(i2c_dev, xfer_size); if (err) return err; - } else { - dma_sync_single_for_cpu(i2c_dev->dma_dev, - i2c_dev->dma_phys, - xfer_size, DMA_TO_DEVICE); } } @@ -1295,12 +1312,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, if (!i2c_dev->msg_read) { if (i2c_dev->dma_mode) { memcpy(i2c_dev->dma_buf + I2C_PACKET_HEADER_SIZE, - msg->buf, msg->len); - - dma_sync_single_for_device(i2c_dev->dma_dev, - i2c_dev->dma_phys, - xfer_size, DMA_TO_DEVICE); - + msg->buf, i2c_dev->msg_len); err = tegra_i2c_dma_submit(i2c_dev, xfer_size); if (err) return err; @@ -1333,27 +1345,16 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, * performs synchronization after the transfer's termination * and we want to get a completion if transfer succeeded. */ - dmaengine_synchronize(i2c_dev->msg_read ? - i2c_dev->rx_dma_chan : - i2c_dev->tx_dma_chan); - - dmaengine_terminate_sync(i2c_dev->msg_read ? - i2c_dev->rx_dma_chan : - i2c_dev->tx_dma_chan); + dmaengine_synchronize(i2c_dev->dma_chan); + dmaengine_terminate_sync(i2c_dev->dma_chan); if (!time_left && !completion_done(&i2c_dev->dma_complete)) { - dev_err(i2c_dev->dev, "DMA transfer timed out\n"); tegra_i2c_init(i2c_dev); return -ETIMEDOUT; } - if (i2c_dev->msg_read && i2c_dev->msg_err == I2C_ERR_NONE) { - dma_sync_single_for_cpu(i2c_dev->dma_dev, - i2c_dev->dma_phys, - xfer_size, DMA_FROM_DEVICE); - - memcpy(i2c_dev->msg_buf, i2c_dev->dma_buf, msg->len); - } + if (i2c_dev->msg_read && i2c_dev->msg_err == I2C_ERR_NONE) + memcpy(i2c_dev->msg_buf, i2c_dev->dma_buf, i2c_dev->msg_len); } time_left = tegra_i2c_wait_completion(i2c_dev, &i2c_dev->msg_complete, @@ -1362,7 +1363,6 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, tegra_i2c_mask_irq(i2c_dev, int_mask); if (time_left == 0) { - dev_err(i2c_dev->dev, "I2C transfer timed out\n"); tegra_i2c_init(i2c_dev); return -ETIMEDOUT; } @@ -1408,8 +1408,13 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], MSG_END_CONTINUE); if (ret) break; - /* Set the read byte as msg len */ - msgs[i].len = msgs[i].buf[0]; + + /* Validate message length before proceeding */ + if (msgs[i].buf[0] == 0 || msgs[i].buf[0] > I2C_SMBUS_BLOCK_MAX) + break; + + /* Set the msg length from first byte */ + msgs[i].len += msgs[i].buf[0]; dev_dbg(i2c_dev->dev, "reading %d bytes\n", msgs[i].len); } ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], end_type); @@ -1448,9 +1453,9 @@ static u32 tegra_i2c_func(struct i2c_adapter *adap) } static const struct i2c_algorithm tegra_i2c_algo = { - .master_xfer = tegra_i2c_xfer, - .master_xfer_atomic = tegra_i2c_xfer_atomic, - .functionality = tegra_i2c_func, + .xfer = tegra_i2c_xfer, + .xfer_atomic = tegra_i2c_xfer_atomic, + .functionality = tegra_i2c_func, }; /* payload size is only 12 bit */ @@ -1480,6 +1485,7 @@ static const struct tegra_i2c_hw_feature tegra20_i2c_hw = { .has_multi_master_mode = false, .has_slcg_override_reg = false, .has_mst_fifo = false, + .has_mst_reset = false, .quirks = &tegra_i2c_quirks, .supports_bus_clear = false, .has_apb_dma = true, @@ -1504,6 +1510,7 @@ static const struct tegra_i2c_hw_feature tegra30_i2c_hw = { .has_multi_master_mode = false, .has_slcg_override_reg = false, .has_mst_fifo = false, + .has_mst_reset = false, .quirks = &tegra_i2c_quirks, .supports_bus_clear = false, .has_apb_dma = true, @@ -1528,6 +1535,7 @@ static const struct tegra_i2c_hw_feature tegra114_i2c_hw = { .has_multi_master_mode = false, .has_slcg_override_reg = false, .has_mst_fifo = false, + .has_mst_reset = false, .quirks = &tegra_i2c_quirks, .supports_bus_clear = true, .has_apb_dma = true, @@ -1552,6 +1560,7 @@ static const struct tegra_i2c_hw_feature tegra124_i2c_hw = { .has_multi_master_mode = false, .has_slcg_override_reg = true, .has_mst_fifo = false, + .has_mst_reset = false, .quirks = &tegra_i2c_quirks, .supports_bus_clear = true, .has_apb_dma = true, @@ -1576,6 +1585,7 @@ static const struct tegra_i2c_hw_feature tegra210_i2c_hw = { .has_multi_master_mode = false, .has_slcg_override_reg = true, .has_mst_fifo = false, + .has_mst_reset = false, .quirks = &tegra_i2c_quirks, .supports_bus_clear = true, .has_apb_dma = true, @@ -1600,6 +1610,7 @@ static const struct tegra_i2c_hw_feature tegra186_i2c_hw = { .has_multi_master_mode = false, .has_slcg_override_reg = true, .has_mst_fifo = false, + .has_mst_reset = false, .quirks = &tegra_i2c_quirks, .supports_bus_clear = true, .has_apb_dma = false, @@ -1624,6 +1635,7 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = { .has_multi_master_mode = true, .has_slcg_override_reg = true, .has_mst_fifo = true, + .has_mst_reset = true, .quirks = &tegra194_i2c_quirks, .supports_bus_clear = true, .has_apb_dma = false, @@ -1637,16 +1649,46 @@ static const struct tegra_i2c_hw_feature tegra194_i2c_hw = { .has_interface_timing_reg = true, }; +static const struct tegra_i2c_hw_feature tegra256_i2c_hw = { + .has_continue_xfer_support = true, + .has_per_pkt_xfer_complete_irq = true, + .clk_divisor_hs_mode = 7, + .clk_divisor_std_mode = 0x7a, + .clk_divisor_fast_mode = 0x40, + .clk_divisor_fast_plus_mode = 0x19, + .has_config_load_reg = true, + .has_multi_master_mode = true, + .has_slcg_override_reg = true, + .has_mst_fifo = true, + .has_mst_reset = true, + .quirks = &tegra194_i2c_quirks, + .supports_bus_clear = true, + .has_apb_dma = false, + .tlow_std_mode = 0x8, + .thigh_std_mode = 0x7, + .tlow_fast_fastplus_mode = 0x3, + .thigh_fast_fastplus_mode = 0x3, + .setup_hold_time_std_mode = 0x08080808, + .setup_hold_time_fast_fast_plus_mode = 0x02020202, + .setup_hold_time_hs_mode = 0x090909, + .has_interface_timing_reg = true, +}; + static const struct of_device_id tegra_i2c_of_match[] = { + { .compatible = "nvidia,tegra256-i2c", .data = &tegra256_i2c_hw, }, { .compatible = "nvidia,tegra194-i2c", .data = &tegra194_i2c_hw, }, { .compatible = "nvidia,tegra186-i2c", .data = &tegra186_i2c_hw, }, +#if IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) { .compatible = "nvidia,tegra210-i2c-vi", .data = &tegra210_i2c_hw, }, +#endif { .compatible = "nvidia,tegra210-i2c", .data = &tegra210_i2c_hw, }, { .compatible = "nvidia,tegra124-i2c", .data = &tegra124_i2c_hw, }, { .compatible = "nvidia,tegra114-i2c", .data = &tegra114_i2c_hw, }, { .compatible = "nvidia,tegra30-i2c", .data = &tegra30_i2c_hw, }, { .compatible = "nvidia,tegra20-i2c", .data = &tegra20_i2c_hw, }, +#if IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) { .compatible = "nvidia,tegra20-i2c-dvc", .data = &tegra20_i2c_hw, }, +#endif {}, }; MODULE_DEVICE_TABLE(of, tegra_i2c_of_match); @@ -1661,26 +1703,15 @@ static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev) multi_mode = device_property_read_bool(i2c_dev->dev, "multi-master"); i2c_dev->multimaster_mode = multi_mode; - if (of_device_is_compatible(np, "nvidia,tegra20-i2c-dvc")) + if (IS_ENABLED(CONFIG_ARCH_TEGRA_2x_SOC) && + of_device_is_compatible(np, "nvidia,tegra20-i2c-dvc")) i2c_dev->is_dvc = true; - if (of_device_is_compatible(np, "nvidia,tegra210-i2c-vi")) + if (IS_ENABLED(CONFIG_ARCH_TEGRA_210_SOC) && + of_device_is_compatible(np, "nvidia,tegra210-i2c-vi")) i2c_dev->is_vi = true; } -static int tegra_i2c_init_reset(struct tegra_i2c_dev *i2c_dev) -{ - if (ACPI_HANDLE(i2c_dev->dev)) - return 0; - - i2c_dev->rst = devm_reset_control_get_exclusive(i2c_dev->dev, "i2c"); - if (IS_ERR(i2c_dev->rst)) - return dev_err_probe(i2c_dev->dev, PTR_ERR(i2c_dev->rst), - "failed to get reset control\n"); - - return 0; -} - static int tegra_i2c_init_clocks(struct tegra_i2c_dev *i2c_dev) { int err; @@ -1693,7 +1724,7 @@ static int tegra_i2c_init_clocks(struct tegra_i2c_dev *i2c_dev) if (i2c_dev->hw == &tegra20_i2c_hw || i2c_dev->hw == &tegra30_i2c_hw) i2c_dev->clocks[i2c_dev->nclocks++].id = "fast-clk"; - if (i2c_dev->is_vi) + if (IS_VI(i2c_dev)) i2c_dev->clocks[i2c_dev->nclocks++].id = "slow"; err = devm_clk_bulk_get(i2c_dev->dev, i2c_dev->nclocks, @@ -1790,10 +1821,6 @@ static int tegra_i2c_probe(struct platform_device *pdev) tegra_i2c_parse_dt(i2c_dev); - err = tegra_i2c_init_reset(i2c_dev); - if (err) - return err; - err = tegra_i2c_init_clocks(i2c_dev); if (err) return err; @@ -1809,9 +1836,9 @@ static int tegra_i2c_probe(struct platform_device *pdev) * domain. * * VI I2C device shouldn't be marked as IRQ-safe because VI I2C won't - * be used for atomic transfers. + * be used for atomic transfers. ACPI device is not IRQ safe also. */ - if (!i2c_dev->is_vi) + if (!IS_VI(i2c_dev) && !has_acpi_companion(i2c_dev->dev)) pm_runtime_irq_safe(i2c_dev->dev); pm_runtime_enable(i2c_dev->dev); @@ -1854,7 +1881,7 @@ release_clocks: return err; } -static int tegra_i2c_remove(struct platform_device *pdev) +static void tegra_i2c_remove(struct platform_device *pdev) { struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev); @@ -1863,8 +1890,6 @@ static int tegra_i2c_remove(struct platform_device *pdev) tegra_i2c_release_dma(i2c_dev); tegra_i2c_release_clocks(i2c_dev); - - return 0; } static int __maybe_unused tegra_i2c_runtime_resume(struct device *dev) @@ -1885,7 +1910,7 @@ static int __maybe_unused tegra_i2c_runtime_resume(struct device *dev) * power ON/OFF during runtime PM resume/suspend, meaning that * controller needs to be re-initialized after power ON. */ - if (i2c_dev->is_vi) { + if (IS_VI(i2c_dev)) { err = tegra_i2c_init(i2c_dev); if (err) goto disable_clocks; diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c index a77cd86fe75e..3959f23fc440 100644 --- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c +++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c @@ -27,7 +27,8 @@ #define PCI_DEVICE_ID_THUNDER_TWSI 0xa012 -#define SYS_FREQ_DEFAULT 700000000 +#define SYS_FREQ_DEFAULT 800000000 +#define OTX2_REF_FREQ_DEFAULT 100000000 #define TWSI_INT_ENA_W1C 0x1028 #define TWSI_INT_ENA_W1S 0x1030 @@ -71,7 +72,7 @@ static u32 thunderx_i2c_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm thunderx_i2c_algo = { - .master_xfer = octeon_i2c_xfer, + .xfer = octeon_i2c_xfer, .functionality = thunderx_i2c_functionality, }; @@ -99,7 +100,8 @@ static void thunder_i2c_clock_enable(struct device *dev, struct octeon_i2c *i2c) i2c->sys_freq = clk_get_rate(i2c->clk); } else { /* ACPI */ - device_property_read_u32(dev, "sclk", &i2c->sys_freq); + if (device_property_read_u32(dev, "sclk", &i2c->sys_freq)) + device_property_read_u32(dev, "ioclk", &i2c->sys_freq); } skip: @@ -165,6 +167,10 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev, i2c->roff.sw_twsi = 0x1000; i2c->roff.twsi_int = 0x1010; i2c->roff.sw_twsi_ext = 0x1018; + i2c->roff.mode = 0x1038; + i2c->roff.block_ctl = 0x1048; + i2c->roff.block_sts = 0x1050; + i2c->roff.block_fifo = 0x1058; i2c->dev = dev; pci_set_drvdata(pdev, i2c); @@ -172,7 +178,7 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev, if (ret) return ret; - ret = pci_request_regions(pdev, DRV_NAME); + ret = pcim_request_all_regions(pdev, DRV_NAME); if (ret) return ret; @@ -205,6 +211,12 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev, if (ret) goto error; + /* + * For OcteonTX2 chips, set reference frequency to 100MHz + * as refclk_src in TWSI_MODE register defaults to 100MHz. + */ + if (octeon_i2c_is_otx2(pdev) && IS_LS_FREQ(i2c->twsi_freq)) + i2c->sys_freq = OTX2_REF_FREQ_DEFAULT; octeon_i2c_set_clock(i2c); i2c->adap = thunderx_i2c_ops; diff --git a/drivers/i2c/busses/i2c-tiny-usb.c b/drivers/i2c/busses/i2c-tiny-usb.c index 7279ca0eaa2d..57dfe5f1a7d9 100644 --- a/drivers/i2c/busses/i2c-tiny-usb.c +++ b/drivers/i2c/busses/i2c-tiny-usb.c @@ -10,6 +10,7 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/string_choices.h> #include <linux/types.h> /* include interfaces to usb layer */ @@ -54,8 +55,6 @@ static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) struct i2c_msg *pmsg; int i, ret; - dev_dbg(&adapter->dev, "master xfer %d messages:\n", num); - pstatus = kmalloc(sizeof(*pstatus), GFP_KERNEL); if (!pstatus) return -ENOMEM; @@ -73,7 +72,7 @@ static int usb_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num) dev_dbg(&adapter->dev, " %d: %s (flags %d) %d bytes to 0x%02x\n", - i, pmsg->flags & I2C_M_RD ? "read" : "write", + i, str_read_write(pmsg->flags & I2C_M_RD), pmsg->flags, pmsg->len, pmsg->addr); /* and directly send the message */ @@ -140,10 +139,15 @@ out: return ret; } +/* prevent invalid 0-length usb_control_msg */ +static const struct i2c_adapter_quirks usb_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN_READ, +}; + /* This is the actual algorithm we define */ static const struct i2c_algorithm usb_algorithm = { - .master_xfer = usb_xfer, - .functionality = usb_func, + .xfer = usb_xfer, + .functionality = usb_func, }; /* ----- end of i2c layer ------------------------------------------------ */ @@ -222,14 +226,16 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface, int retval = -ENOMEM; u16 version; + if (interface->intf_assoc && + interface->intf_assoc->bFunctionClass != USB_CLASS_VENDOR_SPEC) + return -ENODEV; + dev_dbg(&interface->dev, "probing usb device\n"); /* allocate memory for our device state and initialize it */ dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (dev == NULL) { - dev_err(&interface->dev, "Out of memory\n"); + if (!dev) goto error; - } dev->usb_dev = usb_get_dev(interface_to_usbdev(interface)); dev->interface = interface; @@ -246,6 +252,7 @@ static int i2c_tiny_usb_probe(struct usb_interface *interface, /* setup i2c adapter description */ dev->adapter.owner = THIS_MODULE; dev->adapter.class = I2C_CLASS_HWMON; + dev->adapter.quirks = &usb_quirks; dev->adapter.algo = &usb_algorithm; dev->adapter.algo_data = dev; snprintf(dev->adapter.name, sizeof(dev->adapter.name), diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c index d7b622891e52..ca0358e8f928 100644 --- a/drivers/i2c/busses/i2c-uniphier-f.c +++ b/drivers/i2c/busses/i2c-uniphier-f.c @@ -12,15 +12,15 @@ #include <linux/platform_device.h> #define UNIPHIER_FI2C_CR 0x00 /* control register */ -#define UNIPHIER_FI2C_CR_MST BIT(3) /* master mode */ +#define UNIPHIER_FI2C_CR_MST BIT(3) /* controller mode */ #define UNIPHIER_FI2C_CR_STA BIT(2) /* start condition */ #define UNIPHIER_FI2C_CR_STO BIT(1) /* stop condition */ #define UNIPHIER_FI2C_CR_NACK BIT(0) /* do not return ACK */ #define UNIPHIER_FI2C_DTTX 0x04 /* TX FIFO */ -#define UNIPHIER_FI2C_DTTX_CMD BIT(8) /* send command (slave addr) */ +#define UNIPHIER_FI2C_DTTX_CMD BIT(8) /* send command (target addr) */ #define UNIPHIER_FI2C_DTTX_RD BIT(0) /* read transaction */ #define UNIPHIER_FI2C_DTRX 0x04 /* RX FIFO */ -#define UNIPHIER_FI2C_SLAD 0x0c /* slave address */ +#define UNIPHIER_FI2C_SLAD 0x0c /* target address */ #define UNIPHIER_FI2C_CYC 0x10 /* clock cycle control */ #define UNIPHIER_FI2C_LCTL 0x14 /* clock low period control */ #define UNIPHIER_FI2C_SSUT 0x18 /* restart/stop setup time control */ @@ -96,7 +96,7 @@ static void uniphier_fi2c_fill_txfifo(struct uniphier_fi2c_priv *priv, int fifo_space = UNIPHIER_FI2C_FIFO_SIZE; /* - * TX-FIFO stores slave address in it for the first access. + * TX-FIFO stores target address in it for the first access. * Decrement the counter. */ if (first) @@ -252,7 +252,7 @@ static void uniphier_fi2c_tx_init(struct uniphier_fi2c_priv *priv, u16 addr, /* do not use TX byte counter */ writel(0, priv->membase + UNIPHIER_FI2C_TBC); - /* set slave address */ + /* set target address */ writel(UNIPHIER_FI2C_DTTX_CMD | addr << 1, priv->membase + UNIPHIER_FI2C_DTTX); /* @@ -288,7 +288,7 @@ static void uniphier_fi2c_rx_init(struct uniphier_fi2c_priv *priv, u16 addr) uniphier_fi2c_set_irqs(priv); - /* set slave address with RD bit */ + /* set target address with RD bit */ writel(UNIPHIER_FI2C_DTTX_CMD | UNIPHIER_FI2C_DTTX_RD | addr << 1, priv->membase + UNIPHIER_FI2C_DTTX); } @@ -310,9 +310,8 @@ static void uniphier_fi2c_recover(struct uniphier_fi2c_priv *priv) i2c_recover_bus(&priv->adap); } -static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap, - struct i2c_msg *msg, bool repeat, - bool stop) +static int uniphier_fi2c_xfer_one(struct i2c_adapter *adap, struct i2c_msg *msg, + bool repeat, bool stop) { struct uniphier_fi2c_priv *priv = i2c_get_adapdata(adap); bool is_read = msg->flags & I2C_M_RD; @@ -340,7 +339,7 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap, uniphier_fi2c_tx_init(priv, msg->addr, repeat); /* - * For a repeated START condition, writing a slave address to the FIFO + * For a repeated START condition, writing a target address to the FIFO * kicks the controller. So, the UNIPHIER_FI2C_CR register should be * written only for a non-repeated START condition. */ @@ -358,7 +357,6 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap, spin_unlock_irqrestore(&priv->lock, flags); if (!time_left) { - dev_err(&adap->dev, "transaction timeout.\n"); uniphier_fi2c_recover(priv); return -ETIMEDOUT; } @@ -404,8 +402,7 @@ static int uniphier_fi2c_check_bus_busy(struct i2c_adapter *adap) return 0; } -static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) +static int uniphier_fi2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct i2c_msg *msg, *emsg = msgs + num; bool repeat = false; @@ -419,7 +416,7 @@ static int uniphier_fi2c_master_xfer(struct i2c_adapter *adap, /* Emit STOP if it is the last message or I2C_M_STOP is set. */ bool stop = (msg + 1 == emsg) || (msg->flags & I2C_M_STOP); - ret = uniphier_fi2c_master_xfer_one(adap, msg, repeat, stop); + ret = uniphier_fi2c_xfer_one(adap, msg, repeat, stop); if (ret) return ret; @@ -435,7 +432,7 @@ static u32 uniphier_fi2c_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm uniphier_fi2c_algo = { - .master_xfer = uniphier_fi2c_master_xfer, + .xfer = uniphier_fi2c_xfer, .functionality = uniphier_fi2c_functionality, }; @@ -535,27 +532,16 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) if (of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed)) bus_speed = I2C_MAX_STANDARD_MODE_FREQ; - if (!bus_speed || bus_speed > I2C_MAX_FAST_MODE_FREQ) { - dev_err(dev, "invalid clock-frequency %d\n", bus_speed); - return -EINVAL; - } - - priv->clk = devm_clk_get(dev, NULL); - if (IS_ERR(priv->clk)) { - dev_err(dev, "failed to get clock\n"); - return PTR_ERR(priv->clk); - } + if (!bus_speed || bus_speed > I2C_MAX_FAST_MODE_FREQ) + return dev_err_probe(dev, -EINVAL, "invalid clock-frequency %d\n", bus_speed); - ret = clk_prepare_enable(priv->clk); - if (ret) - return ret; + priv->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(priv->clk)) + return dev_err_probe(dev, PTR_ERR(priv->clk), "failed to enable clock\n"); clk_rate = clk_get_rate(priv->clk); - if (!clk_rate) { - dev_err(dev, "input clock rate should not be zero\n"); - ret = -EINVAL; - goto disable_clk; - } + if (!clk_rate) + return dev_err_probe(dev, -EINVAL, "input clock rate should not be zero\n"); priv->clk_cycle = clk_rate / bus_speed; init_completion(&priv->comp); @@ -573,27 +559,17 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0, pdev->name, priv); - if (ret) { - dev_err(dev, "failed to request irq %d\n", irq); - goto disable_clk; - } - - ret = i2c_add_adapter(&priv->adap); -disable_clk: if (ret) - clk_disable_unprepare(priv->clk); + return dev_err_probe(dev, ret, "failed to request irq %d\n", irq); - return ret; + return i2c_add_adapter(&priv->adap); } -static int uniphier_fi2c_remove(struct platform_device *pdev) +static void uniphier_fi2c_remove(struct platform_device *pdev) { struct uniphier_fi2c_priv *priv = platform_get_drvdata(pdev); i2c_del_adapter(&priv->adap); - clk_disable_unprepare(priv->clk); - - return 0; } static int __maybe_unused uniphier_fi2c_suspend(struct device *dev) diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c index e3ebae381f08..9d49a3d5d612 100644 --- a/drivers/i2c/busses/i2c-uniphier.c +++ b/drivers/i2c/busses/i2c-uniphier.c @@ -17,13 +17,13 @@ #define UNIPHIER_I2C_DTRM_NACK BIT(8) /* do not return ACK */ #define UNIPHIER_I2C_DTRM_RD BIT(0) /* read transaction */ #define UNIPHIER_I2C_DREC 0x04 /* RX register */ -#define UNIPHIER_I2C_DREC_MST BIT(14) /* 1 = master, 0 = slave */ +#define UNIPHIER_I2C_DREC_MST BIT(14) /* 1 = controller, 0 = target */ #define UNIPHIER_I2C_DREC_TX BIT(13) /* 1 = transmit, 0 = receive */ #define UNIPHIER_I2C_DREC_STS BIT(12) /* stop condition detected */ #define UNIPHIER_I2C_DREC_LRB BIT(11) /* no ACK */ #define UNIPHIER_I2C_DREC_LAB BIT(9) /* arbitration lost */ #define UNIPHIER_I2C_DREC_BBN BIT(8) /* bus not busy */ -#define UNIPHIER_I2C_MYAD 0x08 /* slave address */ +#define UNIPHIER_I2C_MYAD 0x08 /* local target address */ #define UNIPHIER_I2C_CLK 0x0c /* clock frequency control */ #define UNIPHIER_I2C_BRST 0x10 /* bus reset */ #define UNIPHIER_I2C_BRST_FOEN BIT(1) /* normal operation */ @@ -71,10 +71,8 @@ static int uniphier_i2c_xfer_byte(struct i2c_adapter *adap, u32 txdata, writel(txdata, priv->membase + UNIPHIER_I2C_DTRM); time_left = wait_for_completion_timeout(&priv->comp, adap->timeout); - if (unlikely(!time_left)) { - dev_err(&adap->dev, "transaction timeout\n"); + if (unlikely(!time_left)) return -ETIMEDOUT; - } rxdata = readl(priv->membase + UNIPHIER_I2C_DREC); if (rxdatap) @@ -154,8 +152,8 @@ static int uniphier_i2c_stop(struct i2c_adapter *adap) UNIPHIER_I2C_DTRM_NACK); } -static int uniphier_i2c_master_xfer_one(struct i2c_adapter *adap, - struct i2c_msg *msg, bool stop) +static int uniphier_i2c_xfer_one(struct i2c_adapter *adap, + struct i2c_msg *msg, bool stop) { bool is_read = msg->flags & I2C_M_RD; bool recovery = false; @@ -213,8 +211,7 @@ static int uniphier_i2c_check_bus_busy(struct i2c_adapter *adap) return 0; } -static int uniphier_i2c_master_xfer(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) +static int uniphier_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { struct i2c_msg *msg, *emsg = msgs + num; int ret; @@ -227,7 +224,7 @@ static int uniphier_i2c_master_xfer(struct i2c_adapter *adap, /* Emit STOP if it is the last message or I2C_M_STOP is set. */ bool stop = (msg + 1 == emsg) || (msg->flags & I2C_M_STOP); - ret = uniphier_i2c_master_xfer_one(adap, msg, stop); + ret = uniphier_i2c_xfer_one(adap, msg, stop); if (ret) return ret; } @@ -241,7 +238,7 @@ static u32 uniphier_i2c_functionality(struct i2c_adapter *adap) } static const struct i2c_algorithm uniphier_i2c_algo = { - .master_xfer = uniphier_i2c_master_xfer, + .xfer = uniphier_i2c_xfer, .functionality = uniphier_i2c_functionality, }; @@ -330,27 +327,16 @@ static int uniphier_i2c_probe(struct platform_device *pdev) if (of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed)) bus_speed = I2C_MAX_STANDARD_MODE_FREQ; - if (!bus_speed || bus_speed > I2C_MAX_FAST_MODE_FREQ) { - dev_err(dev, "invalid clock-frequency %d\n", bus_speed); - return -EINVAL; - } - - priv->clk = devm_clk_get(dev, NULL); - if (IS_ERR(priv->clk)) { - dev_err(dev, "failed to get clock\n"); - return PTR_ERR(priv->clk); - } + if (!bus_speed || bus_speed > I2C_MAX_FAST_MODE_FREQ) + return dev_err_probe(dev, -EINVAL, "invalid clock-frequency %d\n", bus_speed); - ret = clk_prepare_enable(priv->clk); - if (ret) - return ret; + priv->clk = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(priv->clk)) + return dev_err_probe(dev, PTR_ERR(priv->clk), "failed to enable clock\n"); clk_rate = clk_get_rate(priv->clk); - if (!clk_rate) { - dev_err(dev, "input clock rate should not be zero\n"); - ret = -EINVAL; - goto disable_clk; - } + if (!clk_rate) + return dev_err_probe(dev, -EINVAL, "input clock rate should not be zero\n"); priv->clk_cycle = clk_rate / bus_speed; init_completion(&priv->comp); @@ -367,27 +353,17 @@ static int uniphier_i2c_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name, priv); - if (ret) { - dev_err(dev, "failed to request irq %d\n", irq); - goto disable_clk; - } - - ret = i2c_add_adapter(&priv->adap); -disable_clk: if (ret) - clk_disable_unprepare(priv->clk); + return dev_err_probe(dev, ret, "failed to request irq %d\n", irq); - return ret; + return i2c_add_adapter(&priv->adap); } -static int uniphier_i2c_remove(struct platform_device *pdev) +static void uniphier_i2c_remove(struct platform_device *pdev) { struct uniphier_i2c_priv *priv = platform_get_drvdata(pdev); i2c_del_adapter(&priv->adap); - clk_disable_unprepare(priv->clk); - - return 0; } static int __maybe_unused uniphier_i2c_suspend(struct device *dev) diff --git a/drivers/i2c/busses/i2c-usbio.c b/drivers/i2c/busses/i2c-usbio.c new file mode 100644 index 000000000000..e7799abf6787 --- /dev/null +++ b/drivers/i2c/busses/i2c-usbio.c @@ -0,0 +1,321 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2025 Intel Corporation. + * Copyright (c) 2025 Red Hat, Inc. + */ + +#include <linux/auxiliary_bus.h> +#include <linux/dev_printk.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/types.h> +#include <linux/usb/usbio.h> + +#define I2C_RW_OVERHEAD (sizeof(struct usbio_bulk_packet) + sizeof(struct usbio_i2c_rw)) + +struct usbio_i2c { + struct i2c_adapter adap; + struct auxiliary_device *adev; + struct usbio_i2c_rw *rwbuf; + unsigned long quirks; + u32 speed; + u16 txbuf_len; + u16 rxbuf_len; +}; + +static const struct acpi_device_id usbio_i2c_acpi_hids[] = { + { "INTC1008" }, /* MTL */ + { "INTC10B3" }, /* ARL */ + { "INTC10B6" }, /* LNL */ + { "INTC10D2" }, /* MTL-CVF */ + { "INTC10E3" }, /* PTL */ + { } +}; + +static const u32 usbio_i2c_speeds[] = { + I2C_MAX_STANDARD_MODE_FREQ, + I2C_MAX_FAST_MODE_FREQ, + I2C_MAX_FAST_MODE_PLUS_FREQ, + I2C_MAX_HIGH_SPEED_MODE_FREQ +}; + +static void usbio_i2c_uninit(struct i2c_adapter *adap, struct i2c_msg *msg) +{ + struct usbio_i2c *i2c = i2c_get_adapdata(adap); + struct usbio_i2c_uninit ubuf; + + ubuf.busid = i2c->adev->id; + ubuf.config = cpu_to_le16(msg->addr); + + usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, USBIO_I2CCMD_UNINIT, true, + &ubuf, sizeof(ubuf), NULL, 0); +} + +static int usbio_i2c_init(struct i2c_adapter *adap, struct i2c_msg *msg) +{ + struct usbio_i2c *i2c = i2c_get_adapdata(adap); + struct usbio_i2c_init ibuf; + void *reply_buf; + u16 reply_len; + int ret; + + ibuf.busid = i2c->adev->id; + ibuf.config = cpu_to_le16(msg->addr); + ibuf.speed = cpu_to_le32(i2c->speed); + + if (i2c->quirks & USBIO_QUIRK_I2C_NO_INIT_ACK) { + reply_buf = NULL; + reply_len = 0; + } else { + reply_buf = &ibuf; + reply_len = sizeof(ibuf); + } + + ret = usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, USBIO_I2CCMD_INIT, true, + &ibuf, sizeof(ibuf), reply_buf, reply_len); + if (ret != sizeof(ibuf)) + return (ret < 0) ? ret : -EIO; + + return 0; +} + +static int usbio_i2c_read(struct i2c_adapter *adap, struct i2c_msg *msg) +{ + struct usbio_i2c *i2c = i2c_get_adapdata(adap); + u16 rxchunk = i2c->rxbuf_len - I2C_RW_OVERHEAD; + struct usbio_i2c_rw *rbuf = i2c->rwbuf; + int ret; + + rbuf->busid = i2c->adev->id; + rbuf->config = cpu_to_le16(msg->addr); + rbuf->size = cpu_to_le16(msg->len); + + if (msg->len > rxchunk) { + /* Need to split the input buffer */ + u16 len = 0; + + do { + if (msg->len - len < rxchunk) + rxchunk = msg->len - len; + + ret = usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, + USBIO_I2CCMD_READ, true, + rbuf, len == 0 ? sizeof(*rbuf) : 0, + rbuf, sizeof(*rbuf) + rxchunk); + if (ret < 0) + return ret; + + memcpy(&msg->buf[len], rbuf->data, rxchunk); + len += rxchunk; + } while (msg->len > len); + + return 0; + } + + ret = usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, USBIO_I2CCMD_READ, true, + rbuf, sizeof(*rbuf), rbuf, sizeof(*rbuf) + msg->len); + if (ret != sizeof(*rbuf) + msg->len) + return (ret < 0) ? ret : -EIO; + + memcpy(msg->buf, rbuf->data, msg->len); + + return 0; +} + +static int usbio_i2c_write(struct i2c_adapter *adap, struct i2c_msg *msg) +{ + struct usbio_i2c *i2c = i2c_get_adapdata(adap); + u16 txchunk = i2c->txbuf_len - I2C_RW_OVERHEAD; + struct usbio_i2c_rw *wbuf = i2c->rwbuf; + int ret; + + if (msg->len > txchunk) { + /* Need to split the output buffer */ + u16 len = 0; + + do { + wbuf->busid = i2c->adev->id; + wbuf->config = cpu_to_le16(msg->addr); + + if (i2c->quirks & USBIO_QUIRK_I2C_USE_CHUNK_LEN) + wbuf->size = cpu_to_le16(txchunk); + else + wbuf->size = cpu_to_le16(msg->len); + + memcpy(wbuf->data, &msg->buf[len], txchunk); + len += txchunk; + + ret = usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, + USBIO_I2CCMD_WRITE, msg->len == len, + wbuf, sizeof(*wbuf) + txchunk, + wbuf, sizeof(*wbuf)); + if (ret < 0) + return ret; + + if (msg->len - len < txchunk) + txchunk = msg->len - len; + } while (msg->len > len); + + return 0; + } + + wbuf->busid = i2c->adev->id; + wbuf->config = cpu_to_le16(msg->addr); + wbuf->size = cpu_to_le16(msg->len); + memcpy(wbuf->data, msg->buf, msg->len); + + ret = usbio_bulk_msg(i2c->adev, USBIO_PKTTYPE_I2C, USBIO_I2CCMD_WRITE, true, + wbuf, sizeof(*wbuf) + msg->len, wbuf, sizeof(*wbuf)); + if (ret != sizeof(*wbuf) || le16_to_cpu(wbuf->size) != msg->len) + return (ret < 0) ? ret : -EIO; + + return 0; +} + +static int usbio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct usbio_i2c *i2c = i2c_get_adapdata(adap); + int ret; + + usbio_acquire(i2c->adev); + + ret = usbio_i2c_init(adap, msgs); + if (ret) + goto out_release; + + for (int i = 0; i < num; ret = ++i) { + if (msgs[i].flags & I2C_M_RD) + ret = usbio_i2c_read(adap, &msgs[i]); + else + ret = usbio_i2c_write(adap, &msgs[i]); + + if (ret) + break; + } + + usbio_i2c_uninit(adap, msgs); + +out_release: + usbio_release(i2c->adev); + + return ret; +} + +static u32 usbio_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_adapter_quirks usbio_i2c_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_NO_REP_START, + .max_read_len = SZ_4K, + .max_write_len = SZ_4K, +}; + +static const struct i2c_adapter_quirks usbio_i2c_quirks_max_rw_len52 = { + .flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_NO_REP_START, + .max_read_len = 52, + .max_write_len = 52, +}; + +static const struct i2c_algorithm usbio_i2c_algo = { + .master_xfer = usbio_i2c_xfer, + .functionality = usbio_i2c_func, +}; + +static int usbio_i2c_probe(struct auxiliary_device *adev, + const struct auxiliary_device_id *adev_id) +{ + struct usbio_i2c_bus_desc *i2c_desc; + struct device *dev = &adev->dev; + struct usbio_i2c *i2c; + u32 max_speed; + int ret; + + i2c_desc = dev_get_platdata(dev); + if (!i2c_desc) + return -EINVAL; + + i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + i2c->adev = adev; + + usbio_acpi_bind(i2c->adev, usbio_i2c_acpi_hids); + usbio_get_txrxbuf_len(i2c->adev, &i2c->txbuf_len, &i2c->rxbuf_len); + + i2c->rwbuf = devm_kzalloc(dev, max(i2c->txbuf_len, i2c->rxbuf_len), GFP_KERNEL); + if (!i2c->rwbuf) + return -ENOMEM; + + i2c->quirks = usbio_get_quirks(i2c->adev); + + max_speed = usbio_i2c_speeds[i2c_desc->caps & USBIO_I2C_BUS_MODE_CAP_MASK]; + if (max_speed < I2C_MAX_FAST_MODE_FREQ && + (i2c->quirks & USBIO_QUIRK_I2C_ALLOW_400KHZ)) + max_speed = I2C_MAX_FAST_MODE_FREQ; + + i2c->speed = i2c_acpi_find_bus_speed(dev); + if (!i2c->speed) + i2c->speed = I2C_MAX_STANDARD_MODE_FREQ; + else if (i2c->speed > max_speed) { + dev_warn(dev, "Invalid speed %u adjusting to bus max %u\n", + i2c->speed, max_speed); + i2c->speed = max_speed; + } + + i2c->adap.owner = THIS_MODULE; + i2c->adap.class = I2C_CLASS_HWMON; + i2c->adap.dev.parent = dev; + i2c->adap.algo = &usbio_i2c_algo; + + if (i2c->quirks & USBIO_QUIRK_I2C_MAX_RW_LEN_52) + i2c->adap.quirks = &usbio_i2c_quirks_max_rw_len52; + else + i2c->adap.quirks = &usbio_i2c_quirks; + + snprintf(i2c->adap.name, sizeof(i2c->adap.name), "%s.%d", + USBIO_I2C_CLIENT, i2c->adev->id); + + device_set_node(&i2c->adap.dev, dev_fwnode(&adev->dev)); + + auxiliary_set_drvdata(adev, i2c); + i2c_set_adapdata(&i2c->adap, i2c); + + ret = i2c_add_adapter(&i2c->adap); + if (ret) + return ret; + + if (has_acpi_companion(&i2c->adap.dev)) + acpi_dev_clear_dependencies(ACPI_COMPANION(&i2c->adap.dev)); + + return 0; +} + +static void usbio_i2c_remove(struct auxiliary_device *adev) +{ + struct usbio_i2c *i2c = auxiliary_get_drvdata(adev); + + i2c_del_adapter(&i2c->adap); +} + +static const struct auxiliary_device_id usbio_i2c_id_table[] = { + { "usbio.usbio-i2c" }, + { } +}; +MODULE_DEVICE_TABLE(auxiliary, usbio_i2c_id_table); + +static struct auxiliary_driver usbio_i2c_driver = { + .name = USBIO_I2C_CLIENT, + .probe = usbio_i2c_probe, + .remove = usbio_i2c_remove, + .id_table = usbio_i2c_id_table +}; +module_auxiliary_driver(usbio_i2c_driver); + +MODULE_DESCRIPTION("Intel USBIO I2C driver"); +MODULE_AUTHOR("Israel Cepeda <israel.a.cepeda.lopez@intel.com>"); +MODULE_AUTHOR("Hans de Goede <hansg@kernel.org>"); +MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS("USBIO"); diff --git a/drivers/i2c/busses/i2c-versatile.c b/drivers/i2c/busses/i2c-versatile.c index 1ab419f8fa52..a1ab6ef6f071 100644 --- a/drivers/i2c/busses/i2c-versatile.c +++ b/drivers/i2c/busses/i2c-versatile.c @@ -64,15 +64,13 @@ static const struct i2c_algo_bit_data i2c_versatile_algo = { static int i2c_versatile_probe(struct platform_device *dev) { struct i2c_versatile *i2c; - struct resource *r; int ret; i2c = devm_kzalloc(&dev->dev, sizeof(struct i2c_versatile), GFP_KERNEL); if (!i2c) return -ENOMEM; - r = platform_get_resource(dev, IORESOURCE_MEM, 0); - i2c->base = devm_ioremap_resource(&dev->dev, r); + i2c->base = devm_platform_get_and_ioremap_resource(dev, 0, NULL); if (IS_ERR(i2c->base)) return PTR_ERR(i2c->base); @@ -96,12 +94,11 @@ static int i2c_versatile_probe(struct platform_device *dev) return 0; } -static int i2c_versatile_remove(struct platform_device *dev) +static void i2c_versatile_remove(struct platform_device *dev) { struct i2c_versatile *i2c = platform_get_drvdata(dev); i2c_del_adapter(&i2c->adap); - return 0; } static const struct of_device_id i2c_versatile_match[] = { diff --git a/drivers/i2c/busses/i2c-via.c b/drivers/i2c/busses/i2c-via.c index ad4f09c7f027..2c26a57883f2 100644 --- a/drivers/i2c/busses/i2c-via.c +++ b/drivers/i2c/busses/i2c-via.c @@ -70,7 +70,7 @@ static struct i2c_algo_bit_data bit_data = { static struct i2c_adapter vt586b_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .name = "VIA i2c", .algo_data = &bit_data, }; @@ -89,10 +89,9 @@ static int vt586b_probe(struct pci_dev *dev, const struct pci_device_id *id) u8 rev; int res; - if (pm_io_base) { - dev_err(&dev->dev, "i2c-via: Will only support one host\n"); - return -ENODEV; - } + if (pm_io_base) + return dev_err_probe(&dev->dev, -ENODEV, + "Will only support one host\n"); pci_read_config_byte(dev, PM_CFG_REVID, &rev); @@ -113,10 +112,10 @@ static int vt586b_probe(struct pci_dev *dev, const struct pci_device_id *id) pci_read_config_word(dev, base, &pm_io_base); pm_io_base &= (0xff << 8); - if (!request_region(I2C_DIR, IOSPACE, vt586b_driver.name)) { - dev_err(&dev->dev, "IO 0x%x-0x%x already in use\n", I2C_DIR, I2C_DIR + IOSPACE); - return -ENODEV; - } + if (!request_region(I2C_DIR, IOSPACE, vt586b_driver.name)) + return dev_err_probe(&dev->dev, -ENODEV, + "IO 0x%x-0x%x already in use\n", + I2C_DIR, I2C_DIR + IOSPACE); outb(inb(I2C_DIR) & ~(I2C_SDA | I2C_SCL), I2C_DIR); outb(inb(I2C_OUT) & ~(I2C_SDA | I2C_SCL), I2C_OUT); diff --git a/drivers/i2c/busses/i2c-viai2c-common.c b/drivers/i2c/busses/i2c-viai2c-common.c new file mode 100644 index 000000000000..5a53ed95a59b --- /dev/null +++ b/drivers/i2c/busses/i2c-viai2c-common.c @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#include <linux/of_irq.h> +#include "i2c-viai2c-common.h" + +int viai2c_wait_bus_not_busy(struct viai2c *i2c) +{ + unsigned long timeout; + + timeout = jiffies + VIAI2C_TIMEOUT; + while (!(readw(i2c->base + VIAI2C_REG_CSR) & VIAI2C_CSR_READY_MASK)) { + if (time_after(jiffies, timeout)) { + dev_warn(i2c->dev, "timeout waiting for bus ready\n"); + return -EBUSY; + } + msleep(20); + } + + return 0; +} +EXPORT_SYMBOL_GPL(viai2c_wait_bus_not_busy); + +static int viai2c_write(struct viai2c *i2c, struct i2c_msg *pmsg, int last) +{ + u16 val, tcr_val = i2c->tcr; + + i2c->last = last; + + if (pmsg->len == 0) { + /* + * We still need to run through the while (..) once, so + * start at -1 and break out early from the loop + */ + i2c->xfered_len = -1; + writew(0, i2c->base + VIAI2C_REG_CDR); + } else { + writew(pmsg->buf[0] & 0xFF, i2c->base + VIAI2C_REG_CDR); + } + + if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) { + val = readw(i2c->base + VIAI2C_REG_CR); + val &= ~VIAI2C_CR_TX_END; + val |= VIAI2C_CR_CPU_RDY; + writew(val, i2c->base + VIAI2C_REG_CR); + } + + reinit_completion(&i2c->complete); + + tcr_val |= pmsg->addr & VIAI2C_TCR_ADDR_MASK; + + writew(tcr_val, i2c->base + VIAI2C_REG_TCR); + + if (i2c->platform == VIAI2C_PLAT_WMT && pmsg->flags & I2C_M_NOSTART) { + val = readw(i2c->base + VIAI2C_REG_CR); + val |= VIAI2C_CR_CPU_RDY; + writew(val, i2c->base + VIAI2C_REG_CR); + } + + if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT)) + return -ETIMEDOUT; + + return i2c->ret; +} + +static int viai2c_read(struct viai2c *i2c, struct i2c_msg *pmsg, bool first) +{ + u16 val, tcr_val = i2c->tcr; + + val = readw(i2c->base + VIAI2C_REG_CR); + val &= ~(VIAI2C_CR_TX_END | VIAI2C_CR_RX_END); + + if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) + val |= VIAI2C_CR_CPU_RDY; + + if (pmsg->len == 1) + val |= VIAI2C_CR_RX_END; + + writew(val, i2c->base + VIAI2C_REG_CR); + + reinit_completion(&i2c->complete); + + tcr_val |= VIAI2C_TCR_READ | (pmsg->addr & VIAI2C_TCR_ADDR_MASK); + + writew(tcr_val, i2c->base + VIAI2C_REG_TCR); + + if ((i2c->platform == VIAI2C_PLAT_WMT && (pmsg->flags & I2C_M_NOSTART)) || + (i2c->platform == VIAI2C_PLAT_ZHAOXIN && !first)) { + val = readw(i2c->base + VIAI2C_REG_CR); + val |= VIAI2C_CR_CPU_RDY; + writew(val, i2c->base + VIAI2C_REG_CR); + } + + if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT)) + return -ETIMEDOUT; + + return i2c->ret; +} + +int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct i2c_msg *pmsg; + int i; + int ret = 0; + struct viai2c *i2c = i2c_get_adapdata(adap); + + i2c->mode = VIAI2C_BYTE_MODE; + for (i = 0; ret >= 0 && i < num; i++) { + pmsg = &msgs[i]; + if (i2c->platform == VIAI2C_PLAT_WMT && !(pmsg->flags & I2C_M_NOSTART)) { + ret = viai2c_wait_bus_not_busy(i2c); + if (ret < 0) + return ret; + } + + i2c->msg = pmsg; + i2c->xfered_len = 0; + + if (pmsg->flags & I2C_M_RD) + ret = viai2c_read(i2c, pmsg, i == 0); + else + ret = viai2c_write(i2c, pmsg, (i + 1) == num); + } + + return (ret < 0) ? ret : i; +} +EXPORT_SYMBOL_GPL(viai2c_xfer); + +/* + * Main process of the byte mode xfer + * + * Return value indicates whether the transfer is complete + * 1: all the data has been successfully transferred + * 0: there is still data that needs to be transferred + * -EIO: error occurred + */ +int viai2c_irq_xfer(struct viai2c *i2c) +{ + u16 val; + struct i2c_msg *msg = i2c->msg; + u8 read = msg->flags & I2C_M_RD; + void __iomem *base = i2c->base; + + if (read) { + msg->buf[i2c->xfered_len] = readw(base + VIAI2C_REG_CDR) >> 8; + + val = readw(base + VIAI2C_REG_CR) | VIAI2C_CR_CPU_RDY; + if (i2c->xfered_len == msg->len - 2) + val |= VIAI2C_CR_RX_END; + writew(val, base + VIAI2C_REG_CR); + } else { + val = readw(base + VIAI2C_REG_CSR); + if (val & VIAI2C_CSR_RCV_NOT_ACK) + return -EIO; + + /* I2C_SMBUS_QUICK */ + if (msg->len == 0) { + val = VIAI2C_CR_TX_END | VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE; + writew(val, base + VIAI2C_REG_CR); + return 1; + } + + if ((i2c->xfered_len + 1) == msg->len) { + if (i2c->platform == VIAI2C_PLAT_WMT && !i2c->last) + writew(VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR); + else if (i2c->platform == VIAI2C_PLAT_ZHAOXIN && i2c->last) + writeb(VIAI2C_CR_TX_END, base + VIAI2C_REG_CR); + } else { + writew(msg->buf[i2c->xfered_len + 1] & 0xFF, base + VIAI2C_REG_CDR); + writew(VIAI2C_CR_CPU_RDY | VIAI2C_CR_ENABLE, base + VIAI2C_REG_CR); + } + } + + i2c->xfered_len++; + + return i2c->xfered_len == msg->len; +} +EXPORT_SYMBOL_GPL(viai2c_irq_xfer); + +int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat) +{ + struct viai2c *i2c; + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, NULL); + if (IS_ERR(i2c->base)) + return PTR_ERR(i2c->base); + + i2c->platform = plat; + + i2c->dev = &pdev->dev; + init_completion(&i2c->complete); + platform_set_drvdata(pdev, i2c); + + *pi2c = i2c; + return 0; +} +EXPORT_SYMBOL_GPL(viai2c_init); + +MODULE_DESCRIPTION("Via/Wondermedia/Zhaoxin I2C controller core"); +MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-viai2c-common.h b/drivers/i2c/busses/i2c-viai2c-common.h new file mode 100644 index 000000000000..00f17733223c --- /dev/null +++ b/drivers/i2c/busses/i2c-viai2c-common.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef __I2C_VIAI2C_COMMON_H_ +#define __I2C_VIAI2C_COMMON_H_ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of_irq.h> +#include <linux/platform_device.h> + +/* REG_CR Bit fields */ +#define VIAI2C_REG_CR 0x00 +#define VIAI2C_CR_ENABLE BIT(0) +#define VIAI2C_CR_RX_END BIT(1) +#define VIAI2C_CR_TX_END BIT(2) +#define VIAI2C_CR_CPU_RDY BIT(3) +#define VIAI2C_CR_END_MASK GENMASK(2, 1) + +/* REG_TCR Bit fields */ +#define VIAI2C_REG_TCR 0x02 +#define VIAI2C_TCR_HS_MODE BIT(13) +#define VIAI2C_TCR_READ BIT(14) +#define VIAI2C_TCR_FAST BIT(15) +#define VIAI2C_TCR_ADDR_MASK GENMASK(6, 0) + +/* REG_CSR Bit fields */ +#define VIAI2C_REG_CSR 0x04 +#define VIAI2C_CSR_RCV_NOT_ACK BIT(0) +#define VIAI2C_CSR_RCV_ACK_MASK BIT(0) +#define VIAI2C_CSR_READY_MASK BIT(1) + +/* REG_ISR Bit fields */ +#define VIAI2C_REG_ISR 0x06 +#define VIAI2C_ISR_NACK_ADDR BIT(0) +#define VIAI2C_ISR_BYTE_END BIT(1) +#define VIAI2C_ISR_SCL_TIMEOUT BIT(2) +#define VIAI2C_ISR_MASK_ALL GENMASK(2, 0) + +/* REG_IMR Bit fields */ +#define VIAI2C_REG_IMR 0x08 +#define VIAI2C_IMR_BYTE BIT(1) +#define VIAI2C_IMR_ENABLE_ALL GENMASK(2, 0) + +#define VIAI2C_REG_CDR 0x0A +#define VIAI2C_REG_TR 0x0C +#define VIAI2C_REG_MCR 0x0E + +#define VIAI2C_TIMEOUT (msecs_to_jiffies(1000)) + +enum { + VIAI2C_PLAT_WMT, + VIAI2C_PLAT_ZHAOXIN +}; + +enum { + VIAI2C_BYTE_MODE, + VIAI2C_FIFO_MODE +}; + +struct viai2c { + struct i2c_adapter adapter; + struct completion complete; + struct device *dev; + void __iomem *base; + struct clk *clk; + u16 tcr; + int irq; + u16 xfered_len; + struct i2c_msg *msg; + int ret; + bool last; + unsigned int mode; + unsigned int platform; + void *pltfm_priv; +}; + +int viai2c_wait_bus_not_busy(struct viai2c *i2c); +int viai2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num); +int viai2c_init(struct platform_device *pdev, struct viai2c **pi2c, int plat); +int viai2c_irq_xfer(struct viai2c *i2c); + +#endif diff --git a/drivers/i2c/busses/i2c-viai2c-wmt.c b/drivers/i2c/busses/i2c-viai2c-wmt.c new file mode 100644 index 000000000000..2cf3cc0165fb --- /dev/null +++ b/drivers/i2c/busses/i2c-viai2c-wmt.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Wondermedia I2C Controller Driver + * + * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> + * + * Derived from GPLv2+ licensed source: + * - Copyright (C) 2008 WonderMedia Technologies, Inc. + */ + +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include "i2c-viai2c-common.h" + +#define REG_SLAVE_CR 0x10 +#define REG_SLAVE_SR 0x12 +#define REG_SLAVE_ISR 0x14 +#define REG_SLAVE_IMR 0x16 +#define REG_SLAVE_DR 0x18 +#define REG_SLAVE_TR 0x1A + +/* REG_TR */ +#define SCL_TIMEOUT(x) (((x) & 0xFF) << 8) +#define TR_STD 0x0064 +#define TR_HS 0x0019 + +/* REG_MCR */ +#define MCR_APB_96M 7 +#define MCR_APB_166M 12 + +static u32 wmt_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART; +} + +static const struct i2c_algorithm wmt_i2c_algo = { + .xfer = viai2c_xfer, + .functionality = wmt_i2c_func, +}; + +static int wmt_i2c_reset_hardware(struct viai2c *i2c) +{ + int err; + + err = clk_prepare_enable(i2c->clk); + if (err) + return dev_err_probe(i2c->dev, err, "failed to enable clock\n"); + + err = clk_set_rate(i2c->clk, 20000000); + if (err) { + clk_disable_unprepare(i2c->clk); + return dev_err_probe(i2c->dev, err, "failed to set clock = 20Mhz\n"); + } + + writew(0, i2c->base + VIAI2C_REG_CR); + writew(MCR_APB_166M, i2c->base + VIAI2C_REG_MCR); + writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR); + writew(VIAI2C_IMR_ENABLE_ALL, i2c->base + VIAI2C_REG_IMR); + writew(VIAI2C_CR_ENABLE, i2c->base + VIAI2C_REG_CR); + readw(i2c->base + VIAI2C_REG_CSR); /* read clear */ + writew(VIAI2C_ISR_MASK_ALL, i2c->base + VIAI2C_REG_ISR); + + if (i2c->tcr == VIAI2C_TCR_FAST) + writew(SCL_TIMEOUT(128) | TR_HS, i2c->base + VIAI2C_REG_TR); + else + writew(SCL_TIMEOUT(128) | TR_STD, i2c->base + VIAI2C_REG_TR); + + return 0; +} + +static irqreturn_t wmt_i2c_isr(int irq, void *data) +{ + struct viai2c *i2c = data; + u8 status; + + /* save the status and write-clear it */ + status = readw(i2c->base + VIAI2C_REG_ISR); + writew(status, i2c->base + VIAI2C_REG_ISR); + + i2c->ret = 0; + if (status & VIAI2C_ISR_NACK_ADDR) + i2c->ret = -EIO; + + if (status & VIAI2C_ISR_SCL_TIMEOUT) + i2c->ret = -ETIMEDOUT; + + if (!i2c->ret) + i2c->ret = viai2c_irq_xfer(i2c); + + /* All the data has been successfully transferred or error occurred */ + if (i2c->ret) + complete(&i2c->complete); + + return IRQ_HANDLED; +} + +static int wmt_i2c_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct viai2c *i2c; + struct i2c_adapter *adap; + int err; + u32 clk_rate; + + err = viai2c_init(pdev, &i2c, VIAI2C_PLAT_WMT); + if (err) + return err; + + i2c->irq = platform_get_irq(pdev, 0); + if (i2c->irq < 0) + return i2c->irq; + + err = devm_request_irq(&pdev->dev, i2c->irq, wmt_i2c_isr, + 0, pdev->name, i2c); + if (err) + return dev_err_probe(&pdev->dev, err, + "failed to request irq %i\n", i2c->irq); + + i2c->clk = of_clk_get(np, 0); + if (IS_ERR(i2c->clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk), + "unable to request clock\n"); + + err = of_property_read_u32(np, "clock-frequency", &clk_rate); + if (!err && clk_rate == I2C_MAX_FAST_MODE_FREQ) + i2c->tcr = VIAI2C_TCR_FAST; + + adap = &i2c->adapter; + i2c_set_adapdata(adap, i2c); + strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name)); + adap->owner = THIS_MODULE; + adap->algo = &wmt_i2c_algo; + adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; + + err = wmt_i2c_reset_hardware(i2c); + if (err) + return err; + + err = i2c_add_adapter(adap); + if (err) + /* wmt_i2c_reset_hardware() enables i2c_dev->clk */ + clk_disable_unprepare(i2c->clk); + + return err; +} + +static void wmt_i2c_remove(struct platform_device *pdev) +{ + struct viai2c *i2c = platform_get_drvdata(pdev); + + /* Disable interrupts, clock and delete adapter */ + writew(0, i2c->base + VIAI2C_REG_IMR); + clk_disable_unprepare(i2c->clk); + i2c_del_adapter(&i2c->adapter); +} + +static const struct of_device_id wmt_i2c_dt_ids[] = { + { .compatible = "wm,wm8505-i2c" }, + { /* Sentinel */ }, +}; + +static struct platform_driver wmt_i2c_driver = { + .probe = wmt_i2c_probe, + .remove = wmt_i2c_remove, + .driver = { + .name = "wmt-i2c", + .of_match_table = wmt_i2c_dt_ids, + }, +}; + +module_platform_driver(wmt_i2c_driver); + +MODULE_DESCRIPTION("Wondermedia I2C controller driver"); +MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids); diff --git a/drivers/i2c/busses/i2c-viai2c-zhaoxin.c b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c new file mode 100644 index 000000000000..95dc64902b7c --- /dev/null +++ b/drivers/i2c/busses/i2c-viai2c-zhaoxin.c @@ -0,0 +1,367 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright(c) 2024 Shanghai Zhaoxin Semiconductor Corporation. + * All rights reserved. + */ + +#include <linux/acpi.h> +#include "i2c-viai2c-common.h" + +/* + * registers + */ +/* Zhaoxin specific register bit fields */ +/* REG_CR Bit fields */ +#define ZXI2C_CR_MST_RST BIT(7) +#define ZXI2C_CR_FIFO_MODE BIT(14) +/* REG_ISR/IMR Bit fields */ +#define ZXI2C_IRQ_FIFONACK BIT(4) +#define ZXI2C_IRQ_FIFOEND BIT(3) +#define ZXI2C_IRQ_MASK (VIAI2C_ISR_MASK_ALL \ + | ZXI2C_IRQ_FIFOEND \ + | ZXI2C_IRQ_FIFONACK) +/* Zhaoxin specific registers */ +#define ZXI2C_REG_CLK 0x10 +#define ZXI2C_CLK_50M BIT(0) +#define ZXI2C_REG_REV 0x11 +#define ZXI2C_REG_HCR 0x12 +#define ZXI2C_HCR_RST_FIFO GENMASK(1, 0) +#define ZXI2C_REG_HTDR 0x13 +#define ZXI2C_REG_HRDR 0x14 +#define ZXI2C_REG_HTLR 0x15 +#define ZXI2C_REG_HRLR 0x16 +#define ZXI2C_REG_HWCNTR 0x18 +#define ZXI2C_REG_HRCNTR 0x19 + +/* parameters Constants */ +#define ZXI2C_GOLD_FSTP_100K 0xF3 +#define ZXI2C_GOLD_FSTP_400K 0x38 +#define ZXI2C_GOLD_FSTP_1M 0x13 +#define ZXI2C_GOLD_FSTP_3400K 0x37 +#define ZXI2C_HS_CTRL_CODE (0x08 << 8) + +#define ZXI2C_FIFO_SIZE 32 + +struct viai2c_zhaoxin { + u8 hrv; + u16 tr; + u16 mcr; + u16 xfer_len; +}; + +static int viai2c_fifo_xfer(struct viai2c *i2c) +{ + u16 i; + u8 tmp; + struct i2c_msg *msg = i2c->msg; + void __iomem *base = i2c->base; + bool read = !!(msg->flags & I2C_M_RD); + struct viai2c_zhaoxin *priv = i2c->pltfm_priv; + + /* reset fifo buffer */ + tmp = ioread8(base + ZXI2C_REG_HCR); + iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR); + + /* set xfer len */ + priv->xfer_len = min_t(u16, msg->len - i2c->xfered_len, ZXI2C_FIFO_SIZE); + if (read) { + iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HRLR); + } else { + iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HTLR); + /* set write data */ + for (i = 0; i < priv->xfer_len; i++) + iowrite8(msg->buf[i2c->xfered_len + i], base + ZXI2C_REG_HTDR); + } + + /* prepare to stop transmission */ + if (priv->hrv && msg->len == (i2c->xfered_len + priv->xfer_len)) { + tmp = ioread8(base + VIAI2C_REG_CR); + tmp |= read ? VIAI2C_CR_RX_END : VIAI2C_CR_TX_END; + iowrite8(tmp, base + VIAI2C_REG_CR); + } + + u16 tcr_val = i2c->tcr; + + /* start transmission */ + tcr_val |= read ? VIAI2C_TCR_READ : 0; + writew(tcr_val | msg->addr, base + VIAI2C_REG_TCR); + + return 0; +} + +static int viai2c_fifo_irq_xfer(struct viai2c *i2c) +{ + u16 i; + u8 tmp; + struct i2c_msg *msg = i2c->msg; + void __iomem *base = i2c->base; + bool read = !!(msg->flags & I2C_M_RD); + struct viai2c_zhaoxin *priv = i2c->pltfm_priv; + + /* get the received data */ + if (read) + for (i = 0; i < priv->xfer_len; i++) + msg->buf[i2c->xfered_len + i] = ioread8(base + ZXI2C_REG_HRDR); + + i2c->xfered_len += priv->xfer_len; + if (i2c->xfered_len == msg->len) + return 1; + + /* reset fifo buffer */ + tmp = ioread8(base + ZXI2C_REG_HCR); + iowrite8(tmp | ZXI2C_HCR_RST_FIFO, base + ZXI2C_REG_HCR); + + /* set xfer len */ + priv->xfer_len = min_t(u16, msg->len - i2c->xfered_len, ZXI2C_FIFO_SIZE); + if (read) { + iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HRLR); + } else { + iowrite8(priv->xfer_len - 1, base + ZXI2C_REG_HTLR); + /* set write data */ + for (i = 0; i < priv->xfer_len; i++) + iowrite8(msg->buf[i2c->xfered_len + i], base + ZXI2C_REG_HTDR); + } + + /* prepare to stop transmission */ + if (priv->hrv && msg->len == (i2c->xfered_len + priv->xfer_len)) { + tmp = ioread8(base + VIAI2C_REG_CR); + tmp |= read ? VIAI2C_CR_RX_END : VIAI2C_CR_TX_END; + iowrite8(tmp, base + VIAI2C_REG_CR); + } + + /* continue transmission */ + tmp = ioread8(base + VIAI2C_REG_CR); + iowrite8(tmp |= VIAI2C_CR_CPU_RDY, base + VIAI2C_REG_CR); + + return 0; +} + +static int zxi2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + u8 tmp; + int ret; + struct viai2c *i2c = (struct viai2c *)i2c_get_adapdata(adap); + struct viai2c_zhaoxin *priv = i2c->pltfm_priv; + void __iomem *base = i2c->base; + + ret = viai2c_wait_bus_not_busy(i2c); + if (ret) + return ret; + + tmp = ioread8(base + VIAI2C_REG_CR); + tmp &= ~(VIAI2C_CR_RX_END | VIAI2C_CR_TX_END); + + if (num == 1 && msgs->len >= 2 && (priv->hrv || msgs->len <= ZXI2C_FIFO_SIZE)) { + /* enable fifo mode */ + iowrite16(ZXI2C_CR_FIFO_MODE | tmp, base + VIAI2C_REG_CR); + /* clear irq status */ + iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR); + /* enable fifo irq */ + iowrite8(VIAI2C_ISR_NACK_ADDR | ZXI2C_IRQ_FIFOEND, base + VIAI2C_REG_IMR); + + i2c->msg = msgs; + i2c->mode = VIAI2C_FIFO_MODE; + priv->xfer_len = 0; + i2c->xfered_len = 0; + + viai2c_fifo_xfer(i2c); + + if (!wait_for_completion_timeout(&i2c->complete, VIAI2C_TIMEOUT)) + return -ETIMEDOUT; + + ret = i2c->ret; + } else { + /* enable byte mode */ + iowrite16(tmp, base + VIAI2C_REG_CR); + /* clear irq status */ + iowrite8(ZXI2C_IRQ_MASK, base + VIAI2C_REG_ISR); + /* enable byte irq */ + iowrite8(VIAI2C_ISR_NACK_ADDR | VIAI2C_IMR_BYTE, base + VIAI2C_REG_IMR); + + ret = viai2c_xfer(adap, msgs, num); + if (ret == -ETIMEDOUT) + iowrite16(tmp | VIAI2C_CR_END_MASK, base + VIAI2C_REG_CR); + } + /* dis interrupt */ + iowrite8(0, base + VIAI2C_REG_IMR); + + return ret; +} + +static u32 zxi2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm zxi2c_algorithm = { + .xfer = zxi2c_xfer, + .functionality = zxi2c_func, +}; + +static const struct i2c_adapter_quirks zxi2c_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN | I2C_AQ_COMB_WRITE_THEN_READ, +}; + +static const u32 zxi2c_speed_params_table[][3] = { + /* speed, ZXI2C_TCR, ZXI2C_FSTP */ + { I2C_MAX_STANDARD_MODE_FREQ, 0, ZXI2C_GOLD_FSTP_100K }, + { I2C_MAX_FAST_MODE_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_400K }, + { I2C_MAX_FAST_MODE_PLUS_FREQ, VIAI2C_TCR_FAST, ZXI2C_GOLD_FSTP_1M }, + { I2C_MAX_HIGH_SPEED_MODE_FREQ, VIAI2C_TCR_HS_MODE | VIAI2C_TCR_FAST, + ZXI2C_GOLD_FSTP_3400K }, +}; + +static void zxi2c_set_bus_speed(struct viai2c *i2c) +{ + struct viai2c_zhaoxin *priv = i2c->pltfm_priv; + + iowrite16(priv->tr, i2c->base + VIAI2C_REG_TR); + iowrite8(ZXI2C_CLK_50M, i2c->base + ZXI2C_REG_CLK); + iowrite16(priv->mcr, i2c->base + VIAI2C_REG_MCR); +} + +static void zxi2c_get_bus_speed(struct viai2c *i2c) +{ + u8 i, count; + u8 fstp; + const u32 *params; + struct viai2c_zhaoxin *priv = i2c->pltfm_priv; + u32 acpi_speed = i2c_acpi_find_bus_speed(i2c->dev); + + count = ARRAY_SIZE(zxi2c_speed_params_table); + for (i = 0; i < count; i++) + if (acpi_speed == zxi2c_speed_params_table[i][0]) + break; + /* if not found, use 400k as default */ + i = i < count ? i : 1; + + params = zxi2c_speed_params_table[i]; + fstp = ioread8(i2c->base + VIAI2C_REG_TR); + if (abs(fstp - params[2]) > 0x10) { + /* + * if BIOS setting value far from golden value, + * use golden value and warn user + */ + dev_warn(i2c->dev, "FW FSTP[%x] might cause wrong timings, dropped\n", fstp); + priv->tr = params[2] | 0xff00; + } else { + priv->tr = fstp | 0xff00; + } + + i2c->tcr = params[1]; + priv->mcr = ioread16(i2c->base + VIAI2C_REG_MCR); + /* for Hs-mode, use 0x80 as controller code */ + if (params[0] == I2C_MAX_HIGH_SPEED_MODE_FREQ) + priv->mcr |= ZXI2C_HS_CTRL_CODE; + + dev_info(i2c->dev, "speed mode is %s\n", i2c_freq_mode_string(params[0])); +} + +static irqreturn_t zxi2c_isr(int irq, void *data) +{ + struct viai2c *i2c = data; + u8 status; + + /* save the status and write-clear it */ + status = readw(i2c->base + VIAI2C_REG_ISR); + if (!status) + return IRQ_NONE; + + writew(status, i2c->base + VIAI2C_REG_ISR); + + i2c->ret = 0; + if (status & VIAI2C_ISR_NACK_ADDR) + i2c->ret = -EIO; + + if (!i2c->ret) { + if (i2c->mode == VIAI2C_BYTE_MODE) + i2c->ret = viai2c_irq_xfer(i2c); + else + i2c->ret = viai2c_fifo_irq_xfer(i2c); + } + + /* All the data has been successfully transferred or error occurred */ + if (i2c->ret) + complete(&i2c->complete); + + return IRQ_HANDLED; +} + +static int zxi2c_probe(struct platform_device *pdev) +{ + int error; + struct viai2c *i2c; + struct i2c_adapter *adap; + struct viai2c_zhaoxin *priv; + + error = viai2c_init(pdev, &i2c, VIAI2C_PLAT_ZHAOXIN); + if (error) + return error; + + i2c->irq = platform_get_irq(pdev, 0); + if (i2c->irq < 0) + return i2c->irq; + + error = devm_request_irq(&pdev->dev, i2c->irq, zxi2c_isr, + IRQF_SHARED, pdev->name, i2c); + if (error) + return dev_err_probe(&pdev->dev, error, + "failed to request irq %i\n", i2c->irq); + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + i2c->pltfm_priv = priv; + + zxi2c_get_bus_speed(i2c); + zxi2c_set_bus_speed(i2c); + + priv->hrv = ioread8(i2c->base + ZXI2C_REG_REV); + + adap = &i2c->adapter; + adap->owner = THIS_MODULE; + adap->algo = &zxi2c_algorithm; + adap->quirks = &zxi2c_quirks; + adap->dev.parent = &pdev->dev; + ACPI_COMPANION_SET(&adap->dev, ACPI_COMPANION(&pdev->dev)); + snprintf(adap->name, sizeof(adap->name), "zhaoxin-%s-%s", + dev_name(pdev->dev.parent), dev_name(i2c->dev)); + i2c_set_adapdata(adap, i2c); + + return devm_i2c_add_adapter(&pdev->dev, adap); +} + +static int __maybe_unused zxi2c_resume(struct device *dev) +{ + struct viai2c *i2c = dev_get_drvdata(dev); + + iowrite8(ZXI2C_CR_MST_RST, i2c->base + VIAI2C_REG_CR); + zxi2c_set_bus_speed(i2c); + + return 0; +} + +static const struct dev_pm_ops zxi2c_pm = { + SET_SYSTEM_SLEEP_PM_OPS(NULL, zxi2c_resume) +}; + +static const struct acpi_device_id zxi2c_acpi_match[] = { + {"IIC1D17", 0 }, + { } +}; +MODULE_DEVICE_TABLE(acpi, zxi2c_acpi_match); + +static struct platform_driver zxi2c_driver = { + .probe = zxi2c_probe, + .driver = { + .name = "i2c_zhaoxin", + .acpi_match_table = zxi2c_acpi_match, + .pm = &zxi2c_pm, + }, +}; + +module_platform_driver(zxi2c_driver); + +MODULE_AUTHOR("HansHu@zhaoxin.com"); +MODULE_DESCRIPTION("Shanghai Zhaoxin IIC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c index 970ccdcbb889..c58843609107 100644 --- a/drivers/i2c/busses/i2c-viapro.c +++ b/drivers/i2c/busses/i2c-viapro.c @@ -304,7 +304,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter vt596_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, }; @@ -330,30 +330,27 @@ static int vt596_probe(struct pci_dev *pdev, SMBHSTCFG = 0x84; } else { /* no matches at all */ - dev_err(&pdev->dev, "Cannot configure " - "SMBus I/O Base address\n"); - return -ENODEV; + return dev_err_probe(&pdev->dev, -ENODEV, + "Cannot configure " + "SMBus I/O Base address\n"); } } vt596_smba &= 0xfff0; - if (vt596_smba == 0) { - dev_err(&pdev->dev, "SMBus base address " - "uninitialized - upgrade BIOS or use " - "force_addr=0xaddr\n"); - return -ENODEV; - } + if (vt596_smba == 0) + return dev_err_probe(&pdev->dev, -ENODEV, "SMBus base address " + "uninitialized - upgrade BIOS or use " + "force_addr=0xaddr\n"); found: error = acpi_check_region(vt596_smba, 8, vt596_driver.name); if (error) return -ENODEV; - if (!request_region(vt596_smba, 8, vt596_driver.name)) { - dev_err(&pdev->dev, "SMBus region 0x%x already in use!\n", - vt596_smba); - return -ENODEV; - } + if (!request_region(vt596_smba, 8, vt596_driver.name)) + return dev_err_probe(&pdev->dev, -ENODEV, + "SMBus region 0x%x already in use!\n", + vt596_smba); pci_read_config_byte(pdev, SMBHSTCFG, &temp); /* If force_addr is set, we program the new address here. Just to make @@ -375,10 +372,10 @@ found: pci_write_config_byte(pdev, SMBHSTCFG, temp | 0x01); dev_info(&pdev->dev, "Enabling SMBus device\n"); } else { - dev_err(&pdev->dev, "SMBUS: Error: Host SMBus " - "controller not enabled! - upgrade BIOS or " - "use force=1\n"); - error = -ENODEV; + error = dev_err_probe(&pdev->dev, -ENODEV, + "SMBUS: Error: Host SMBus " + "controller not enabled! - " + "upgrade BIOS or use force=1\n"); goto release_region; } } diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c index 8b5322c3bce0..f596efcc291c 100644 --- a/drivers/i2c/busses/i2c-viperboard.c +++ b/drivers/i2c/busses/i2c-viperboard.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-or-later /* - * Nano River Technologies viperboard i2c master driver + * Nano River Technologies viperboard i2c controller driver * * (C) 2012 by Lemonage GmbH * Author: Lars Poeschel <poeschel@lemonage.de> @@ -11,6 +11,7 @@ #include <linux/errno.h> #include <linux/module.h> #include <linux/slab.h> +#include <linux/string_choices.h> #include <linux/types.h> #include <linux/mutex.h> #include <linux/platform_device.h> @@ -203,7 +204,7 @@ static int vprbrd_i2c_read(struct vprbrd *vb, struct i2c_msg *msg) /* copy the received data */ memcpy(msg->buf + start, rmsg, len1); - /* second read transfer if neccessary */ + /* second read transfer if necessary */ if (len2 > 0) { ret = vprbrd_i2c_receive(vb->usb_dev, rmsg, len2); if (ret < 0) @@ -273,14 +274,12 @@ static int vprbrd_i2c_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs, (struct vprbrd_i2c_addr_msg *)vb->buf; struct vprbrd_i2c_status *smsg = (struct vprbrd_i2c_status *)vb->buf; - dev_dbg(&i2c->dev, "master xfer %d messages:\n", num); - for (i = 0 ; i < num ; i++) { pmsg = &msgs[i]; dev_dbg(&i2c->dev, " %d: %s (flags %d) %d bytes to 0x%02x\n", - i, pmsg->flags & I2C_M_RD ? "read" : "write", + i, str_read_write(pmsg->flags & I2C_M_RD), pmsg->flags, pmsg->len, pmsg->addr); mutex_lock(&vb->lock); @@ -345,8 +344,8 @@ static u32 vprbrd_i2c_func(struct i2c_adapter *i2c) /* This is the actual algorithm we define */ static const struct i2c_algorithm vprbrd_algorithm = { - .master_xfer = vprbrd_i2c_xfer, - .functionality = vprbrd_i2c_func, + .xfer = vprbrd_i2c_xfer, + .functionality = vprbrd_i2c_func, }; static const struct i2c_adapter_quirks vprbrd_quirks = { @@ -386,15 +385,13 @@ static int vprbrd_i2c_probe(struct platform_device *pdev) VPRBRD_USB_REQUEST_I2C_FREQ, VPRBRD_USB_TYPE_OUT, 0x0000, 0x0000, &vb_i2c->bus_freq_param, 1, VPRBRD_USB_TIMEOUT_MS); - if (ret != 1) { - dev_err(&pdev->dev, "failure setting i2c_bus_freq to %d\n", - i2c_bus_freq); - return -EIO; - } + if (ret != 1) + return dev_err_probe(&pdev->dev, -EIO, + "failure setting i2c_bus_freq to %d\n", + i2c_bus_freq); } else { - dev_err(&pdev->dev, - "invalid i2c_bus_freq setting:%d\n", i2c_bus_freq); - return -EIO; + return dev_err_probe(&pdev->dev, -EIO, + "invalid i2c_bus_freq setting:%d\n", i2c_bus_freq); } vb_i2c->i2c.dev.parent = &pdev->dev; @@ -407,18 +404,15 @@ static int vprbrd_i2c_probe(struct platform_device *pdev) return 0; } -static int vprbrd_i2c_remove(struct platform_device *pdev) +static void vprbrd_i2c_remove(struct platform_device *pdev) { struct vprbrd_i2c *vb_i2c = platform_get_drvdata(pdev); i2c_del_adapter(&vb_i2c->i2c); - - return 0; } static struct platform_driver vprbrd_i2c_driver = { .driver.name = "viperboard-i2c", - .driver.owner = THIS_MODULE, .probe = vprbrd_i2c_probe, .remove = vprbrd_i2c_remove, }; @@ -463,6 +457,6 @@ static void __exit vprbrd_i2c_exit(void) module_exit(vprbrd_i2c_exit); MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>"); -MODULE_DESCRIPTION("I2C master driver for Nano River Techs Viperboard"); +MODULE_DESCRIPTION("I2C controller driver for Nano River Techs Viperboard"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:viperboard-i2c"); diff --git a/drivers/i2c/busses/i2c-virtio.c b/drivers/i2c/busses/i2c-virtio.c index 4b9536f50800..af1381949f50 100644 --- a/drivers/i2c/busses/i2c-virtio.c +++ b/drivers/i2c/busses/i2c-virtio.c @@ -116,15 +116,16 @@ static int virtio_i2c_complete_reqs(struct virtqueue *vq, for (i = 0; i < num; i++) { struct virtio_i2c_req *req = &reqs[i]; - wait_for_completion(&req->completion); - - if (!failed && req->in_hdr.status != VIRTIO_I2C_MSG_OK) - failed = true; + if (!failed) { + if (wait_for_completion_interruptible(&req->completion)) + failed = true; + else if (req->in_hdr.status != VIRTIO_I2C_MSG_OK) + failed = true; + else + j++; + } i2c_put_dma_safe_msg_buf(reqs[i].buf, &msgs[i], !failed); - - if (!failed) - j++; } return j; @@ -182,8 +183,8 @@ static u32 virtio_i2c_func(struct i2c_adapter *adap) return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; } -static struct i2c_algorithm virtio_algorithm = { - .master_xfer = virtio_i2c_xfer, +static const struct i2c_algorithm virtio_algorithm = { + .xfer = virtio_i2c_xfer, .functionality = virtio_i2c_func, }; @@ -192,10 +193,9 @@ static int virtio_i2c_probe(struct virtio_device *vdev) struct virtio_i2c *vi; int ret; - if (!virtio_has_feature(vdev, VIRTIO_I2C_F_ZERO_LENGTH_REQUEST)) { - dev_err(&vdev->dev, "Zero-length request feature is mandatory\n"); - return -EINVAL; - } + if (!virtio_has_feature(vdev, VIRTIO_I2C_F_ZERO_LENGTH_REQUEST)) + return dev_err_probe(&vdev->dev, -EINVAL, + "Zero-length request feature is mandatory\n"); vi = devm_kzalloc(&vdev->dev, sizeof(*vi), GFP_KERNEL); if (!vi) @@ -237,13 +237,12 @@ static void virtio_i2c_remove(struct virtio_device *vdev) virtio_i2c_del_vqs(vdev); } -static struct virtio_device_id id_table[] = { +static const struct virtio_device_id id_table[] = { { VIRTIO_ID_I2C_ADAPTER, VIRTIO_DEV_ANY_ID }, {} }; MODULE_DEVICE_TABLE(virtio, id_table); -#ifdef CONFIG_PM_SLEEP static int virtio_i2c_freeze(struct virtio_device *vdev) { virtio_i2c_del_vqs(vdev); @@ -254,7 +253,6 @@ static int virtio_i2c_restore(struct virtio_device *vdev) { return virtio_i2c_setup_vqs(vdev->priv); } -#endif static const unsigned int features[] = { VIRTIO_I2C_F_ZERO_LENGTH_REQUEST, @@ -269,10 +267,8 @@ static struct virtio_driver virtio_i2c_driver = { .driver = { .name = "i2c_virtio", }, -#ifdef CONFIG_PM_SLEEP - .freeze = virtio_i2c_freeze, - .restore = virtio_i2c_restore, -#endif + .freeze = pm_sleep_ptr(virtio_i2c_freeze), + .restore = pm_sleep_ptr(virtio_i2c_restore), }; module_virtio_driver(virtio_i2c_driver); diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c deleted file mode 100644 index 7d4bc8736079..000000000000 --- a/drivers/i2c/busses/i2c-wmt.c +++ /dev/null @@ -1,470 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/* - * Wondermedia I2C Master Mode Driver - * - * Copyright (C) 2012 Tony Prisk <linux@prisktech.co.nz> - * - * Derived from GPLv2+ licensed source: - * - Copyright (C) 2008 WonderMedia Technologies, Inc. - */ - -#include <linux/clk.h> -#include <linux/delay.h> -#include <linux/err.h> -#include <linux/i2c.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/module.h> -#include <linux/of.h> -#include <linux/of_address.h> -#include <linux/of_irq.h> -#include <linux/platform_device.h> - -#define REG_CR 0x00 -#define REG_TCR 0x02 -#define REG_CSR 0x04 -#define REG_ISR 0x06 -#define REG_IMR 0x08 -#define REG_CDR 0x0A -#define REG_TR 0x0C -#define REG_MCR 0x0E -#define REG_SLAVE_CR 0x10 -#define REG_SLAVE_SR 0x12 -#define REG_SLAVE_ISR 0x14 -#define REG_SLAVE_IMR 0x16 -#define REG_SLAVE_DR 0x18 -#define REG_SLAVE_TR 0x1A - -/* REG_CR Bit fields */ -#define CR_TX_NEXT_ACK 0x0000 -#define CR_ENABLE 0x0001 -#define CR_TX_NEXT_NO_ACK 0x0002 -#define CR_TX_END 0x0004 -#define CR_CPU_RDY 0x0008 -#define SLAV_MODE_SEL 0x8000 - -/* REG_TCR Bit fields */ -#define TCR_STANDARD_MODE 0x0000 -#define TCR_MASTER_WRITE 0x0000 -#define TCR_HS_MODE 0x2000 -#define TCR_MASTER_READ 0x4000 -#define TCR_FAST_MODE 0x8000 -#define TCR_SLAVE_ADDR_MASK 0x007F - -/* REG_ISR Bit fields */ -#define ISR_NACK_ADDR 0x0001 -#define ISR_BYTE_END 0x0002 -#define ISR_SCL_TIMEOUT 0x0004 -#define ISR_WRITE_ALL 0x0007 - -/* REG_IMR Bit fields */ -#define IMR_ENABLE_ALL 0x0007 - -/* REG_CSR Bit fields */ -#define CSR_RCV_NOT_ACK 0x0001 -#define CSR_RCV_ACK_MASK 0x0001 -#define CSR_READY_MASK 0x0002 - -/* REG_TR */ -#define SCL_TIMEOUT(x) (((x) & 0xFF) << 8) -#define TR_STD 0x0064 -#define TR_HS 0x0019 - -/* REG_MCR */ -#define MCR_APB_96M 7 -#define MCR_APB_166M 12 - -#define I2C_MODE_STANDARD 0 -#define I2C_MODE_FAST 1 - -#define WMT_I2C_TIMEOUT (msecs_to_jiffies(1000)) - -struct wmt_i2c_dev { - struct i2c_adapter adapter; - struct completion complete; - struct device *dev; - void __iomem *base; - struct clk *clk; - int mode; - int irq; - u16 cmd_status; -}; - -static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev) -{ - unsigned long timeout; - - timeout = jiffies + WMT_I2C_TIMEOUT; - while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) { - if (time_after(jiffies, timeout)) { - dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n"); - return -EBUSY; - } - msleep(20); - } - - return 0; -} - -static int wmt_check_status(struct wmt_i2c_dev *i2c_dev) -{ - int ret = 0; - - if (i2c_dev->cmd_status & ISR_NACK_ADDR) - ret = -EIO; - - if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT) - ret = -ETIMEDOUT; - - return ret; -} - -static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg, - int last) -{ - struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); - u16 val, tcr_val; - int ret; - unsigned long wait_result; - int xfer_len = 0; - - if (!(pmsg->flags & I2C_M_NOSTART)) { - ret = wmt_i2c_wait_bus_not_busy(i2c_dev); - if (ret < 0) - return ret; - } - - if (pmsg->len == 0) { - /* - * We still need to run through the while (..) once, so - * start at -1 and break out early from the loop - */ - xfer_len = -1; - writew(0, i2c_dev->base + REG_CDR); - } else { - writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR); - } - - if (!(pmsg->flags & I2C_M_NOSTART)) { - val = readw(i2c_dev->base + REG_CR); - val &= ~CR_TX_END; - writew(val, i2c_dev->base + REG_CR); - - val = readw(i2c_dev->base + REG_CR); - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); - } - - reinit_completion(&i2c_dev->complete); - - if (i2c_dev->mode == I2C_MODE_STANDARD) - tcr_val = TCR_STANDARD_MODE; - else - tcr_val = TCR_FAST_MODE; - - tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK)); - - writew(tcr_val, i2c_dev->base + REG_TCR); - - if (pmsg->flags & I2C_M_NOSTART) { - val = readw(i2c_dev->base + REG_CR); - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); - } - - while (xfer_len < pmsg->len) { - wait_result = wait_for_completion_timeout(&i2c_dev->complete, - msecs_to_jiffies(500)); - - if (wait_result == 0) - return -ETIMEDOUT; - - ret = wmt_check_status(i2c_dev); - if (ret) - return ret; - - xfer_len++; - - val = readw(i2c_dev->base + REG_CSR); - if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) { - dev_dbg(i2c_dev->dev, "write RCV NACK error\n"); - return -EIO; - } - - if (pmsg->len == 0) { - val = CR_TX_END | CR_CPU_RDY | CR_ENABLE; - writew(val, i2c_dev->base + REG_CR); - break; - } - - if (xfer_len == pmsg->len) { - if (last != 1) - writew(CR_ENABLE, i2c_dev->base + REG_CR); - } else { - writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base + - REG_CDR); - writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR); - } - } - - return 0; -} - -static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg, - int last) -{ - struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); - u16 val, tcr_val; - int ret; - unsigned long wait_result; - u32 xfer_len = 0; - - if (!(pmsg->flags & I2C_M_NOSTART)) { - ret = wmt_i2c_wait_bus_not_busy(i2c_dev); - if (ret < 0) - return ret; - } - - val = readw(i2c_dev->base + REG_CR); - val &= ~CR_TX_END; - writew(val, i2c_dev->base + REG_CR); - - val = readw(i2c_dev->base + REG_CR); - val &= ~CR_TX_NEXT_NO_ACK; - writew(val, i2c_dev->base + REG_CR); - - if (!(pmsg->flags & I2C_M_NOSTART)) { - val = readw(i2c_dev->base + REG_CR); - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); - } - - if (pmsg->len == 1) { - val = readw(i2c_dev->base + REG_CR); - val |= CR_TX_NEXT_NO_ACK; - writew(val, i2c_dev->base + REG_CR); - } - - reinit_completion(&i2c_dev->complete); - - if (i2c_dev->mode == I2C_MODE_STANDARD) - tcr_val = TCR_STANDARD_MODE; - else - tcr_val = TCR_FAST_MODE; - - tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK); - - writew(tcr_val, i2c_dev->base + REG_TCR); - - if (pmsg->flags & I2C_M_NOSTART) { - val = readw(i2c_dev->base + REG_CR); - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); - } - - while (xfer_len < pmsg->len) { - wait_result = wait_for_completion_timeout(&i2c_dev->complete, - msecs_to_jiffies(500)); - - if (!wait_result) - return -ETIMEDOUT; - - ret = wmt_check_status(i2c_dev); - if (ret) - return ret; - - pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8; - xfer_len++; - - if (xfer_len == pmsg->len - 1) { - val = readw(i2c_dev->base + REG_CR); - val |= (CR_TX_NEXT_NO_ACK | CR_CPU_RDY); - writew(val, i2c_dev->base + REG_CR); - } else { - val = readw(i2c_dev->base + REG_CR); - val |= CR_CPU_RDY; - writew(val, i2c_dev->base + REG_CR); - } - } - - return 0; -} - -static int wmt_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg msgs[], - int num) -{ - struct i2c_msg *pmsg; - int i, is_last; - int ret = 0; - - for (i = 0; ret >= 0 && i < num; i++) { - is_last = ((i + 1) == num); - - pmsg = &msgs[i]; - if (pmsg->flags & I2C_M_RD) - ret = wmt_i2c_read(adap, pmsg, is_last); - else - ret = wmt_i2c_write(adap, pmsg, is_last); - } - - return (ret < 0) ? ret : i; -} - -static u32 wmt_i2c_func(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART; -} - -static const struct i2c_algorithm wmt_i2c_algo = { - .master_xfer = wmt_i2c_xfer, - .functionality = wmt_i2c_func, -}; - -static irqreturn_t wmt_i2c_isr(int irq, void *data) -{ - struct wmt_i2c_dev *i2c_dev = data; - - /* save the status and write-clear it */ - i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR); - writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR); - - complete(&i2c_dev->complete); - - return IRQ_HANDLED; -} - -static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev) -{ - int err; - - err = clk_prepare_enable(i2c_dev->clk); - if (err) { - dev_err(i2c_dev->dev, "failed to enable clock\n"); - return err; - } - - err = clk_set_rate(i2c_dev->clk, 20000000); - if (err) { - dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n"); - clk_disable_unprepare(i2c_dev->clk); - return err; - } - - writew(0, i2c_dev->base + REG_CR); - writew(MCR_APB_166M, i2c_dev->base + REG_MCR); - writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); - writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR); - writew(CR_ENABLE, i2c_dev->base + REG_CR); - readw(i2c_dev->base + REG_CSR); /* read clear */ - writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); - - if (i2c_dev->mode == I2C_MODE_STANDARD) - writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR); - else - writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR); - - return 0; -} - -static int wmt_i2c_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct wmt_i2c_dev *i2c_dev; - struct i2c_adapter *adap; - struct resource *res; - int err; - u32 clk_rate; - - i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); - if (!i2c_dev) - return -ENOMEM; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2c_dev->base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(i2c_dev->base)) - return PTR_ERR(i2c_dev->base); - - i2c_dev->irq = irq_of_parse_and_map(np, 0); - if (!i2c_dev->irq) { - dev_err(&pdev->dev, "irq missing or invalid\n"); - return -EINVAL; - } - - i2c_dev->clk = of_clk_get(np, 0); - if (IS_ERR(i2c_dev->clk)) { - dev_err(&pdev->dev, "unable to request clock\n"); - return PTR_ERR(i2c_dev->clk); - } - - i2c_dev->mode = I2C_MODE_STANDARD; - err = of_property_read_u32(np, "clock-frequency", &clk_rate); - if (!err && (clk_rate == I2C_MAX_FAST_MODE_FREQ)) - i2c_dev->mode = I2C_MODE_FAST; - - i2c_dev->dev = &pdev->dev; - - err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0, - "i2c", i2c_dev); - if (err) { - dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq); - return err; - } - - adap = &i2c_dev->adapter; - i2c_set_adapdata(adap, i2c_dev); - strscpy(adap->name, "WMT I2C adapter", sizeof(adap->name)); - adap->owner = THIS_MODULE; - adap->algo = &wmt_i2c_algo; - adap->dev.parent = &pdev->dev; - adap->dev.of_node = pdev->dev.of_node; - - init_completion(&i2c_dev->complete); - - err = wmt_i2c_reset_hardware(i2c_dev); - if (err) { - dev_err(&pdev->dev, "error initializing hardware\n"); - return err; - } - - err = i2c_add_adapter(adap); - if (err) - return err; - - platform_set_drvdata(pdev, i2c_dev); - - return 0; -} - -static int wmt_i2c_remove(struct platform_device *pdev) -{ - struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev); - - /* Disable interrupts, clock and delete adapter */ - writew(0, i2c_dev->base + REG_IMR); - clk_disable_unprepare(i2c_dev->clk); - i2c_del_adapter(&i2c_dev->adapter); - - return 0; -} - -static const struct of_device_id wmt_i2c_dt_ids[] = { - { .compatible = "wm,wm8505-i2c" }, - { /* Sentinel */ }, -}; - -static struct platform_driver wmt_i2c_driver = { - .probe = wmt_i2c_probe, - .remove = wmt_i2c_remove, - .driver = { - .name = "wmt-i2c", - .of_match_table = wmt_i2c_dt_ids, - }, -}; - -module_platform_driver(wmt_i2c_driver); - -MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter"); -MODULE_AUTHOR("Tony Prisk <linux@prisktech.co.nz>"); -MODULE_LICENSE("GPL"); -MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids); diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c index 63259b3ea5ab..b29dec66b2c3 100644 --- a/drivers/i2c/busses/i2c-xgene-slimpro.c +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -91,14 +91,6 @@ #define SLIMPRO_IIC_MSG_DWORD_COUNT 3 -/* PCC related defines */ -#define PCC_SIGNATURE 0x50424300 -#define PCC_STS_CMD_COMPLETE BIT(0) -#define PCC_STS_SCI_DOORBELL BIT(1) -#define PCC_STS_ERR BIT(2) -#define PCC_STS_PLAT_NOTIFY BIT(3) -#define PCC_CMD_GENERATE_DB_INT BIT(15) - struct slimpro_i2c_dev { struct i2c_adapter adapter; struct device *dev; @@ -109,8 +101,6 @@ struct slimpro_i2c_dev { struct completion rd_complete; u8 dma_buffer[I2C_SMBUS_BLOCK_MAX + 1]; /* dma_buffer[0] is used for length */ u32 *resp_msg; - phys_addr_t comm_base_addr; - void *pcc_comm_addr; }; #define to_slimpro_i2c_dev(cl) \ @@ -156,15 +146,16 @@ static void slimpro_i2c_rx_cb(struct mbox_client *cl, void *mssg) static void slimpro_i2c_pcc_rx_cb(struct mbox_client *cl, void *msg) { struct slimpro_i2c_dev *ctx = to_slimpro_i2c_dev(cl); - struct acpi_pcct_shared_memory *generic_comm_base = ctx->pcc_comm_addr; + struct acpi_pcct_shared_memory __iomem *generic_comm_base = + ctx->pcc_chan->shmem; /* Check if platform sends interrupt */ if (!xgene_word_tst_and_clr(&generic_comm_base->status, - PCC_STS_SCI_DOORBELL)) + PCC_STATUS_SCI_DOORBELL)) return; if (xgene_word_tst_and_clr(&generic_comm_base->status, - PCC_STS_CMD_COMPLETE)) { + PCC_STATUS_CMD_COMPLETE)) { msg = generic_comm_base + 1; /* Response message msg[1] contains the return value. */ @@ -177,7 +168,8 @@ static void slimpro_i2c_pcc_rx_cb(struct mbox_client *cl, void *msg) static void slimpro_i2c_pcc_tx_prepare(struct slimpro_i2c_dev *ctx, u32 *msg) { - struct acpi_pcct_shared_memory *generic_comm_base = ctx->pcc_comm_addr; + struct acpi_pcct_shared_memory __iomem *generic_comm_base = + ctx->pcc_chan->shmem; u32 *ptr = (void *)(generic_comm_base + 1); u16 status; int i; @@ -186,10 +178,10 @@ static void slimpro_i2c_pcc_tx_prepare(struct slimpro_i2c_dev *ctx, u32 *msg) cpu_to_le32(PCC_SIGNATURE | ctx->mbox_idx)); WRITE_ONCE(generic_comm_base->command, - cpu_to_le16(SLIMPRO_MSG_TYPE(msg[0]) | PCC_CMD_GENERATE_DB_INT)); + cpu_to_le16(SLIMPRO_MSG_TYPE(msg[0]) | PCC_CMD_GENERATE_DB_INTR)); status = le16_to_cpu(READ_ONCE(generic_comm_base->status)); - status &= ~PCC_STS_CMD_COMPLETE; + status &= ~PCC_STATUS_CMD_COMPLETE; WRITE_ONCE(generic_comm_base->status, cpu_to_le16(status)); /* Copy the message to the PCC comm space */ @@ -308,6 +300,9 @@ static int slimpro_i2c_blkwr(struct slimpro_i2c_dev *ctx, u32 chip, u32 msg[3]; int rc; + if (writelen > I2C_SMBUS_BLOCK_MAX) + return -EINVAL; + memcpy(ctx->dma_buffer, data, writelen); paddr = dma_map_single(ctx->dev, ctx->dma_buffer, writelen, DMA_TO_DEVICE); @@ -462,22 +457,18 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) cl->tx_block = true; cl->rx_callback = slimpro_i2c_rx_cb; ctx->mbox_chan = mbox_request_channel(cl, MAILBOX_I2C_INDEX); - if (IS_ERR(ctx->mbox_chan)) { - dev_err(&pdev->dev, "i2c mailbox channel request failed\n"); - return PTR_ERR(ctx->mbox_chan); - } + if (IS_ERR(ctx->mbox_chan)) + return dev_err_probe(&pdev->dev, PTR_ERR(ctx->mbox_chan), + "i2c mailbox channel request failed\n"); } else { struct pcc_mbox_chan *pcc_chan; const struct acpi_device_id *acpi_id; - int version = XGENE_SLIMPRO_I2C_V1; acpi_id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev); if (!acpi_id) return -EINVAL; - version = (int)acpi_id->driver_data; - if (device_property_read_u32(&pdev->dev, "pcc-channel", &ctx->mbox_idx)) ctx->mbox_idx = MAILBOX_I2C_INDEX; @@ -485,48 +476,19 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) cl->tx_block = false; cl->rx_callback = slimpro_i2c_pcc_rx_cb; pcc_chan = pcc_mbox_request_channel(cl, ctx->mbox_idx); - if (IS_ERR(pcc_chan)) { - dev_err(&pdev->dev, "PCC mailbox channel request failed\n"); - return PTR_ERR(pcc_chan); - } + if (IS_ERR(pcc_chan)) + return dev_err_probe(&pdev->dev, PTR_ERR(pcc_chan), + "PCC mailbox channel request failed\n"); ctx->pcc_chan = pcc_chan; ctx->mbox_chan = pcc_chan->mchan; if (!ctx->mbox_chan->mbox->txdone_irq) { - dev_err(&pdev->dev, "PCC IRQ not supported\n"); - rc = -ENOENT; + rc = dev_err_probe(&pdev->dev, -ENOENT, + "PCC IRQ not supported\n"); goto mbox_err; } - /* - * This is the shared communication region - * for the OS and Platform to communicate over. - */ - ctx->comm_base_addr = pcc_chan->shmem_base_addr; - if (ctx->comm_base_addr) { - if (version == XGENE_SLIMPRO_I2C_V2) - ctx->pcc_comm_addr = memremap( - ctx->comm_base_addr, - pcc_chan->shmem_size, - MEMREMAP_WT); - else - ctx->pcc_comm_addr = memremap( - ctx->comm_base_addr, - pcc_chan->shmem_size, - MEMREMAP_WB); - } else { - dev_err(&pdev->dev, "Failed to get PCC comm region\n"); - rc = -ENOENT; - goto mbox_err; - } - - if (!ctx->pcc_comm_addr) { - dev_err(&pdev->dev, - "Failed to ioremap PCC comm region\n"); - rc = -ENOMEM; - goto mbox_err; - } } rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); if (rc) @@ -557,7 +519,7 @@ mbox_err: return rc; } -static int xgene_slimpro_i2c_remove(struct platform_device *pdev) +static void xgene_slimpro_i2c_remove(struct platform_device *pdev) { struct slimpro_i2c_dev *ctx = platform_get_drvdata(pdev); @@ -567,8 +529,6 @@ static int xgene_slimpro_i2c_remove(struct platform_device *pdev) mbox_free_channel(ctx->mbox_chan); else pcc_mbox_free_channel(ctx->pcc_chan); - - return 0; } static const struct of_device_id xgene_slimpro_i2c_dt_ids[] = { @@ -588,7 +548,7 @@ MODULE_DEVICE_TABLE(acpi, xgene_slimpro_i2c_acpi_ids); static struct platform_driver xgene_slimpro_i2c_driver = { .probe = xgene_slimpro_i2c_probe, - .remove = xgene_slimpro_i2c_remove, + .remove = xgene_slimpro_i2c_remove, .driver = { .name = "xgene-slimpro-i2c", .of_match_table = of_match_ptr(xgene_slimpro_i2c_dt_ids), diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index bee5a2ef1f22..28015d77599d 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -30,8 +30,12 @@ #include <linux/of.h> #include <linux/clk.h> #include <linux/pm_runtime.h> +#include <linux/iopoll.h> +#include <linux/spinlock.h> #define DRIVER_NAME "xiic-i2c" +#define DYNAMIC_MODE_READ_BROKEN_BIT BIT(0) +#define SMBUS_BLOCK_READ_MIN_LEN 3 enum xilinx_i2c_state { STATE_DONE, @@ -44,6 +48,12 @@ enum xiic_endian { BIG }; +enum i2c_scl_freq { + REG_VALUES_100KHZ = 0, + REG_VALUES_400KHZ = 1, + REG_VALUES_1MHZ = 2 +}; + /** * struct xiic_i2c - Internal representation of the XIIC I2C bus * @dev: Pointer to device structure @@ -60,6 +70,15 @@ enum xiic_endian { * @clk: Pointer to AXI4-lite input clock * @state: See STATE_ * @singlemaster: Indicates bus is single master + * @dynamic: Mode of controller + * @prev_msg_tx: Previous message is Tx + * @quirks: To hold platform specific bug info + * @smbus_block_read: Flag to handle block read + * @input_clk: Input clock to I2C controller + * @i2c_clk: I2C SCL frequency + * @atomic: Mode of transfer + * @atomic_lock: Lock for atomic transfer mode + * @atomic_xfer_state: See STATE_ */ struct xiic_i2c { struct device *dev; @@ -76,6 +95,42 @@ struct xiic_i2c { struct clk *clk; enum xilinx_i2c_state state; bool singlemaster; + bool dynamic; + bool prev_msg_tx; + u32 quirks; + bool smbus_block_read; + unsigned long input_clk; + unsigned int i2c_clk; + bool atomic; + spinlock_t atomic_lock; /* Lock for atomic transfer mode */ + enum xilinx_i2c_state atomic_xfer_state; +}; + +struct xiic_version_data { + u32 quirks; +}; + +/** + * struct timing_regs - AXI I2C timing registers that depend on I2C spec + * @tsusta: setup time for a repeated START condition + * @tsusto: setup time for a STOP condition + * @thdsta: hold time for a repeated START condition + * @tsudat: setup time for data + * @tbuf: bus free time between STOP and START + */ +struct timing_regs { + unsigned int tsusta; + unsigned int tsusto; + unsigned int thdsta; + unsigned int tsudat; + unsigned int tbuf; +}; + +/* Reg values in ns derived from I2C spec and AXI I2C PG for different frequencies */ +static const struct timing_regs timing_reg_values[] = { + { 5700, 5000, 4300, 550, 5000 }, /* Reg values for 100KHz */ + { 900, 900, 900, 400, 1600 }, /* Reg values for 400KHz */ + { 380, 380, 380, 170, 620 }, /* Reg values for 1MHz */ }; #define XIIC_MSB_OFFSET 0 @@ -96,6 +151,19 @@ struct xiic_i2c { #define XIIC_RFD_REG_OFFSET (0x20 + XIIC_REG_OFFSET) /* Rx FIFO Depth reg */ #define XIIC_GPO_REG_OFFSET (0x24 + XIIC_REG_OFFSET) /* Output Register */ +/* + * Timing register offsets from RegisterBase. These are used only for + * setting i2c clock frequency for the line. + */ +#define XIIC_TSUSTA_REG_OFFSET (0x28 + XIIC_REG_OFFSET) /* TSUSTA Register */ +#define XIIC_TSUSTO_REG_OFFSET (0x2C + XIIC_REG_OFFSET) /* TSUSTO Register */ +#define XIIC_THDSTA_REG_OFFSET (0x30 + XIIC_REG_OFFSET) /* THDSTA Register */ +#define XIIC_TSUDAT_REG_OFFSET (0x34 + XIIC_REG_OFFSET) /* TSUDAT Register */ +#define XIIC_TBUF_REG_OFFSET (0x38 + XIIC_REG_OFFSET) /* TBUF Register */ +#define XIIC_THIGH_REG_OFFSET (0x3C + XIIC_REG_OFFSET) /* THIGH Register */ +#define XIIC_TLOW_REG_OFFSET (0x40 + XIIC_REG_OFFSET) /* TLOW Register */ +#define XIIC_THDDAT_REG_OFFSET (0x44 + XIIC_REG_OFFSET) /* THDDAT Register */ + /* Control Register masks */ #define XIIC_CR_ENABLE_DEVICE_MASK 0x01 /* Device enable = 1 */ #define XIIC_CR_TX_FIFO_RESET_MASK 0x02 /* Transmit FIFO reset=1 */ @@ -143,6 +211,9 @@ struct xiic_i2c { #define XIIC_TX_DYN_START_MASK 0x0100 /* 1 = Set dynamic start */ #define XIIC_TX_DYN_STOP_MASK 0x0200 /* 1 = Set dynamic stop */ +/* Dynamic mode constants */ +#define MAX_READ_LENGTH_DYNAMIC 255 /* Max length for dynamic read */ + /* * The following constants define the register offsets for the Interrupt * registers. There are some holes in the memory map for reserved addresses @@ -161,6 +232,8 @@ struct xiic_i2c { #define XIIC_I2C_TIMEOUT (msecs_to_jiffies(1000)) /* timeout waiting for the controller finish transfers */ #define XIIC_XFER_TIMEOUT (msecs_to_jiffies(10000)) +/* timeout waiting for the controller finish transfers in micro seconds */ +#define XIIC_XFER_TIMEOUT_US 10000000 /* * The following constant is used for the device global interrupt enable @@ -175,6 +248,29 @@ struct xiic_i2c { static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num); static void __xiic_start_xfer(struct xiic_i2c *i2c); +static int xiic_i2c_runtime_suspend(struct device *dev) +{ + struct xiic_i2c *i2c = dev_get_drvdata(dev); + + clk_disable(i2c->clk); + + return 0; +} + +static int xiic_i2c_runtime_resume(struct device *dev) +{ + struct xiic_i2c *i2c = dev_get_drvdata(dev); + int ret; + + ret = clk_enable(i2c->clk); + if (ret) { + dev_err(dev, "Cannot enable clock.\n"); + return ret; + } + + return 0; +} + /* * For the register read and write functions, a little-endian and big-endian * version are necessary. Endianness is detected during the probe function. @@ -275,12 +371,121 @@ static int xiic_clear_rx_fifo(struct xiic_i2c *i2c) return 0; } +static int xiic_wait_tx_empty(struct xiic_i2c *i2c) +{ + u8 isr; + unsigned long timeout; + + timeout = jiffies + XIIC_I2C_TIMEOUT; + for (isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET); + !(isr & XIIC_INTR_TX_EMPTY_MASK); + isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET)) { + if (time_after(jiffies, timeout)) { + dev_err(i2c->dev, "Timeout waiting at Tx empty\n"); + return -ETIMEDOUT; + } + } + + return 0; +} + +/** + * xiic_setclk - Sets the configured clock rate + * @i2c: Pointer to the xiic device structure + * + * The timing register values are calculated according to the input clock + * frequency and configured scl frequency. For details, please refer the + * AXI I2C PG and NXP I2C Spec. + * Supported frequencies are 100KHz, 400KHz and 1MHz. + * + * Return: 0 on success (Supported frequency selected or not configurable in SW) + * -EINVAL on failure (scl frequency not supported or THIGH is 0) + */ +static int xiic_setclk(struct xiic_i2c *i2c) +{ + unsigned int clk_in_mhz; + unsigned int index = 0; + u32 reg_val; + + if (!i2c->atomic) + dev_dbg(i2c->adap.dev.parent, + "%s entry, i2c->input_clk: %ld, i2c->i2c_clk: %d\n", + __func__, i2c->input_clk, i2c->i2c_clk); + + /* If not specified in DT, do not configure in SW. Rely only on Vivado design */ + if (!i2c->i2c_clk || !i2c->input_clk) + return 0; + + clk_in_mhz = DIV_ROUND_UP(i2c->input_clk, 1000000); + + switch (i2c->i2c_clk) { + case I2C_MAX_FAST_MODE_PLUS_FREQ: + index = REG_VALUES_1MHZ; + break; + case I2C_MAX_FAST_MODE_FREQ: + index = REG_VALUES_400KHZ; + break; + case I2C_MAX_STANDARD_MODE_FREQ: + index = REG_VALUES_100KHZ; + break; + default: + dev_warn(i2c->adap.dev.parent, "Unsupported scl frequency\n"); + return -EINVAL; + } + + /* + * Value to be stored in a register is the number of clock cycles required + * for the time duration. So the time is divided by the input clock time + * period to get the number of clock cycles required. Refer Xilinx AXI I2C + * PG document and I2C specification for further details. + */ + + /* THIGH - Depends on SCL clock frequency(i2c_clk) as below */ + reg_val = (DIV_ROUND_UP(i2c->input_clk, 2 * i2c->i2c_clk)) - 7; + if (reg_val == 0) + return -EINVAL; + + xiic_setreg32(i2c, XIIC_THIGH_REG_OFFSET, reg_val - 1); + + /* TLOW - Value same as THIGH */ + xiic_setreg32(i2c, XIIC_TLOW_REG_OFFSET, reg_val - 1); + + /* TSUSTA */ + reg_val = (timing_reg_values[index].tsusta * clk_in_mhz) / 1000; + xiic_setreg32(i2c, XIIC_TSUSTA_REG_OFFSET, reg_val - 1); + + /* TSUSTO */ + reg_val = (timing_reg_values[index].tsusto * clk_in_mhz) / 1000; + xiic_setreg32(i2c, XIIC_TSUSTO_REG_OFFSET, reg_val - 1); + + /* THDSTA */ + reg_val = (timing_reg_values[index].thdsta * clk_in_mhz) / 1000; + xiic_setreg32(i2c, XIIC_THDSTA_REG_OFFSET, reg_val - 1); + + /* TSUDAT */ + reg_val = (timing_reg_values[index].tsudat * clk_in_mhz) / 1000; + xiic_setreg32(i2c, XIIC_TSUDAT_REG_OFFSET, reg_val - 1); + + /* TBUF */ + reg_val = (timing_reg_values[index].tbuf * clk_in_mhz) / 1000; + xiic_setreg32(i2c, XIIC_TBUF_REG_OFFSET, reg_val - 1); + + /* THDDAT */ + xiic_setreg32(i2c, XIIC_THDDAT_REG_OFFSET, 1); + + return 0; +} + static int xiic_reinit(struct xiic_i2c *i2c) { int ret; xiic_setreg32(i2c, XIIC_RESETR_OFFSET, XIIC_RESET_MASK); + ret = xiic_setclk(i2c); + if (ret) + return ret; + /* Set receive Fifo depth to maximum (zero based). */ xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, IIC_RX_FIFO_DEPTH - 1); @@ -296,7 +501,8 @@ static int xiic_reinit(struct xiic_i2c *i2c) return ret; /* Enable interrupts */ - xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK); + if (!i2c->atomic) + xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK); xiic_irq_clr_en(i2c, XIIC_INTR_ARB_LOST_MASK); @@ -314,29 +520,152 @@ static void xiic_deinit(struct xiic_i2c *i2c) xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr & ~XIIC_CR_ENABLE_DEVICE_MASK); } +static void xiic_smbus_block_read_setup(struct xiic_i2c *i2c) +{ + u8 rxmsg_len, rfd_set = 0; + + /* + * Clear the I2C_M_RECV_LEN flag to avoid setting + * message length again + */ + i2c->rx_msg->flags &= ~I2C_M_RECV_LEN; + + /* Set smbus_block_read flag to identify in isr */ + i2c->smbus_block_read = true; + + /* Read byte from rx fifo and set message length */ + rxmsg_len = xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET); + + i2c->rx_msg->buf[i2c->rx_pos++] = rxmsg_len; + + /* Check if received length is valid */ + if (rxmsg_len <= I2C_SMBUS_BLOCK_MAX) { + /* Set Receive fifo depth */ + if (rxmsg_len > IIC_RX_FIFO_DEPTH) { + /* + * When Rx msg len greater than or equal to Rx fifo capacity + * Receive fifo depth should set to Rx fifo capacity minus 1 + */ + rfd_set = IIC_RX_FIFO_DEPTH - 1; + i2c->rx_msg->len = rxmsg_len + 1; + } else if ((rxmsg_len == 1) || + (rxmsg_len == 0)) { + /* + * Minimum of 3 bytes required to exit cleanly. 1 byte + * already received, Second byte is being received. Have + * to set NACK in read_rx before receiving the last byte + */ + rfd_set = 0; + i2c->rx_msg->len = SMBUS_BLOCK_READ_MIN_LEN; + } else { + /* + * When Rx msg len less than Rx fifo capacity + * Receive fifo depth should set to Rx msg len minus 2 + */ + rfd_set = rxmsg_len - 2; + i2c->rx_msg->len = rxmsg_len + 1; + } + xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rfd_set); + + return; + } + + /* Invalid message length, trigger STATE_ERROR with tx_msg_len in ISR */ + i2c->tx_msg->len = 3; + i2c->smbus_block_read = false; + dev_err(i2c->adap.dev.parent, "smbus_block_read Invalid msg length\n"); +} + static void xiic_read_rx(struct xiic_i2c *i2c) { - u8 bytes_in_fifo; + u8 bytes_in_fifo, cr = 0, bytes_to_read = 0; + u32 bytes_rem = 0; int i; bytes_in_fifo = xiic_getreg8(i2c, XIIC_RFO_REG_OFFSET) + 1; - dev_dbg(i2c->adap.dev.parent, - "%s entry, bytes in fifo: %d, msg: %d, SR: 0x%x, CR: 0x%x\n", - __func__, bytes_in_fifo, xiic_rx_space(i2c), - xiic_getreg8(i2c, XIIC_SR_REG_OFFSET), - xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); + if (!i2c->atomic) + dev_dbg(i2c->adap.dev.parent, + "%s entry, bytes in fifo: %d, rem: %d, SR: 0x%x, CR: 0x%x\n", + __func__, bytes_in_fifo, xiic_rx_space(i2c), + xiic_getreg8(i2c, XIIC_SR_REG_OFFSET), + xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); if (bytes_in_fifo > xiic_rx_space(i2c)) bytes_in_fifo = xiic_rx_space(i2c); - for (i = 0; i < bytes_in_fifo; i++) + bytes_to_read = bytes_in_fifo; + + if (!i2c->dynamic) { + bytes_rem = xiic_rx_space(i2c) - bytes_in_fifo; + + /* Set msg length if smbus_block_read */ + if (i2c->rx_msg->flags & I2C_M_RECV_LEN) { + xiic_smbus_block_read_setup(i2c); + return; + } + + if (bytes_rem > IIC_RX_FIFO_DEPTH) { + bytes_to_read = bytes_in_fifo; + } else if (bytes_rem > 1) { + bytes_to_read = bytes_rem - 1; + } else if (bytes_rem == 1) { + bytes_to_read = 1; + /* Set NACK in CR to indicate slave transmitter */ + cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET); + xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr | + XIIC_CR_NO_ACK_MASK); + } else if (bytes_rem == 0) { + bytes_to_read = bytes_in_fifo; + + /* Generate stop on the bus if it is last message */ + if (i2c->nmsgs == 1) { + cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET); + xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr & + ~XIIC_CR_MSMS_MASK); + } + + /* Make TXACK=0, clean up for next transaction */ + cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET); + xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr & + ~XIIC_CR_NO_ACK_MASK); + } + } + + /* Read the fifo */ + for (i = 0; i < bytes_to_read; i++) { i2c->rx_msg->buf[i2c->rx_pos++] = xiic_getreg8(i2c, XIIC_DRR_REG_OFFSET); + } + + if (i2c->dynamic) { + u8 bytes; + + /* Receive remaining bytes if less than fifo depth */ + bytes = min_t(u8, xiic_rx_space(i2c), IIC_RX_FIFO_DEPTH); + bytes--; + xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, bytes); + } +} + +static bool xiic_error_check(struct xiic_i2c *i2c) +{ + bool status = false; + u32 pend, isr, ier; - xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, - (xiic_rx_space(i2c) > IIC_RX_FIFO_DEPTH) ? - IIC_RX_FIFO_DEPTH - 1 : xiic_rx_space(i2c) - 1); + isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET); + ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET); + pend = isr & ier; + + if ((pend & XIIC_INTR_ARB_LOST_MASK) || + ((pend & XIIC_INTR_TX_ERROR_MASK) && + !(pend & XIIC_INTR_RX_FULL_MASK))) { + xiic_reinit(i2c); + status = true; + if (i2c->tx_msg || i2c->rx_msg) + i2c->atomic_xfer_state = STATE_ERROR; + } + return status; } static int xiic_tx_fifo_space(struct xiic_i2c *i2c) @@ -352,18 +681,38 @@ static void xiic_fill_tx_fifo(struct xiic_i2c *i2c) len = (len > fifo_space) ? fifo_space : len; - dev_dbg(i2c->adap.dev.parent, "%s entry, len: %d, fifo space: %d\n", - __func__, len, fifo_space); + if (!i2c->atomic) + dev_dbg(i2c->adap.dev.parent, "%s entry, len: %d, fifo space: %d\n", + __func__, len, fifo_space); while (len--) { u16 data = i2c->tx_msg->buf[i2c->tx_pos++]; if (!xiic_tx_space(i2c) && i2c->nmsgs == 1) { /* last message in transfer -> STOP */ - data |= XIIC_TX_DYN_STOP_MASK; - dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__); + if (i2c->dynamic) { + data |= XIIC_TX_DYN_STOP_MASK; + } else { + u8 cr; + int status; + + /* Wait till FIFO is empty so STOP is sent last */ + status = xiic_wait_tx_empty(i2c); + if (status) + return; + + /* Write to CR to stop */ + cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET); + xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr & + ~XIIC_CR_MSMS_MASK); + } + if (!i2c->atomic) + dev_dbg(i2c->adap.dev.parent, "%s TX STOP\n", __func__); } xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data); + + if (i2c->atomic && xiic_error_check(i2c)) + return; } } @@ -401,7 +750,9 @@ static irqreturn_t xiic_process(int irq, void *dev_id) dev_dbg(i2c->adap.dev.parent, "%s: SR: 0x%x, msg: %p, nmsgs: %d\n", __func__, xiic_getreg8(i2c, XIIC_SR_REG_OFFSET), i2c->tx_msg, i2c->nmsgs); - + dev_dbg(i2c->adap.dev.parent, "%s, ISR: 0x%x, CR: 0x%x\n", + __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET), + xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); /* Service requesting interrupt */ if ((pend & XIIC_INTR_ARB_LOST_MASK) || @@ -420,7 +771,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id) * reset the IP instead of just flush fifos */ ret = xiic_reinit(i2c); - if (!ret) + if (ret < 0) dev_dbg(i2c->adap.dev.parent, "reinit failed\n"); if (i2c->rx_msg) { @@ -431,6 +782,8 @@ static irqreturn_t xiic_process(int irq, void *dev_id) wakeup_req = 1; wakeup_code = STATE_ERROR; } + /* don't try to handle other events */ + goto out; } if (pend & XIIC_INTR_RX_FULL_MASK) { /* Receive register/FIFO is full */ @@ -480,14 +833,17 @@ static irqreturn_t xiic_process(int irq, void *dev_id) goto out; } - xiic_fill_tx_fifo(i2c); - - /* current message sent and there is space in the fifo */ - if (!xiic_tx_space(i2c) && xiic_tx_fifo_space(i2c) >= 2) { + if (xiic_tx_space(i2c)) { + xiic_fill_tx_fifo(i2c); + } else { + /* current message fully written */ dev_dbg(i2c->adap.dev.parent, "%s end of message sent, nmsgs: %d\n", __func__, i2c->nmsgs); - if (i2c->nmsgs > 1) { + /* Don't move onto the next message until the TX FIFO empties, + * to ensure that a NAK is not missed. + */ + if (i2c->nmsgs > 1 && (pend & XIIC_INTR_TX_EMPTY_MASK)) { i2c->nmsgs--; i2c->tx_msg++; xfer_more = 1; @@ -498,11 +854,7 @@ static irqreturn_t xiic_process(int irq, void *dev_id) "%s Got TX IRQ but no more to do...\n", __func__); } - } else if (!xiic_tx_space(i2c) && (i2c->nmsgs == 1)) - /* current frame is sent and is last, - * make sure to disable tx half - */ - xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK); + } } if (pend & XIIC_INTR_BNB_MASK) { @@ -512,6 +864,12 @@ static irqreturn_t xiic_process(int irq, void *dev_id) /* The bus is not busy, disable BusNotBusy interrupt */ xiic_irq_dis(i2c, XIIC_INTR_BNB_MASK); + if (i2c->tx_msg && i2c->smbus_block_read) { + i2c->smbus_block_read = false; + /* Set requested message len=1 to indicate STATE_DONE */ + i2c->tx_msg->len = 1; + } + if (!i2c->tx_msg) goto out; @@ -546,64 +904,164 @@ static int xiic_bus_busy(struct xiic_i2c *i2c) return (sr & XIIC_SR_BUS_BUSY_MASK) ? -EBUSY : 0; } -static int xiic_busy(struct xiic_i2c *i2c) +static int xiic_wait_not_busy(struct xiic_i2c *i2c) { int tries = 3; int err; - if (i2c->tx_msg || i2c->rx_msg) - return -EBUSY; - - /* In single master mode bus can only be busy, when in use by this - * driver. If the register indicates bus being busy for some reason we - * should ignore it, since bus will never be released and i2c will be - * stuck forever. - */ - if (i2c->singlemaster) { - return 0; - } - /* for instance if previous transfer was terminated due to TX error * it might be that the bus is on it's way to become available * give it at most 3 ms to wake */ err = xiic_bus_busy(i2c); while (err && tries--) { - msleep(1); + if (i2c->atomic) + udelay(1000); + else + usleep_range(1000, 1100); err = xiic_bus_busy(i2c); } return err; } +static void xiic_recv_atomic(struct xiic_i2c *i2c) +{ + while (xiic_rx_space(i2c)) { + if (xiic_getreg32(i2c, XIIC_IISR_OFFSET) & XIIC_INTR_RX_FULL_MASK) { + xiic_read_rx(i2c); + + /* Clear Rx full and Tx error interrupts. */ + xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | + XIIC_INTR_TX_ERROR_MASK); + } + if (xiic_error_check(i2c)) + return; + } + + i2c->rx_msg = NULL; + xiic_irq_clr_en(i2c, XIIC_INTR_TX_ERROR_MASK); + + /* send next message if this wasn't the last. */ + if (i2c->nmsgs > 1) { + i2c->nmsgs--; + i2c->tx_msg++; + __xiic_start_xfer(i2c); + } +} + static void xiic_start_recv(struct xiic_i2c *i2c) { u16 rx_watermark; + u8 cr = 0, rfd_set = 0; struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg; - /* Clear and enable Rx full interrupt. */ - xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | XIIC_INTR_TX_ERROR_MASK); + if (!i2c->atomic) + dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n", + __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET), + xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); + + /* Disable Tx interrupts */ + xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK | XIIC_INTR_TX_EMPTY_MASK); + + if (i2c->dynamic) { + u8 bytes; + u16 val; + + /* Clear and enable Rx full interrupt. */ + xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | + XIIC_INTR_TX_ERROR_MASK); + + /* + * We want to get all but last byte, because the TX_ERROR IRQ + * is used to indicate error ACK on the address, and + * negative ack on the last received byte, so to not mix + * them receive all but last. + * In the case where there is only one byte to receive + * we can check if ERROR and RX full is set at the same time + */ + rx_watermark = msg->len; + bytes = min_t(u8, rx_watermark, IIC_RX_FIFO_DEPTH); - /* we want to get all but last byte, because the TX_ERROR IRQ is used - * to inidicate error ACK on the address, and negative ack on the last - * received byte, so to not mix them receive all but last. - * In the case where there is only one byte to receive - * we can check if ERROR and RX full is set at the same time - */ - rx_watermark = msg->len; - if (rx_watermark > IIC_RX_FIFO_DEPTH) - rx_watermark = IIC_RX_FIFO_DEPTH; - xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, (u8)(rx_watermark - 1)); + if (rx_watermark > 0) + bytes--; + xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, bytes); - if (!(msg->flags & I2C_M_NOSTART)) /* write the address */ xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, - i2c_8bit_addr_from_msg(msg) | XIIC_TX_DYN_START_MASK); + i2c_8bit_addr_from_msg(msg) | + XIIC_TX_DYN_START_MASK); - xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK); + /* If last message, include dynamic stop bit with length */ + val = (i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0; + val |= msg->len; - xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, - msg->len | ((i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0)); + xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, val); + + xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK); + } else { + /* + * If previous message is Tx, make sure that Tx FIFO is empty + * before starting a new transfer as the repeated start in + * standard mode can corrupt the transaction if there are + * still bytes to be transmitted in FIFO + */ + if (i2c->prev_msg_tx) { + int status; + + status = xiic_wait_tx_empty(i2c); + if (status) + return; + } + + cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET); + + /* Set Receive fifo depth */ + rx_watermark = msg->len; + if (rx_watermark > IIC_RX_FIFO_DEPTH) { + rfd_set = IIC_RX_FIFO_DEPTH - 1; + } else if (rx_watermark == 1) { + rfd_set = rx_watermark - 1; + + /* Set No_ACK, except for smbus_block_read */ + if (!(i2c->rx_msg->flags & I2C_M_RECV_LEN)) { + /* Handle single byte transfer separately */ + cr |= XIIC_CR_NO_ACK_MASK; + } + } else if (rx_watermark == 0) { + rfd_set = rx_watermark; + } else { + rfd_set = rx_watermark - 2; + } + /* Check if RSTA should be set */ + if (cr & XIIC_CR_MSMS_MASK) { + /* Already a master, RSTA should be set */ + xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, (cr | + XIIC_CR_REPEATED_START_MASK) & + ~(XIIC_CR_DIR_IS_TX_MASK)); + } + + xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, rfd_set); + + /* Clear and enable Rx full and transmit complete interrupts */ + xiic_irq_clr_en(i2c, XIIC_INTR_RX_FULL_MASK | + XIIC_INTR_TX_ERROR_MASK); + + /* Write the address */ + xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, + i2c_8bit_addr_from_msg(msg)); + + /* Write to Control Register,to start transaction in Rx mode */ + if ((cr & XIIC_CR_MSMS_MASK) == 0) { + xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, (cr | + XIIC_CR_MSMS_MASK) + & ~(XIIC_CR_DIR_IS_TX_MASK)); + } + if (!i2c->atomic) + dev_dbg(i2c->adap.dev.parent, "%s end, ISR: 0x%x, CR: 0x%x\n", + __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET), + xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); + } if (i2c->nmsgs == 1) /* very last, enable bus not busy as well */ @@ -611,48 +1069,156 @@ static void xiic_start_recv(struct xiic_i2c *i2c) /* the message is tx:ed */ i2c->tx_pos = msg->len; + + i2c->prev_msg_tx = false; + + /* Enable interrupts */ + if (!i2c->atomic) + xiic_setreg32(i2c, XIIC_DGIER_OFFSET, XIIC_GINTR_ENABLE_MASK); + else + xiic_recv_atomic(i2c); +} + +static void xiic_send_rem_atomic(struct xiic_i2c *i2c) +{ + while (xiic_tx_space(i2c)) { + if (xiic_tx_fifo_space(i2c)) { + u16 data; + + data = i2c->tx_msg->buf[i2c->tx_pos]; + i2c->tx_pos++; + if (!xiic_tx_space(i2c) && i2c->nmsgs == 1) { + /* last message in transfer -> STOP */ + if (i2c->dynamic) { + data |= XIIC_TX_DYN_STOP_MASK; + } else { + u8 cr; + int status; + + /* Wait till FIFO is empty so STOP is sent last */ + status = xiic_wait_tx_empty(i2c); + if (status) + return; + + /* Write to CR to stop */ + cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET); + xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr & + ~XIIC_CR_MSMS_MASK); + } + } + xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data); + } + if (xiic_error_check(i2c)) + return; + } + + if (i2c->nmsgs > 1) { + i2c->nmsgs--; + i2c->tx_msg++; + __xiic_start_xfer(i2c); + } else { + xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK); + } } static void xiic_start_send(struct xiic_i2c *i2c) { + u8 cr = 0; + u16 data; struct i2c_msg *msg = i2c->tx_msg; - dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d", - __func__, msg, msg->len); - dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n", - __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET), - xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); + if (!i2c->atomic) { + dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, len: %d", + __func__, msg, msg->len); + dev_dbg(i2c->adap.dev.parent, "%s entry, ISR: 0x%x, CR: 0x%x\n", + __func__, xiic_getreg32(i2c, XIIC_IISR_OFFSET), + xiic_getreg8(i2c, XIIC_CR_REG_OFFSET)); + } - if (!(msg->flags & I2C_M_NOSTART)) { + if (i2c->dynamic) { /* write the address */ - u16 data = i2c_8bit_addr_from_msg(msg) | - XIIC_TX_DYN_START_MASK; - if ((i2c->nmsgs == 1) && msg->len == 0) + data = i2c_8bit_addr_from_msg(msg) | + XIIC_TX_DYN_START_MASK; + + if (i2c->nmsgs == 1 && msg->len == 0) /* no data and last message -> add STOP */ data |= XIIC_TX_DYN_STOP_MASK; xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data); + + /* Clear any pending Tx empty, Tx Error and then enable them */ + xiic_irq_clr_en(i2c, XIIC_INTR_TX_EMPTY_MASK | + XIIC_INTR_TX_ERROR_MASK | + XIIC_INTR_BNB_MASK | + ((i2c->nmsgs > 1 || xiic_tx_space(i2c)) ? + XIIC_INTR_TX_HALF_MASK : 0)); + + xiic_fill_tx_fifo(i2c); + } else { + /* + * If previous message is Tx, make sure that Tx FIFO is empty + * before starting a new transfer as the repeated start in + * standard mode can corrupt the transaction if there are + * still bytes to be transmitted in FIFO + */ + if (i2c->prev_msg_tx) { + int status; + + status = xiic_wait_tx_empty(i2c); + if (status) + return; + } + /* Check if RSTA should be set */ + cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET); + if (cr & XIIC_CR_MSMS_MASK) { + /* Already a master, RSTA should be set */ + xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, (cr | + XIIC_CR_REPEATED_START_MASK | + XIIC_CR_DIR_IS_TX_MASK) & + ~(XIIC_CR_NO_ACK_MASK)); + } + + /* Write address to FIFO */ + data = i2c_8bit_addr_from_msg(msg); + xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data); + + /* Fill fifo */ + xiic_fill_tx_fifo(i2c); + + if ((cr & XIIC_CR_MSMS_MASK) == 0) { + /* Start Tx by writing to CR */ + cr = xiic_getreg8(i2c, XIIC_CR_REG_OFFSET); + xiic_setreg8(i2c, XIIC_CR_REG_OFFSET, cr | + XIIC_CR_MSMS_MASK | + XIIC_CR_DIR_IS_TX_MASK); + } + + /* Clear any pending Tx empty, Tx Error and then enable them */ + xiic_irq_clr_en(i2c, XIIC_INTR_TX_EMPTY_MASK | + XIIC_INTR_TX_ERROR_MASK | + XIIC_INTR_BNB_MASK); } - /* Clear any pending Tx empty, Tx Error and then enable them. */ - xiic_irq_clr_en(i2c, XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_ERROR_MASK | - XIIC_INTR_BNB_MASK | - ((i2c->nmsgs > 1 || xiic_tx_space(i2c)) ? - XIIC_INTR_TX_HALF_MASK : 0)); + i2c->prev_msg_tx = true; - xiic_fill_tx_fifo(i2c); + if (i2c->atomic && !i2c->atomic_xfer_state) + xiic_send_rem_atomic(i2c); } static void __xiic_start_xfer(struct xiic_i2c *i2c) { int fifo_space = xiic_tx_fifo_space(i2c); - dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, fifos space: %d\n", - __func__, i2c->tx_msg, fifo_space); + if (!i2c->atomic) + dev_dbg(i2c->adap.dev.parent, "%s entry, msg: %p, fifos space: %d\n", + __func__, i2c->tx_msg, fifo_space); if (!i2c->tx_msg) return; + if (i2c->atomic && xiic_error_check(i2c)) + return; + i2c->rx_pos = 0; i2c->tx_pos = 0; i2c->state = STATE_START; @@ -666,25 +1232,90 @@ static void __xiic_start_xfer(struct xiic_i2c *i2c) static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num) { - int ret; + bool broken_read, max_read_len, smbus_blk_read; + int ret, count; - mutex_lock(&i2c->lock); + if (i2c->atomic) + spin_lock(&i2c->atomic_lock); + else + mutex_lock(&i2c->lock); - ret = xiic_busy(i2c); - if (ret) + if (i2c->tx_msg || i2c->rx_msg) { + dev_err(i2c->adap.dev.parent, + "cannot start a transfer while busy\n"); + ret = -EBUSY; goto out; + } + + i2c->atomic_xfer_state = STATE_DONE; + + /* In single master mode bus can only be busy, when in use by this + * driver. If the register indicates bus being busy for some reason we + * should ignore it, since bus will never be released and i2c will be + * stuck forever. + */ + if (!i2c->singlemaster) { + ret = xiic_wait_not_busy(i2c); + if (ret) { + /* If the bus is stuck in a busy state, such as due to spurious low + * pulses on the bus causing a false start condition to be detected, + * then try to recover by re-initializing the controller and check + * again if the bus is still busy. + */ + dev_warn(i2c->adap.dev.parent, "I2C bus busy timeout, reinitializing\n"); + ret = xiic_reinit(i2c); + if (ret) + goto out; + ret = xiic_wait_not_busy(i2c); + if (ret) + goto out; + } + } i2c->tx_msg = msgs; i2c->rx_msg = NULL; i2c->nmsgs = num; - init_completion(&i2c->completion); + + if (!i2c->atomic) + init_completion(&i2c->completion); + + /* Decide standard mode or Dynamic mode */ + i2c->dynamic = true; + + /* Initialize prev message type */ + i2c->prev_msg_tx = false; + + /* + * Scan through nmsgs, use dynamic mode when none of the below three + * conditions occur. We need standard mode even if one condition holds + * true in the entire array of messages in a single transfer. + * If read transaction as dynamic mode is broken for delayed reads + * in xlnx,axi-iic-2.0 / xlnx,xps-iic-2.00.a IP versions. + * If read length is > 255 bytes. + * If smbus_block_read transaction. + */ + for (count = 0; count < i2c->nmsgs; count++) { + broken_read = (i2c->quirks & DYNAMIC_MODE_READ_BROKEN_BIT) && + (i2c->tx_msg[count].flags & I2C_M_RD); + max_read_len = (i2c->tx_msg[count].flags & I2C_M_RD) && + (i2c->tx_msg[count].len > MAX_READ_LENGTH_DYNAMIC); + smbus_blk_read = (i2c->tx_msg[count].flags & I2C_M_RECV_LEN); + + if (broken_read || max_read_len || smbus_blk_read) { + i2c->dynamic = false; + break; + } + } ret = xiic_reinit(i2c); if (!ret) __xiic_start_xfer(i2c); out: - mutex_unlock(&i2c->lock); + if (i2c->atomic) + spin_unlock(&i2c->atomic_lock); + else + mutex_unlock(&i2c->lock); return ret; } @@ -702,10 +1333,8 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) return err; err = xiic_start_xfer(i2c, msgs, num); - if (err < 0) { - dev_err(adap->dev.parent, "Error xiic_start_xfer\n"); - return err; - } + if (err < 0) + goto out; err = wait_for_completion_timeout(&i2c->completion, XIIC_XFER_TIMEOUT); mutex_lock(&i2c->lock); @@ -714,44 +1343,89 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) i2c->rx_msg = NULL; i2c->nmsgs = 0; err = -ETIMEDOUT; - } else if (err < 0) { /* Completion error */ - i2c->tx_msg = NULL; - i2c->rx_msg = NULL; - i2c->nmsgs = 0; } else { err = (i2c->state == STATE_DONE) ? num : -EIO; } mutex_unlock(&i2c->lock); - pm_runtime_mark_last_busy(i2c->dev); + +out: pm_runtime_put_autosuspend(i2c->dev); return err; } +static int xiic_xfer_atomic(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) +{ + struct xiic_i2c *i2c = i2c_get_adapdata(adap); + u32 status_reg; + int err; + + err = xiic_i2c_runtime_resume(i2c->dev); + if (err) + return err; + + i2c->atomic = true; + err = xiic_start_xfer(i2c, msgs, num); + if (err < 0) + return err; + + err = readl_poll_timeout_atomic(i2c->base + XIIC_SR_REG_OFFSET, + status_reg, !(status_reg & XIIC_SR_BUS_BUSY_MASK), + 1, XIIC_XFER_TIMEOUT_US); + + if (err) /* Timeout */ + err = -ETIMEDOUT; + + spin_lock(&i2c->atomic_lock); + if (err || i2c->state) { + i2c->tx_msg = NULL; + i2c->rx_msg = NULL; + i2c->nmsgs = 0; + } + + err = (i2c->atomic_xfer_state == STATE_DONE) ? num : -EIO; + spin_unlock(&i2c->atomic_lock); + + i2c->atomic = false; + xiic_i2c_runtime_suspend(i2c->dev); + + return err; +} + static u32 xiic_func(struct i2c_adapter *adap) { - return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_SMBUS_BLOCK_DATA; } static const struct i2c_algorithm xiic_algorithm = { - .master_xfer = xiic_xfer, + .xfer = xiic_xfer, + .xfer_atomic = xiic_xfer_atomic, .functionality = xiic_func, }; -static const struct i2c_adapter_quirks xiic_quirks = { - .max_read_len = 255, -}; - static const struct i2c_adapter xiic_adapter = { .owner = THIS_MODULE, .class = I2C_CLASS_DEPRECATED, .algo = &xiic_algorithm, - .quirks = &xiic_quirks, }; +#if defined(CONFIG_OF) +static const struct xiic_version_data xiic_2_00 = { + .quirks = DYNAMIC_MODE_READ_BROKEN_BIT, +}; + +static const struct of_device_id xiic_of_match[] = { + { .compatible = "xlnx,xps-iic-2.00.a", .data = &xiic_2_00 }, + { .compatible = "xlnx,axi-iic-2.1", }, + {}, +}; +MODULE_DEVICE_TABLE(of, xiic_of_match); +#endif + static int xiic_i2c_probe(struct platform_device *pdev) { struct xiic_i2c *i2c; struct xiic_i2c_platform_data *pdata; + const struct of_device_id *match; struct resource *res; int ret, irq; u8 i; @@ -761,8 +1435,14 @@ static int xiic_i2c_probe(struct platform_device *pdev) if (!i2c) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2c->base = devm_ioremap_resource(&pdev->dev, res); + match = of_match_node(xiic_of_match, pdev->dev.of_node); + if (match && match->data) { + const struct xiic_version_data *data = match->data; + + i2c->quirks = data->quirks; + } + + i2c->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(i2c->base)) return PTR_ERR(i2c->base); @@ -782,29 +1462,34 @@ static int xiic_i2c_probe(struct platform_device *pdev) DRIVER_NAME " %s", pdev->name); mutex_init(&i2c->lock); + spin_lock_init(&i2c->atomic_lock); - i2c->clk = devm_clk_get(&pdev->dev, NULL); + i2c->clk = devm_clk_get_enabled(&pdev->dev, NULL); if (IS_ERR(i2c->clk)) return dev_err_probe(&pdev->dev, PTR_ERR(i2c->clk), - "input clock not found.\n"); + "failed to enable input clock.\n"); - ret = clk_prepare_enable(i2c->clk); - if (ret) { - dev_err(&pdev->dev, "Unable to enable clock.\n"); - return ret; - } i2c->dev = &pdev->dev; pm_runtime_set_autosuspend_delay(i2c->dev, XIIC_PM_TIMEOUT); pm_runtime_use_autosuspend(i2c->dev); pm_runtime_set_active(i2c->dev); pm_runtime_enable(i2c->dev); + + /* SCL frequency configuration */ + i2c->input_clk = clk_get_rate(i2c->clk); + ret = of_property_read_u32(pdev->dev.of_node, "clock-frequency", + &i2c->i2c_clk); + /* If clock-frequency not specified in DT, do not configure in SW */ + if (ret || i2c->i2c_clk > I2C_MAX_FAST_MODE_PLUS_FREQ) + i2c->i2c_clk = 0; + ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, xiic_process, IRQF_ONESHOT, pdev->name, i2c); if (ret < 0) { - dev_err(&pdev->dev, "Cannot claim IRQ\n"); - goto err_clk_dis; + dev_err_probe(&pdev->dev, ret, "Cannot claim IRQ\n"); + goto err_pm_disable; } i2c->singlemaster = @@ -824,15 +1509,15 @@ static int xiic_i2c_probe(struct platform_device *pdev) ret = xiic_reinit(i2c); if (ret < 0) { - dev_err(&pdev->dev, "Cannot xiic_reinit\n"); - goto err_clk_dis; + dev_err_probe(&pdev->dev, ret, "Cannot xiic_reinit\n"); + goto err_pm_disable; } /* add i2c adapter to i2c tree */ ret = i2c_add_adapter(&i2c->adap); if (ret) { xiic_deinit(i2c); - goto err_clk_dis; + goto err_pm_disable; } if (pdata) { @@ -841,16 +1526,19 @@ static int xiic_i2c_probe(struct platform_device *pdev) i2c_new_client_device(&i2c->adap, pdata->devices + i); } + dev_dbg(&pdev->dev, "mmio %08lx irq %d scl clock frequency %d\n", + (unsigned long)res->start, irq, i2c->i2c_clk); + return 0; -err_clk_dis: - pm_runtime_set_suspended(&pdev->dev); +err_pm_disable: pm_runtime_disable(&pdev->dev); - clk_disable_unprepare(i2c->clk); + pm_runtime_set_suspended(&pdev->dev); + return ret; } -static int xiic_i2c_remove(struct platform_device *pdev) +static void xiic_i2c_remove(struct platform_device *pdev) { struct xiic_i2c *i2c = platform_get_drvdata(pdev); int ret; @@ -867,43 +1555,9 @@ static int xiic_i2c_remove(struct platform_device *pdev) xiic_deinit(i2c); pm_runtime_put_sync(i2c->dev); - clk_disable_unprepare(i2c->clk); pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); - - return 0; -} - -#if defined(CONFIG_OF) -static const struct of_device_id xiic_of_match[] = { - { .compatible = "xlnx,xps-iic-2.00.a", }, - {}, -}; -MODULE_DEVICE_TABLE(of, xiic_of_match); -#endif - -static int __maybe_unused xiic_i2c_runtime_suspend(struct device *dev) -{ - struct xiic_i2c *i2c = dev_get_drvdata(dev); - - clk_disable(i2c->clk); - - return 0; -} - -static int __maybe_unused xiic_i2c_runtime_resume(struct device *dev) -{ - struct xiic_i2c *i2c = dev_get_drvdata(dev); - int ret; - - ret = clk_enable(i2c->clk); - if (ret) { - dev_err(dev, "Cannot enable clock.\n"); - return ret; - } - - return 0; } static const struct dev_pm_ops xiic_dev_pm_ops = { @@ -913,7 +1567,7 @@ static const struct dev_pm_ops xiic_dev_pm_ops = { static struct platform_driver xiic_i2c_driver = { .probe = xiic_i2c_probe, - .remove = xiic_i2c_remove, + .remove = xiic_i2c_remove, .driver = { .name = DRIVER_NAME, .of_match_table = of_match_ptr(xiic_of_match), diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index 4e3b11c0f732..ddb1c3e8bc9d 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -452,7 +452,7 @@ static u32 xlp9xx_i2c_functionality(struct i2c_adapter *adapter) } static const struct i2c_algorithm xlp9xx_i2c_algo = { - .master_xfer = xlp9xx_i2c_xfer, + .xfer = xlp9xx_i2c_xfer, .functionality = xlp9xx_i2c_functionality, }; @@ -529,10 +529,8 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev) err = devm_request_irq(&pdev->dev, priv->irq, xlp9xx_i2c_isr, 0, pdev->name, priv); - if (err) { - dev_err(&pdev->dev, "IRQ request failed!\n"); - return err; - } + if (err) + return dev_err_probe(&pdev->dev, err, "IRQ request failed!\n"); init_completion(&priv->msg_complete); priv->adapter.dev.parent = &pdev->dev; @@ -559,7 +557,7 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev) return 0; } -static int xlp9xx_i2c_remove(struct platform_device *pdev) +static void xlp9xx_i2c_remove(struct platform_device *pdev) { struct xlp9xx_i2c_dev *priv; @@ -568,8 +566,6 @@ static int xlp9xx_i2c_remove(struct platform_device *pdev) synchronize_irq(priv->irq); i2c_del_adapter(&priv->adapter); xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, 0); - - return 0; } #ifdef CONFIG_ACPI diff --git a/drivers/i2c/busses/scx200_acb.c b/drivers/i2c/busses/scx200_acb.c index 7b42a18bd05c..06cf221557f2 100644 --- a/drivers/i2c/busses/scx200_acb.c +++ b/drivers/i2c/busses/scx200_acb.c @@ -427,7 +427,7 @@ static struct scx200_acb_iface *scx200_create_iface(const char *text, snprintf(adapter->name, sizeof(adapter->name), "%s ACB%d", text, index); adapter->owner = THIS_MODULE; adapter->algo = &scx200_acb_algorithm; - adapter->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + adapter->class = I2C_CLASS_HWMON; adapter->dev.parent = dev; mutex_init(&iface->mutex); @@ -500,10 +500,8 @@ static int scx200_probe(struct platform_device *pdev) struct resource *res; res = platform_get_resource(pdev, IORESOURCE_IO, 0); - if (!res) { - dev_err(&pdev->dev, "can't fetch device resource info\n"); - return -ENODEV; - } + if (!res) + return dev_err_probe(&pdev->dev, -ENODEV, "can't fetch device resource info\n"); iface = scx200_create_dev("CS5535", res->start, 0, &pdev->dev); if (!iface) @@ -523,14 +521,12 @@ static void scx200_cleanup_iface(struct scx200_acb_iface *iface) kfree(iface); } -static int scx200_remove(struct platform_device *pdev) +static void scx200_remove(struct platform_device *pdev) { struct scx200_acb_iface *iface; iface = platform_get_drvdata(pdev); scx200_cleanup_iface(iface); - - return 0; } static struct platform_driver scx200_pci_driver = { diff --git a/drivers/i2c/i2c-atr.c b/drivers/i2c/i2c-atr.c new file mode 100644 index 000000000000..dd194476b118 --- /dev/null +++ b/drivers/i2c/i2c-atr.c @@ -0,0 +1,954 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * I2C Address Translator + * + * Copyright (c) 2019,2022 Luca Ceresoli <luca@lucaceresoli.net> + * Copyright (c) 2022,2023 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com> + * + * Originally based on i2c-mux.c + */ + +#include <linux/i2c-atr.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/property.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/lockdep.h> + +#define ATR_MAX_ADAPTERS 100 /* Just a sanity limit */ +#define ATR_MAX_SYMLINK_LEN 11 /* Longest name is 10 chars: "channel-99" */ + +/** + * struct i2c_atr_alias_pair - Holds the alias assigned to a client address. + * @node: List node + * @addr: Address of the client on the child bus. + * @alias: I2C alias address assigned by the driver. + * This is the address that will be used to issue I2C transactions + * on the parent (physical) bus. + * @fixed: Alias pair cannot be replaced during dynamic address attachment. + * This flag is necessary for situations where a single I2C transaction + * contains more distinct target addresses than the ATR channel can handle. + * It marks addresses that have already been attached to an alias so + * that their alias pair is not evicted by a subsequent address in the same + * transaction. + * + */ +struct i2c_atr_alias_pair { + struct list_head node; + bool fixed; + u16 addr; + u16 alias; +}; + +/** + * struct i2c_atr_alias_pool - Pool of client aliases available for an ATR. + * @size: Total number of aliases + * @shared: Indicates if this alias pool is shared by multiple channels + * + * @lock: Lock protecting @aliases and @use_mask + * @aliases: Array of aliases, must hold exactly @size elements + * @use_mask: Mask of used aliases + */ +struct i2c_atr_alias_pool { + size_t size; + bool shared; + + /* Protects aliases and use_mask */ + spinlock_t lock; + u16 *aliases; + unsigned long *use_mask; +}; + +/** + * struct i2c_atr_chan - Data for a channel. + * @adap: The &struct i2c_adapter for the channel + * @atr: The parent I2C ATR + * @chan_id: The ID of this channel + * @alias_pairs_lock: Mutex protecting @alias_pairs + * @alias_pairs_lock_key: Lock key for @alias_pairs_lock + * @alias_pairs: List of @struct i2c_atr_alias_pair containing the + * assigned aliases + * @alias_pool: Pool of available client aliases + * + * @orig_addrs_lock: Mutex protecting @orig_addrs + * @orig_addrs_lock_key: Lock key for @orig_addrs_lock + * @orig_addrs: Buffer used to store the original addresses during transmit + * @orig_addrs_size: Size of @orig_addrs + */ +struct i2c_atr_chan { + struct i2c_adapter adap; + struct i2c_atr *atr; + u32 chan_id; + + /* Lock alias_pairs during attach/detach */ + struct mutex alias_pairs_lock; + struct lock_class_key alias_pairs_lock_key; + struct list_head alias_pairs; + struct i2c_atr_alias_pool *alias_pool; + + /* Lock orig_addrs during xfer */ + struct mutex orig_addrs_lock; + struct lock_class_key orig_addrs_lock_key; + u16 *orig_addrs; + unsigned int orig_addrs_size; +}; + +/** + * struct i2c_atr - The I2C ATR instance + * @parent: The parent &struct i2c_adapter + * @dev: The device that owns the I2C ATR instance + * @ops: &struct i2c_atr_ops + * @priv: Private driver data, set with i2c_atr_set_driver_data() + * @algo: The &struct i2c_algorithm for adapters + * @lock: Lock for the I2C bus segment (see &struct i2c_lock_operations) + * @lock_key: Lock key for @lock + * @max_adapters: Maximum number of adapters this I2C ATR can have + * @flags: Flags for ATR + * @alias_pool: Optional common pool of available client aliases + * @i2c_nb: Notifier for remote client add & del events + * @adapter: Array of adapters + */ +struct i2c_atr { + struct i2c_adapter *parent; + struct device *dev; + const struct i2c_atr_ops *ops; + + void *priv; + + struct i2c_algorithm algo; + /* lock for the I2C bus segment (see struct i2c_lock_operations) */ + struct mutex lock; + struct lock_class_key lock_key; + int max_adapters; + u32 flags; + + struct i2c_atr_alias_pool *alias_pool; + + struct notifier_block i2c_nb; + + struct i2c_adapter *adapter[] __counted_by(max_adapters); +}; + +static struct i2c_atr_alias_pool *i2c_atr_alloc_alias_pool(size_t num_aliases, bool shared) +{ + struct i2c_atr_alias_pool *alias_pool; + int ret; + + alias_pool = kzalloc(sizeof(*alias_pool), GFP_KERNEL); + if (!alias_pool) + return ERR_PTR(-ENOMEM); + + alias_pool->size = num_aliases; + + alias_pool->aliases = kcalloc(num_aliases, sizeof(*alias_pool->aliases), GFP_KERNEL); + if (!alias_pool->aliases) { + ret = -ENOMEM; + goto err_free_alias_pool; + } + + alias_pool->use_mask = bitmap_zalloc(num_aliases, GFP_KERNEL); + if (!alias_pool->use_mask) { + ret = -ENOMEM; + goto err_free_aliases; + } + + alias_pool->shared = shared; + + spin_lock_init(&alias_pool->lock); + + return alias_pool; + +err_free_aliases: + kfree(alias_pool->aliases); +err_free_alias_pool: + kfree(alias_pool); + return ERR_PTR(ret); +} + +static void i2c_atr_free_alias_pool(struct i2c_atr_alias_pool *alias_pool) +{ + bitmap_free(alias_pool->use_mask); + kfree(alias_pool->aliases); + kfree(alias_pool); +} + +/* Must be called with alias_pairs_lock held */ +static struct i2c_atr_alias_pair *i2c_atr_create_c2a(struct i2c_atr_chan *chan, + u16 alias, u16 addr) +{ + struct i2c_atr_alias_pair *c2a; + + lockdep_assert_held(&chan->alias_pairs_lock); + + c2a = kzalloc(sizeof(*c2a), GFP_KERNEL); + if (!c2a) + return NULL; + + c2a->addr = addr; + c2a->alias = alias; + + list_add(&c2a->node, &chan->alias_pairs); + + return c2a; +} + +/* Must be called with alias_pairs_lock held */ +static void i2c_atr_destroy_c2a(struct i2c_atr_alias_pair **pc2a) +{ + list_del(&(*pc2a)->node); + kfree(*pc2a); + *pc2a = NULL; +} + +static int i2c_atr_reserve_alias(struct i2c_atr_alias_pool *alias_pool) +{ + unsigned long idx; + u16 alias; + + spin_lock(&alias_pool->lock); + + idx = find_first_zero_bit(alias_pool->use_mask, alias_pool->size); + if (idx >= alias_pool->size) { + spin_unlock(&alias_pool->lock); + return -EBUSY; + } + + set_bit(idx, alias_pool->use_mask); + + alias = alias_pool->aliases[idx]; + + spin_unlock(&alias_pool->lock); + return alias; +} + +static void i2c_atr_release_alias(struct i2c_atr_alias_pool *alias_pool, u16 alias) +{ + unsigned int idx; + + spin_lock(&alias_pool->lock); + + for (idx = 0; idx < alias_pool->size; ++idx) { + if (alias_pool->aliases[idx] == alias) { + clear_bit(idx, alias_pool->use_mask); + spin_unlock(&alias_pool->lock); + return; + } + } + + spin_unlock(&alias_pool->lock); +} + +static struct i2c_atr_alias_pair * +i2c_atr_find_mapping_by_addr(struct i2c_atr_chan *chan, u16 addr) +{ + struct i2c_atr_alias_pair *c2a; + + lockdep_assert_held(&chan->alias_pairs_lock); + + list_for_each_entry(c2a, &chan->alias_pairs, node) { + if (c2a->addr == addr) + return c2a; + } + + return NULL; +} + +static struct i2c_atr_alias_pair * +i2c_atr_create_mapping_by_addr(struct i2c_atr_chan *chan, u16 addr) +{ + struct i2c_atr *atr = chan->atr; + struct i2c_atr_alias_pair *c2a; + u16 alias; + int ret; + + lockdep_assert_held(&chan->alias_pairs_lock); + + ret = i2c_atr_reserve_alias(chan->alias_pool); + if (ret < 0) + return NULL; + + alias = ret; + + c2a = i2c_atr_create_c2a(chan, alias, addr); + if (!c2a) + goto err_release_alias; + + ret = atr->ops->attach_addr(atr, chan->chan_id, c2a->addr, c2a->alias); + if (ret) { + dev_err(atr->dev, "failed to attach 0x%02x on channel %d: err %d\n", + addr, chan->chan_id, ret); + goto err_del_c2a; + } + + return c2a; + +err_del_c2a: + i2c_atr_destroy_c2a(&c2a); +err_release_alias: + i2c_atr_release_alias(chan->alias_pool, alias); + return NULL; +} + +static struct i2c_atr_alias_pair * +i2c_atr_replace_mapping_by_addr(struct i2c_atr_chan *chan, u16 addr) +{ + struct i2c_atr *atr = chan->atr; + struct i2c_atr_alias_pair *c2a; + struct list_head *alias_pairs; + bool found = false; + u16 alias; + int ret; + + lockdep_assert_held(&chan->alias_pairs_lock); + + alias_pairs = &chan->alias_pairs; + + if (unlikely(list_empty(alias_pairs))) + return NULL; + + list_for_each_entry_reverse(c2a, alias_pairs, node) { + if (!c2a->fixed) { + found = true; + break; + } + } + + if (!found) + return NULL; + + atr->ops->detach_addr(atr, chan->chan_id, c2a->addr); + c2a->addr = addr; + + list_move(&c2a->node, alias_pairs); + + alias = c2a->alias; + + ret = atr->ops->attach_addr(atr, chan->chan_id, c2a->addr, c2a->alias); + if (ret) { + dev_err(atr->dev, "failed to attach 0x%02x on channel %d: err %d\n", + addr, chan->chan_id, ret); + i2c_atr_destroy_c2a(&c2a); + i2c_atr_release_alias(chan->alias_pool, alias); + return NULL; + } + + return c2a; +} + +static struct i2c_atr_alias_pair * +i2c_atr_get_mapping_by_addr(struct i2c_atr_chan *chan, u16 addr) +{ + struct i2c_atr *atr = chan->atr; + struct i2c_atr_alias_pair *c2a; + + c2a = i2c_atr_find_mapping_by_addr(chan, addr); + if (c2a) + return c2a; + + if (atr->flags & I2C_ATR_F_STATIC) + return NULL; + + c2a = i2c_atr_create_mapping_by_addr(chan, addr); + if (c2a) + return c2a; + + return i2c_atr_replace_mapping_by_addr(chan, addr); +} + +/* + * Replace all message addresses with their aliases, saving the original + * addresses. + * + * This function is internal for use in i2c_atr_master_xfer(). It must be + * followed by i2c_atr_unmap_msgs() to restore the original addresses. + */ +static int i2c_atr_map_msgs(struct i2c_atr_chan *chan, struct i2c_msg *msgs, + int num) +{ + struct i2c_atr *atr = chan->atr; + static struct i2c_atr_alias_pair *c2a; + int i, ret = 0; + + /* Ensure we have enough room to save the original addresses */ + if (unlikely(chan->orig_addrs_size < num)) { + u16 *new_buf; + + /* We don't care about old data, hence no realloc() */ + new_buf = kmalloc_array(num, sizeof(*new_buf), GFP_KERNEL); + if (!new_buf) + return -ENOMEM; + + kfree(chan->orig_addrs); + chan->orig_addrs = new_buf; + chan->orig_addrs_size = num; + } + + mutex_lock(&chan->alias_pairs_lock); + + for (i = 0; i < num; i++) { + chan->orig_addrs[i] = msgs[i].addr; + + c2a = i2c_atr_get_mapping_by_addr(chan, msgs[i].addr); + + if (!c2a) { + if (atr->flags & I2C_ATR_F_PASSTHROUGH) + continue; + + dev_err(atr->dev, "client 0x%02x not mapped!\n", + msgs[i].addr); + + while (i--) + msgs[i].addr = chan->orig_addrs[i]; + + ret = -ENXIO; + goto out_unlock; + } + + // Prevent c2a from being overwritten by another client in this transaction + c2a->fixed = true; + + msgs[i].addr = c2a->alias; + } + +out_unlock: + mutex_unlock(&chan->alias_pairs_lock); + return ret; +} + +/* + * Restore all message address aliases with the original addresses. This + * function is internal for use in i2c_atr_master_xfer() and for this reason it + * needs no null and size checks on orig_addr. + * + * @see i2c_atr_map_msgs() + */ +static void i2c_atr_unmap_msgs(struct i2c_atr_chan *chan, struct i2c_msg *msgs, + int num) +{ + struct i2c_atr_alias_pair *c2a; + int i; + + for (i = 0; i < num; i++) + msgs[i].addr = chan->orig_addrs[i]; + + mutex_lock(&chan->alias_pairs_lock); + + if (unlikely(list_empty(&chan->alias_pairs))) + goto out_unlock; + + // unfix c2a entries so that subsequent transfers can reuse their aliases + list_for_each_entry(c2a, &chan->alias_pairs, node) { + c2a->fixed = false; + } + +out_unlock: + mutex_unlock(&chan->alias_pairs_lock); +} + +static int i2c_atr_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct i2c_atr_chan *chan = adap->algo_data; + struct i2c_atr *atr = chan->atr; + struct i2c_adapter *parent = atr->parent; + int ret; + + /* Translate addresses */ + mutex_lock(&chan->orig_addrs_lock); + + ret = i2c_atr_map_msgs(chan, msgs, num); + if (ret < 0) + goto err_unlock; + + /* Perform the transfer */ + ret = i2c_transfer(parent, msgs, num); + + /* Restore addresses */ + i2c_atr_unmap_msgs(chan, msgs, num); + +err_unlock: + mutex_unlock(&chan->orig_addrs_lock); + + return ret; +} + +static int i2c_atr_smbus_xfer(struct i2c_adapter *adap, u16 addr, + unsigned short flags, char read_write, u8 command, + int size, union i2c_smbus_data *data) +{ + struct i2c_atr_chan *chan = adap->algo_data; + struct i2c_atr *atr = chan->atr; + struct i2c_adapter *parent = atr->parent; + struct i2c_atr_alias_pair *c2a; + u16 alias; + + mutex_lock(&chan->alias_pairs_lock); + + c2a = i2c_atr_get_mapping_by_addr(chan, addr); + + if (!c2a && !(atr->flags & I2C_ATR_F_PASSTHROUGH)) { + dev_err(atr->dev, "client 0x%02x not mapped!\n", addr); + mutex_unlock(&chan->alias_pairs_lock); + return -ENXIO; + } + + alias = c2a ? c2a->alias : addr; + + mutex_unlock(&chan->alias_pairs_lock); + + return i2c_smbus_xfer(parent, alias, flags, read_write, command, + size, data); +} + +static u32 i2c_atr_functionality(struct i2c_adapter *adap) +{ + struct i2c_atr_chan *chan = adap->algo_data; + struct i2c_adapter *parent = chan->atr->parent; + + return parent->algo->functionality(parent); +} + +static void i2c_atr_lock_bus(struct i2c_adapter *adapter, unsigned int flags) +{ + struct i2c_atr_chan *chan = adapter->algo_data; + struct i2c_atr *atr = chan->atr; + + mutex_lock(&atr->lock); +} + +static int i2c_atr_trylock_bus(struct i2c_adapter *adapter, unsigned int flags) +{ + struct i2c_atr_chan *chan = adapter->algo_data; + struct i2c_atr *atr = chan->atr; + + return mutex_trylock(&atr->lock); +} + +static void i2c_atr_unlock_bus(struct i2c_adapter *adapter, unsigned int flags) +{ + struct i2c_atr_chan *chan = adapter->algo_data; + struct i2c_atr *atr = chan->atr; + + mutex_unlock(&atr->lock); +} + +static const struct i2c_lock_operations i2c_atr_lock_ops = { + .lock_bus = i2c_atr_lock_bus, + .trylock_bus = i2c_atr_trylock_bus, + .unlock_bus = i2c_atr_unlock_bus, +}; + +static int i2c_atr_attach_addr(struct i2c_adapter *adapter, + u16 addr) +{ + struct i2c_atr_chan *chan = adapter->algo_data; + struct i2c_atr *atr = chan->atr; + struct i2c_atr_alias_pair *c2a; + int ret = 0; + + mutex_lock(&chan->alias_pairs_lock); + + c2a = i2c_atr_create_mapping_by_addr(chan, addr); + if (!c2a && !(atr->flags & I2C_ATR_F_STATIC)) + c2a = i2c_atr_replace_mapping_by_addr(chan, addr); + + if (!c2a) { + dev_err(atr->dev, "failed to find a free alias\n"); + ret = -EBUSY; + goto out_unlock; + } + + dev_dbg(atr->dev, "chan%u: using alias 0x%02x for addr 0x%02x\n", + chan->chan_id, c2a->alias, addr); + +out_unlock: + mutex_unlock(&chan->alias_pairs_lock); + return ret; +} + +static void i2c_atr_detach_addr(struct i2c_adapter *adapter, + u16 addr) +{ + struct i2c_atr_chan *chan = adapter->algo_data; + struct i2c_atr *atr = chan->atr; + struct i2c_atr_alias_pair *c2a; + + atr->ops->detach_addr(atr, chan->chan_id, addr); + + mutex_lock(&chan->alias_pairs_lock); + + c2a = i2c_atr_find_mapping_by_addr(chan, addr); + if (!c2a) { + mutex_unlock(&chan->alias_pairs_lock); + return; + } + + i2c_atr_release_alias(chan->alias_pool, c2a->alias); + + dev_dbg(atr->dev, + "chan%u: detached alias 0x%02x from addr 0x%02x\n", + chan->chan_id, c2a->alias, addr); + + i2c_atr_destroy_c2a(&c2a); + + mutex_unlock(&chan->alias_pairs_lock); +} + +static int i2c_atr_bus_notifier_call(struct notifier_block *nb, + unsigned long event, void *device) +{ + struct i2c_atr *atr = container_of(nb, struct i2c_atr, i2c_nb); + struct device *dev = device; + struct i2c_client *client; + u32 chan_id; + int ret; + + client = i2c_verify_client(dev); + if (!client) + return NOTIFY_DONE; + + /* Is the client in one of our adapters? */ + for (chan_id = 0; chan_id < atr->max_adapters; ++chan_id) { + if (client->adapter == atr->adapter[chan_id]) + break; + } + + if (chan_id == atr->max_adapters) + return NOTIFY_DONE; + + switch (event) { + case BUS_NOTIFY_ADD_DEVICE: + ret = i2c_atr_attach_addr(client->adapter, client->addr); + if (ret) + dev_err(atr->dev, + "Failed to attach remote client '%s': %d\n", + dev_name(dev), ret); + break; + + case BUS_NOTIFY_REMOVED_DEVICE: + i2c_atr_detach_addr(client->adapter, client->addr); + break; + + default: + break; + } + + return NOTIFY_DONE; +} + +static int i2c_atr_parse_alias_pool(struct i2c_atr *atr) +{ + struct i2c_atr_alias_pool *alias_pool; + struct device *dev = atr->dev; + size_t num_aliases; + unsigned int i; + u32 *aliases32; + int ret; + + if (!fwnode_property_present(dev_fwnode(dev), "i2c-alias-pool")) { + num_aliases = 0; + } else { + ret = fwnode_property_count_u32(dev_fwnode(dev), "i2c-alias-pool"); + if (ret < 0) { + dev_err(dev, "Failed to count 'i2c-alias-pool' property: %d\n", + ret); + return ret; + } + + num_aliases = ret; + } + + alias_pool = i2c_atr_alloc_alias_pool(num_aliases, true); + if (IS_ERR(alias_pool)) { + ret = PTR_ERR(alias_pool); + dev_err(dev, "Failed to allocate alias pool, err %d\n", ret); + return ret; + } + + atr->alias_pool = alias_pool; + + if (!alias_pool->size) + return 0; + + aliases32 = kcalloc(num_aliases, sizeof(*aliases32), GFP_KERNEL); + if (!aliases32) { + ret = -ENOMEM; + goto err_free_alias_pool; + } + + ret = fwnode_property_read_u32_array(dev_fwnode(dev), "i2c-alias-pool", + aliases32, num_aliases); + if (ret < 0) { + dev_err(dev, "Failed to read 'i2c-alias-pool' property: %d\n", + ret); + goto err_free_aliases32; + } + + for (i = 0; i < num_aliases; i++) { + if (!(aliases32[i] & 0xffff0000)) { + alias_pool->aliases[i] = aliases32[i]; + continue; + } + + dev_err(dev, "Failed to parse 'i2c-alias-pool' property: I2C flags are not supported\n"); + ret = -EINVAL; + goto err_free_aliases32; + } + + kfree(aliases32); + + dev_dbg(dev, "i2c-alias-pool has %zu aliases\n", alias_pool->size); + + return 0; + +err_free_aliases32: + kfree(aliases32); +err_free_alias_pool: + i2c_atr_free_alias_pool(alias_pool); + return ret; +} + +struct i2c_atr *i2c_atr_new(struct i2c_adapter *parent, struct device *dev, + const struct i2c_atr_ops *ops, int max_adapters, + u32 flags) +{ + struct i2c_atr *atr; + int ret; + + if (max_adapters > ATR_MAX_ADAPTERS) + return ERR_PTR(-EINVAL); + + if (!ops || !ops->attach_addr || !ops->detach_addr) + return ERR_PTR(-EINVAL); + + atr = kzalloc(struct_size(atr, adapter, max_adapters), GFP_KERNEL); + if (!atr) + return ERR_PTR(-ENOMEM); + + lockdep_register_key(&atr->lock_key); + mutex_init_with_key(&atr->lock, &atr->lock_key); + + atr->parent = parent; + atr->dev = dev; + atr->ops = ops; + atr->max_adapters = max_adapters; + atr->flags = flags; + + if (parent->algo->master_xfer) + atr->algo.xfer = i2c_atr_master_xfer; + if (parent->algo->smbus_xfer) + atr->algo.smbus_xfer = i2c_atr_smbus_xfer; + atr->algo.functionality = i2c_atr_functionality; + + ret = i2c_atr_parse_alias_pool(atr); + if (ret) + goto err_destroy_mutex; + + atr->i2c_nb.notifier_call = i2c_atr_bus_notifier_call; + ret = bus_register_notifier(&i2c_bus_type, &atr->i2c_nb); + if (ret) + goto err_free_alias_pool; + + return atr; + +err_free_alias_pool: + i2c_atr_free_alias_pool(atr->alias_pool); +err_destroy_mutex: + mutex_destroy(&atr->lock); + lockdep_unregister_key(&atr->lock_key); + kfree(atr); + + return ERR_PTR(ret); +} +EXPORT_SYMBOL_NS_GPL(i2c_atr_new, "I2C_ATR"); + +void i2c_atr_delete(struct i2c_atr *atr) +{ + unsigned int i; + + for (i = 0; i < atr->max_adapters; ++i) + WARN_ON(atr->adapter[i]); + + bus_unregister_notifier(&i2c_bus_type, &atr->i2c_nb); + i2c_atr_free_alias_pool(atr->alias_pool); + mutex_destroy(&atr->lock); + lockdep_unregister_key(&atr->lock_key); + kfree(atr); +} +EXPORT_SYMBOL_NS_GPL(i2c_atr_delete, "I2C_ATR"); + +int i2c_atr_add_adapter(struct i2c_atr *atr, struct i2c_atr_adap_desc *desc) +{ + struct fwnode_handle *bus_handle = desc->bus_handle; + struct i2c_adapter *parent = atr->parent; + char symlink_name[ATR_MAX_SYMLINK_LEN]; + struct device *dev = atr->dev; + u32 chan_id = desc->chan_id; + struct i2c_atr_chan *chan; + int ret, idx; + + if (chan_id >= atr->max_adapters) { + dev_err(dev, "No room for more i2c-atr adapters\n"); + return -EINVAL; + } + + if (atr->adapter[chan_id]) { + dev_err(dev, "Adapter %d already present\n", chan_id); + return -EEXIST; + } + + chan = kzalloc(sizeof(*chan), GFP_KERNEL); + if (!chan) + return -ENOMEM; + + if (!desc->parent) + desc->parent = dev; + + chan->atr = atr; + chan->chan_id = chan_id; + INIT_LIST_HEAD(&chan->alias_pairs); + lockdep_register_key(&chan->alias_pairs_lock_key); + lockdep_register_key(&chan->orig_addrs_lock_key); + mutex_init_with_key(&chan->alias_pairs_lock, &chan->alias_pairs_lock_key); + mutex_init_with_key(&chan->orig_addrs_lock, &chan->orig_addrs_lock_key); + + snprintf(chan->adap.name, sizeof(chan->adap.name), "i2c-%d-atr-%d", + i2c_adapter_id(parent), chan_id); + chan->adap.owner = THIS_MODULE; + chan->adap.algo = &atr->algo; + chan->adap.algo_data = chan; + chan->adap.dev.parent = desc->parent; + chan->adap.retries = parent->retries; + chan->adap.timeout = parent->timeout; + chan->adap.quirks = parent->quirks; + chan->adap.lock_ops = &i2c_atr_lock_ops; + + if (bus_handle) { + device_set_node(&chan->adap.dev, fwnode_handle_get(bus_handle)); + } else { + struct fwnode_handle *atr_node; + struct fwnode_handle *child; + u32 reg; + + atr_node = device_get_named_child_node(dev, "i2c-atr"); + + fwnode_for_each_child_node(atr_node, child) { + ret = fwnode_property_read_u32(child, "reg", ®); + if (ret) + continue; + if (chan_id == reg) + break; + } + + device_set_node(&chan->adap.dev, child); + fwnode_handle_put(atr_node); + } + + if (desc->num_aliases > 0) { + chan->alias_pool = i2c_atr_alloc_alias_pool(desc->num_aliases, false); + if (IS_ERR(chan->alias_pool)) { + ret = PTR_ERR(chan->alias_pool); + goto err_fwnode_put; + } + + for (idx = 0; idx < desc->num_aliases; idx++) + chan->alias_pool->aliases[idx] = desc->aliases[idx]; + } else { + chan->alias_pool = atr->alias_pool; + } + + atr->adapter[chan_id] = &chan->adap; + + ret = i2c_add_adapter(&chan->adap); + if (ret) { + dev_err(dev, "failed to add atr-adapter %u (error=%d)\n", + chan_id, ret); + goto err_free_alias_pool; + } + + snprintf(symlink_name, sizeof(symlink_name), "channel-%u", + chan->chan_id); + + ret = sysfs_create_link(&chan->adap.dev.kobj, &dev->kobj, "atr_device"); + if (ret) + dev_warn(dev, "can't create symlink to atr device\n"); + ret = sysfs_create_link(&dev->kobj, &chan->adap.dev.kobj, symlink_name); + if (ret) + dev_warn(dev, "can't create symlink for channel %u\n", chan_id); + + dev_dbg(dev, "Added ATR child bus %d\n", i2c_adapter_id(&chan->adap)); + + return 0; + +err_free_alias_pool: + if (!chan->alias_pool->shared) + i2c_atr_free_alias_pool(chan->alias_pool); +err_fwnode_put: + fwnode_handle_put(dev_fwnode(&chan->adap.dev)); + mutex_destroy(&chan->orig_addrs_lock); + mutex_destroy(&chan->alias_pairs_lock); + lockdep_unregister_key(&chan->orig_addrs_lock_key); + lockdep_unregister_key(&chan->alias_pairs_lock_key); + kfree(chan); + return ret; +} +EXPORT_SYMBOL_NS_GPL(i2c_atr_add_adapter, "I2C_ATR"); + +void i2c_atr_del_adapter(struct i2c_atr *atr, u32 chan_id) +{ + char symlink_name[ATR_MAX_SYMLINK_LEN]; + struct i2c_adapter *adap; + struct i2c_atr_chan *chan; + struct fwnode_handle *fwnode; + struct device *dev = atr->dev; + + adap = atr->adapter[chan_id]; + if (!adap) + return; + + chan = adap->algo_data; + fwnode = dev_fwnode(&adap->dev); + + dev_dbg(dev, "Removing ATR child bus %d\n", i2c_adapter_id(adap)); + + snprintf(symlink_name, sizeof(symlink_name), "channel-%u", + chan->chan_id); + sysfs_remove_link(&dev->kobj, symlink_name); + sysfs_remove_link(&chan->adap.dev.kobj, "atr_device"); + + i2c_del_adapter(adap); + + if (!chan->alias_pool->shared) + i2c_atr_free_alias_pool(chan->alias_pool); + + atr->adapter[chan_id] = NULL; + + fwnode_handle_put(fwnode); + mutex_destroy(&chan->orig_addrs_lock); + mutex_destroy(&chan->alias_pairs_lock); + lockdep_unregister_key(&chan->orig_addrs_lock_key); + lockdep_unregister_key(&chan->alias_pairs_lock_key); + kfree(chan->orig_addrs); + kfree(chan); +} +EXPORT_SYMBOL_NS_GPL(i2c_atr_del_adapter, "I2C_ATR"); + +void i2c_atr_set_driver_data(struct i2c_atr *atr, void *data) +{ + atr->priv = data; +} +EXPORT_SYMBOL_NS_GPL(i2c_atr_set_driver_data, "I2C_ATR"); + +void *i2c_atr_get_driver_data(struct i2c_atr *atr) +{ + return atr->priv; +} +EXPORT_SYMBOL_NS_GPL(i2c_atr_get_driver_data, "I2C_ATR"); + +MODULE_AUTHOR("Luca Ceresoli <luca.ceresoli@bootlin.com>"); +MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>"); +MODULE_DESCRIPTION("I2C Address Translator"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/i2c-core-acpi.c b/drivers/i2c/i2c-core-acpi.c index 4dd777cc0c89..ed90858a27b7 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -250,7 +250,7 @@ static int i2c_acpi_get_info(struct acpi_device *adev, if (adapter) { /* The adapter must match the one in I2cSerialBus() connector */ - if (ACPI_HANDLE(&adapter->dev) != lookup.adapter_handle) + if (!device_match_acpi_handle(&adapter->dev, lookup.adapter_handle)) return -ENODEV; } else { struct acpi_device *adapter_adev; @@ -355,6 +355,26 @@ static const struct acpi_device_id i2c_acpi_force_400khz_device_ids[] = { {} }; +static const struct acpi_device_id i2c_acpi_force_100khz_device_ids[] = { + /* + * When a 400KHz freq is used on this model of ELAN touchpad in Linux, + * excessive smoothing (similar to when the touchpad's firmware detects + * a noisy signal) is sometimes applied. As some devices' (e.g, Lenovo + * V15 G4) ACPI tables specify a 400KHz frequency for this device and + * some I2C busses (e.g, Designware I2C) default to a 400KHz freq, + * force the speed to 100KHz as a workaround. + * + * For future investigation: This problem may be related to the default + * HCNT/LCNT values given by some busses' drivers, because they are not + * specified in the aforementioned devices' ACPI tables, and because + * the device works without issues on Windows at what is expected to be + * a 400KHz frequency. The root cause of the issue is not known. + */ + { "DLL0945", 0 }, + { "ELAN06FA", 0 }, + {} +}; + static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level, void *data, void **return_value) { @@ -373,6 +393,9 @@ static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level, if (acpi_match_device_ids(adev, i2c_acpi_force_400khz_device_ids) == 0) lookup->force_speed = I2C_MAX_FAST_MODE_FREQ; + if (acpi_match_device_ids(adev, i2c_acpi_force_100khz_device_ids) == 0) + lookup->force_speed = I2C_MAX_STANDARD_MODE_FREQ; + return AE_OK; } @@ -442,18 +465,12 @@ EXPORT_SYMBOL_GPL(i2c_acpi_find_adapter_by_handle); static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev) { - struct device *dev; - struct i2c_client *client; - - dev = bus_find_device_by_acpi_dev(&i2c_bus_type, adev); - if (!dev) - return NULL; - - client = i2c_verify_client(dev); - if (!client) - put_device(dev); + return i2c_find_device_by_fwnode(acpi_fwnode_handle(adev)); +} - return client; +static struct i2c_adapter *i2c_acpi_find_adapter_by_adev(struct acpi_device *adev) +{ + return i2c_find_adapter_by_fwnode(acpi_fwnode_handle(adev)); } static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, @@ -482,11 +499,17 @@ static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, break; client = i2c_acpi_find_client_by_adev(adev); - if (!client) - break; + if (client) { + i2c_unregister_device(client); + put_device(&client->dev); + } + + adapter = i2c_acpi_find_adapter_by_adev(adev); + if (adapter) { + acpi_unbind_one(&adapter->dev); + put_device(&adapter->dev); + } - i2c_unregister_device(client); - put_device(&client->dev); break; } diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 087e480b624c..ae7e9c8b65a6 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -16,6 +16,7 @@ #include <linux/acpi.h> #include <linux/clk/clk-conf.h> #include <linux/completion.h> +#include <linux/debugfs.h> #include <linux/delay.h> #include <linux/err.h> #include <linux/errno.h> @@ -25,21 +26,22 @@ #include <linux/idr.h> #include <linux/init.h> #include <linux/interrupt.h> -#include <linux/irqflags.h> +#include <linux/irq.h> #include <linux/jump_label.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/mutex.h> #include <linux/of_device.h> #include <linux/of.h> -#include <linux/of_irq.h> #include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/devinfo.h> #include <linux/pm_domain.h> #include <linux/pm_runtime.h> #include <linux/pm_wakeirq.h> #include <linux/property.h> #include <linux/rwsem.h> #include <linux/slab.h> +#include <linux/string_choices.h> #include "i2c-core.h" @@ -66,6 +68,8 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); static DEFINE_STATIC_KEY_FALSE(i2c_trace_msg_key); static bool is_registered; +static struct dentry *i2c_debugfs_root; + int i2c_transfer_trace_reg(void) { static_branch_inc(&i2c_trace_msg_key); @@ -113,10 +117,29 @@ const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, } EXPORT_SYMBOL_GPL(i2c_match_id); -static int i2c_device_match(struct device *dev, struct device_driver *drv) +const void *i2c_get_match_data(const struct i2c_client *client) +{ + struct i2c_driver *driver = to_i2c_driver(client->dev.driver); + const struct i2c_device_id *match; + const void *data; + + data = device_get_match_data(&client->dev); + if (!data) { + match = i2c_match_id(driver->id_table, client); + if (!match) + return NULL; + + data = (const void *)match->driver_data; + } + + return data; +} +EXPORT_SYMBOL(i2c_get_match_data); + +static int i2c_device_match(struct device *dev, const struct device_driver *drv) { struct i2c_client *client = i2c_verify_client(dev); - struct i2c_driver *driver; + const struct i2c_driver *driver; /* Attempt an OF style match */ @@ -136,9 +159,9 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv) return 0; } -static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) +static int i2c_device_uevent(const struct device *dev, struct kobj_uevent_env *env) { - struct i2c_client *client = to_i2c_client(dev); + const struct i2c_client *client = to_i2c_client(dev); int rc; rc = of_device_uevent_modalias(dev, env); @@ -282,7 +305,9 @@ static void i2c_gpio_init_pinctrl_recovery(struct i2c_adapter *adap) { struct i2c_bus_recovery_info *bri = adap->bus_recovery_info; struct device *dev = &adap->dev; - struct pinctrl *p = bri->pinctrl; + struct pinctrl *p = bri->pinctrl ?: dev_pinctrl(dev->parent); + + bri->pinctrl = p; /* * we can't change states without pinctrl, so remove the states if @@ -465,6 +490,7 @@ static int i2c_smbus_host_notify_to_irq(const struct i2c_client *client) static int i2c_device_probe(struct device *dev) { + struct fwnode_handle *fwnode = dev_fwnode(dev); struct i2c_client *client = i2c_verify_client(dev); struct i2c_driver *driver; bool do_power_on; @@ -483,11 +509,11 @@ static int i2c_device_probe(struct device *dev) /* Keep adapter active when Host Notify is required */ pm_runtime_get_sync(&client->adapter->dev); irq = i2c_smbus_host_notify_to_irq(client); - } else if (dev->of_node) { - irq = of_irq_get_byname(dev->of_node, "irq"); + } else if (is_of_node(fwnode)) { + irq = fwnode_irq_get_byname(fwnode, "irq"); if (irq == -EINVAL || irq == -ENODATA) - irq = of_irq_get(dev->of_node, 0); - } else if (ACPI_COMPANION(dev)) { + irq = fwnode_irq_get(fwnode, 0); + } else if (is_acpi_device_node(fwnode)) { bool wake_capable; irq = i2c_acpi_get_irq(client, &wake_capable); @@ -495,7 +521,7 @@ static int i2c_device_probe(struct device *dev) client->flags |= I2C_CLIENT_WAKE; } if (irq == -EPROBE_DEFER) { - status = irq; + status = dev_err_probe(dev, irq, "can't get irq\n"); goto put_sync_adapter; } @@ -521,9 +547,9 @@ static int i2c_device_probe(struct device *dev) if (client->flags & I2C_CLIENT_WAKE) { int wakeirq; - wakeirq = of_irq_get_byname(dev->of_node, "wakeup"); + wakeirq = fwnode_irq_get_byname(fwnode, "wakeup"); if (wakeirq == -EPROBE_DEFER) { - status = wakeirq; + status = dev_err_probe(dev, wakeirq, "can't get wakeirq\n"); goto put_sync_adapter; } @@ -542,12 +568,13 @@ static int i2c_device_probe(struct device *dev) dev_dbg(dev, "probe\n"); - status = of_clk_set_defaults(dev->of_node, false); + status = of_clk_set_defaults(to_of_node(fwnode), false); if (status < 0) goto err_clear_wakeup_irq; do_power_on = !i2c_acpi_waive_d0_probe(dev); - status = dev_pm_domain_attach(&client->dev, do_power_on); + status = dev_pm_domain_attach(&client->dev, PD_FLAG_DETACH_POWER_OFF | + (do_power_on ? PD_FLAG_ATTACH_POWER_ON : 0)); if (status) goto err_clear_wakeup_irq; @@ -555,18 +582,14 @@ static int i2c_device_probe(struct device *dev) GFP_KERNEL); if (!client->devres_group_id) { status = -ENOMEM; - goto err_detach_pm_domain; + goto err_clear_wakeup_irq; } - /* - * When there are no more users of probe(), - * rename probe_new to probe. - */ - if (driver->probe_new) - status = driver->probe_new(client); - else if (driver->probe) - status = driver->probe(client, - i2c_match_id(driver->id_table, client)); + client->debugfs = debugfs_create_dir(dev_name(&client->dev), + client->adapter->debugfs); + + if (driver->probe) + status = driver->probe(client); else status = -EINVAL; @@ -584,9 +607,8 @@ static int i2c_device_probe(struct device *dev) return 0; err_release_driver_resources: + debugfs_remove_recursive(client->debugfs); devres_release_group(&client->dev, client->devres_group_id); -err_detach_pm_domain: - dev_pm_domain_detach(&client->dev, do_power_on); err_clear_wakeup_irq: dev_pm_clear_wake_irq(&client->dev); device_init_wakeup(&client->dev, false); @@ -609,9 +631,9 @@ static void i2c_device_remove(struct device *dev) driver->remove(client); } - devres_release_group(&client->dev, client->devres_group_id); + debugfs_remove_recursive(client->debugfs); - dev_pm_domain_detach(&client->dev, true); + devres_release_group(&client->dev, client->devres_group_id); dev_pm_clear_wake_irq(&client->dev); device_init_wakeup(&client->dev, false); @@ -674,7 +696,7 @@ static struct attribute *i2c_dev_attrs[] = { }; ATTRIBUTE_GROUPS(i2c_dev); -struct bus_type i2c_bus_type = { +const struct bus_type i2c_bus_type = { .name = "i2c", .match = i2c_device_match, .probe = i2c_device_probe, @@ -683,7 +705,7 @@ struct bus_type i2c_bus_type = { }; EXPORT_SYMBOL_GPL(i2c_bus_type); -struct device_type i2c_client_type = { +const struct device_type i2c_client_type = { .groups = i2c_dev_groups, .uevent = i2c_device_uevent, .release = i2c_client_dev_release, @@ -897,6 +919,27 @@ int i2c_dev_irq_from_resources(const struct resource *resources, return 0; } +/* + * Serialize device instantiation in case it can be instantiated explicitly + * and by auto-detection + */ +static int i2c_lock_addr(struct i2c_adapter *adap, unsigned short addr, + unsigned short flags) +{ + if (!(flags & I2C_CLIENT_TEN) && + test_and_set_bit(addr, adap->addrs_in_instantiation)) + return -EBUSY; + + return 0; +} + +static void i2c_unlock_addr(struct i2c_adapter *adap, unsigned short addr, + unsigned short flags) +{ + if (!(flags & I2C_CLIENT_TEN)) + clear_bit(addr, adap->addrs_in_instantiation); +} + /** * i2c_new_client_device - instantiate an i2c device * @adap: the adapter managing the device @@ -916,8 +959,10 @@ int i2c_dev_irq_from_resources(const struct resource *resources, struct i2c_client * i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *info) { - struct i2c_client *client; - int status; + struct fwnode_handle *fwnode = info->fwnode; + struct i2c_client *client; + bool need_put = false; + int status; client = kzalloc(sizeof *client, GFP_KERNEL); if (!client) @@ -943,6 +988,10 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf goto out_err_silent; } + status = i2c_lock_addr(adap, client->addr, client->flags); + if (status) + goto out_err_silent; + /* Check for address business */ status = i2c_check_addr_busy(adap, i2c_encode_flags_to_addr(client)); if (status) @@ -951,11 +1000,10 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf client->dev.parent = &client->adapter->dev; client->dev.bus = &i2c_bus_type; client->dev.type = &i2c_client_type; - client->dev.of_node = of_node_get(info->of_node); - client->dev.fwnode = info->fwnode; device_enable_async_suspend(&client->dev); - i2c_dev_set_name(adap, client, info); + + device_set_node(&client->dev, fwnode_handle_get(fwnode)); if (info->swnode) { status = device_add_software_node(&client->dev, info->swnode); @@ -963,10 +1011,11 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf dev_err(&adap->dev, "Failed to add software node to client %s: %d\n", client->name, status); - goto out_err_put_of_node; + goto out_err_put_fwnode; } } + i2c_dev_set_name(adap, client, info); status = device_register(&client->dev); if (status) goto out_remove_swnode; @@ -974,18 +1023,25 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n", client->name, dev_name(&client->dev)); + i2c_unlock_addr(adap, client->addr, client->flags); + return client; out_remove_swnode: device_remove_software_node(&client->dev); -out_err_put_of_node: - of_node_put(info->of_node); + need_put = true; +out_err_put_fwnode: + fwnode_handle_put(fwnode); out_err: dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x (%d)\n", client->name, client->addr, status); + i2c_unlock_addr(adap, client->addr, client->flags); out_err_silent: - kfree(client); + if (need_put) + put_device(&client->dev); + else + kfree(client); return ERR_PTR(status); } EXPORT_SYMBOL_GPL(i2c_new_client_device); @@ -997,25 +1053,63 @@ EXPORT_SYMBOL_GPL(i2c_new_client_device); */ void i2c_unregister_device(struct i2c_client *client) { + struct fwnode_handle *fwnode; + if (IS_ERR_OR_NULL(client)) return; - if (client->dev.of_node) { - of_node_clear_flag(client->dev.of_node, OF_POPULATED); - of_node_put(client->dev.of_node); - } + fwnode = dev_fwnode(&client->dev); + if (is_of_node(fwnode)) + of_node_clear_flag(to_of_node(fwnode), OF_POPULATED); + else if (is_acpi_device_node(fwnode)) + acpi_device_clear_enumerated(to_acpi_device_node(fwnode)); + + /* + * If the primary fwnode is a software node it is free-ed by + * device_remove_software_node() below, avoid double-free. + */ + if (!is_software_node(fwnode)) + fwnode_handle_put(fwnode); - if (ACPI_COMPANION(&client->dev)) - acpi_device_clear_enumerated(ACPI_COMPANION(&client->dev)); device_remove_software_node(&client->dev); device_unregister(&client->dev); } EXPORT_SYMBOL_GPL(i2c_unregister_device); +/** + * i2c_find_device_by_fwnode() - find an i2c_client for the fwnode + * @fwnode: &struct fwnode_handle corresponding to the &struct i2c_client + * + * Look up and return the &struct i2c_client corresponding to the @fwnode. + * If no client can be found, or @fwnode is NULL, this returns NULL. + * + * The user must call put_device(&client->dev) once done with the i2c client. + */ +struct i2c_client *i2c_find_device_by_fwnode(struct fwnode_handle *fwnode) +{ + struct i2c_client *client; + struct device *dev; + + if (!fwnode) + return NULL; + + dev = bus_find_device_by_fwnode(&i2c_bus_type, fwnode); + if (!dev) + return NULL; + + client = i2c_verify_client(dev); + if (!client) + put_device(dev); + + return client; +} +EXPORT_SYMBOL(i2c_find_device_by_fwnode); + static const struct i2c_device_id dummy_id[] = { - { "dummy", 0 }, - { }, + { "dummy", }, + { "smbus_host_notify", }, + { } }; static int dummy_probe(struct i2c_client *client) @@ -1025,7 +1119,7 @@ static int dummy_probe(struct i2c_client *client) static struct i2c_driver dummy_driver = { .driver.name = "dummy", - .probe_new = dummy_probe, + .probe = dummy_probe, .id_table = dummy_id, }; @@ -1121,11 +1215,9 @@ struct i2c_client *i2c_new_ancillary_device(struct i2c_client *client, u32 addr = default_addr; int i; - if (np) { - i = of_property_match_string(np, "reg-names", name); - if (i >= 0) - of_property_read_u32_index(np, "reg", i, &addr); - } + i = of_property_match_string(np, "reg-names", name); + if (i >= 0) + of_property_read_u32_index(np, "reg", i, &addr); dev_dbg(&client->adapter->dev, "Address for %s : 0x%x\n", name, addr); return i2c_new_dummy_device(client->adapter, addr); @@ -1145,9 +1237,11 @@ static void i2c_adapter_dev_release(struct device *dev) unsigned int i2c_adapter_depth(struct i2c_adapter *adapter) { unsigned int depth = 0; + struct device *parent; - while ((adapter = i2c_parent_is_i2c_adapter(adapter))) - depth++; + for (parent = adapter->dev.parent; parent; parent = parent->parent) + if (parent->type == &i2c_adapter_type) + depth++; WARN_ONCE(depth >= MAX_LOCKDEP_SUBCLASSES, "adapter depth exceeds lockdep subclass limit\n"); @@ -1289,7 +1383,7 @@ static struct attribute *i2c_adapter_attrs[] = { }; ATTRIBUTE_GROUPS(i2c_adapter); -struct device_type i2c_adapter_type = { +const struct device_type i2c_adapter_type = { .groups = i2c_adapter_groups, .release = i2c_adapter_dev_release, }; @@ -1312,10 +1406,6 @@ struct i2c_adapter *i2c_verify_adapter(struct device *dev) } EXPORT_SYMBOL(i2c_verify_adapter); -#ifdef CONFIG_I2C_COMPAT -static struct class_compat *i2c_adapter_compat_class; -#endif - static void i2c_scan_static_board_info(struct i2c_adapter *adapter) { struct i2c_devinfo *devinfo; @@ -1414,6 +1504,8 @@ int i2c_handle_smbus_host_notify(struct i2c_adapter *adap, unsigned short addr) if (!adap) return -EINVAL; + dev_dbg(&adap->dev, "Detected HostNotify from address 0x%02x", addr); + irq = irq_find_mapping(adap->host_notify_domain, addr); if (irq <= 0) return -ENXIO; @@ -1467,35 +1559,36 @@ static int i2c_register_adapter(struct i2c_adapter *adap) dev_set_name(&adap->dev, "i2c-%d", adap->nr); adap->dev.bus = &i2c_bus_type; adap->dev.type = &i2c_adapter_type; - res = device_register(&adap->dev); + device_initialize(&adap->dev); + + /* + * This adapter can be used as a parent immediately after device_add(), + * setup runtime-pm (especially ignore-children) before hand. + */ + device_enable_async_suspend(&adap->dev); + pm_runtime_no_callbacks(&adap->dev); + pm_suspend_ignore_children(&adap->dev, true); + pm_runtime_enable(&adap->dev); + + res = device_add(&adap->dev); if (res) { pr_err("adapter '%s': can't register device (%d)\n", adap->name, res); + put_device(&adap->dev); goto out_list; } + adap->debugfs = debugfs_create_dir(dev_name(&adap->dev), i2c_debugfs_root); + res = i2c_setup_smbus_alert(adap); if (res) goto out_reg; - device_enable_async_suspend(&adap->dev); - pm_runtime_no_callbacks(&adap->dev); - pm_suspend_ignore_children(&adap->dev, true); - pm_runtime_enable(&adap->dev); - res = i2c_init_recovery(adap); if (res == -EPROBE_DEFER) goto out_reg; dev_dbg(&adap->dev, "adapter [%s] registered\n", adap->name); -#ifdef CONFIG_I2C_COMPAT - res = class_compat_create_link(i2c_adapter_compat_class, &adap->dev, - adap->dev.parent); - if (res) - dev_warn(&adap->dev, - "Failed to create compatibility class link\n"); -#endif - /* create pre-declared device nodes */ of_i2c_register_devices(adap); i2c_acpi_install_space_handler(adap); @@ -1512,6 +1605,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap) return 0; out_reg: + debugfs_remove_recursive(adap->debugfs); init_completion(&adap->dev_released); device_unregister(&adap->dev); wait_for_completion(&adap->dev_released); @@ -1561,12 +1655,10 @@ int i2c_add_adapter(struct i2c_adapter *adapter) struct device *dev = &adapter->dev; int id; - if (dev->of_node) { - id = of_alias_get_id(dev->of_node, "i2c"); - if (id >= 0) { - adapter->nr = id; - return __i2c_add_numbered_adapter(adapter); - } + id = of_alias_get_id(dev->of_node, "i2c"); + if (id >= 0) { + adapter->nr = id; + return __i2c_add_numbered_adapter(adapter); } mutex_lock(&core_lock); @@ -1701,11 +1793,6 @@ void i2c_del_adapter(struct i2c_adapter *adap) device_for_each_child(&adap->dev, NULL, __unregister_client); device_for_each_child(&adap->dev, NULL, __unregister_dummy); -#ifdef CONFIG_I2C_COMPAT - class_compat_remove_link(i2c_adapter_compat_class, &adap->dev, - adap->dev.parent); -#endif - /* device name is gone after device_unregister */ dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name); @@ -1713,6 +1800,8 @@ void i2c_del_adapter(struct i2c_adapter *adap) i2c_host_notify_irq_teardown(adap); + debugfs_remove_recursive(adap->debugfs); + /* wait until all references to the device are gone * * FIXME: This is old code and should ideally be replaced by an @@ -1761,6 +1850,75 @@ int devm_i2c_add_adapter(struct device *dev, struct i2c_adapter *adapter) } EXPORT_SYMBOL_GPL(devm_i2c_add_adapter); +static int i2c_dev_or_parent_fwnode_match(struct device *dev, const void *data) +{ + if (dev_fwnode(dev) == data) + return 1; + + if (dev->parent && dev_fwnode(dev->parent) == data) + return 1; + + return 0; +} + +/** + * i2c_find_adapter_by_fwnode() - find an i2c_adapter for the fwnode + * @fwnode: &struct fwnode_handle corresponding to the &struct i2c_adapter + * + * Look up and return the &struct i2c_adapter corresponding to the @fwnode. + * If no adapter can be found, or @fwnode is NULL, this returns NULL. + * + * The user must call put_device(&adapter->dev) once done with the i2c adapter. + */ +struct i2c_adapter *i2c_find_adapter_by_fwnode(struct fwnode_handle *fwnode) +{ + struct i2c_adapter *adapter; + struct device *dev; + + if (!fwnode) + return NULL; + + dev = bus_find_device(&i2c_bus_type, NULL, fwnode, + i2c_dev_or_parent_fwnode_match); + if (!dev) + return NULL; + + adapter = i2c_verify_adapter(dev); + if (!adapter) + put_device(dev); + + return adapter; +} +EXPORT_SYMBOL(i2c_find_adapter_by_fwnode); + +/** + * i2c_get_adapter_by_fwnode() - find an i2c_adapter for the fwnode + * @fwnode: &struct fwnode_handle corresponding to the &struct i2c_adapter + * + * Look up and return the &struct i2c_adapter corresponding to the @fwnode, + * and increment the adapter module's use count. If no adapter can be found, + * or @fwnode is NULL, this returns NULL. + * + * The user must call i2c_put_adapter(adapter) once done with the i2c adapter. + * Note that this is different from i2c_find_adapter_by_node(). + */ +struct i2c_adapter *i2c_get_adapter_by_fwnode(struct fwnode_handle *fwnode) +{ + struct i2c_adapter *adapter; + + adapter = i2c_find_adapter_by_fwnode(fwnode); + if (!adapter) + return NULL; + + if (!try_module_get(adapter->owner)) { + put_device(&adapter->dev); + adapter = NULL; + } + + return adapter; +} +EXPORT_SYMBOL(i2c_get_adapter_by_fwnode); + static void i2c_parse_timing(struct device *dev, char *prop_name, u32 *cur_val_p, u32 def_val, bool use_def) { @@ -1941,13 +2099,8 @@ static int __init i2c_init(void) is_registered = true; -#ifdef CONFIG_I2C_COMPAT - i2c_adapter_compat_class = class_compat_register("i2c-adapter"); - if (!i2c_adapter_compat_class) { - retval = -ENOMEM; - goto bus_err; - } -#endif + i2c_debugfs_root = debugfs_create_dir("i2c", NULL); + retval = i2c_add_driver(&dummy_driver); if (retval) goto class_err; @@ -1960,10 +2113,6 @@ static int __init i2c_init(void) return 0; class_err: -#ifdef CONFIG_I2C_COMPAT - class_compat_unregister(i2c_adapter_compat_class); -bus_err: -#endif is_registered = false; bus_unregister(&i2c_bus_type); return retval; @@ -1976,9 +2125,7 @@ static void __exit i2c_exit(void) if (IS_ENABLED(CONFIG_OF_DYNAMIC)) WARN_ON(of_reconfig_notifier_unregister(&i2c_of_notifier)); i2c_del_driver(&dummy_driver); -#ifdef CONFIG_I2C_COMPAT - class_compat_unregister(i2c_adapter_compat_class); -#endif + debugfs_remove_recursive(i2c_debugfs_root); bus_unregister(&i2c_bus_type); tracepoint_synchronize_unregister(); } @@ -2001,7 +2148,7 @@ static int i2c_quirk_error(struct i2c_adapter *adap, struct i2c_msg *msg, char * { dev_err_ratelimited(&adap->dev, "adapter quirk: %s (addr 0x%04x, size %u, %s)\n", err_msg, msg->addr, msg->len, - msg->flags & I2C_M_RD ? "read" : "write"); + str_read_write(msg->flags & I2C_M_RD)); return -EOPNOTSUPP; } @@ -2069,13 +2216,18 @@ static int i2c_check_for_quirks(struct i2c_adapter *adap, struct i2c_msg *msgs, * Returns negative errno, else the number of messages executed. * * Adapter lock must be held when calling this function. No debug logging - * takes place. adap->algo->master_xfer existence isn't checked. + * takes place. */ int __i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { unsigned long orig_jiffies; int ret, try; + if (!adap->algo->master_xfer) { + dev_dbg(&adap->dev, "I2C level transfers not supported\n"); + return -EOPNOTSUPP; + } + if (WARN_ON(!msgs || num < 1)) return -EINVAL; @@ -2142,11 +2294,6 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) { int ret; - if (!adap->algo->master_xfer) { - dev_dbg(&adap->dev, "I2C level transfers not supported\n"); - return -EOPNOTSUPP; - } - /* REVISIT the fault reporting model here is weak: * * - When we get an error after receiving N bytes from a slave, @@ -2382,9 +2529,10 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) return 0; /* Set up a temporary client to help detect callback */ - temp_client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); + temp_client = kzalloc(sizeof(*temp_client), GFP_KERNEL); if (!temp_client) return -ENOMEM; + temp_client->adapter = adapter; for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) { @@ -2398,6 +2546,7 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) } kfree(temp_client); + return err; } diff --git a/drivers/i2c/i2c-core-of-prober.c b/drivers/i2c/i2c-core-of-prober.c new file mode 100644 index 000000000000..0a66267e4836 --- /dev/null +++ b/drivers/i2c/i2c-core-of-prober.c @@ -0,0 +1,415 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Linux I2C core OF component prober code + * + * Copyright (C) 2024 Google LLC + */ + +#include <linux/cleanup.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/dev_printk.h> +#include <linux/err.h> +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/i2c-of-prober.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/regulator/consumer.h> +#include <linux/slab.h> +#include <linux/stddef.h> + +/* + * Some devices, such as Google Hana Chromebooks, are produced by multiple + * vendors each using their preferred components. Such components are all + * in the device tree. Instead of having all of them enabled and having each + * driver separately try and probe its device while fighting over shared + * resources, they can be marked as "fail-needs-probe" and have a prober + * figure out which one is actually used beforehand. + * + * This prober assumes such drop-in parts are on the same I2C bus, have + * non-conflicting addresses, and can be directly probed by seeing which + * address responds. + * + * TODO: + * - Support I2C muxes + */ + +static struct device_node *i2c_of_probe_get_i2c_node(struct device *dev, const char *type) +{ + struct device_node *node __free(device_node) = of_find_node_by_name(NULL, type); + if (!node) { + dev_err(dev, "Could not find %s device node\n", type); + return NULL; + } + + struct device_node *i2c_node __free(device_node) = of_get_parent(node); + if (!of_node_name_eq(i2c_node, "i2c")) { + dev_err(dev, "%s device isn't on I2C bus\n", type); + return NULL; + } + + if (!of_device_is_available(i2c_node)) { + dev_err(dev, "I2C controller not available\n"); + return NULL; + } + + return no_free_ptr(i2c_node); +} + +static int i2c_of_probe_enable_node(struct device *dev, struct device_node *node) +{ + int ret; + + dev_dbg(dev, "Enabling %pOF\n", node); + + struct of_changeset *ocs __free(kfree) = kzalloc(sizeof(*ocs), GFP_KERNEL); + if (!ocs) + return -ENOMEM; + + of_changeset_init(ocs); + ret = of_changeset_update_prop_string(ocs, node, "status", "okay"); + if (ret) + return ret; + + ret = of_changeset_apply(ocs); + if (ret) { + /* ocs needs to be explicitly cleaned up before being freed. */ + of_changeset_destroy(ocs); + } else { + /* + * ocs is intentionally kept around as it needs to + * exist as long as the change is applied. + */ + void *ptr __always_unused = no_free_ptr(ocs); + } + + return ret; +} + +static const struct i2c_of_probe_ops i2c_of_probe_dummy_ops; + +/** + * i2c_of_probe_component() - probe for devices of "type" on the same i2c bus + * @dev: Pointer to the &struct device of the caller, only used for dev_printk() messages. + * @cfg: Pointer to the &struct i2c_of_probe_cfg containing callbacks and other options + * for the prober. + * @ctx: Context data for callbacks. + * + * Probe for possible I2C components of the same "type" (&i2c_of_probe_cfg->type) + * on the same I2C bus that have their status marked as "fail-needs-probe". + * + * Assumes that across the entire device tree the only instances of nodes + * with "type" prefixed node names (not including the address portion) are + * the ones that need handling for second source components. In other words, + * if "type" is "touchscreen", then all device nodes named "touchscreen*" + * are the ones that need probing. There cannot be another "touchscreen*" + * node that is already enabled. + * + * Assumes that for each "type" of component, only one actually exists. In + * other words, only one matching and existing device will be enabled. + * + * Context: Process context only. Does non-atomic I2C transfers. + * Should only be used from a driver probe function, as the function + * can return -EPROBE_DEFER if the I2C adapter or other resources + * are unavailable. + * Return: 0 on success or no-op, error code otherwise. + * A no-op can happen when it seems like the device tree already + * has components of the type to be probed already enabled. This + * can happen when the device tree had not been updated to mark + * the status of the to-be-probed components as "fail-needs-probe". + * Or this function was already run with the same parameters and + * succeeded in enabling a component. The latter could happen if + * the user had multiple types of components to probe, and one of + * them down the list caused a deferred probe. This is expected + * behavior. + */ +int i2c_of_probe_component(struct device *dev, const struct i2c_of_probe_cfg *cfg, void *ctx) +{ + const struct i2c_of_probe_ops *ops; + const char *type; + struct i2c_adapter *i2c; + int ret; + + ops = cfg->ops ?: &i2c_of_probe_dummy_ops; + type = cfg->type; + + struct device_node *i2c_node __free(device_node) = i2c_of_probe_get_i2c_node(dev, type); + if (!i2c_node) + return -ENODEV; + + /* + * If any devices of the given "type" are already enabled then this function is a no-op. + * Either the device tree hasn't been modified to work with this probe function, or the + * function had already run before and enabled some component. + */ + for_each_child_of_node_with_prefix(i2c_node, node, type) + if (of_device_is_available(node)) + return 0; + + i2c = of_get_i2c_adapter_by_node(i2c_node); + if (!i2c) + return dev_err_probe(dev, -EPROBE_DEFER, "Couldn't get I2C adapter\n"); + + /* Grab and enable resources */ + ret = 0; + if (ops->enable) + ret = ops->enable(dev, i2c_node, ctx); + if (ret) + goto out_put_i2c_adapter; + + for_each_child_of_node_with_prefix(i2c_node, node, type) { + union i2c_smbus_data data; + u32 addr; + + if (of_property_read_u32(node, "reg", &addr)) + continue; + if (i2c_smbus_xfer(i2c, addr, 0, I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &data) < 0) + continue; + + /* Found a device that is responding */ + if (ops->cleanup_early) + ops->cleanup_early(dev, ctx); + ret = i2c_of_probe_enable_node(dev, node); + break; + } + + if (ops->cleanup) + ops->cleanup(dev, ctx); +out_put_i2c_adapter: + i2c_put_adapter(i2c); + + return ret; +} +EXPORT_SYMBOL_NS_GPL(i2c_of_probe_component, "I2C_OF_PROBER"); + +static int i2c_of_probe_simple_get_supply(struct device *dev, struct device_node *node, + struct i2c_of_probe_simple_ctx *ctx) +{ + const char *supply_name; + struct regulator *supply; + + /* + * It's entirely possible for the component's device node to not have the + * regulator supplies. While it does not make sense from a hardware perspective, + * the supplies could be always on or otherwise not modeled in the device tree, + * but the device would still work. + */ + supply_name = ctx->opts->supply_name; + if (!supply_name) + return 0; + + supply = of_regulator_get_optional(dev, node, supply_name); + if (IS_ERR(supply)) { + return dev_err_probe(dev, PTR_ERR(supply), + "Failed to get regulator supply \"%s\" from %pOF\n", + supply_name, node); + } + + ctx->supply = supply; + + return 0; +} + +static void i2c_of_probe_simple_put_supply(struct i2c_of_probe_simple_ctx *ctx) +{ + regulator_put(ctx->supply); + ctx->supply = NULL; +} + +static int i2c_of_probe_simple_enable_regulator(struct device *dev, struct i2c_of_probe_simple_ctx *ctx) +{ + int ret; + + if (!ctx->supply) + return 0; + + dev_dbg(dev, "Enabling regulator supply \"%s\"\n", ctx->opts->supply_name); + + ret = regulator_enable(ctx->supply); + if (ret) + return ret; + + if (ctx->opts->post_power_on_delay_ms) + msleep(ctx->opts->post_power_on_delay_ms); + + return 0; +} + +static void i2c_of_probe_simple_disable_regulator(struct device *dev, struct i2c_of_probe_simple_ctx *ctx) +{ + if (!ctx->supply) + return; + + dev_dbg(dev, "Disabling regulator supply \"%s\"\n", ctx->opts->supply_name); + + regulator_disable(ctx->supply); +} + +static int i2c_of_probe_simple_get_gpiod(struct device *dev, struct device_node *node, + struct i2c_of_probe_simple_ctx *ctx) +{ + struct fwnode_handle *fwnode = of_fwnode_handle(node); + struct gpio_desc *gpiod; + const char *con_id; + + /* NULL signals no GPIO needed */ + if (!ctx->opts->gpio_name) + return 0; + + /* An empty string signals an unnamed GPIO */ + if (!ctx->opts->gpio_name[0]) + con_id = NULL; + else + con_id = ctx->opts->gpio_name; + + gpiod = fwnode_gpiod_get_index(fwnode, con_id, 0, GPIOD_ASIS, "i2c-of-prober"); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + + ctx->gpiod = gpiod; + + return 0; +} + +static void i2c_of_probe_simple_put_gpiod(struct i2c_of_probe_simple_ctx *ctx) +{ + gpiod_put(ctx->gpiod); + ctx->gpiod = NULL; +} + +static int i2c_of_probe_simple_set_gpio(struct device *dev, struct i2c_of_probe_simple_ctx *ctx) +{ + int ret; + + if (!ctx->gpiod) + return 0; + + dev_dbg(dev, "Configuring GPIO\n"); + + ret = gpiod_direction_output(ctx->gpiod, ctx->opts->gpio_assert_to_enable); + if (ret) + return ret; + + if (ctx->opts->post_gpio_config_delay_ms) + msleep(ctx->opts->post_gpio_config_delay_ms); + + return 0; +} + +static void i2c_of_probe_simple_disable_gpio(struct device *dev, struct i2c_of_probe_simple_ctx *ctx) +{ + gpiod_set_value(ctx->gpiod, !ctx->opts->gpio_assert_to_enable); +} + +/** + * i2c_of_probe_simple_enable - Simple helper for I2C OF prober to get and enable resources + * @dev: Pointer to the &struct device of the caller, only used for dev_printk() messages + * @bus_node: Pointer to the &struct device_node of the I2C adapter. + * @data: Pointer to &struct i2c_of_probe_simple_ctx helper context. + * + * If &i2c_of_probe_simple_opts->supply_name is given, request the named regulator supply. + * If &i2c_of_probe_simple_opts->gpio_name is given, request the named GPIO. Or if it is + * the empty string, request the unnamed GPIO. + * If a regulator supply was found, enable that regulator. + * If a GPIO line was found, configure the GPIO line to output and set value + * according to given options. + * + * Return: %0 on success or no-op, or a negative error number on failure. + */ +int i2c_of_probe_simple_enable(struct device *dev, struct device_node *bus_node, void *data) +{ + struct i2c_of_probe_simple_ctx *ctx = data; + struct device_node *node; + const char *compat; + int ret; + + dev_dbg(dev, "Requesting resources for components under I2C bus %pOF\n", bus_node); + + if (!ctx || !ctx->opts) + return -EINVAL; + + compat = ctx->opts->res_node_compatible; + if (!compat) + return -EINVAL; + + node = of_get_compatible_child(bus_node, compat); + if (!node) + return dev_err_probe(dev, -ENODEV, "No device compatible with \"%s\" found\n", + compat); + + ret = i2c_of_probe_simple_get_supply(dev, node, ctx); + if (ret) + goto out_put_node; + + ret = i2c_of_probe_simple_get_gpiod(dev, node, ctx); + if (ret) + goto out_put_supply; + + ret = i2c_of_probe_simple_enable_regulator(dev, ctx); + if (ret) + goto out_put_gpiod; + + ret = i2c_of_probe_simple_set_gpio(dev, ctx); + if (ret) + goto out_disable_regulator; + + return 0; + +out_disable_regulator: + i2c_of_probe_simple_disable_regulator(dev, ctx); +out_put_gpiod: + i2c_of_probe_simple_put_gpiod(ctx); +out_put_supply: + i2c_of_probe_simple_put_supply(ctx); +out_put_node: + of_node_put(node); + return ret; +} +EXPORT_SYMBOL_NS_GPL(i2c_of_probe_simple_enable, "I2C_OF_PROBER"); + +/** + * i2c_of_probe_simple_cleanup_early - \ + * Simple helper for I2C OF prober to release GPIOs before component is enabled + * @dev: Pointer to the &struct device of the caller; unused. + * @data: Pointer to &struct i2c_of_probe_simple_ctx helper context. + * + * GPIO descriptors are exclusive and have to be released before the + * actual driver probes so that the latter can acquire them. + */ +void i2c_of_probe_simple_cleanup_early(struct device *dev, void *data) +{ + struct i2c_of_probe_simple_ctx *ctx = data; + + i2c_of_probe_simple_put_gpiod(ctx); +} +EXPORT_SYMBOL_NS_GPL(i2c_of_probe_simple_cleanup_early, "I2C_OF_PROBER"); + +/** + * i2c_of_probe_simple_cleanup - Clean up and release resources for I2C OF prober simple helpers + * @dev: Pointer to the &struct device of the caller, only used for dev_printk() messages + * @data: Pointer to &struct i2c_of_probe_simple_ctx helper context. + * + * * If a GPIO line was found and not yet released, set its value to the opposite of that + * set in i2c_of_probe_simple_enable() and release it. + * * If a regulator supply was found, disable that regulator and release it. + */ +void i2c_of_probe_simple_cleanup(struct device *dev, void *data) +{ + struct i2c_of_probe_simple_ctx *ctx = data; + + /* GPIO operations here are no-ops if i2c_of_probe_simple_cleanup_early was called. */ + i2c_of_probe_simple_disable_gpio(dev, ctx); + i2c_of_probe_simple_put_gpiod(ctx); + + i2c_of_probe_simple_disable_regulator(dev, ctx); + i2c_of_probe_simple_put_supply(ctx); +} +EXPORT_SYMBOL_NS_GPL(i2c_of_probe_simple_cleanup, "I2C_OF_PROBER"); + +struct i2c_of_probe_ops i2c_of_probe_simple_ops = { + .enable = i2c_of_probe_simple_enable, + .cleanup_early = i2c_of_probe_simple_cleanup_early, + .cleanup = i2c_of_probe_simple_cleanup, +}; +EXPORT_SYMBOL_NS_GPL(i2c_of_probe_simple_ops, "I2C_OF_PROBER"); diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 3ed74aa4b44b..eb7fb202355f 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -27,7 +27,7 @@ int of_i2c_get_board_info(struct device *dev, struct device_node *node, memset(info, 0, sizeof(*info)); - if (of_modalias_node(node, info->type, sizeof(info->type)) < 0) { + if (of_alias_from_compatible(node, info->type, sizeof(info->type)) < 0) { dev_err(dev, "of_i2c: modalias failure on %pOF\n", node); return -EINVAL; } @@ -49,13 +49,12 @@ int of_i2c_get_board_info(struct device *dev, struct device_node *node, } info->addr = addr; - info->of_node = node; info->fwnode = of_fwnode_handle(node); if (of_property_read_bool(node, "host-notify")) info->flags |= I2C_CLIENT_HOST_NOTIFY; - if (of_get_property(node, "wakeup-source", NULL)) + if (of_property_read_bool(node, "wakeup-source")) info->flags |= I2C_CLIENT_WAKE; return 0; @@ -113,72 +112,6 @@ void of_i2c_register_devices(struct i2c_adapter *adap) of_node_put(bus); } -static int of_dev_or_parent_node_match(struct device *dev, const void *data) -{ - if (dev->of_node == data) - return 1; - - if (dev->parent) - return dev->parent->of_node == data; - - return 0; -} - -/* must call put_device() when done with returned i2c_client device */ -struct i2c_client *of_find_i2c_device_by_node(struct device_node *node) -{ - struct device *dev; - struct i2c_client *client; - - dev = bus_find_device_by_of_node(&i2c_bus_type, node); - if (!dev) - return NULL; - - client = i2c_verify_client(dev); - if (!client) - put_device(dev); - - return client; -} -EXPORT_SYMBOL(of_find_i2c_device_by_node); - -/* must call put_device() when done with returned i2c_adapter device */ -struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node *node) -{ - struct device *dev; - struct i2c_adapter *adapter; - - dev = bus_find_device(&i2c_bus_type, NULL, node, - of_dev_or_parent_node_match); - if (!dev) - return NULL; - - adapter = i2c_verify_adapter(dev); - if (!adapter) - put_device(dev); - - return adapter; -} -EXPORT_SYMBOL(of_find_i2c_adapter_by_node); - -/* must call i2c_put_adapter() when done with returned i2c_adapter device */ -struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node *node) -{ - struct i2c_adapter *adapter; - - adapter = of_find_i2c_adapter_by_node(node); - if (!adapter) - return NULL; - - if (!try_module_get(adapter->owner)) { - put_device(&adapter->dev); - adapter = NULL; - } - - return adapter; -} -EXPORT_SYMBOL(of_get_i2c_adapter_by_node); - static const struct of_device_id* i2c_of_match_device_sysfs(const struct of_device_id *matches, struct i2c_client *client) @@ -223,7 +156,6 @@ const struct of_device_id return i2c_of_match_device_sysfs(matches, client); } -EXPORT_SYMBOL_GPL(i2c_of_match_device); #if IS_ENABLED(CONFIG_OF_DYNAMIC) static int of_i2c_notify(struct notifier_block *nb, unsigned long action, @@ -244,6 +176,11 @@ static int of_i2c_notify(struct notifier_block *nb, unsigned long action, return NOTIFY_OK; } + /* + * Clear the flag before adding the device so that fw_devlink + * doesn't skip adding consumers to this device. + */ + rd->dn->fwnode.flags &= ~FWNODE_FLAG_NOT_DEVICE; client = of_i2c_register_device(adap, rd->dn); if (IS_ERR(client)) { dev_err(&adap->dev, "failed to create client for '%pOF'\n", diff --git a/drivers/i2c/i2c-core-slave.c b/drivers/i2c/i2c-core-slave.c index e3765e12f93b..02ca55c2246b 100644 --- a/drivers/i2c/i2c-core-slave.c +++ b/drivers/i2c/i2c-core-slave.c @@ -11,6 +11,7 @@ #include <linux/err.h> #include <linux/i2c.h> #include <linux/of.h> +#include <linux/property.h> #include "i2c-core.h" @@ -108,18 +109,17 @@ EXPORT_SYMBOL_GPL(i2c_slave_event); */ bool i2c_detect_slave_mode(struct device *dev) { - if (IS_BUILTIN(CONFIG_OF) && dev->of_node) { - struct device_node *child; + struct fwnode_handle *fwnode = dev_fwnode(dev); + + if (is_of_node(fwnode)) { u32 reg; - for_each_child_of_node(dev->of_node, child) { - of_property_read_u32(child, "reg", ®); - if (reg & I2C_OWN_SLAVE_ADDRESS) { - of_node_put(child); + fwnode_for_each_child_node_scoped(fwnode, child) { + fwnode_property_read_u32(child, "reg", ®); + if (reg & I2C_OWN_SLAVE_ADDRESS) return true; - } } - } else if (IS_BUILTIN(CONFIG_ACPI) && ACPI_HANDLE(dev)) { + } else if (is_acpi_device_node(fwnode)) { dev_dbg(dev, "ACPI slave is not supported yet\n"); } return false; diff --git a/drivers/i2c/i2c-core-smbus.c b/drivers/i2c/i2c-core-smbus.c index e3b96fc53b5c..71eb1ef56f0c 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -16,6 +16,7 @@ #include <linux/i2c-smbus.h> #include <linux/property.h> #include <linux/slab.h> +#include <linux/string_choices.h> #include "i2c-core.h" @@ -122,7 +123,7 @@ EXPORT_SYMBOL(i2c_smbus_read_byte); s32 i2c_smbus_write_byte(const struct i2c_client *client, u8 value) { return i2c_smbus_xfer(client->adapter, client->addr, client->flags, - I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); + I2C_SMBUS_WRITE, value, I2C_SMBUS_BYTE, NULL); } EXPORT_SYMBOL(i2c_smbus_write_byte); @@ -433,7 +434,7 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter *adapter, u16 addr, case I2C_SMBUS_I2C_BLOCK_DATA: if (data->block[0] > I2C_SMBUS_BLOCK_MAX) { dev_err(&adapter->dev, "Invalid block %s size %d\n", - read_write == I2C_SMBUS_READ ? "read" : "write", + str_read_write(read_write == I2C_SMBUS_READ), data->block[0]); return -EINVAL; } @@ -712,12 +713,15 @@ int i2c_setup_smbus_alert(struct i2c_adapter *adapter) if (!parent) return 0; + /* Report serious errors */ irq = device_property_match_string(parent, "interrupt-names", "smbus_alert"); - if (irq == -EINVAL || irq == -ENODATA) - return 0; - else if (irq < 0) + if (irq < 0 && irq != -EINVAL && irq != -ENODATA) return irq; + /* Skip setup when no irq was found */ + if (irq < 0 && !device_property_present(parent, "smbalert-gpios")) + return 0; + return PTR_ERR_OR_ZERO(i2c_new_smbus_alert_device(adapter, NULL)); } #endif diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h index 1247e6e6e975..4797ba88331c 100644 --- a/drivers/i2c/i2c-core.h +++ b/drivers/i2c/i2c-core.h @@ -3,6 +3,7 @@ * i2c-core.h - interfaces internal to the I2C framework */ +#include <linux/kconfig.h> #include <linux/rwsem.h> struct i2c_devinfo { @@ -29,7 +30,8 @@ int i2c_dev_irq_from_resources(const struct resource *resources, */ static inline bool i2c_in_atomic_xfer_mode(void) { - return system_state > SYSTEM_RUNNING && irqs_disabled(); + return system_state > SYSTEM_RUNNING && + (IS_ENABLED(CONFIG_PREEMPT_COUNT) ? !preemptible() : irqs_disabled()); } static inline int __i2c_lock_bus_helper(struct i2c_adapter *adap) @@ -82,8 +84,17 @@ static inline void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) { #ifdef CONFIG_OF void of_i2c_register_devices(struct i2c_adapter *adap); +const struct of_device_id *i2c_of_match_device(const struct of_device_id *matches, + struct i2c_client *client); + #else static inline void of_i2c_register_devices(struct i2c_adapter *adap) { } +static inline +const struct of_device_id *i2c_of_match_device(const struct of_device_id *matches, + struct i2c_client *client) +{ + return NULL; +} #endif extern struct notifier_block i2c_of_notifier; diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index ab0adaa130da..e9577f920286 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -139,6 +139,10 @@ static ssize_t i2cdev_read(struct file *file, char __user *buf, size_t count, struct i2c_client *client = file->private_data; + /* Adapter must support I2C transfers */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -EOPNOTSUPP; + if (count > 8192) count = 8192; @@ -163,6 +167,10 @@ static ssize_t i2cdev_write(struct file *file, const char __user *buf, char *tmp; struct i2c_client *client = file->private_data; + /* Adapter must support I2C transfers */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -EOPNOTSUPP; + if (count > 8192) count = 8192; @@ -238,11 +246,13 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, u8 __user **data_ptrs; int i, res; + /* Adapter must support I2C transfers */ + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) + return -EOPNOTSUPP; + data_ptrs = kmalloc_array(nmsgs, sizeof(u8 __user *), GFP_KERNEL); - if (data_ptrs == NULL) { - kfree(msgs); + if (!data_ptrs) return -ENOMEM; - } res = 0; for (i = 0; i < nmsgs; i++) { @@ -290,7 +300,6 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, for (j = 0; j < i; ++j) kfree(msgs[j].buf); kfree(data_ptrs); - kfree(msgs); return res; } @@ -304,7 +313,6 @@ static noinline int i2cdev_ioctl_rdwr(struct i2c_client *client, kfree(msgs[i].buf); } kfree(data_ptrs); - kfree(msgs); return res; } @@ -434,6 +442,7 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case I2C_RDWR: { struct i2c_rdwr_ioctl_data rdwr_arg; struct i2c_msg *rdwr_pa; + int res; if (copy_from_user(&rdwr_arg, (struct i2c_rdwr_ioctl_data __user *)arg, @@ -450,12 +459,14 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) return -EINVAL; - rdwr_pa = memdup_user(rdwr_arg.msgs, - rdwr_arg.nmsgs * sizeof(struct i2c_msg)); + rdwr_pa = memdup_array_user(rdwr_arg.msgs, + rdwr_arg.nmsgs, sizeof(struct i2c_msg)); if (IS_ERR(rdwr_pa)) return PTR_ERR(rdwr_pa); - return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + res = i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + kfree(rdwr_pa); + return res; } case I2C_SMBUS: { @@ -528,7 +539,7 @@ static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned lo struct i2c_rdwr_ioctl_data32 rdwr_arg; struct i2c_msg32 __user *p; struct i2c_msg *rdwr_pa; - int i; + int i, res; if (copy_from_user(&rdwr_arg, (struct i2c_rdwr_ioctl_data32 __user *)arg, @@ -561,7 +572,9 @@ static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned lo }; } - return i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + res = i2cdev_ioctl_rdwr(client, rdwr_arg.nmsgs, rdwr_pa); + kfree(rdwr_pa); + return res; } case I2C_SMBUS: { struct i2c_smbus_ioctl_data32 data32; @@ -625,7 +638,6 @@ static int i2cdev_release(struct inode *inode, struct file *file) static const struct file_operations i2cdev_fops = { .owner = THIS_MODULE, - .llseek = no_llseek, .read = i2cdev_read, .write = i2cdev_write, .unlocked_ioctl = i2cdev_ioctl, @@ -636,7 +648,10 @@ static const struct file_operations i2cdev_fops = { /* ------------------------------------------------------------------------- */ -static struct class *i2c_dev_class; +static const struct class i2c_dev_class = { + .name = "i2c-dev", + .dev_groups = i2c_groups, +}; static void i2cdev_dev_release(struct device *dev) { @@ -646,26 +661,26 @@ static void i2cdev_dev_release(struct device *dev) kfree(i2c_dev); } -static int i2cdev_attach_adapter(struct device *dev, void *dummy) +static int i2cdev_attach_adapter(struct device *dev) { struct i2c_adapter *adap; struct i2c_dev *i2c_dev; int res; if (dev->type != &i2c_adapter_type) - return 0; + return NOTIFY_DONE; adap = to_i2c_adapter(dev); i2c_dev = get_free_i2c_dev(adap); if (IS_ERR(i2c_dev)) - return PTR_ERR(i2c_dev); + return NOTIFY_DONE; cdev_init(&i2c_dev->cdev, &i2cdev_fops); i2c_dev->cdev.owner = THIS_MODULE; device_initialize(&i2c_dev->dev); i2c_dev->dev.devt = MKDEV(I2C_MAJOR, adap->nr); - i2c_dev->dev.class = i2c_dev_class; + i2c_dev->dev.class = &i2c_dev_class; i2c_dev->dev.parent = &adap->dev; i2c_dev->dev.release = i2cdev_dev_release; @@ -678,30 +693,30 @@ static int i2cdev_attach_adapter(struct device *dev, void *dummy) goto err_put_i2c_dev; pr_debug("adapter [%s] registered as minor %d\n", adap->name, adap->nr); - return 0; + return NOTIFY_OK; err_put_i2c_dev: put_i2c_dev(i2c_dev, false); - return res; + return NOTIFY_DONE; } -static int i2cdev_detach_adapter(struct device *dev, void *dummy) +static int i2cdev_detach_adapter(struct device *dev) { struct i2c_adapter *adap; struct i2c_dev *i2c_dev; if (dev->type != &i2c_adapter_type) - return 0; + return NOTIFY_DONE; adap = to_i2c_adapter(dev); i2c_dev = i2c_dev_get_by_minor(adap->nr); if (!i2c_dev) /* attach_adapter must have failed */ - return 0; + return NOTIFY_DONE; put_i2c_dev(i2c_dev, true); pr_debug("adapter [%s] unregistered\n", adap->name); - return 0; + return NOTIFY_OK; } static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action, @@ -711,12 +726,12 @@ static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action, switch (action) { case BUS_NOTIFY_ADD_DEVICE: - return i2cdev_attach_adapter(dev, NULL); + return i2cdev_attach_adapter(dev); case BUS_NOTIFY_DEL_DEVICE: - return i2cdev_detach_adapter(dev, NULL); + return i2cdev_detach_adapter(dev); } - return 0; + return NOTIFY_DONE; } static struct notifier_block i2cdev_notifier = { @@ -725,6 +740,18 @@ static struct notifier_block i2cdev_notifier = { /* ------------------------------------------------------------------------- */ +static int __init i2c_dev_attach_adapter(struct device *dev, void *dummy) +{ + i2cdev_attach_adapter(dev); + return 0; +} + +static int __exit i2c_dev_detach_adapter(struct device *dev, void *dummy) +{ + i2cdev_detach_adapter(dev); + return 0; +} + /* * module load/unload record keeping */ @@ -739,12 +766,9 @@ static int __init i2c_dev_init(void) if (res) goto out; - i2c_dev_class = class_create(THIS_MODULE, "i2c-dev"); - if (IS_ERR(i2c_dev_class)) { - res = PTR_ERR(i2c_dev_class); + res = class_register(&i2c_dev_class); + if (res) goto out_unreg_chrdev; - } - i2c_dev_class->dev_groups = i2c_groups; /* Keep track of adapters which will be added or removed later */ res = bus_register_notifier(&i2c_bus_type, &i2cdev_notifier); @@ -752,12 +776,12 @@ static int __init i2c_dev_init(void) goto out_unreg_class; /* Bind to already existing adapters right away */ - i2c_for_each_dev(NULL, i2cdev_attach_adapter); + i2c_for_each_dev(NULL, i2c_dev_attach_adapter); return 0; out_unreg_class: - class_destroy(i2c_dev_class); + class_unregister(&i2c_dev_class); out_unreg_chrdev: unregister_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS); out: @@ -768,8 +792,8 @@ out: static void __exit i2c_dev_exit(void) { bus_unregister_notifier(&i2c_bus_type, &i2cdev_notifier); - i2c_for_each_dev(NULL, i2cdev_detach_adapter); - class_destroy(i2c_dev_class); + i2c_for_each_dev(NULL, i2c_dev_detach_adapter); + class_unregister(&i2c_dev_class); unregister_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS); } diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 313904be5f3b..d59644e50f14 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -127,19 +127,6 @@ static u32 i2c_mux_functionality(struct i2c_adapter *adap) return parent->algo->functionality(parent); } -/* Return all parent classes, merged */ -static unsigned int i2c_mux_parent_classes(struct i2c_adapter *parent) -{ - unsigned int class = 0; - - do { - class |= parent->class; - parent = i2c_parent_is_i2c_adapter(parent); - } while (parent); - - return class; -} - static void i2c_mux_lock_bus(struct i2c_adapter *adapter, unsigned int flags) { struct i2c_mux_priv *priv = adapter->algo_data; @@ -254,12 +241,9 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent, muxc->parent = parent; muxc->dev = dev; - if (flags & I2C_MUX_LOCKED) - muxc->mux_locked = true; - if (flags & I2C_MUX_ARBITRATOR) - muxc->arbitrator = true; - if (flags & I2C_MUX_GATE) - muxc->gate = true; + muxc->mux_locked = !!(flags & I2C_MUX_LOCKED); + muxc->arbitrator = !!(flags & I2C_MUX_ARBITRATOR); + muxc->gate = !!(flags & I2C_MUX_GATE); muxc->select = select; muxc->deselect = deselect; muxc->max_adapters = max_adapters; @@ -281,8 +265,7 @@ static const struct i2c_lock_operations i2c_parent_lock_ops = { }; int i2c_mux_add_adapter(struct i2c_mux_core *muxc, - u32 force_nr, u32 chan_id, - unsigned int class) + u32 force_nr, u32 chan_id) { struct i2c_adapter *parent = muxc->parent; struct i2c_mux_priv *priv; @@ -307,12 +290,12 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, */ if (parent->algo->master_xfer) { if (muxc->mux_locked) - priv->algo.master_xfer = i2c_mux_master_xfer; + priv->algo.xfer = i2c_mux_master_xfer; else - priv->algo.master_xfer = __i2c_mux_master_xfer; + priv->algo.xfer = __i2c_mux_master_xfer; } if (parent->algo->master_xfer_atomic) - priv->algo.master_xfer_atomic = priv->algo.master_xfer; + priv->algo.xfer_atomic = priv->algo.master_xfer; if (parent->algo->smbus_xfer) { if (muxc->mux_locked) @@ -340,14 +323,6 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, else priv->adap.lock_ops = &i2c_parent_lock_ops; - /* Sanity check on class */ - if (i2c_mux_parent_classes(parent) & class) - dev_err(&parent->dev, - "Segment %d behind mux can't share classes with ancestors\n", - chan_id); - else - priv->adap.class = class; - /* * Try to populate the mux adapter's of_node, expands to * nothing if !CONFIG_OF. diff --git a/drivers/i2c/i2c-slave-eeprom.c b/drivers/i2c/i2c-slave-eeprom.c index 5f25f23c4ff8..6bc2ef650a74 100644 --- a/drivers/i2c/i2c-slave-eeprom.c +++ b/drivers/i2c/i2c-slave-eeprom.c @@ -91,7 +91,7 @@ static int i2c_slave_eeprom_slave_cb(struct i2c_client *client, } static ssize_t i2c_slave_eeprom_bin_read(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, loff_t off, size_t count) + const struct bin_attribute *attr, char *buf, loff_t off, size_t count) { struct eeprom_data *eeprom; unsigned long flags; @@ -106,7 +106,7 @@ static ssize_t i2c_slave_eeprom_bin_read(struct file *filp, struct kobject *kobj } static ssize_t i2c_slave_eeprom_bin_write(struct file *filp, struct kobject *kobj, - struct bin_attribute *attr, char *buf, loff_t off, size_t count) + const struct bin_attribute *attr, char *buf, loff_t off, size_t count) { struct eeprom_data *eeprom; unsigned long flags; @@ -207,7 +207,7 @@ static struct i2c_driver i2c_slave_eeprom_driver = { .driver = { .name = "i2c-slave-eeprom", }, - .probe_new = i2c_slave_eeprom_probe, + .probe = i2c_slave_eeprom_probe, .remove = i2c_slave_eeprom_remove, .id_table = i2c_slave_eeprom_id, }; diff --git a/drivers/i2c/i2c-slave-testunit.c b/drivers/i2c/i2c-slave-testunit.c index 75ee7ebdb614..6de4307050dd 100644 --- a/drivers/i2c/i2c-slave-testunit.c +++ b/drivers/i2c/i2c-slave-testunit.c @@ -6,7 +6,10 @@ * Copyright (C) 2020 by Renesas Electronics Corporation */ +#include <generated/utsrelease.h> #include <linux/bitops.h> +#include <linux/completion.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/module.h> @@ -14,12 +17,14 @@ #include <linux/slab.h> #include <linux/workqueue.h> /* FIXME: is system_long_wq the best choice? */ -#define TU_CUR_VERSION 0x01 +#define TU_VERSION_MAX_LENGTH 128 enum testunit_cmds { TU_CMD_READ_BYTES = 1, /* save 0 for ABORT, RESET or similar */ - TU_CMD_HOST_NOTIFY, + TU_CMD_SMBUS_HOST_NOTIFY, TU_CMD_SMBUS_BLOCK_PROC_CALL, + TU_CMD_GET_VERSION_WITH_REP_START, + TU_CMD_SMBUS_ALERT_REQUEST, TU_NUM_CMDS }; @@ -33,56 +38,45 @@ enum testunit_regs { enum testunit_flags { TU_FLAG_IN_PROCESS, + TU_FLAG_NACK, }; struct testunit_data { unsigned long flags; u8 regs[TU_NUM_REGS]; u8 reg_idx; + u8 read_idx; struct i2c_client *client; struct delayed_work worker; + struct gpio_desc *gpio; + struct completion alert_done; }; -static void i2c_slave_testunit_work(struct work_struct *work) -{ - struct testunit_data *tu = container_of(work, struct testunit_data, worker.work); - struct i2c_msg msg; - u8 msgbuf[256]; - int ret = 0; +static char tu_version_info[] = "v" UTS_RELEASE "\n\0"; - msg.addr = I2C_CLIENT_END; - msg.buf = msgbuf; - - switch (tu->regs[TU_REG_CMD]) { - case TU_CMD_READ_BYTES: - msg.addr = tu->regs[TU_REG_DATAL]; - msg.flags = I2C_M_RD; - msg.len = tu->regs[TU_REG_DATAH]; - break; +static int i2c_slave_testunit_smbalert_cb(struct i2c_client *client, + enum i2c_slave_event event, u8 *val) +{ + struct testunit_data *tu = i2c_get_clientdata(client); - case TU_CMD_HOST_NOTIFY: - msg.addr = 0x08; - msg.flags = 0; - msg.len = 3; - msgbuf[0] = tu->client->addr; - msgbuf[1] = tu->regs[TU_REG_DATAL]; - msgbuf[2] = tu->regs[TU_REG_DATAH]; + switch (event) { + case I2C_SLAVE_READ_PROCESSED: + gpiod_set_value(tu->gpio, 0); + fallthrough; + case I2C_SLAVE_READ_REQUESTED: + *val = tu->regs[TU_REG_DATAL]; break; - default: + case I2C_SLAVE_STOP: + complete(&tu->alert_done); break; - } - if (msg.addr != I2C_CLIENT_END) { - ret = i2c_transfer(tu->client->adapter, &msg, 1); - /* convert '0 msgs transferred' to errno */ - ret = (ret == 0) ? -EIO : ret; + case I2C_SLAVE_WRITE_REQUESTED: + case I2C_SLAVE_WRITE_RECEIVED: + return -EOPNOTSUPP; } - if (ret < 0) - dev_err(&tu->client->dev, "CMD%02X failed (%d)\n", tu->regs[TU_REG_CMD], ret); - - clear_bit(TU_FLAG_IN_PROCESS, &tu->flags); + return 0; } static int i2c_slave_testunit_slave_cb(struct i2c_client *client, @@ -91,12 +85,27 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client, struct testunit_data *tu = i2c_get_clientdata(client); bool is_proc_call = tu->reg_idx == 3 && tu->regs[TU_REG_DATAL] == 1 && tu->regs[TU_REG_CMD] == TU_CMD_SMBUS_BLOCK_PROC_CALL; + bool is_get_version = tu->reg_idx == 3 && + tu->regs[TU_REG_CMD] == TU_CMD_GET_VERSION_WITH_REP_START; int ret = 0; switch (event) { + case I2C_SLAVE_WRITE_REQUESTED: + if (test_bit(TU_FLAG_IN_PROCESS | TU_FLAG_NACK, &tu->flags)) { + ret = -EBUSY; + break; + } + + memset(tu->regs, 0, TU_NUM_REGS); + tu->reg_idx = 0; + tu->read_idx = 0; + break; + case I2C_SLAVE_WRITE_RECEIVED: - if (test_bit(TU_FLAG_IN_PROCESS, &tu->flags)) - return -EBUSY; + if (test_bit(TU_FLAG_IN_PROCESS | TU_FLAG_NACK, &tu->flags)) { + ret = -EBUSY; + break; + } if (tu->reg_idx < TU_NUM_REGS) tu->regs[tu->reg_idx] = *val; @@ -118,26 +127,112 @@ static int i2c_slave_testunit_slave_cb(struct i2c_client *client, queue_delayed_work(system_long_wq, &tu->worker, msecs_to_jiffies(10 * tu->regs[TU_REG_DELAY])); } - fallthrough; - case I2C_SLAVE_WRITE_REQUESTED: - memset(tu->regs, 0, TU_NUM_REGS); + /* + * Reset reg_idx to avoid that work gets queued again in case of + * STOP after a following read message. But do not clear TU regs + * here because we still need them in the workqueue! + */ tu->reg_idx = 0; + + clear_bit(TU_FLAG_NACK, &tu->flags); break; case I2C_SLAVE_READ_PROCESSED: - if (is_proc_call && tu->regs[TU_REG_DATAH]) + /* Advance until we reach the NUL character */ + if (is_get_version && tu_version_info[tu->read_idx] != 0) + tu->read_idx++; + else if (is_proc_call && tu->regs[TU_REG_DATAH]) tu->regs[TU_REG_DATAH]--; + fallthrough; case I2C_SLAVE_READ_REQUESTED: - *val = is_proc_call ? tu->regs[TU_REG_DATAH] : TU_CUR_VERSION; + if (is_get_version) + *val = tu_version_info[tu->read_idx]; + else if (is_proc_call) + *val = tu->regs[TU_REG_DATAH]; + else + *val = test_bit(TU_FLAG_IN_PROCESS, &tu->flags) ? + tu->regs[TU_REG_CMD] : 0; break; } + /* If an error occurred somewhen, we NACK everything until next STOP */ + if (ret) + set_bit(TU_FLAG_NACK, &tu->flags); + return ret; } +static void i2c_slave_testunit_work(struct work_struct *work) +{ + struct testunit_data *tu = container_of(work, struct testunit_data, worker.work); + unsigned long time_left; + struct i2c_msg msg; + u8 msgbuf[256]; + u16 orig_addr; + int ret = 0; + + msg.addr = I2C_CLIENT_END; + msg.buf = msgbuf; + + switch (tu->regs[TU_REG_CMD]) { + case TU_CMD_READ_BYTES: + msg.addr = tu->regs[TU_REG_DATAL]; + msg.flags = I2C_M_RD; + msg.len = tu->regs[TU_REG_DATAH]; + break; + + case TU_CMD_SMBUS_HOST_NOTIFY: + msg.addr = 0x08; + msg.flags = 0; + msg.len = 3; + msgbuf[0] = tu->client->addr; + msgbuf[1] = tu->regs[TU_REG_DATAL]; + msgbuf[2] = tu->regs[TU_REG_DATAH]; + break; + + case TU_CMD_SMBUS_ALERT_REQUEST: + if (!tu->gpio) { + ret = -ENOENT; + break; + } + i2c_slave_unregister(tu->client); + orig_addr = tu->client->addr; + tu->client->addr = 0x0c; + ret = i2c_slave_register(tu->client, i2c_slave_testunit_smbalert_cb); + if (ret) + goto out_smbalert; + + reinit_completion(&tu->alert_done); + gpiod_set_value(tu->gpio, 1); + time_left = wait_for_completion_timeout(&tu->alert_done, HZ); + if (!time_left) + ret = -ETIMEDOUT; + + i2c_slave_unregister(tu->client); +out_smbalert: + tu->client->addr = orig_addr; + i2c_slave_register(tu->client, i2c_slave_testunit_slave_cb); + break; + + default: + break; + } + + if (msg.addr != I2C_CLIENT_END) { + ret = i2c_transfer(tu->client->adapter, &msg, 1); + /* convert '0 msgs transferred' to errno */ + ret = (ret == 0) ? -EIO : ret; + } + + if (ret < 0) + dev_err(&tu->client->dev, "CMD%02X failed (%d)\n", tu->regs[TU_REG_CMD], ret); + + clear_bit(TU_FLAG_IN_PROCESS, &tu->flags); +} + static int i2c_slave_testunit_probe(struct i2c_client *client) { struct testunit_data *tu; @@ -148,8 +243,21 @@ static int i2c_slave_testunit_probe(struct i2c_client *client) tu->client = client; i2c_set_clientdata(client, tu); + init_completion(&tu->alert_done); INIT_DELAYED_WORK(&tu->worker, i2c_slave_testunit_work); + tu->gpio = devm_gpiod_get_index_optional(&client->dev, NULL, 0, GPIOD_OUT_LOW); + if (IS_ERR(tu->gpio)) + return PTR_ERR(tu->gpio); + + if (gpiod_cansleep(tu->gpio)) { + dev_err(&client->dev, "GPIO access which may sleep is not allowed\n"); + return -EDEADLK; + } + + if (sizeof(tu_version_info) > TU_VERSION_MAX_LENGTH) + tu_version_info[TU_VERSION_MAX_LENGTH - 1] = 0; + return i2c_slave_register(client, i2c_slave_testunit_slave_cb); }; @@ -162,7 +270,7 @@ static void i2c_slave_testunit_remove(struct i2c_client *client) } static const struct i2c_device_id i2c_slave_testunit_id[] = { - { "slave-testunit", 0 }, + { "slave-testunit" }, { } }; MODULE_DEVICE_TABLE(i2c, i2c_slave_testunit_id); @@ -171,7 +279,7 @@ static struct i2c_driver i2c_slave_testunit_driver = { .driver = { .name = "i2c-slave-testunit", }, - .probe_new = i2c_slave_testunit_probe, + .probe = i2c_slave_testunit_probe, .remove = i2c_slave_testunit_remove, .id_table = i2c_slave_testunit_id, }; diff --git a/drivers/i2c/i2c-smbus.c b/drivers/i2c/i2c-smbus.c index cd19546d31fc..0316b347f9e7 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -8,6 +8,7 @@ #include <linux/device.h> #include <linux/dmi.h> +#include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/i2c-smbus.h> #include <linux/interrupt.h> @@ -34,6 +35,7 @@ static int smbus_do_alert(struct device *dev, void *addrp) struct i2c_client *client = i2c_verify_client(dev); struct alert_data *data = addrp; struct i2c_driver *driver; + int ret; if (!client || client->addr != data->addr) return 0; @@ -47,16 +49,47 @@ static int smbus_do_alert(struct device *dev, void *addrp) device_lock(dev); if (client->dev.driver) { driver = to_i2c_driver(client->dev.driver); - if (driver->alert) + if (driver->alert) { + /* Stop iterating after we find the device */ driver->alert(client, data->type, data->data); - else + ret = -EBUSY; + } else { dev_warn(&client->dev, "no driver alert()!\n"); - } else + ret = -EOPNOTSUPP; + } + } else { dev_dbg(&client->dev, "alert with no driver\n"); + ret = -ENODEV; + } + device_unlock(dev); + + return ret; +} + +/* Same as above, but call back all drivers with alert handler */ + +static int smbus_do_alert_force(struct device *dev, void *addrp) +{ + struct i2c_client *client = i2c_verify_client(dev); + struct alert_data *data = addrp; + struct i2c_driver *driver; + + if (!client || (client->flags & I2C_CLIENT_TEN)) + return 0; + + /* + * Drivers should either disable alerts, or provide at least + * a minimal handler. Lock so the driver won't change. + */ + device_lock(dev); + if (client->dev.driver) { + driver = to_i2c_driver(client->dev.driver); + if (driver->alert) + driver->alert(client, data->type, data->data); + } device_unlock(dev); - /* Stop iterating after we find the device */ - return -EBUSY; + return 0; } /* @@ -67,6 +100,7 @@ static irqreturn_t smbus_alert(int irq, void *d) { struct i2c_smbus_alert *alert = d; struct i2c_client *ara; + unsigned short prev_addr = I2C_CLIENT_END; /* Not a valid address */ ara = alert->ara; @@ -94,8 +128,25 @@ static irqreturn_t smbus_alert(int irq, void *d) data.addr, data.data); /* Notify driver for the device which issued the alert */ - device_for_each_child(&ara->adapter->dev, &data, - smbus_do_alert); + status = device_for_each_child(&ara->adapter->dev, &data, + smbus_do_alert); + /* + * If we read the same address more than once, and the alert + * was not handled by a driver, it won't do any good to repeat + * the loop because it will never terminate. Try again, this + * time calling the alert handlers of all devices connected to + * the bus, and abort the loop afterwards. If this helps, we + * are all set. If it doesn't, there is nothing else we can do, + * so we might as well abort the loop. + * Note: This assumes that a driver with alert handler handles + * the alert properly and clears it if necessary. + */ + if (data.addr == prev_addr && status != -EBUSY) { + device_for_each_child(&ara->adapter->dev, &data, + smbus_do_alert_force); + break; + } + prev_addr = data.addr; } return IRQ_HANDLED; @@ -117,6 +168,8 @@ static int smbalert_probe(struct i2c_client *ara) struct i2c_smbus_alert_setup *setup = dev_get_platdata(&ara->dev); struct i2c_smbus_alert *alert; struct i2c_adapter *adapter = ara->adapter; + unsigned long irqflags = IRQF_SHARED | IRQF_ONESHOT; + struct gpio_desc *gpiod; int res, irq; alert = devm_kzalloc(&ara->dev, sizeof(struct i2c_smbus_alert), @@ -129,18 +182,25 @@ static int smbalert_probe(struct i2c_client *ara) } else { irq = fwnode_irq_get_byname(dev_fwnode(adapter->dev.parent), "smbus_alert"); - if (irq <= 0) - return irq; + if (irq <= 0) { + gpiod = devm_gpiod_get(adapter->dev.parent, "smbalert", GPIOD_IN); + if (IS_ERR(gpiod)) + return PTR_ERR(gpiod); + + irq = gpiod_to_irq(gpiod); + if (irq <= 0) + return irq; + + irqflags |= IRQF_TRIGGER_FALLING; + } } INIT_WORK(&alert->alert, smbalert_work); alert->ara = ara; if (irq > 0) { - res = devm_request_threaded_irq(&ara->dev, irq, - NULL, smbus_alert, - IRQF_SHARED | IRQF_ONESHOT, - "smbus_alert", alert); + res = devm_request_threaded_irq(&ara->dev, irq, NULL, smbus_alert, + irqflags, "smbus_alert", alert); if (res) return res; } @@ -160,7 +220,7 @@ static void smbalert_remove(struct i2c_client *ara) } static const struct i2c_device_id smbalert_ids[] = { - { "smbus_alert", 0 }, + { "smbus_alert" }, { /* LIST END */ } }; MODULE_DEVICE_TABLE(i2c, smbalert_ids); @@ -169,7 +229,7 @@ static struct i2c_driver smbalert_driver = { .driver = { .name = "smbus_alert", }, - .probe_new = smbalert_probe, + .probe = smbalert_probe, .remove = smbalert_remove, .id_table = smbalert_ids, }; @@ -308,16 +368,17 @@ EXPORT_SYMBOL_GPL(i2c_free_slave_host_notify_device); * target systems are the same. * Restrictions to automatic SPD instantiation: * - Only works if all filled slots have the same memory type - * - Only works for DDR2, DDR3 and DDR4 for now - * - Only works on systems with 1 to 4 memory slots + * - Only works for (LP)DDR memory types up to DDR5 + * - Only works on systems with 1 to 8 memory slots */ #if IS_ENABLED(CONFIG_DMI) -void i2c_register_spd(struct i2c_adapter *adap) +static void i2c_register_spd(struct i2c_adapter *adap, bool write_disabled) { int n, slot_count = 0, dimm_count = 0; u16 handle; u8 common_mem_type = 0x0, mem_type; u64 mem_size; + bool instantiate = true; const char *name; while ((handle = dmi_memdev_handle(slot_count)) != 0xffff) { @@ -351,14 +412,12 @@ void i2c_register_spd(struct i2c_adapter *adap) if (!dimm_count) return; - dev_info(&adap->dev, "%d/%d memory slots populated (from DMI)\n", - dimm_count, slot_count); - - if (slot_count > 4) { - dev_warn(&adap->dev, - "Systems with more than 4 memory slots not supported yet, not instantiating SPD\n"); - return; - } + /* + * The max number of SPD EEPROMs that can be addressed per bus is 8. + * If more slots are present either muxed or multiple busses are + * necessary or the additional slots are ignored. + */ + slot_count = min(slot_count, 8); /* * Memory types could be found at section 7.18.2 (Memory Device — Type), table 78 @@ -377,6 +436,11 @@ void i2c_register_spd(struct i2c_adapter *adap) case 0x1E: /* LPDDR4 */ name = "ee1004"; break; + case 0x22: /* DDR5 */ + case 0x23: /* LPDDR5 */ + name = "spd5118"; + instantiate = !write_disabled; + break; default: dev_info(&adap->dev, "Memory type 0x%02x not supported yet, not instantiating SPD\n", @@ -399,6 +463,9 @@ void i2c_register_spd(struct i2c_adapter *adap) addr_list[0] = 0x50 + n; addr_list[1] = I2C_CLIENT_END; + if (!instantiate) + continue; + if (!IS_ERR(i2c_new_scanned_device(adap, &info, addr_list, NULL))) { dev_info(&adap->dev, "Successfully instantiated SPD at 0x%hx\n", @@ -407,7 +474,19 @@ void i2c_register_spd(struct i2c_adapter *adap) } } } -EXPORT_SYMBOL_GPL(i2c_register_spd); + +void i2c_register_spd_write_disable(struct i2c_adapter *adap) +{ + i2c_register_spd(adap, true); +} +EXPORT_SYMBOL_GPL(i2c_register_spd_write_disable); + +void i2c_register_spd_write_enable(struct i2c_adapter *adap) +{ + i2c_register_spd(adap, false); +} +EXPORT_SYMBOL_GPL(i2c_register_spd_write_enable); + #endif MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); diff --git a/drivers/i2c/i2c-stub.c b/drivers/i2c/i2c-stub.c index d642cad219d9..09e7b7bf4c5f 100644 --- a/drivers/i2c/i2c-stub.c +++ b/drivers/i2c/i2c-stub.c @@ -308,7 +308,7 @@ static const struct i2c_algorithm smbus_algorithm = { static struct i2c_adapter stub_adapter = { .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .class = I2C_CLASS_HWMON, .algo = &smbus_algorithm, .name = "SMBus stub driver", }; diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig index ea838dbae32e..6d2f66810cdc 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -65,11 +65,11 @@ config I2C_MUX_PCA9541 will be called i2c-mux-pca9541. config I2C_MUX_PCA954x - tristate "NXP PCA954x and PCA984x I2C Mux/switches" + tristate "NXP PCA954x/PCA984x and Maxim MAX735x/MAX736x I2C Mux/switches" depends on GPIOLIB || COMPILE_TEST help - If you say yes here you get support for the NXP PCA954x - and PCA984x I2C mux/switch devices. + If you say yes here you get support for NXP PCA954x/PCA984x + and Maxim MAX735x/MAX736x I2C mux/switch devices. This driver can also be built as a module. If so, the module will be called i2c-mux-pca954x. @@ -119,4 +119,20 @@ config I2C_MUX_MLXCPLD This driver can also be built as a module. If so, the module will be called i2c-mux-mlxcpld. +config I2C_MUX_MULE + tristate "Theobroma Systems Mule I2C device multiplexer" + depends on OF && SENSORS_AMC6821 + help + Mule is an MCU that emulates a set of I2C devices, among which + devices that are reachable through an I2C-mux. The devices on the mux + can be selected by writing the appropriate device number to an I2C + configuration register. + + If you say yes to this option, support will be included for a + Theobroma Systems Mule I2C multiplexer. This driver provides access to + I2C devices connected on this mux. + + This driver can also be built as a module. If so, the module + will be called i2c-mux-mule. + endmenu diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile index 6d9d865e8518..4b24f49515a7 100644 --- a/drivers/i2c/muxes/Makefile +++ b/drivers/i2c/muxes/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o obj-$(CONFIG_I2C_MUX_GPMUX) += i2c-mux-gpmux.o obj-$(CONFIG_I2C_MUX_LTC4306) += i2c-mux-ltc4306.o obj-$(CONFIG_I2C_MUX_MLXCPLD) += i2c-mux-mlxcpld.o +obj-$(CONFIG_I2C_MUX_MULE) += i2c-mux-mule.o obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c index 1c78657631f4..d6ef91b888c6 100644 --- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c +++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c @@ -167,20 +167,19 @@ static int i2c_arbitrator_probe(struct platform_device *pdev) } /* Actually add the mux adapter */ - ret = i2c_mux_add_adapter(muxc, 0, 0, 0); + ret = i2c_mux_add_adapter(muxc, 0, 0); if (ret) i2c_put_adapter(muxc->parent); return ret; } -static int i2c_arbitrator_remove(struct platform_device *pdev) +static void i2c_arbitrator_remove(struct platform_device *pdev) { struct i2c_mux_core *muxc = platform_get_drvdata(pdev); i2c_mux_del_adapters(muxc); i2c_put_adapter(muxc->parent); - return 0; } static const struct of_device_id i2c_arbitrator_of_match[] = { @@ -191,7 +190,7 @@ MODULE_DEVICE_TABLE(of, i2c_arbitrator_of_match); static struct platform_driver i2c_arbitrator_driver = { .probe = i2c_arbitrator_probe, - .remove = i2c_arbitrator_remove, + .remove = i2c_arbitrator_remove, .driver = { .name = "i2c-arb-gpio-challenge", .of_match_table = i2c_arbitrator_of_match, diff --git a/drivers/i2c/muxes/i2c-demux-pinctrl.c b/drivers/i2c/muxes/i2c-demux-pinctrl.c index f7a7405d4350..f2a1f4744978 100644 --- a/drivers/i2c/muxes/i2c-demux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-demux-pinctrl.c @@ -32,7 +32,7 @@ struct i2c_demux_pinctrl_priv { const char *bus_name; struct i2c_adapter cur_adap; struct i2c_algorithm algo; - struct i2c_demux_pinctrl_chan chan[]; + struct i2c_demux_pinctrl_chan chan[] __counted_by(num_chan); }; static int i2c_demux_master_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) @@ -61,14 +61,14 @@ static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 ne if (ret) goto err; - adap = of_find_i2c_adapter_by_node(priv->chan[new_chan].parent_np); + adap = of_get_i2c_adapter_by_node(priv->chan[new_chan].parent_np); if (!adap) { ret = -ENODEV; goto err_with_revert; } /* - * Check if there are pinctrl states at all. Note: we cant' use + * Check if there are pinctrl states at all. Note: we can't use * devm_pinctrl_get_select() because we need to distinguish between * the -ENODEV from devm_pinctrl_get() and pinctrl_lookup_state(). */ @@ -95,9 +95,9 @@ static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 ne priv->cur_chan = new_chan; /* Now fill out current adapter structure. cur_chan must be up to date */ - priv->algo.master_xfer = i2c_demux_master_xfer; + priv->algo.xfer = i2c_demux_master_xfer; if (adap->algo->master_xfer_atomic) - priv->algo.master_xfer_atomic = i2c_demux_master_xfer; + priv->algo.xfer_atomic = i2c_demux_master_xfer; priv->algo.functionality = i2c_demux_functionality; snprintf(priv->cur_adap.name, sizeof(priv->cur_adap.name), @@ -167,9 +167,9 @@ static ssize_t available_masters_show(struct device *dev, int count = 0, i; for (i = 0; i < priv->num_chan && count < PAGE_SIZE; i++) - count += scnprintf(buf + count, PAGE_SIZE - count, "%d:%pOF%c", - i, priv->chan[i].parent_np, - i == priv->num_chan - 1 ? '\n' : ' '); + count += sysfs_emit_at(buf, count, "%d:%pOF%c", + i, priv->chan[i].parent_np, + i == priv->num_chan - 1 ? '\n' : ' '); return count; } @@ -226,6 +226,8 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) if (!priv || !props) return -ENOMEM; + priv->num_chan = num_chan; + err = of_property_read_string(np, "i2c-bus-name", &priv->bus_name); if (err) return err; @@ -243,21 +245,25 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) props[i].name = devm_kstrdup(&pdev->dev, "status", GFP_KERNEL); props[i].value = devm_kstrdup(&pdev->dev, "ok", GFP_KERNEL); + if (!props[i].name || !props[i].value) { + err = -ENOMEM; + goto err_rollback; + } props[i].length = 3; of_changeset_init(&priv->chan[i].chgset); of_changeset_update_property(&priv->chan[i].chgset, adap_np, &props[i]); } - priv->num_chan = num_chan; priv->dev = &pdev->dev; - platform_set_drvdata(pdev, priv); pm_runtime_no_callbacks(&pdev->dev); /* switch to first parent as active master */ - i2c_demux_activate_master(priv, 0); + err = i2c_demux_activate_master(priv, 0); + if (err) + goto err_rollback; err = device_create_file(&pdev->dev, &dev_attr_available_masters); if (err) @@ -282,7 +288,7 @@ err_rollback: return err; } -static int i2c_demux_pinctrl_remove(struct platform_device *pdev) +static void i2c_demux_pinctrl_remove(struct platform_device *pdev) { struct i2c_demux_pinctrl_priv *priv = platform_get_drvdata(pdev); int i; @@ -296,8 +302,6 @@ static int i2c_demux_pinctrl_remove(struct platform_device *pdev) of_node_put(priv->chan[i].parent_np); of_changeset_destroy(&priv->chan[i].chgset); } - - return 0; } static const struct of_device_id i2c_demux_pinctrl_of_match[] = { @@ -312,7 +316,7 @@ static struct platform_driver i2c_demux_pinctrl_driver = { .of_match_table = i2c_demux_pinctrl_of_match, }, .probe = i2c_demux_pinctrl_probe, - .remove = i2c_demux_pinctrl_remove, + .remove = i2c_demux_pinctrl_remove, }; module_platform_driver(i2c_demux_pinctrl_driver); diff --git a/drivers/i2c/muxes/i2c-mux-gpio.c b/drivers/i2c/muxes/i2c-mux-gpio.c index 73a23e117ebe..9b46b84e84fb 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -5,17 +5,17 @@ * Peter Korsgaard <peter.korsgaard@barco.com> */ +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/gpio/consumer.h> +#include <linux/gpio/driver.h> #include <linux/i2c.h> #include <linux/i2c-mux.h> +#include <linux/module.h> #include <linux/overflow.h> #include <linux/platform_data/i2c-mux-gpio.h> #include <linux/platform_device.h> -#include <linux/module.h> #include <linux/slab.h> -#include <linux/bits.h> -#include <linux/gpio/consumer.h> -/* FIXME: stop poking around inside gpiolib */ -#include "../../gpio/gpiolib.h" struct gpiomux { struct i2c_mux_gpio_platform_data data; @@ -23,7 +23,7 @@ struct gpiomux { struct gpio_desc **gpios; }; -static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned val) +static void i2c_mux_gpio_set(const struct gpiomux *mux, unsigned int val) { DECLARE_BITMAP(values, BITS_PER_TYPE(val)); @@ -38,6 +38,9 @@ static int i2c_mux_gpio_select(struct i2c_mux_core *muxc, u32 chan) i2c_mux_gpio_set(mux, chan); + if (mux->data.settle_time) + fsleep(mux->data.settle_time); + return 0; } @@ -59,7 +62,7 @@ static int i2c_mux_gpio_probe_fw(struct gpiomux *mux, struct device_node *adapter_np; struct i2c_adapter *adapter = NULL; struct fwnode_handle *child; - unsigned *values; + unsigned int *values; int rc, i = 0; if (is_of_node(fwnode)) { @@ -102,11 +105,12 @@ static int i2c_mux_gpio_probe_fw(struct gpiomux *mux, device_for_each_child_node(dev, child) { if (is_of_node(child)) { fwnode_property_read_u32(child, "reg", values + i); - } else if (is_acpi_node(child)) { rc = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), values + i); - if (rc) + if (rc) { + fwnode_handle_put(child); return dev_err_probe(dev, rc, "Cannot get address\n"); + } } i++; @@ -116,6 +120,8 @@ static int i2c_mux_gpio_probe_fw(struct gpiomux *mux, if (device_property_read_u32(dev, "idle-state", &mux->data.idle)) mux->data.idle = I2C_MUX_GPIO_NO_IDLE; + device_property_read_u32(dev, "settle-time-us", &mux->data.settle_time); + return 0; } @@ -125,7 +131,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) struct gpiomux *mux; struct i2c_adapter *parent; struct i2c_adapter *root; - unsigned initial_state; + unsigned int initial_state; int i, ngpios, ret; mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); @@ -176,7 +182,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) } for (i = 0; i < ngpios; i++) { - struct device *gpio_dev; + struct gpio_device *gdev; + struct device *dev; struct gpio_desc *gpiod; enum gpiod_flags flag; @@ -195,9 +202,9 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) if (!muxc->mux_locked) continue; - /* FIXME: find a proper way to access the GPIO device */ - gpio_dev = &gpiod->gdev->dev; - muxc->mux_locked = i2c_root_adapter(gpio_dev) == root; + gdev = gpiod_to_gpio_device(gpiod); + dev = gpio_device_to_device(gdev); + muxc->mux_locked = i2c_root_adapter(dev) == root; } if (muxc->mux_locked) @@ -205,9 +212,8 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) for (i = 0; i < mux->data.n_values; i++) { u32 nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0; - unsigned int class = mux->data.classes ? mux->data.classes[i] : 0; - ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class); + ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i]); if (ret) goto add_adapter_failed; } @@ -225,14 +231,12 @@ alloc_failed: return ret; } -static int i2c_mux_gpio_remove(struct platform_device *pdev) +static void i2c_mux_gpio_remove(struct platform_device *pdev) { struct i2c_mux_core *muxc = platform_get_drvdata(pdev); i2c_mux_del_adapters(muxc); i2c_put_adapter(muxc->parent); - - return 0; } static const struct of_device_id i2c_mux_gpio_of_match[] = { @@ -243,7 +247,7 @@ MODULE_DEVICE_TABLE(of, i2c_mux_gpio_of_match); static struct platform_driver i2c_mux_gpio_driver = { .probe = i2c_mux_gpio_probe, - .remove = i2c_mux_gpio_remove, + .remove = i2c_mux_gpio_remove, .driver = { .name = "i2c-mux-gpio", .of_match_table = i2c_mux_gpio_of_match, diff --git a/drivers/i2c/muxes/i2c-mux-gpmux.c b/drivers/i2c/muxes/i2c-mux-gpmux.c index 33024acaac02..ab8e11661052 100644 --- a/drivers/i2c/muxes/i2c-mux-gpmux.c +++ b/drivers/i2c/muxes/i2c-mux-gpmux.c @@ -11,7 +11,7 @@ #include <linux/i2c-mux.h> #include <linux/module.h> #include <linux/mux/consumer.h> -#include <linux/of_device.h> +#include <linux/of.h> #include <linux/platform_device.h> struct mux { @@ -52,7 +52,7 @@ static struct i2c_adapter *mux_parent_adapter(struct device *dev) dev_err(dev, "Cannot parse i2c-parent\n"); return ERR_PTR(-ENODEV); } - parent = of_find_i2c_adapter_by_node(parent_np); + parent = of_get_i2c_adapter_by_node(parent_np); of_node_put(parent_np); if (!parent) return ERR_PTR(-EPROBE_DEFER); @@ -124,7 +124,7 @@ static int i2c_mux_probe(struct platform_device *pdev) goto err_children; } - ret = i2c_mux_add_adapter(muxc, 0, chan, 0); + ret = i2c_mux_add_adapter(muxc, 0, chan); if (ret) goto err_children; } @@ -142,19 +142,17 @@ err_parent: return ret; } -static int i2c_mux_remove(struct platform_device *pdev) +static void i2c_mux_remove(struct platform_device *pdev) { struct i2c_mux_core *muxc = platform_get_drvdata(pdev); i2c_mux_del_adapters(muxc); i2c_put_adapter(muxc->parent); - - return 0; } static struct platform_driver i2c_mux_driver = { .probe = i2c_mux_probe, - .remove = i2c_mux_remove, + .remove = i2c_mux_remove, .driver = { .name = "i2c-mux-gpmux", .of_match_table = i2c_mux_of_match, diff --git a/drivers/i2c/muxes/i2c-mux-ltc4306.c b/drivers/i2c/muxes/i2c-mux-ltc4306.c index 70835825083f..50fbc0d06e62 100644 --- a/drivers/i2c/muxes/i2c-mux-ltc4306.c +++ b/drivers/i2c/muxes/i2c-mux-ltc4306.c @@ -15,7 +15,6 @@ #include <linux/i2c.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/property.h> #include <linux/regmap.h> #include <linux/slab.h> @@ -62,7 +61,7 @@ static const struct chip_desc chips[] = { static bool ltc4306_is_volatile_reg(struct device *dev, unsigned int reg) { - return (reg == LTC_REG_CONFIG) ? true : false; + return reg == LTC_REG_CONFIG; } static const struct regmap_config ltc4306_regmap_config = { @@ -86,13 +85,13 @@ static int ltc4306_gpio_get(struct gpio_chip *chip, unsigned int offset) return !!(val & BIT(1 - offset)); } -static void ltc4306_gpio_set(struct gpio_chip *chip, unsigned int offset, - int value) +static int ltc4306_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct ltc4306 *data = gpiochip_get_data(chip); - regmap_update_bits(data->regmap, LTC_REG_CONFIG, BIT(5 - offset), - value ? BIT(5 - offset) : 0); + return regmap_update_bits(data->regmap, LTC_REG_CONFIG, + BIT(5 - offset), value ? BIT(5 - offset) : 0); } static int ltc4306_gpio_get_direction(struct gpio_chip *chip, @@ -280,7 +279,7 @@ static int ltc4306_probe(struct i2c_client *client) /* Now create an adapter for each channel */ for (num = 0; num < chip->nchans; num++) { - ret = i2c_mux_add_adapter(muxc, 0, num, 0); + ret = i2c_mux_add_adapter(muxc, 0, num); if (ret) { i2c_mux_del_adapters(muxc); return ret; @@ -304,9 +303,9 @@ static void ltc4306_remove(struct i2c_client *client) static struct i2c_driver ltc4306_driver = { .driver = { .name = "ltc4306", - .of_match_table = of_match_ptr(ltc4306_of_match), + .of_match_table = ltc4306_of_match, }, - .probe_new = ltc4306_probe, + .probe = ltc4306_probe, .remove = ltc4306_remove, .id_table = ltc4306_id, }; diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index 1a879f6a31ef..1c2debcf379c 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -154,7 +154,7 @@ static int mlxcpld_mux_probe(struct platform_device *pdev) /* Create an adapter for each channel. */ for (num = 0; num < pdata->num_adaps; num++) { - err = i2c_mux_add_adapter(muxc, 0, pdata->chan_ids[num], 0); + err = i2c_mux_add_adapter(muxc, 0, pdata->chan_ids[num]); if (err) goto virt_reg_failed; } @@ -170,12 +170,11 @@ virt_reg_failed: return err; } -static int mlxcpld_mux_remove(struct platform_device *pdev) +static void mlxcpld_mux_remove(struct platform_device *pdev) { struct i2c_mux_core *muxc = platform_get_drvdata(pdev); i2c_mux_del_adapters(muxc); - return 0; } static struct platform_driver mlxcpld_mux_driver = { @@ -188,7 +187,7 @@ static struct platform_driver mlxcpld_mux_driver = { module_platform_driver(mlxcpld_mux_driver); -MODULE_AUTHOR("Michael Shych (michaels@mellanox.com)"); +MODULE_AUTHOR("Michael Shych <michaels@mellanox.com>"); MODULE_DESCRIPTION("Mellanox I2C-CPLD-MUX driver"); MODULE_LICENSE("Dual BSD/GPL"); MODULE_ALIAS("platform:i2c-mux-mlxcpld"); diff --git a/drivers/i2c/muxes/i2c-mux-mule.c b/drivers/i2c/muxes/i2c-mux-mule.c new file mode 100644 index 000000000000..d3b32b794172 --- /dev/null +++ b/drivers/i2c/muxes/i2c-mux-mule.c @@ -0,0 +1,147 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Theobroma Systems Mule I2C device multiplexer + * + * Copyright (C) 2024 Theobroma Systems Design und Consulting GmbH + */ + +#include <linux/i2c-mux.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/property.h> +#include <linux/regmap.h> + +#define MULE_I2C_MUX_CONFIG_REG 0xff +#define MULE_I2C_MUX_DEFAULT_DEV 0x0 + +struct mule_i2c_reg_mux { + struct regmap *regmap; +}; + +static int mule_i2c_mux_select(struct i2c_mux_core *muxc, u32 dev) +{ + struct mule_i2c_reg_mux *mux = muxc->priv; + + return regmap_write(mux->regmap, MULE_I2C_MUX_CONFIG_REG, dev); +} + +static int mule_i2c_mux_deselect(struct i2c_mux_core *muxc, u32 dev) +{ + return mule_i2c_mux_select(muxc, MULE_I2C_MUX_DEFAULT_DEV); +} + +static void mule_i2c_mux_remove(void *data) +{ + struct i2c_mux_core *muxc = data; + + i2c_mux_del_adapters(muxc); + + mule_i2c_mux_deselect(muxc, MULE_I2C_MUX_DEFAULT_DEV); +} + +static int mule_i2c_mux_probe(struct platform_device *pdev) +{ + struct device *mux_dev = &pdev->dev; + struct mule_i2c_reg_mux *priv; + struct i2c_client *client; + struct i2c_mux_core *muxc; + unsigned int readback; + int ndev, ret; + bool old_fw; + + /* Count devices on the mux */ + ndev = of_get_child_count(mux_dev->of_node); + dev_dbg(mux_dev, "%d devices on the mux\n", ndev); + + client = to_i2c_client(mux_dev->parent); + + muxc = i2c_mux_alloc(client->adapter, mux_dev, ndev, sizeof(*priv), + I2C_MUX_LOCKED, mule_i2c_mux_select, mule_i2c_mux_deselect); + if (!muxc) + return -ENOMEM; + + priv = i2c_mux_priv(muxc); + + priv->regmap = dev_get_regmap(mux_dev->parent, NULL); + if (!priv->regmap) + return dev_err_probe(mux_dev, -ENODEV, + "No parent i2c register map\n"); + + platform_set_drvdata(pdev, muxc); + + /* + * MULE_I2C_MUX_DEFAULT_DEV is guaranteed to exist on all old and new + * mule fw. Mule fw without mux support will accept write ops to the + * config register, but readback returns 0xff (register not updated). + */ + ret = mule_i2c_mux_select(muxc, MULE_I2C_MUX_DEFAULT_DEV); + if (ret) + return dev_err_probe(mux_dev, ret, + "Failed to write config register\n"); + + ret = regmap_read(priv->regmap, MULE_I2C_MUX_CONFIG_REG, &readback); + if (ret) + return dev_err_probe(mux_dev, ret, + "Failed to read config register\n"); + + old_fw = (readback != MULE_I2C_MUX_DEFAULT_DEV); + + ret = devm_add_action_or_reset(mux_dev, mule_i2c_mux_remove, muxc); + if (ret) + return dev_err_probe(mux_dev, ret, + "Failed to register mux remove\n"); + + /* Create device adapters */ + for_each_child_of_node_scoped(mux_dev->of_node, dev) { + u32 reg; + + ret = of_property_read_u32(dev, "reg", ®); + if (ret) + return dev_err_probe(mux_dev, ret, + "No reg property found for %s\n", + of_node_full_name(dev)); + + if (old_fw && reg != 0) { + dev_warn(mux_dev, + "Mux is not supported, please update Mule FW\n"); + continue; + } + + ret = mule_i2c_mux_select(muxc, reg); + if (ret) { + dev_warn(mux_dev, + "Device %d not supported, please update Mule FW\n", reg); + continue; + } + + ret = i2c_mux_add_adapter(muxc, 0, reg); + if (ret) + return ret; + } + + mule_i2c_mux_deselect(muxc, MULE_I2C_MUX_DEFAULT_DEV); + + return 0; +} + +static const struct of_device_id mule_i2c_mux_of_match[] = { + { .compatible = "tsd,mule-i2c-mux", }, + {}, +}; +MODULE_DEVICE_TABLE(of, mule_i2c_mux_of_match); + +static struct platform_driver mule_i2c_mux_driver = { + .driver = { + .name = "mule-i2c-mux", + .of_match_table = mule_i2c_mux_of_match, + }, + .probe = mule_i2c_mux_probe, +}; + +module_platform_driver(mule_i2c_mux_driver); + +MODULE_AUTHOR("Farouk Bouabid <farouk.bouabid@cherry.de>"); +MODULE_DESCRIPTION("I2C mux driver for Theobroma Systems Mule"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c index 09d1d9e67e31..3d8002caf703 100644 --- a/drivers/i2c/muxes/i2c-mux-pca9541.c +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c @@ -63,10 +63,6 @@ #define mybus(x) (!((x) & MYBUS) || ((x) & MYBUS) == MYBUS) #define busoff(x) (!((x) & BUSON) || ((x) & BUSON) == BUSON) -/* arbitration timeouts, in jiffies */ -#define ARB_TIMEOUT (HZ / 8) /* 125 ms until forcing bus ownership */ -#define ARB2_TIMEOUT (HZ / 4) /* 250 ms until acquisition failure */ - /* arbitration retry delays, in us */ #define SELECT_DELAY_SHORT 50 #define SELECT_DELAY_LONG 1000 @@ -78,7 +74,7 @@ struct pca9541 { }; static const struct i2c_device_id pca9541_id[] = { - {"pca9541", 0}, + { "pca9541" }, {} }; @@ -229,6 +225,9 @@ static int pca9541_arbitrate(struct i2c_client *client) */ data->select_timeout = SELECT_DELAY_LONG; if (time_is_before_eq_jiffies(data->arb_timeout)) { + dev_warn(&client->dev, + "Arbitration timeout on I2C bus, forcing bus ownership\n"); + /* Time is up, take the bus and reset it. */ pca9541_reg_write(client, PCA9541_CONTROL, @@ -251,10 +250,10 @@ static int pca9541_select_chan(struct i2c_mux_core *muxc, u32 chan) struct pca9541 *data = i2c_mux_priv(muxc); struct i2c_client *client = data->client; int ret; - unsigned long timeout = jiffies + ARB2_TIMEOUT; + unsigned long timeout = jiffies + (2 * client->adapter->timeout); /* give up after this time */ - data->arb_timeout = jiffies + ARB_TIMEOUT; + data->arb_timeout = jiffies + client->adapter->timeout; /* force bus ownership after this time */ do { @@ -267,6 +266,7 @@ static int pca9541_select_chan(struct i2c_mux_core *muxc, u32 chan) else msleep(data->select_timeout / 1000); } while (time_is_after_eq_jiffies(timeout)); + dev_warn(&client->dev, "Failed to acquire I2C bus, timed out\n"); return -ETIMEDOUT; } @@ -314,7 +314,7 @@ static int pca9541_probe(struct i2c_client *client) i2c_set_clientdata(client, muxc); - ret = i2c_mux_add_adapter(muxc, 0, 0, 0); + ret = i2c_mux_add_adapter(muxc, 0, 0); if (ret) return ret; @@ -336,7 +336,7 @@ static struct i2c_driver pca9541_driver = { .name = "pca9541", .of_match_table = of_match_ptr(pca9541_of_match), }, - .probe_new = pca9541_probe, + .probe = pca9541_probe, .remove = pca9541_remove, .id_table = pca9541_id, }; diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 3639e6d7304c..b9f370c9f018 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -11,6 +11,12 @@ * PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547, * PCA9548, PCA9846, PCA9847, PCA9848 and PCA9849. * + * It's also compatible to Maxims MAX735x I2C switch chips, which are controlled + * as the NXP PCA9548 and the MAX736x chips that act like the PCA9544. + * + * This includes the: + * MAX7356, MAX7357, MAX7358, MAX7367, MAX7368 and MAX7369 + * * These chips are all controlled via the I2C bus itself, and all have a * single 8-bit register. The upstream "parent" bus fans out to two, * four, or eight downstream busses or channels; which of these @@ -42,6 +48,8 @@ #include <linux/module.h> #include <linux/pm.h> #include <linux/property.h> +#include <linux/regulator/consumer.h> +#include <linux/reset.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <dt-bindings/mux/mux.h> @@ -50,7 +58,27 @@ #define PCA954X_IRQ_OFFSET 4 +/* + * MAX7357's configuration register is writeable after POR, but + * can be locked by setting the basic mode bit. MAX7358 configuration + * register is locked by default and needs to be unlocked first. + * The configuration register holds the following settings: + */ +#define MAX7357_CONF_INT_ENABLE BIT(0) +#define MAX7357_CONF_FLUSH_OUT BIT(1) +#define MAX7357_CONF_RELEASE_INT BIT(2) +#define MAX7357_CONF_DISCON_SINGLE_CHAN BIT(4) +#define MAX7357_CONF_PRECONNECT_TEST BIT(7) + +#define MAX7357_POR_DEFAULT_CONF MAX7357_CONF_INT_ENABLE + enum pca_type { + max_7356, + max_7357, + max_7358, + max_7367, + max_7368, + max_7369, pca_9540, pca_9542, pca_9543, @@ -88,10 +116,55 @@ struct pca954x { struct irq_domain *irq; unsigned int irq_mask; raw_spinlock_t lock; + struct regulator *supply; + + struct gpio_desc *reset_gpio; + struct reset_control *reset_cont; }; -/* Provide specs for the PCA954x types we know about */ +/* Provide specs for the MAX735x, PCA954x and PCA984x types we know about */ static const struct chip_desc chips[] = { + [max_7356] = { + .nchans = 8, + .muxtype = pca954x_isswi, + .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, + }, + [max_7357] = { + .nchans = 8, + .muxtype = pca954x_isswi, + .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, + /* + * No interrupt controller support. The interrupt + * provides information about stuck channels. + */ + }, + [max_7358] = { + .nchans = 8, + .muxtype = pca954x_isswi, + .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, + /* + * No interrupt controller support. The interrupt + * provides information about stuck channels. + */ + }, + [max_7367] = { + .nchans = 4, + .muxtype = pca954x_isswi, + .has_irq = 1, + .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, + }, + [max_7368] = { + .nchans = 4, + .muxtype = pca954x_isswi, + .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, + }, + [max_7369] = { + .nchans = 4, + .enable = 0x4, + .muxtype = pca954x_ismux, + .has_irq = 1, + .id = { .manufacturer_id = I2C_DEVICE_ID_NONE }, + }, [pca_9540] = { .nchans = 2, .enable = 0x4, @@ -177,6 +250,12 @@ static const struct chip_desc chips[] = { }; static const struct i2c_device_id pca954x_id[] = { + { "max7356", max_7356 }, + { "max7357", max_7357 }, + { "max7358", max_7358 }, + { "max7367", max_7367 }, + { "max7368", max_7368 }, + { "max7369", max_7369 }, { "pca9540", pca_9540 }, { "pca9542", pca_9542 }, { "pca9543", pca_9543 }, @@ -194,6 +273,12 @@ static const struct i2c_device_id pca954x_id[] = { MODULE_DEVICE_TABLE(i2c, pca954x_id); static const struct of_device_id pca954x_of_match[] = { + { .compatible = "maxim,max7356", .data = &chips[max_7356] }, + { .compatible = "maxim,max7357", .data = &chips[max_7357] }, + { .compatible = "maxim,max7358", .data = &chips[max_7358] }, + { .compatible = "maxim,max7367", .data = &chips[max_7367] }, + { .compatible = "maxim,max7368", .data = &chips[max_7368] }, + { .compatible = "maxim,max7369", .data = &chips[max_7369] }, { .compatible = "nxp,pca9540", .data = &chips[pca_9540] }, { .compatible = "nxp,pca9542", .data = &chips[pca_9542] }, { .compatible = "nxp,pca9543", .data = &chips[pca_9543] }, @@ -329,7 +414,7 @@ static irqreturn_t pca954x_irq_handler(int irq, void *dev_id) pending = (ret >> PCA954X_IRQ_OFFSET) & (BIT(data->chip->nchans) - 1); for_each_set_bit(i, &pending, data->chip->nchans) - handle_nested_irq(irq_linear_revmap(data->irq, i)); + handle_nested_irq(irq_find_mapping(data->irq, i)); return IRQ_RETVAL(pending); } @@ -357,9 +442,8 @@ static int pca954x_irq_setup(struct i2c_mux_core *muxc) raw_spin_lock_init(&data->lock); - data->irq = irq_domain_add_linear(client->dev.of_node, - data->chip->nchans, - &irq_domain_simple_ops, data); + data->irq = irq_domain_create_linear(dev_fwnode(&client->dev), data->chip->nchans, + &irq_domain_simple_ops, data); if (!data->irq) return -ENODEV; @@ -382,6 +466,8 @@ static void pca954x_cleanup(struct i2c_mux_core *muxc) struct pca954x *data = i2c_mux_priv(muxc); int c, irq; + regulator_disable(data->supply); + if (data->irq) { for (c = 0; c < data->chip->nchans; c++) { irq = irq_find_mapping(data->irq, c); @@ -401,13 +487,69 @@ static int pca954x_init(struct i2c_client *client, struct pca954x *data) else data->last_chan = 0; /* Disconnect multiplexer */ - ret = i2c_smbus_write_byte(client, data->last_chan); + if (device_is_compatible(&client->dev, "maxim,max7357")) { + if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE_DATA)) { + u8 conf = MAX7357_POR_DEFAULT_CONF; + /* + * The interrupt signal is shared with the reset pin. Release the + * interrupt after 1.6 seconds to allow using the pin as reset. + */ + conf |= MAX7357_CONF_RELEASE_INT; + + if (device_property_read_bool(&client->dev, "maxim,isolate-stuck-channel")) + conf |= MAX7357_CONF_DISCON_SINGLE_CHAN; + if (device_property_read_bool(&client->dev, + "maxim,send-flush-out-sequence")) + conf |= MAX7357_CONF_FLUSH_OUT; + if (device_property_read_bool(&client->dev, + "maxim,preconnection-wiggle-test-enable")) + conf |= MAX7357_CONF_PRECONNECT_TEST; + + ret = i2c_smbus_write_byte_data(client, data->last_chan, conf); + } else { + dev_warn(&client->dev, "Write byte data not supported." + "Cannot enable enhanced mode features\n"); + ret = i2c_smbus_write_byte(client, data->last_chan); + } + } else { + ret = i2c_smbus_write_byte(client, data->last_chan); + } + if (ret < 0) data->last_chan = 0; return ret; } +static int pca954x_get_reset(struct device *dev, struct pca954x *data) +{ + data->reset_cont = devm_reset_control_get_optional_shared(dev, NULL); + if (IS_ERR(data->reset_cont)) + return dev_err_probe(dev, PTR_ERR(data->reset_cont), + "Failed to get reset\n"); + else if (data->reset_cont) + return 0; + + /* + * fallback to legacy reset-gpios + */ + data->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); + if (IS_ERR(data->reset_gpio)) { + return dev_err_probe(dev, PTR_ERR(data->reset_gpio), + "Failed to get reset gpio"); + } + + return 0; +} + +static void pca954x_reset_deassert(struct pca954x *data) +{ + if (data->reset_cont) + reset_control_deassert(data->reset_cont); + else + gpiod_set_value_cansleep(data->reset_gpio, 0); +} + /* * I2C init/probing/exit functions */ @@ -416,7 +558,6 @@ static int pca954x_probe(struct i2c_client *client) const struct i2c_device_id *id = i2c_client_get_device_id(client); struct i2c_adapter *adap = client->adapter; struct device *dev = &client->dev; - struct gpio_desc *gpio; struct i2c_mux_core *muxc; struct pca954x *data; int num; @@ -434,13 +575,23 @@ static int pca954x_probe(struct i2c_client *client) i2c_set_clientdata(client, muxc); data->client = client; - /* Reset the mux if a reset GPIO is specified. */ - gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); - if (IS_ERR(gpio)) - return PTR_ERR(gpio); - if (gpio) { + data->supply = devm_regulator_get(dev, "vdd"); + if (IS_ERR(data->supply)) + return dev_err_probe(dev, PTR_ERR(data->supply), + "Failed to request regulator\n"); + + ret = regulator_enable(data->supply); + if (ret) + return dev_err_probe(dev, ret, + "Failed to enable vdd supply\n"); + + ret = pca954x_get_reset(dev, data); + if (ret) + goto fail_cleanup; + + if (data->reset_cont || data->reset_gpio) { udelay(1); - gpiod_set_value_cansleep(gpio, 0); + pca954x_reset_deassert(data); /* Give the chip some time to recover. */ udelay(1); } @@ -454,7 +605,7 @@ static int pca954x_probe(struct i2c_client *client) ret = i2c_get_device_id(client, &id); if (ret && ret != -EOPNOTSUPP) - return ret; + goto fail_cleanup; if (!ret && (id.manufacturer_id != data->chip->id.manufacturer_id || @@ -462,7 +613,8 @@ static int pca954x_probe(struct i2c_client *client) dev_warn(dev, "unexpected device id %03x-%03x-%x\n", id.manufacturer_id, id.part_id, id.die_revision); - return -ENODEV; + ret = -ENODEV; + goto fail_cleanup; } } @@ -481,7 +633,8 @@ static int pca954x_probe(struct i2c_client *client) ret = pca954x_init(client, data); if (ret < 0) { dev_warn(dev, "probe failed\n"); - return -ENODEV; + ret = -ENODEV; + goto fail_cleanup; } ret = pca954x_irq_setup(muxc); @@ -490,7 +643,7 @@ static int pca954x_probe(struct i2c_client *client) /* Now create an adapter for each channel */ for (num = 0; num < data->chip->nchans; num++) { - ret = i2c_mux_add_adapter(muxc, 0, num, 0); + ret = i2c_mux_add_adapter(muxc, 0, num); if (ret) goto fail_cleanup; } @@ -530,7 +683,6 @@ static void pca954x_remove(struct i2c_client *client) pca954x_cleanup(muxc); } -#ifdef CONFIG_PM_SLEEP static int pca954x_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -544,17 +696,16 @@ static int pca954x_resume(struct device *dev) return ret; } -#endif -static SIMPLE_DEV_PM_OPS(pca954x_pm, NULL, pca954x_resume); +static DEFINE_SIMPLE_DEV_PM_OPS(pca954x_pm, NULL, pca954x_resume); static struct i2c_driver pca954x_driver = { .driver = { .name = "pca954x", - .pm = &pca954x_pm, + .pm = pm_sleep_ptr(&pca954x_pm), .of_match_table = pca954x_of_match, }, - .probe_new = pca954x_probe, + .probe = pca954x_probe, .remove = pca954x_remove, .id_table = pca954x_id, }; diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c index d5ad904756fd..fc686a350ae8 100644 --- a/drivers/i2c/muxes/i2c-mux-pinctrl.c +++ b/drivers/i2c/muxes/i2c-mux-pinctrl.c @@ -62,7 +62,7 @@ static struct i2c_adapter *i2c_mux_pinctrl_parent_adapter(struct device *dev) dev_err(dev, "Cannot parse i2c-parent\n"); return ERR_PTR(-ENODEV); } - parent = of_find_i2c_adapter_by_node(parent_np); + parent = of_get_i2c_adapter_by_node(parent_np); of_node_put(parent_np); if (!parent) return ERR_PTR(-EPROBE_DEFER); @@ -151,7 +151,7 @@ static int i2c_mux_pinctrl_probe(struct platform_device *pdev) /* Do not add any adapter for the idle state (if it's there at all). */ for (i = 0; i < num_names - !!muxc->deselect; i++) { - ret = i2c_mux_add_adapter(muxc, 0, i, 0); + ret = i2c_mux_add_adapter(muxc, 0, i); if (ret) goto err_del_adapter; } @@ -166,14 +166,12 @@ err_put_parent: return ret; } -static int i2c_mux_pinctrl_remove(struct platform_device *pdev) +static void i2c_mux_pinctrl_remove(struct platform_device *pdev) { struct i2c_mux_core *muxc = platform_get_drvdata(pdev); i2c_mux_del_adapters(muxc); i2c_put_adapter(muxc->parent); - - return 0; } static const struct of_device_id i2c_mux_pinctrl_of_match[] = { @@ -188,7 +186,7 @@ static struct platform_driver i2c_mux_pinctrl_driver = { .of_match_table = i2c_mux_pinctrl_of_match, }, .probe = i2c_mux_pinctrl_probe, - .remove = i2c_mux_pinctrl_remove, + .remove = i2c_mux_pinctrl_remove, }; module_platform_driver(i2c_mux_pinctrl_driver); diff --git a/drivers/i2c/muxes/i2c-mux-reg.c b/drivers/i2c/muxes/i2c-mux-reg.c index 30a6de1694e0..1e566ea92bc9 100644 --- a/drivers/i2c/muxes/i2c-mux-reg.c +++ b/drivers/i2c/muxes/i2c-mux-reg.c @@ -159,7 +159,6 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) struct regmux *mux; struct i2c_adapter *parent; struct resource *res; - unsigned int class; int i, ret, nr; mux = devm_kzalloc(&pdev->dev, sizeof(*mux), GFP_KERNEL); @@ -213,9 +212,8 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) for (i = 0; i < mux->data.n_values; i++) { nr = mux->data.base_nr ? (mux->data.base_nr + i) : 0; - class = mux->data.classes ? mux->data.classes[i] : 0; - ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i], class); + ret = i2c_mux_add_adapter(muxc, nr, mux->data.values[i]); if (ret) goto err_del_mux_adapters; } @@ -233,14 +231,12 @@ err_put_parent: return ret; } -static int i2c_mux_reg_remove(struct platform_device *pdev) +static void i2c_mux_reg_remove(struct platform_device *pdev) { struct i2c_mux_core *muxc = platform_get_drvdata(pdev); i2c_mux_del_adapters(muxc); i2c_put_adapter(muxc->parent); - - return 0; } static const struct of_device_id i2c_mux_reg_of_match[] = { @@ -251,10 +247,10 @@ MODULE_DEVICE_TABLE(of, i2c_mux_reg_of_match); static struct platform_driver i2c_mux_reg_driver = { .probe = i2c_mux_reg_probe, - .remove = i2c_mux_reg_remove, + .remove = i2c_mux_reg_remove, .driver = { .name = "i2c-mux-reg", - .of_match_table = of_match_ptr(i2c_mux_reg_of_match), + .of_match_table = i2c_mux_reg_of_match, }, }; |
