diff options
Diffstat (limited to 'drivers/i2c')
188 files changed, 23836 insertions, 10639 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 10acece9d7b9..cea87fcb4a1a 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -9,9 +9,16 @@ menu "I2C Hardware Bus support" comment "PC SMBus host controller drivers" depends on PCI +config I2C_CCGX_UCSI + tristate + help + A common module to provide an API to instantiate UCSI device + for Cypress CCGx Type-C controller. Individual bus drivers + need to select this one on demand. + 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 @@ -23,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 @@ -35,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. @@ -45,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 @@ -55,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. @@ -88,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 @@ -100,7 +111,8 @@ 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 help @@ -148,13 +160,28 @@ config I2C_I801 Jasper Lake (SOC) Emmitsburg (PCH) Alder Lake (PCH) + Raptor Lake (PCH) + 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 @@ -175,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 @@ -221,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. @@ -229,22 +257,10 @@ 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 + select I2C_CCGX_UCSI help If you say yes to this option, support will be included for the NVIDIA GPU I2C controller which is used to communicate with the GPU's @@ -253,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. @@ -263,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. @@ -273,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 @@ -291,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 @@ -302,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 @@ -324,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 @@ -390,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. @@ -407,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 @@ -416,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 @@ -477,9 +503,9 @@ config I2C_BCM_KONA config I2C_BRCMSTB tristate "BRCM Settop/DSL I2C controller" - depends on ARCH_BCM2835 || ARCH_BRCMSTB || BMIPS_GENERIC || \ - ARCH_BCM_63XX || COMPILE_TEST - default y + depends on ARCH_BCM2835 || ARCH_BCMBCA || ARCH_BRCMSTB || \ + BMIPS_GENERIC || COMPILE_TEST + 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. @@ -488,7 +514,7 @@ config I2C_BRCMSTB config I2C_CADENCE tristate "Cadence I2C Controller" - depends on ARCH_ZYNQ || ARM64 || XTENSA + 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. @@ -503,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 @@ -527,32 +563,62 @@ 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 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. + + You should say Y if running on an AMD system equipped with the PSP. + config I2C_DESIGNWARE_BAYTRAIL bool "Intel Baytrail I2C semaphore support" depends on ACPI @@ -567,16 +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 @@ -615,7 +684,10 @@ config I2C_EXYNOS5 depends on ARCH_EXYNOS || COMPILE_TEST default y if ARCH_EXYNOS help - High-speed I2C controller on Exynos5 and newer Samsung SoCs. + High-speed I2C controller on Samsung Exynos5 and newer Samsung SoCs: + Exynos5250, Exynos5260, Exynos5410, Exynos542x, Exynos5800, + Exynos5433, Exynos7, Exynos850 and ExynosAutoV9. + Choose Y here only if you build for such Samsung SoC. config I2C_GPIO tristate "GPIO-based bitbanging I2C" @@ -633,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 @@ -647,7 +726,7 @@ config I2C_HIGHLANDER config I2C_HISI tristate "HiSilicon I2C controller" - depends on (ARM64 && ACPI) || COMPILE_TEST + depends on ARM64 || COMPILE_TEST help Say Y here if you want to have Hisilicon I2C controller support available on the Kunpeng Server. @@ -677,18 +756,20 @@ config I2C_IMG config I2C_IMX tristate "IMX I2C interface" - depends on ARCH_MXC || ARCH_LAYERSCAPE || COLDFIRE + 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. @@ -697,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. @@ -715,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 @@ -735,9 +845,21 @@ 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 Enabling this option will add I2C SMBus support for Mellanox BlueField @@ -757,6 +879,17 @@ config I2C_MESON If you say yes to this option, support will be included for the I2C interface on the Amlogic Meson family of SoCs. +config I2C_MICROCHIP_CORE + tristate "Microchip FPGA I2C controller" + depends on ARCH_MICROCHIP_POLARFIRE || COMPILE_TEST + depends on OF + help + If you say yes to this option, support will be included for the + I2C interface on Microchip FPGAs. + + This driver can also be built as a module. If so, the module will be + called i2c-microchip-core. + config I2C_MPC tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx" depends on PPC @@ -779,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. @@ -808,19 +941,19 @@ 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, as well as the STA2X11 PCIe I/O HUB. -config I2C_NPCM7XX +config I2C_NPCM tristate "Nuvoton I2C Controller" - depends on ARCH_NPCM7XX || COMPILE_TEST + depends on ARCH_NPCM || COMPILE_TEST help If you say yes to this option, support will be included for the - Nuvoton I2C controller, which is available on the NPCM7xx BMC - controller. + Nuvoton I2C controller, which is available on the NPCM BMC + controllers. Driver can also support slave mode (select I2C_SLAVE). config I2C_OCORES @@ -836,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. @@ -856,6 +990,17 @@ config I2C_PASEMI help Supports the PA Semi PWRficient on-chip SMBus interfaces. +config I2C_APPLE + tristate "Apple SMBus platform driver" + depends on !I2C_PASEMI + depends on ARCH_APPLE || COMPILE_TEST + help + Say Y here if you want to use the I2C controller present on Apple + Silicon chips such as the M1. + + This driver can also be built as a module. If so, the module + will be called i2c-apple. + config I2C_PCA_PLATFORM tristate "PCA9564/PCA9665 as platform device" select I2C_ALGOPCA @@ -866,15 +1011,6 @@ config I2C_PCA_PLATFORM This driver can also be built as a module. If so, the module will be called i2c-pca-platform. -config I2C_PMCMSP - tristate "PMC MSP I2C TWI Controller" - depends on PMC_MSP || COMPILE_TEST - help - This driver supports the PMC TWI controller on MSP devices. - - This driver can also be built as module. If so, the module - will be called i2c-pmcmsp. - config I2C_PNX tristate "I2C bus support for Philips PNX and NXP LPC targets" depends on ARCH_LPC32XX || COMPILE_TEST @@ -930,7 +1066,7 @@ config I2C_QCOM_GENI config I2C_QUP tristate "Qualcomm QUP based I2C controller" - depends on ARCH_QCOM + depends on ARCH_QCOM || COMPILE_TEST help If you say yes to this option, support will be included for the built-in I2C interface on the Qualcomm SoCs. @@ -958,16 +1094,29 @@ config I2C_RK3X This driver can also be built as a module. If so, the module will be called i2c-rk3x. -config HAVE_S3C2410_I2C - bool +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 - This will include I2C support for Samsung SoCs. If you want to - include I2C support for any machine, kindly select this in the - respective Kconfig file. + If you say yes to this option, support will be included for the + 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 HAVE_S3C2410_I2C || 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). @@ -1154,22 +1303,12 @@ config I2C_XILINX This driver can also be built as a module. If so, the module will be called xilinx_i2c. -config I2C_XLR - tristate "Netlogic XLR I2C support" - depends on CPU_XLR || COMPILE_TEST - help - This driver enables support for the on-chip I2C interface of - the Netlogic XLR/XLS MIPS processors and Sigma Designs SOCs. - - This driver can also be built as a module. If so, the module - will be called i2c-xlr. - config I2C_XLP9XX - tristate "XLP9XX I2C support" - depends on CPU_XLP || ARCH_THUNDER2 || COMPILE_TEST + tristate "Cavium ThunderX2 I2C support" + depends on ARCH_THUNDER2 || COMPILE_TEST help This driver enables support for the on-chip I2C interface of - the Broadcom XLP9xx/XLP5xx MIPS and Vulcan ARM64 processors. + the Cavium ThunderX2 processors. (Originally on Netlogic XLP SoCs.) This driver can also be built as a module. If so, the module will be called i2c-xlp9xx. @@ -1179,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. @@ -1209,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 @@ -1234,6 +1405,16 @@ config I2C_PARPORT This support is also available as a module. If so, the module will be called i2c-parport. +config I2C_PCI1XXXX + tristate "PCI1XXXX I2C Host Adapter" + depends on PCI + help + If you say yes to this option, support will be included for + Microchip PCI1XXXX's I2C interface. + + This driver can also be built as a module. If so, the module will + be called i2c-mchp-pci1xxxx. + config I2C_ROBOTFUZZ_OSIF tristate "RobotFuzz Open Source InterFace USB adapter" depends on USB @@ -1294,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 @@ -1319,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 @@ -1370,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. @@ -1402,4 +1584,15 @@ config I2C_FSI This driver can also be built as a module. If so, the module will be called as i2c-fsi. +config I2C_VIRTIO + tristate "Virtio I2C Adapter" + select VIRTIO + help + If you say yes to this option, support will be included for the virtio + I2C adapter driver. The hardware can be emulated by any device model + software according to the virtio protocol. + + This driver can also be built as a module. If so, the module + will be called i2c-virtio. + endmenu diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 69e9963615f6..fb985769f5ff 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -6,19 +6,20 @@ # ACPI drivers obj-$(CONFIG_I2C_SCMI) += i2c-scmi.o +# Auxiliary I2C/SMBus modules +obj-$(CONFIG_I2C_CCGX_UCSI) += i2c-ccgx-ucsi.o + # PC SMBus host controller drivers 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 @@ -26,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 @@ -34,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 @@ -54,7 +56,9 @@ i2c-designware-core-y += i2c-designware-master.o i2c-designware-core-$(CONFIG_I2C_DESIGNWARE_SLAVE) += i2c-designware-slave.o 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 @@ -71,22 +75,26 @@ 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 obj-$(CONFIG_I2C_MT65XX) += i2c-mt65xx.o obj-$(CONFIG_I2C_MT7621) += i2c-mt7621.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o obj-$(CONFIG_I2C_MXS) += i2c-mxs.o obj-$(CONFIG_I2C_NOMADIK) += i2c-nomadik.o -obj-$(CONFIG_I2C_NPCM7XX) += i2c-npcm7xx.o +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 -obj-$(CONFIG_I2C_PASEMI) += i2c-pasemi.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_PMCMSP) += i2c-pmcmsp.o obj-$(CONFIG_I2C_PNX) += i2c-pnx.o obj-$(CONFIG_I2C_PXA) += i2c-pxa.o obj-$(CONFIG_I2C_PXA_PCI) += i2c-pxa-pci.o @@ -95,6 +103,8 @@ 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 obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o @@ -102,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 @@ -111,21 +121,25 @@ 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_XLR) += i2c-xlr.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 obj-$(CONFIG_I2C_ROBOTFUZZ_OSIF) += i2c-robotfuzz-osif.o obj-$(CONFIG_I2C_TAOS_EVM) += i2c-taos-evm.o obj-$(CONFIG_I2C_TINY_USB) += i2c-tiny-usb.o @@ -146,5 +160,6 @@ obj-$(CONFIG_I2C_SIBYTE) += i2c-sibyte.o obj-$(CONFIG_I2C_XGENE_SLIMPRO) += i2c-xgene-slimpro.o obj-$(CONFIG_SCx200_ACB) += scx200_acb.o obj-$(CONFIG_I2C_FSI) += i2c-fsi.o +obj-$(CONFIG_I2C_VIRTIO) += i2c-virtio.o ccflags-$(CONFIG_I2C_DEBUG_BUS) := -DDEBUG 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 354cf7e45c4a..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, }; @@ -447,7 +447,7 @@ static int altr_i2c_probe(struct platform_device *pdev) mutex_unlock(&idev->isr_mutex); i2c_set_adapdata(&idev->adapter, idev); - strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name)); + strscpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name)); idev->adapter.owner = THIS_MODULE; idev->adapter.algo = &altr_i2c_algo; idev->adapter.dev.parent = &pdev->dev; @@ -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 ce130a821ea5..60edbabc2986 100644 --- a/drivers/i2c/busses/i2c-amd-mp2-pci.c +++ b/drivers/i2c/busses/i2c-amd-mp2-pci.c @@ -288,7 +288,7 @@ static void amd_mp2_clear_reg(struct amd_mp2_dev *privdata) static int amd_mp2_pci_init(struct amd_mp2_dev *privdata, struct pci_dev *pci_dev) { - int rc; + int irq_flag = 0, rc; pci_set_drvdata(pci_dev, privdata); @@ -307,21 +307,28 @@ static int amd_mp2_pci_init(struct amd_mp2_dev *privdata, pci_set_master(pci_dev); - rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(64)); - if (rc) { - rc = pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)); - if (rc) - goto err_dma_mask; - } + rc = dma_set_mask(&pci_dev->dev, DMA_BIT_MASK(64)); + if (rc) + goto err_dma_mask; - /* Set up intx irq */ + /* request and enable interrupt */ writel(0, privdata->mmio + AMD_P2C_MSG_INTEN); - pci_intx(pci_dev, 1); - rc = devm_request_irq(&pci_dev->dev, pci_dev->irq, amd_mp2_irq_isr, - IRQF_SHARED, dev_name(&pci_dev->dev), privdata); - if (rc) - pci_err(pci_dev, "Failure requesting irq %i: %d\n", - pci_dev->irq, rc); + rc = pci_alloc_irq_vectors(pci_dev, 1, 1, PCI_IRQ_ALL_TYPES); + if (rc < 0) { + dev_err(&pci_dev->dev, "Failed to allocate single IRQ err=%d\n", rc); + goto err_dma_mask; + } + + privdata->dev_irq = pci_irq_vector(pci_dev, 0); + if (!pci_dev->msix_enabled && !pci_dev->msi_enabled) + irq_flag = IRQF_SHARED; + + rc = devm_request_irq(&pci_dev->dev, privdata->dev_irq, + 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 err_dma_mask; + } return rc; @@ -367,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); - pci_intx(pci_dev, 0); pci_clear_master(pci_dev); amd_mp2_clear_reg(privdata); @@ -452,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 de058671f9b8..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, }; @@ -244,15 +244,18 @@ static const struct i2c_adapter_quirks amd_i2c_dev_quirks = { static int i2c_amd_probe(struct platform_device *pdev) { + struct device *dev = &pdev->dev; int ret; struct amd_i2c_dev *i2c_dev; - acpi_handle handle = ACPI_HANDLE(&pdev->dev); - struct acpi_device *adev; struct amd_mp2_dev *mp2_dev; - const char *uid; + u64 uid; - if (acpi_bus_get_device(handle, &adev)) - return -ENODEV; + ret = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &uid); + if (ret) + return dev_err_probe(dev, ret, "missing UID/bus id!\n"); + if (uid >= 2) + return dev_err_probe(dev, -EINVAL, "incorrect UID/bus id \"%llu\"!\n", uid); + dev_dbg(dev, "bus id is %llu\n", uid); /* The ACPI namespace doesn't contain information about which MP2 PCI * device an AMDI0011 ACPI device is related to, so assume that there's @@ -267,6 +270,7 @@ static int i2c_amd_probe(struct platform_device *pdev) if (!i2c_dev) return -ENOMEM; + i2c_dev->common.bus_id = uid; i2c_dev->common.mp2_dev = mp2_dev; i2c_dev->pdev = pdev; platform_set_drvdata(pdev, i2c_dev); @@ -277,20 +281,6 @@ static int i2c_amd_probe(struct platform_device *pdev) i2c_dev->common.resume = &i2c_amd_resume; #endif - uid = adev->pnp.unique_id; - if (!uid) { - dev_err(&pdev->dev, "missing UID/bus id!\n"); - return -EINVAL; - } else if (strcmp(uid, "0") == 0) { - i2c_dev->common.bus_id = 0; - } else if (strcmp(uid, "1") == 0) { - i2c_dev->common.bus_id = 1; - } else { - dev_err(&pdev->dev, "incorrect UID/bus id \"%s\"!\n", uid); - return -EINVAL; - } - dev_dbg(&pdev->dev, "bus id is %u\n", i2c_dev->common.bus_id); - /* Register the adapter */ amd_mp2_pm_runtime_get(mp2_dev); @@ -332,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; @@ -346,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 ddecd0c88656..9b7e9494dd12 100644 --- a/drivers/i2c/busses/i2c-amd-mp2.h +++ b/drivers/i2c/busses/i2c-amd-mp2.h @@ -183,6 +183,7 @@ struct amd_mp2_dev { struct mutex c2p_lock; u8 c2p_lock_busid; unsigned int probed; + int dev_irq; }; /* PCIe communication driver */ @@ -206,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 67e8b97c0c95..a26b74c71206 100644 --- a/drivers/i2c/busses/i2c-aspeed.c +++ b/drivers/i2c/busses/i2c-aspeed.c @@ -16,8 +16,6 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> -#include <linux/irqchip/chained_irq.h> -#include <linux/irqdomain.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/of_address.h> @@ -172,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; @@ -189,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( @@ -246,22 +251,51 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) u32 command, irq_handled = 0; struct i2c_client *slave = bus->slave; u8 value; + int ret; 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); @@ -280,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)) @@ -313,14 +336,19 @@ static u32 aspeed_i2c_slave_irq(struct aspeed_i2c_bus *bus, u32 irq_status) break; case ASPEED_I2C_SLAVE_WRITE_REQUESTED: bus->slave_state = ASPEED_I2C_SLAVE_WRITE_RECEIVED; - i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); + ret = i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); + /* + * Slave ACK's on this address phase already but as the backend driver + * returns an errno, the bus driver should nack the next incoming byte. + */ + if (ret < 0) + writel(ASPEED_I2CD_M_S_RX_CMD_LAST, bus->base + ASPEED_I2C_CMD_REG); break; case ASPEED_I2C_SLAVE_WRITE_RECEIVED: 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. */; @@ -370,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) { @@ -424,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; @@ -693,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 @@ -741,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) @@ -757,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; @@ -788,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 */ }; @@ -965,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); @@ -974,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); @@ -1024,7 +1048,7 @@ static int aspeed_i2c_probe_bus(struct platform_device *pdev) bus->adap.algo = &aspeed_i2c_algo; bus->adap.dev.parent = &pdev->dev; bus->adap.dev.of_node = pdev->dev.of_node; - strlcpy(bus->adap.name, pdev->name, sizeof(bus->adap.name)); + strscpy(bus->adap.name, pdev->name, sizeof(bus->adap.name)); i2c_set_adapdata(&bus->adap, bus); bus->dev = &pdev->dev; @@ -1058,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; @@ -1074,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 e14edd236108..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,22 +264,17 @@ 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; } -#ifdef CONFIG_PM - -static int at91_twi_runtime_suspend(struct device *dev) +static int __maybe_unused at91_twi_runtime_suspend(struct device *dev) { struct at91_twi_dev *twi_dev = dev_get_drvdata(dev); @@ -299,7 +285,7 @@ static int at91_twi_runtime_suspend(struct device *dev) return 0; } -static int at91_twi_runtime_resume(struct device *dev) +static int __maybe_unused at91_twi_runtime_resume(struct device *dev) { struct at91_twi_dev *twi_dev = dev_get_drvdata(dev); @@ -308,7 +294,7 @@ static int at91_twi_runtime_resume(struct device *dev) return clk_prepare_enable(twi_dev->clk); } -static int at91_twi_suspend_noirq(struct device *dev) +static int __maybe_unused at91_twi_suspend_noirq(struct device *dev) { if (!pm_runtime_status_suspended(dev)) at91_twi_runtime_suspend(dev); @@ -316,7 +302,7 @@ static int at91_twi_suspend_noirq(struct device *dev) return 0; } -static int at91_twi_resume_noirq(struct device *dev) +static int __maybe_unused at91_twi_resume_noirq(struct device *dev) { struct at91_twi_dev *twi_dev = dev_get_drvdata(dev); int ret; @@ -327,7 +313,6 @@ static int 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); @@ -335,18 +320,13 @@ static int at91_twi_resume_noirq(struct device *dev) return 0; } -static const struct dev_pm_ops at91_twi_pm = { +static const struct dev_pm_ops __maybe_unused at91_twi_pm = { .suspend_noirq = at91_twi_suspend_noirq, .resume_noirq = at91_twi_resume_noirq, .runtime_suspend = at91_twi_runtime_suspend, .runtime_resume = at91_twi_runtime_resume, }; -#define at91_twi_pm_ops (&at91_twi_pm) -#else -#define at91_twi_pm_ops NULL -#endif - static struct platform_driver at91_twi_driver = { .probe = at91_twi_probe, .remove = at91_twi_remove, @@ -354,7 +334,7 @@ static struct platform_driver at91_twi_driver = { .driver = { .name = "at91_i2c", .of_match_table = of_match_ptr(atmel_twi_dt_ids), - .pm = at91_twi_pm_ops, + .pm = pm_ptr(&at91_twi_pm), }, }; diff --git a/drivers/i2c/busses/i2c-at91-master.c b/drivers/i2c/busses/i2c-at91-master.c index 1cceb6866689..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" @@ -138,9 +138,9 @@ static void at91_twi_dma_cleanup(struct at91_twi_dev *dev) if (dma->xfer_in_progress) { if (dma->direction == DMA_FROM_DEVICE) - dmaengine_terminate_all(dma->chan_rx); + dmaengine_terminate_sync(dma->chan_rx); else - dmaengine_terminate_all(dma->chan_tx); + dmaengine_terminate_sync(dma->chan_tx); dma->xfer_in_progress = false; } if (dma->buf_mapped) { @@ -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; @@ -656,6 +655,7 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) unsigned int_addr_flag = 0; struct i2c_msg *m_start = msg; bool is_read; + u8 *dma_buf = NULL; dev_dbg(&adap->dev, "at91_xfer: processing %d messages:\n", num); @@ -703,11 +703,20 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num) dev->msg = m_start; dev->recv_len_abort = false; + if (dev->use_dma) { + dma_buf = i2c_get_dma_safe_msg_buf(m_start, 1); + if (!dma_buf) { + ret = -ENOMEM; + goto out; + } + dev->buf = dma_buf; + } + ret = at91_do_twi_transfer(dev); + i2c_put_dma_safe_msg_buf(dma_buf, m_start, !ret); ret = (ret < 0) ? ret : num; out: - pm_runtime_mark_last_busy(dev->dev); pm_runtime_put_autosuspend(dev->dev); return ret; @@ -729,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) @@ -821,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 22aed922552b..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); @@ -321,7 +318,7 @@ i2c_au1550_probe(struct platform_device *pdev) priv->adap.algo = &au1550_algo; priv->adap.algo_data = priv; priv->adap.dev.parent = &pdev->dev; - strlcpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name)); + strscpy(priv->adap.name, "Au1xxx PSC I2C", sizeof(priv->adap.name)); /* Now, set up the PSC for SMBus PIO mode. */ i2c_au1550_setup(priv); @@ -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 5294b73beca8..0555eeb6903a 100644 --- a/drivers/i2c/busses/i2c-axxia.c +++ b/drivers/i2c/busses/i2c-axxia.c @@ -118,7 +118,7 @@ #define SDA_HOLD_TIME 0x90 /** - * axxia_i2c_dev - I2C device context + * struct axxia_i2c_dev - I2C device context * @base: pointer to register struct * @msg: pointer to current message * @msg_r: pointer to current read message (sequence transfer) @@ -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, @@ -783,7 +770,7 @@ static int axxia_i2c_probe(struct platform_device *pdev) } i2c_set_adapdata(&idev->adapter, idev); - strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name)); + strscpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name)); idev->adapter.owner = THIS_MODULE; idev->adapter.algo = &axxia_i2c_algo; idev->adapter.bus_recovery_info = &axxia_i2c_recovery_info; @@ -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 cceaf69279a9..e418a4f23f15 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include <linux/delay.h> #include <linux/i2c.h> @@ -17,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> @@ -234,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); } @@ -260,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; @@ -283,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)); @@ -323,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); +} - 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"); +static bool bcm_iproc_i2c_check_slave_status + (struct bcm_iproc_i2c_dev *iproc_i2c, u32 status) +{ + u32 val; + bool recover = false; + + /* 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) @@ -427,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) @@ -500,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); @@ -522,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; } @@ -532,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) { @@ -668,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; @@ -678,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)); @@ -696,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, @@ -726,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); @@ -801,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); @@ -827,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; @@ -836,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; } @@ -964,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; @@ -983,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, @@ -1004,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); @@ -1033,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); @@ -1049,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); @@ -1077,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) @@ -1090,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 { @@ -1106,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; @@ -1117,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); @@ -1133,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); @@ -1162,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); @@ -1189,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); - - /* 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); - - tasklet_kill(&iproc_i2c->slave_rx_tasklet); - - /* 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", @@ -1267,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 ed5e1275ae46..9d8838bbd938 100644 --- a/drivers/i2c/busses/i2c-bcm-kona.c +++ b/drivers/i2c/busses/i2c-bcm-kona.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2013 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2013 Broadcom Corporation #include <linux/device.h> #include <linux/kernel.h> @@ -95,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 */ @@ -481,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; @@ -496,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; } @@ -554,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; @@ -597,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) { @@ -647,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) { @@ -707,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, }; @@ -732,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; @@ -763,7 +752,7 @@ static int bcm_kona_i2c_probe(struct platform_device *pdev) /* Map hardware registers */ dev->base = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(dev->base)) - return -ENOMEM; + return PTR_ERR(dev->base); /* Get and enable external clock */ dev->external_clk = devm_clk_get(dev->device, NULL); @@ -849,7 +838,7 @@ static int bcm_kona_i2c_probe(struct platform_device *pdev) adap = &dev->adapter; i2c_set_adapdata(adap, dev); adap->owner = THIS_MODULE; - strlcpy(adap->name, "Broadcom I2C adapter", sizeof(adap->name)); + strscpy(adap->name, "Broadcom I2C adapter", sizeof(adap->name)); adap->algo = &bcm_algo; adap->dev.parent = &pdev->dev; adap->dev.of_node = pdev->dev.of_node; @@ -869,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 37443edbf754..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> @@ -23,6 +23,11 @@ #define BCM2835_I2C_FIFO 0x10 #define BCM2835_I2C_DIV 0x14 #define BCM2835_I2C_DEL 0x18 +/* + * 16-bit field for the number of SCL cycles to wait after rising SCL + * before deciding the target is not responding. 0 disables the + * timeout detection. + */ #define BCM2835_I2C_CLKT 0x1c #define BCM2835_I2C_C_READ BIT(0) @@ -132,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); + + req->rate = DIV_ROUND_UP(req->best_parent_rate, divider); - return DIV_ROUND_UP(*parent_rate, divider); + return 0; } static unsigned long clk_bcm2835_i2c_recalc_rate(struct clk_hw *hw, @@ -151,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, }; @@ -218,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 @@ -365,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; } @@ -386,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, }; /* @@ -402,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, *irq; int ret; struct i2c_adapter *adap; struct clk *mclk; @@ -415,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); @@ -427,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); @@ -441,29 +444,27 @@ 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) { dev_err(&pdev->dev, "Couldn't prepare clock"); - return ret; + goto err_put_exclusive_rate; } - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (!irq) { - dev_err(&pdev->dev, "No IRQ resource\n"); - return -ENODEV; + i2c_dev->irq = platform_get_irq(pdev, 0); + if (i2c_dev->irq < 0) { + ret = i2c_dev->irq; + goto err_disable_unprepare_clk; } - i2c_dev->irq = irq->start; ret = request_irq(i2c_dev->irq, bcm2835_i2c_isr, IRQF_SHARED, dev_name(&pdev->dev), i2c_dev); if (ret) { dev_err(&pdev->dev, "Could not request IRQ\n"); - return -ENODEV; + goto err_disable_unprepare_clk; } adap = &i2c_dev->adapter; @@ -477,16 +478,31 @@ static int bcm2835_i2c_probe(struct platform_device *pdev) adap->dev.of_node = pdev->dev.of_node; adap->quirks = of_device_get_match_data(&pdev->dev); + /* + * Disable the hardware clock stretching timeout. SMBUS + * specifies a limit for how long the device can stretch the + * clock, but core I2C doesn't. + */ + bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_CLKT, 0); bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, 0); ret = i2c_add_adapter(adap); if (ret) - free_irq(i2c_dev->irq, i2c_dev); + goto err_free_irq; + + return 0; + +err_free_irq: + free_irq(i2c_dev->irq, i2c_dev); +err_disable_unprepare_clk: + clk_disable_unprepare(i2c_dev->bus_clk); +err_put_exclusive_rate: + clk_rate_exclusive_put(i2c_dev->bus_clk); 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); @@ -495,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 490ee3962645..5fa30e8926c5 100644 --- a/drivers/i2c/busses/i2c-brcmstb.c +++ b/drivers/i2c/busses/i2c-brcmstb.c @@ -1,15 +1,5 @@ -/* - * Copyright (C) 2014 Broadcom Corporation - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ +// SPDX-License-Identifier: GPL-2.0-only +// Copyright (C) 2014 Broadcom Corporation #include <linux/clk.h> #include <linux/delay.h> @@ -77,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 */ @@ -170,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 */ @@ -250,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 { @@ -297,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 */ @@ -329,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) @@ -423,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); @@ -450,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) { @@ -482,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) { @@ -530,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 @@ -537,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, }; @@ -585,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); @@ -606,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); @@ -626,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", @@ -673,7 +674,7 @@ static int brcmstb_i2c_probe(struct platform_device *pdev) /* set the data in/out register size for compatible SoCs */ if (of_device_is_compatible(dev->device->of_node, - "brcmstb,brcmper-i2c")) + "brcm,brcmper-i2c")) dev->data_regsz = sizeof(u8); else dev->data_regsz = sizeof(u32); @@ -684,35 +685,28 @@ static int brcmstb_i2c_probe(struct platform_device *pdev) adap = &dev->adapter; i2c_set_adapdata(adap, dev); adap->owner = THIS_MODULE; - strlcpy(adap->name, "Broadcom STB : ", sizeof(adap->name)); - if (int_name) - strlcat(adap->name, int_name, sizeof(adap->name)); + strscpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); adap->algo = &brcmstb_i2c_algo; adap->dev.parent = &pdev->dev; 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); @@ -730,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"}, @@ -747,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 20aa3398e642..0fb728ade92e 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -10,10 +10,13 @@ #include <linux/i2c.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/module.h> #include <linux/platform_device.h> #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 */ @@ -112,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" @@ -127,6 +128,9 @@ #define CDNS_I2C_TIMEOUT_MAX 0xFF #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) #define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset) @@ -171,17 +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; @@ -195,19 +205,25 @@ 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; #if IS_ENABLED(CONFIG_I2C_SLAVE) u16 ctrl_reg_diva_divb; struct i2c_client *slave; 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 { @@ -218,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 * @@ -233,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) @@ -386,9 +462,9 @@ static irqreturn_t cdns_i2c_slave_isr(void *ptr) */ static irqreturn_t cdns_i2c_master_isr(void *ptr) { - unsigned int isr_status, avail_bytes, updatetx; + unsigned int isr_status, avail_bytes; unsigned int bytes_to_send; - bool hold_quirk; + bool updatetx; struct cdns_i2c *id = ptr; /* Signal completion only after everything is updated */ int done_flag = 0; @@ -408,11 +484,7 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr) * Check if transfer size register needs to be updated again for a * large data receive operation. */ - updatetx = 0; - if (id->recv_count > id->curr_recv_count) - updatetx = 1; - - hold_quirk = (id->quirks & CDNS_I2C_BROKEN_HOLD_BIT) && updatetx; + updatetx = id->recv_count > id->curr_recv_count; /* When receiving, handle data interrupt and completion interrupt */ if (id->p_recv_buf && @@ -432,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); @@ -443,7 +515,7 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr) break; } - if (cdns_is_holdquirk(id, hold_quirk)) + if (cdns_is_holdquirk(id, updatetx)) break; } @@ -454,44 +526,28 @@ static irqreturn_t cdns_i2c_master_isr(void *ptr) * maintain transfer size non-zero while performing a large * receive operation. */ - if (cdns_is_holdquirk(id, hold_quirk)) { + 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; } - } else if (id->recv_count && !hold_quirk && - !id->curr_recv_count) { - - /* Set the slave address in address register*/ - cdns_i2c_writereg(id->p_msg->addr & CDNS_I2C_ADDR_MASK, - CDNS_I2C_ADDR_OFFSET); - - if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) { - cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE, - CDNS_I2C_XFER_SIZE_OFFSET); - id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE; - } else { - cdns_i2c_writereg(id->recv_count, - CDNS_I2C_XFER_SIZE_OFFSET); - id->curr_recv_count = id->recv_count; - } } /* Clear hold (if not repeated start) and signal completion */ @@ -511,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; @@ -570,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 @@ -591,8 +730,13 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id) ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); ctrl_reg |= CDNS_I2C_CR_RW | CDNS_I2C_CR_CLR_FIFO; + /* + * Receive up to I2C_SMBUS_BLOCK_MAX data bytes, plus one message length + * byte, plus one checksum byte if PEC is enabled. p_msg->len will be 2 if + * PEC is enabled, otherwise 1. + */ if (id->p_msg->flags & I2C_M_RECV_LEN) - id->recv_count = I2C_SMBUS_BLOCK_MAX + 1; + id->recv_count = I2C_SMBUS_BLOCK_MAX + id->p_msg->len; id->curr_recv_count = id->recv_count; @@ -600,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); @@ -615,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; @@ -638,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 @@ -660,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); } /** @@ -687,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); @@ -700,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) @@ -723,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); } /** @@ -758,12 +931,13 @@ static void cdns_i2c_master_reset(struct i2c_adapter *adap) static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, struct i2c_adapter *adap) { - unsigned long time_left; + unsigned long time_left, msg_timeout; u32 reg; 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); @@ -783,12 +957,35 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, else cdns_i2c_msend(id); - /* Wait for the signal of completion */ - time_left = wait_for_completion_timeout(&id->xfer_done, adap->timeout); + /* Minimal time to execute this message */ + msg_timeout = msecs_to_jiffies((1000 * msg->len * BITS_PER_BYTE) / id->i2c_clk); + + /* + * 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; + + 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; } @@ -799,52 +996,37 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg, if (id->err_status & CDNS_I2C_IXR_ARB_LOST) return -EAGAIN; + if (msg->flags & I2C_M_RECV_LEN) + msg->len += min_t(unsigned int, msg->buf[0], I2C_SMBUS_BLOCK_MAX); + 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 */ - if (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) & CDNS_I2C_SR_BA) { + 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; - goto out; + if (id->adap.bus_recovery_info) + i2c_recover_bus(adap); + return ret; } hold_quirk = !!(id->quirks & CDNS_I2C_BROKEN_HOLD_BIT); @@ -864,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; @@ -883,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 * @@ -976,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 }; @@ -1026,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; @@ -1071,10 +1325,11 @@ static int cdns_i2c_setclk(unsigned long clk_in, struct cdns_i2c *id) if (ret) return ret; - ctrl_reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET); + ctrl_reg = id->ctrl_reg; ctrl_reg &= ~(CDNS_I2C_CR_DIVA_MASK | CDNS_I2C_CR_DIVB_MASK); ctrl_reg |= ((div_a << CDNS_I2C_CR_DIVA_SHIFT) | (div_b << CDNS_I2C_CR_DIVB_SHIFT)); + id->ctrl_reg = ctrl_reg; cdns_i2c_writereg(ctrl_reg, CDNS_I2C_CR_OFFSET); #if IS_ENABLED(CONFIG_I2C_SLAVE) id->ctrl_reg_diva_divb = ctrl_reg & (CDNS_I2C_CR_DIVA_MASK | @@ -1145,46 +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_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; } + 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) }; @@ -1201,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 * @@ -1214,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); @@ -1230,14 +1510,24 @@ static int cdns_i2c_probe(struct platform_device *pdev) id->quirks = data->quirks; } + id->rinfo.pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(id->rinfo.pinctrl)) { + int err = PTR_ERR(id->rinfo.pinctrl); + + dev_info(&pdev->dev, "can't get pinctrl, bus recovery not supported\n"); + if (err != -ENODEV) + return err; + } else { + id->adap.bus_recovery_info = &id->rinfo; + } + id->membase = devm_platform_get_and_ioremap_resource(pdev, 0, &r_mem); 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; @@ -1250,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); @@ -1279,44 +1575,42 @@ static int cdns_i2c_probe(struct platform_device *pdev) id->dev_mode = CDNS_I2C_MODE_MASTER; id->slave_state = CDNS_I2C_SLAVE_STATE_IDLE; #endif - cdns_i2c_writereg(CDNS_I2C_CR_MASTER_EN_MASK, CDNS_I2C_CR_OFFSET); + 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; } - - /* - * 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_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: - clk_disable_unprepare(id->clk); +err_clk_notifier_unregister: + clk_notifier_unregister(id->clk, &id->clk_rate_change_nb); pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); + reset_control_assert(id->reset); return ret; } @@ -1328,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); @@ -1338,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 72df563477b1..8065c7e4462e 100644 --- a/drivers/i2c/busses/i2c-cbus-gpio.c +++ b/drivers/i2c/busses/i2c-cbus-gpio.c @@ -195,17 +195,16 @@ static u32 cbus_i2c_func(struct i2c_adapter *adapter) } static const struct i2c_algorithm cbus_i2c_algo = { - .smbus_xfer = cbus_i2c_smbus_xfer, - .functionality = cbus_i2c_func, + .smbus_xfer = cbus_i2c_smbus_xfer, + .smbus_xfer_atomic = cbus_i2c_smbus_xfer, + .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) @@ -244,7 +243,7 @@ static int cbus_i2c_probe(struct platform_device *pdev) adapter->nr = pdev->id; adapter->timeout = HZ; adapter->algo = &cbus_i2c_algo; - strlcpy(adapter->name, "CBUS I2C adapter", sizeof(adapter->name)); + strscpy(adapter->name, "CBUS I2C adapter", sizeof(adapter->name)); spin_lock_init(&chost->lock); chost->dev = &pdev->dev; @@ -265,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 new file mode 100644 index 000000000000..d97233862a6c --- /dev/null +++ b/drivers/i2c/busses/i2c-ccgx-ucsi.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Instantiate UCSI device for Cypress CCGx Type-C controller. + * Derived from i2c-designware-pcidrv.c and i2c-nvidia-gpu.c. + */ + +#include <linux/i2c.h> +#include <linux/export.h> +#include <linux/module.h> +#include <linux/string.h> + +#include "i2c-ccgx-ucsi.h" + +struct software_node; + +struct i2c_client *i2c_new_ccgx_ucsi(struct i2c_adapter *adapter, int irq, + const struct software_node *swnode) +{ + struct i2c_board_info info = {}; + + strscpy(info.type, "ccgx-ucsi", sizeof(info.type)); + info.addr = 0x08; + info.irq = irq; + info.swnode = swnode; + + return i2c_new_client_device(adapter, &info); +} +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-ccgx-ucsi.h b/drivers/i2c/busses/i2c-ccgx-ucsi.h new file mode 100644 index 000000000000..739ac7a4b117 --- /dev/null +++ b/drivers/i2c/busses/i2c-ccgx-ucsi.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef __I2C_CCGX_UCSI_H_ +#define __I2C_CCGX_UCSI_H_ + +struct i2c_adapter; +struct i2c_client; +struct software_node; + +struct i2c_client *i2c_new_ccgx_ucsi(struct i2c_adapter *adapter, int irq, + const struct software_node *swnode); +#endif /* __I2C_CCGX_UCSI_H_ */ 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 1cf68f85b2e1..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: @@ -18,6 +18,7 @@ #include <linux/module.h> #include <linux/platform_device.h> #include <linux/power/bq24190_charger.h> +#include <linux/power/bq25890_charger.h> #include <linux/slab.h> #define CHT_WC_I2C_CTRL 0x5e24 @@ -99,20 +100,13 @@ static irqreturn_t cht_wc_i2c_adap_thread_handler(int id, void *data) * interrupt handler as well, so running the client irq handler from * this thread will cause things to lock up. */ - if (reg & CHT_WC_EXTCHGRIRQ_CLIENT_IRQ) { - /* - * generic_handle_irq expects local IRQs to be disabled - * as normally it is called from interrupt context. - */ - local_irq_disable(); - generic_handle_irq(adap->client_irq); - local_irq_enable(); - } + if (reg & CHT_WC_EXTCHGRIRQ_CLIENT_IRQ) + generic_handle_irq_safe(adap->client_irq); 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; @@ -174,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, }; @@ -270,6 +264,7 @@ static const struct irq_chip cht_wc_i2c_irq_chip = { .name = "cht_wc_ext_chrg_irq_chip", }; +/********** GPD Win / Pocket charger IC settings **********/ static const char * const bq24190_suppliers[] = { "tcpm-source-psy-i2c-fusb302" }; @@ -304,17 +299,135 @@ static struct bq24190_platform_data bq24190_pdata = { .regulator_init_data = &bq24190_vbus_init_data, }; +static struct i2c_board_info gpd_win_board_info = { + .type = "bq24190", + .addr = 0x6b, + .dev_name = "bq24190", + .swnode = &bq24190_node, + .platform_data = &bq24190_pdata, +}; + +/********** Xiaomi Mi Pad 2 charger IC settings **********/ +static struct regulator_consumer_supply bq2589x_vbus_consumer = { + .supply = "vbus", + .dev_name = "cht_wcove_pwrsrc", +}; + +static const struct regulator_init_data bq2589x_vbus_init_data = { + .constraints = { + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + }, + .consumer_supplies = &bq2589x_vbus_consumer, + .num_consumer_supplies = 1, +}; + +static struct bq25890_platform_data bq2589x_pdata = { + .regulator_init_data = &bq2589x_vbus_init_data, +}; + +static const struct property_entry xiaomi_mipad2_props[] = { + PROPERTY_ENTRY_BOOL("linux,skip-reset"), + PROPERTY_ENTRY_BOOL("linux,read-back-settings"), + { } +}; + +static const struct software_node xiaomi_mipad2_node = { + .properties = xiaomi_mipad2_props, +}; + +static struct i2c_board_info xiaomi_mipad2_board_info = { + .type = "bq25890", + .addr = 0x6a, + .dev_name = "bq25890", + .swnode = &xiaomi_mipad2_node, + .platform_data = &bq2589x_pdata, +}; + +/********** Lenovo Yogabook YB1-X90F/-X91F/-X91L charger settings **********/ +static const char * const lenovo_yb1_bq25892_suppliers[] = { "cht_wcove_pwrsrc" }; + +static const struct property_entry lenovo_yb1_bq25892_props[] = { + PROPERTY_ENTRY_STRING_ARRAY("supplied-from", + lenovo_yb1_bq25892_suppliers), + PROPERTY_ENTRY_U32("linux,pump-express-vbus-max", 12000000), + PROPERTY_ENTRY_BOOL("linux,skip-reset"), + /* + * The firmware sets everything to the defaults, which leads to a + * somewhat low charge-current of 2048mA and worse to a battery-voltage + * of 4.2V instead of 4.35V (when booted without a charger connected). + * Use our own values instead of "linux,read-back-settings" to fix this. + */ + PROPERTY_ENTRY_U32("ti,charge-current", 4224000), + PROPERTY_ENTRY_U32("ti,battery-regulation-voltage", 4352000), + PROPERTY_ENTRY_U32("ti,termination-current", 256000), + PROPERTY_ENTRY_U32("ti,precharge-current", 128000), + PROPERTY_ENTRY_U32("ti,minimum-sys-voltage", 3500000), + PROPERTY_ENTRY_U32("ti,boost-voltage", 4998000), + PROPERTY_ENTRY_U32("ti,boost-max-current", 1400000), + PROPERTY_ENTRY_BOOL("ti,use-ilim-pin"), + { } +}; + +static const struct software_node lenovo_yb1_bq25892_node = { + .properties = lenovo_yb1_bq25892_props, +}; + +static struct i2c_board_info lenovo_yogabook1_board_info = { + .type = "bq25892", + .addr = 0x6b, + .dev_name = "bq25892", + .swnode = &lenovo_yb1_bq25892_node, + .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); + struct i2c_board_info *board_info = NULL; struct cht_wc_i2c_adap *adap; - struct i2c_board_info board_info = { - .type = "bq24190", - .addr = 0x6b, - .dev_name = "bq24190", - .swnode = &bq24190_node, - .platform_data = &bq24190_pdata, - }; int ret, reg, irq; irq = platform_get_irq(pdev, 0); @@ -334,7 +447,7 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) adap->adapter.class = I2C_CLASS_HWMON; adap->adapter.algo = &cht_wc_i2c_adap_algo; adap->adapter.lock_ops = &cht_wc_i2c_adap_lock_ops; - strlcpy(adap->adapter.name, "PMIC I2C Adapter", + strscpy(adap->adapter.name, "PMIC I2C Adapter", sizeof(adap->adapter.name)); adap->adapter.dev.parent = &pdev->dev; @@ -354,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; @@ -379,17 +492,27 @@ static int cht_wc_i2c_adap_i2c_probe(struct platform_device *pdev) if (ret) goto remove_irq_domain; - /* - * Normally the Whiskey Cove PMIC is paired with a TI bq24292i charger, - * connected to this i2c bus, and a max17047 fuel-gauge and a fusb302 - * USB Type-C controller connected to another i2c bus. In this setup - * the max17047 and fusb302 devices are enumerated through an INT33FE - * ACPI device. If this device is present register an i2c-client for - * the TI bq24292i charger. - */ - if (acpi_dev_present("INT33FE", NULL, -1)) { - board_info.irq = adap->client_irq; - adap->client = i2c_new_client_device(&adap->adapter, &board_info); + switch (pmic->cht_wc_model) { + case INTEL_CHT_WC_GPD_WIN_POCKET: + board_info = &gpd_win_board_info; + break; + case INTEL_CHT_WC_XIAOMI_MIPAD2: + board_info = &xiaomi_mipad2_board_info; + break; + 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; + } + + if (board_info) { + board_info->irq = adap->client_irq; + adap->client = i2c_new_client_device(&adap->adapter, board_info); if (IS_ERR(adap->client)) { ret = PTR_ERR(adap->client); goto del_adapter; @@ -406,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[] = { @@ -433,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 790ea3fda693..208ce4f9e782 100644 --- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c +++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c @@ -107,7 +107,7 @@ static int ec_i2c_construct_message(u8 *buf, const struct i2c_msg i2c_msgs[], /** * ec_i2c_count_response - Count bytes needed for ec_i2c_parse_response * - * @i2c_msgs: The i2c messages to to fill up. + * @i2c_msgs: The i2c messages to fill up. * @num: The number of i2c messages expected. * * Returns the number of response bytes expeced. @@ -131,7 +131,7 @@ static int ec_i2c_count_response(struct i2c_msg i2c_msgs[], int num) * We'll take the EC's response and copy it back into msgs. * * @buf: The buffer to parse. - * @i2c_msgs: The i2c messages to to fill up. + * @i2c_msgs: The i2c messages to fill up. * @num: The number of i2c messages; will be modified to include the actual * number received. * @@ -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; @@ -267,7 +270,7 @@ static int ec_i2c_probe(struct platform_device *pdev) bus->dev = dev; bus->adap.owner = THIS_MODULE; - strlcpy(bus->adap.name, "cros-ec-i2c-tunnel", sizeof(bus->adap.name)); + strscpy(bus->adap.name, "cros-ec-i2c-tunnel", sizeof(bus->adap.name)); bus->adap.algo = &ec_i2c_algorithm; bus->adap.algo_data = bus; bus->adap.dev.parent = &pdev->dev; @@ -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 e9d07323c604..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; @@ -539,10 +520,9 @@ i2c_davinci_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev_dbg(dev->dev, "%s: msgs: %d\n", __func__, num); - ret = pm_runtime_get_sync(dev->dev); + ret = pm_runtime_resume_and_get(dev->dev); if (ret < 0) { dev_err(dev->dev, "Failed to runtime_get device: %d\n", ret); - pm_runtime_put_noidle(dev->dev); return ret; } @@ -563,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; @@ -571,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) @@ -689,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: @@ -746,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[] = { @@ -761,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)) @@ -821,11 +781,10 @@ static int davinci_i2c_probe(struct platform_device *pdev) pm_runtime_enable(dev->dev); - r = pm_runtime_get_sync(dev->dev); + r = pm_runtime_resume_and_get(dev->dev); if (r < 0) { dev_err(dev->dev, "failed to runtime_get device: %d\n", r); - pm_runtime_put_noidle(dev->dev); - return r; + goto err_pm; } i2c_davinci_init(dev); @@ -847,36 +806,20 @@ static int davinci_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(adap, dev); adap->owner = THIS_MODULE; adap->class = I2C_CLASS_DEPRECATED; - strlcpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name)); + strscpy(adap->name, "DaVinci I2C adapter", sizeof(adap->name)); 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; @@ -884,12 +827,13 @@ static int davinci_i2c_probe(struct platform_device *pdev) err_unuse_clocks: pm_runtime_dont_use_autosuspend(dev->dev); pm_runtime_put_sync(dev->dev); +err_pm: pm_runtime_disable(dev->dev); 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; @@ -899,21 +843,16 @@ static int davinci_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&dev->adapter); ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) { - pm_runtime_put_noidle(&pdev->dev); - return ret; - } - - davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, 0); + if (ret < 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); @@ -937,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 new file mode 100644 index 000000000000..404571ad61a8 --- /dev/null +++ b/drivers/i2c/busses/i2c-designware-amdpsp.c @@ -0,0 +1,310 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include <linux/i2c.h> +#include <linux/pci.h> +#include <linux/psp-platform-access.h> +#include <linux/psp.h> +#include <linux/workqueue.h> + +#include "i2c-designware-core.h" + +#define PSP_I2C_RESERVATION_TIME_MS 100 + +#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 + +enum psp_i2c_req_type { + PSP_I2C_REQ_ACQUIRE, + PSP_I2C_REQ_RELEASE, + PSP_I2C_REQ_MAX +}; + +struct psp_i2c_req { + struct psp_req_buffer_hdr hdr; + enum psp_i2c_req_type type; +}; + +static DEFINE_MUTEX(psp_i2c_access_mutex); +static unsigned long psp_i2c_sem_acquired; +static u32 psp_i2c_access_count; +static bool psp_i2c_mbox_fail; +static struct device *psp_i2c_dev; + +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) +{ + u32 status; + + /* Status field in command-response buffer is updated by PSP */ + status = READ_ONCE(req->hdr.status); + + switch (status) { + case PSP_I2C_REQ_STS_OK: + return 0; + case PSP_I2C_REQ_STS_BUS_BUSY: + return -EBUSY; + case PSP_I2C_REQ_STS_INV_PARAM: + default: + return -EIO; + } +} + +/* + * 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) +{ + int ret; + + 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) +{ + struct psp_i2c_req *req; + unsigned long start; + int status, ret; + + /* Allocate command-response buffer */ + req = kzalloc(sizeof(*req), GFP_KERNEL); + if (!req) + return -ENOMEM; + + req->hdr.payload_size = sizeof(*req); + req->type = i2c_req_type; + + start = jiffies; + 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, + 0, req); + if (ret) { + dev_err(psp_i2c_dev, "Timed out waiting for PSP to %s I2C bus\n", + (i2c_req_type == PSP_I2C_REQ_ACQUIRE) ? + "release" : "acquire"); + goto cleanup; + } + + ret = status; + if (ret) { + dev_err(psp_i2c_dev, "PSP communication error\n"); + goto cleanup; + } + + dev_dbg(psp_i2c_dev, "Request accepted by PSP after %ums\n", + jiffies_to_msecs(jiffies - start)); + +cleanup: + if (ret) { + dev_err(psp_i2c_dev, "Assume i2c bus is for exclusive host usage\n"); + psp_i2c_mbox_fail = true; + } + + kfree(req); + return ret; +} + +static void release_bus(void) +{ + int status; + + if (!psp_i2c_sem_acquired) + return; + + status = psp_send_i2c_req(PSP_I2C_REQ_RELEASE); + if (status) + return; + + dev_dbg(psp_i2c_dev, "PSP semaphore held for %ums\n", + jiffies_to_msecs(jiffies - psp_i2c_sem_acquired)); + + psp_i2c_sem_acquired = 0; +} + +static void psp_release_i2c_bus_deferred(struct work_struct *work) +{ + 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. + */ + if (psp_i2c_access_count) + return; + + release_bus(); +} +static DECLARE_DELAYED_WORK(release_queue, psp_release_i2c_bus_deferred); + +static int psp_acquire_i2c_bus(void) +{ + int status; + + guard(mutex)(&psp_i2c_access_mutex); + + /* Return early if mailbox malfunctioned */ + if (psp_i2c_mbox_fail) + return 0; + + psp_i2c_access_count++; + + /* + * No need to request bus arbitration once we are inside semaphore + * reservation period. + */ + if (psp_i2c_sem_acquired) + return 0; + + status = psp_send_i2c_req(PSP_I2C_REQ_ACQUIRE); + if (status) + return 0; + + psp_i2c_sem_acquired = jiffies; + + schedule_delayed_work(&release_queue, + msecs_to_jiffies(PSP_I2C_RESERVATION_TIME_MS)); + + /* + * In case of errors with PSP arbitrator psp_i2c_mbox_fail variable is + * set above. As a consequence consecutive calls to acquire will bypass + * communication with PSP. At any case i2c bus is granted to the caller, + * thus always return success. + */ + return 0; +} + +static void psp_release_i2c_bus(void) +{ + guard(mutex)(&psp_i2c_access_mutex); + + /* Return early if mailbox was malfunctioned */ + if (psp_i2c_mbox_fail) + return; + + /* + * If we are last owner of PSP semaphore, need to release arbitration + * via mailbox. + */ + psp_i2c_access_count--; + if (psp_i2c_access_count) + return; + + /* + * Send a release command to PSP if the semaphore reservation timeout + * elapsed but x86 still owns the controller. + */ + if (!delayed_work_pending(&release_queue)) + release_bus(); +} + +/* + * Locking methods are based on the default implementation from + * 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 + * operations - that is e.g. write-wait-read. + */ +static void i2c_adapter_dw_psp_lock_bus(struct i2c_adapter *adapter, + unsigned int flags) +{ + psp_acquire_i2c_bus(); + rt_mutex_lock_nested(&adapter->bus_lock, i2c_adapter_depth(adapter)); +} + +static int i2c_adapter_dw_psp_trylock_bus(struct i2c_adapter *adapter, + unsigned int flags) +{ + int ret; + + ret = rt_mutex_trylock(&adapter->bus_lock); + if (ret) + return ret; + + psp_acquire_i2c_bus(); + + return ret; +} + +static void i2c_adapter_dw_psp_unlock_bus(struct i2c_adapter *adapter, + unsigned int flags) +{ + psp_release_i2c_bus(); + rt_mutex_unlock(&adapter->bus_lock); +} + +static const struct i2c_lock_operations i2c_dw_psp_lock_ops = { + .lock_bus = i2c_adapter_dw_psp_lock_bus, + .trylock_bus = i2c_adapter_dw_psp_trylock_bus, + .unlock_bus = i2c_adapter_dw_psp_unlock_bus, +}; + +int i2c_dw_amdpsp_probe_lock_support(struct dw_i2c_dev *dev) +{ + struct pci_dev *rdev; + + if (!IS_REACHABLE(CONFIG_CRYPTO_DEV_CCP_DD)) + return -ENODEV; + + if (!dev) + return -ENODEV; + + if (!(dev->flags & ARBITRATION_SEMAPHORE)) + return -ENODEV; + + /* Allow to bind only one instance of a driver */ + if (psp_i2c_dev) + return -EEXIST; + + /* 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); + + 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"); + + /* + * Install global locking callbacks for adapter as well as internal i2c + * controller locks. + */ + dev->adapter.lock_ops = &i2c_dw_psp_lock_ops; + dev->acquire_lock = psp_acquire_i2c_bus; + dev->release_lock = psp_release_i2c_bus; + + return 0; +} diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c index c6a7a00e1d52..45774aa47c28 100644 --- a/drivers/i2c/busses/i2c-designware-baytrail.c +++ b/drivers/i2c/busses/i2c-designware-baytrail.c @@ -12,25 +12,25 @@ #include "i2c-designware-core.h" -int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) +int i2c_dw_baytrail_probe_lock_support(struct dw_i2c_dev *dev) { acpi_status status; unsigned long long shared_host = 0; acpi_handle handle; - if (!dev || !dev->dev) - return 0; + if (!dev) + return -ENODEV; handle = ACPI_HANDLE(dev->dev); if (!handle) - return 0; + return -ENODEV; status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host); if (ACPI_FAILURE(status)) - return 0; + return -ENODEV; if (!shared_host) - return 0; + return -ENODEV; if (!iosf_mbi_available()) return -EPROBE_DEFER; diff --git a/drivers/i2c/busses/i2c-designware-common.c b/drivers/i2c/busses/i2c-designware-common.c index fdc34d9e3702..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,14 +23,18 @@ #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> +#include <linux/units.h> #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] = @@ -62,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; } @@ -71,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; } @@ -80,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; } @@ -89,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; } @@ -98,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; } @@ -108,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; } @@ -121,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) { @@ -168,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); @@ -187,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; @@ -207,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 @@ -254,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; @@ -265,9 +311,9 @@ int i2c_dw_acpi_configure(struct device *device) * selected speed modes. */ i2c_dw_acpi_params(device, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, &ss_ht); + i2c_dw_acpi_params(device, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, &fs_ht); i2c_dw_acpi_params(device, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt, &fp_ht); i2c_dw_acpi_params(device, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, &hs_ht); - i2c_dw_acpi_params(device, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, &fs_ht); switch (t->bus_freq_hz) { case I2C_MAX_STANDARD_MODE_FREQ: @@ -284,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) { @@ -296,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++) { @@ -309,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; @@ -329,49 +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 (ic_clk * tSYMBOL + 500000) / 1000000 - 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 (ic_clk * (tSYMBOL + tf) + 500000) / 1000000 - - 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: * @@ -383,12 +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 ((ic_clk * (tLOW + tf) + 500000) / 1000000) - 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); @@ -438,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); @@ -453,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); @@ -462,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); } @@ -477,9 +583,6 @@ int i2c_dw_prepare_clk(struct dw_i2c_dev *dev, bool prepare) { int ret; - if (IS_ERR(dev->clk)) - return PTR_ERR(dev->clk); - if (prepare) { /* Optional interface clock */ ret = clk_prepare_enable(dev->pclk); @@ -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,22 +666,36 @@ 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. */ + ret = i2c_dw_acquire_lock(dev); + if (ret) + return ret; + ret = regmap_read(dev->map, DW_IC_COMP_PARAM_1, ¶m); + i2c_dw_release_lock(dev); if (ret) return ret; @@ -606,20 +723,100 @@ 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); + if (ret) + return; /* Disable controller */ __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; } -void i2c_dw_disable_int(struct dw_i2c_dev *dev) +static int i2c_dw_resume(struct device *device) { - regmap_write(dev->map, DW_IC_INTR_MASK, 0); + 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 6a53f75abf7c..bb5ce0a382f9 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -10,20 +10,19 @@ */ #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> -#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \ - I2C_FUNC_SMBUS_BYTE | \ - I2C_FUNC_SMBUS_BYTE_DATA | \ - I2C_FUNC_SMBUS_WORD_DATA | \ - I2C_FUNC_SMBUS_BLOCK_DATA | \ - I2C_FUNC_SMBUS_I2C_BLOCK) +#define DW_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \ + I2C_FUNC_SMBUS_BYTE | \ + I2C_FUNC_SMBUS_BYTE_DATA | \ + I2C_FUNC_SMBUS_WORD_DATA | \ + I2C_FUNC_SMBUS_BLOCK_DATA | \ + I2C_FUNC_SMBUS_I2C_BLOCK) #define DW_IC_CON_MASTER BIT(0) #define DW_IC_CON_SPEED_STD (1 << 1) @@ -37,124 +36,133 @@ #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 */ -#define DW_IC_CON 0x00 -#define DW_IC_TAR 0x04 -#define DW_IC_SAR 0x08 -#define DW_IC_DATA_CMD 0x10 -#define DW_IC_SS_SCL_HCNT 0x14 -#define DW_IC_SS_SCL_LCNT 0x18 -#define DW_IC_FS_SCL_HCNT 0x1c -#define DW_IC_FS_SCL_LCNT 0x20 -#define DW_IC_HS_SCL_HCNT 0x24 -#define DW_IC_HS_SCL_LCNT 0x28 -#define DW_IC_INTR_STAT 0x2c -#define DW_IC_INTR_MASK 0x30 -#define DW_IC_RAW_INTR_STAT 0x34 -#define DW_IC_RX_TL 0x38 -#define DW_IC_TX_TL 0x3c -#define DW_IC_CLR_INTR 0x40 -#define DW_IC_CLR_RX_UNDER 0x44 -#define DW_IC_CLR_RX_OVER 0x48 -#define DW_IC_CLR_TX_OVER 0x4c -#define DW_IC_CLR_RD_REQ 0x50 -#define DW_IC_CLR_TX_ABRT 0x54 -#define DW_IC_CLR_RX_DONE 0x58 -#define DW_IC_CLR_ACTIVITY 0x5c -#define DW_IC_CLR_STOP_DET 0x60 -#define DW_IC_CLR_START_DET 0x64 -#define DW_IC_CLR_GEN_CALL 0x68 -#define DW_IC_ENABLE 0x6c -#define DW_IC_STATUS 0x70 -#define DW_IC_TXFLR 0x74 -#define DW_IC_RXFLR 0x78 -#define DW_IC_SDA_HOLD 0x7c -#define DW_IC_TX_ABRT_SOURCE 0x80 -#define DW_IC_ENABLE_STATUS 0x9c -#define DW_IC_CLR_RESTART_DET 0xa8 -#define DW_IC_COMP_PARAM_1 0xf4 -#define DW_IC_COMP_VERSION 0xf8 -#define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A -#define DW_IC_COMP_TYPE 0xfc -#define DW_IC_COMP_TYPE_VALUE 0x44570140 - -#define DW_IC_INTR_RX_UNDER BIT(0) -#define DW_IC_INTR_RX_OVER BIT(1) -#define DW_IC_INTR_RX_FULL BIT(2) -#define DW_IC_INTR_TX_OVER BIT(3) -#define DW_IC_INTR_TX_EMPTY BIT(4) -#define DW_IC_INTR_RD_REQ BIT(5) -#define DW_IC_INTR_TX_ABRT BIT(6) -#define DW_IC_INTR_RX_DONE BIT(7) -#define DW_IC_INTR_ACTIVITY BIT(8) -#define DW_IC_INTR_STOP_DET BIT(9) -#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_DEFAULT_MASK (DW_IC_INTR_RX_FULL | \ - DW_IC_INTR_TX_ABRT | \ - DW_IC_INTR_STOP_DET) -#define DW_IC_INTR_MASTER_MASK (DW_IC_INTR_DEFAULT_MASK | \ - DW_IC_INTR_TX_EMPTY) -#define DW_IC_INTR_SLAVE_MASK (DW_IC_INTR_DEFAULT_MASK | \ - DW_IC_INTR_RX_DONE | \ - DW_IC_INTR_RX_UNDER | \ - DW_IC_INTR_RD_REQ) - -#define DW_IC_STATUS_ACTIVITY BIT(0) -#define DW_IC_STATUS_TFE BIT(2) -#define DW_IC_STATUS_MASTER_ACTIVITY BIT(5) -#define DW_IC_STATUS_SLAVE_ACTIVITY BIT(6) - -#define DW_IC_SDA_HOLD_RX_SHIFT 16 -#define DW_IC_SDA_HOLD_RX_MASK GENMASK(23, 16) - -#define DW_IC_ERR_TX_ABRT 0x1 - -#define DW_IC_TAR_10BITADDR_MASTER BIT(12) +#define DW_IC_CON 0x00 +#define DW_IC_TAR 0x04 +#define DW_IC_SAR 0x08 +#define DW_IC_DATA_CMD 0x10 +#define DW_IC_SS_SCL_HCNT 0x14 +#define DW_IC_SS_SCL_LCNT 0x18 +#define DW_IC_FS_SCL_HCNT 0x1c +#define DW_IC_FS_SCL_LCNT 0x20 +#define DW_IC_HS_SCL_HCNT 0x24 +#define DW_IC_HS_SCL_LCNT 0x28 +#define DW_IC_INTR_STAT 0x2c +#define DW_IC_INTR_MASK 0x30 +#define DW_IC_RAW_INTR_STAT 0x34 +#define DW_IC_RX_TL 0x38 +#define DW_IC_TX_TL 0x3c +#define DW_IC_CLR_INTR 0x40 +#define DW_IC_CLR_RX_UNDER 0x44 +#define DW_IC_CLR_RX_OVER 0x48 +#define DW_IC_CLR_TX_OVER 0x4c +#define DW_IC_CLR_RD_REQ 0x50 +#define DW_IC_CLR_TX_ABRT 0x54 +#define DW_IC_CLR_RX_DONE 0x58 +#define DW_IC_CLR_ACTIVITY 0x5c +#define DW_IC_CLR_STOP_DET 0x60 +#define DW_IC_CLR_START_DET 0x64 +#define DW_IC_CLR_GEN_CALL 0x68 +#define DW_IC_ENABLE 0x6c +#define DW_IC_STATUS 0x70 +#define DW_IC_TXFLR 0x74 +#define DW_IC_RXFLR 0x78 +#define DW_IC_SDA_HOLD 0x7c +#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* */ +#define DW_IC_COMP_TYPE 0xfc +#define DW_IC_COMP_TYPE_VALUE 0x44570140 /* "DW" + 0x0140 */ + +#define DW_IC_INTR_RX_UNDER BIT(0) +#define DW_IC_INTR_RX_OVER BIT(1) +#define DW_IC_INTR_RX_FULL BIT(2) +#define DW_IC_INTR_TX_OVER BIT(3) +#define DW_IC_INTR_TX_EMPTY BIT(4) +#define DW_IC_INTR_RD_REQ BIT(5) +#define DW_IC_INTR_TX_ABRT BIT(6) +#define DW_IC_INTR_RX_DONE BIT(7) +#define DW_IC_INTR_ACTIVITY BIT(8) +#define DW_IC_INTR_STOP_DET BIT(9) +#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 | \ + DW_IC_INTR_STOP_DET) +#define DW_IC_INTR_MASTER_MASK (DW_IC_INTR_DEFAULT_MASK | \ + DW_IC_INTR_TX_EMPTY) +#define DW_IC_INTR_SLAVE_MASK (DW_IC_INTR_DEFAULT_MASK | \ + 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) + +#define DW_IC_ERR_TX_ABRT 0x1 + +#define DW_IC_TAR_10BITADDR_MASTER BIT(12) #define DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH (BIT(2) | BIT(3)) #define DW_IC_COMP_PARAM_1_SPEED_MODE_MASK GENMASK(3, 2) /* - * status codes + * Sofware status flags */ -#define STATUS_IDLE 0x0 -#define STATUS_WRITE_IN_PROGRESS 0x1 -#define STATUS_READ_IN_PROGRESS 0x2 +#define STATUS_ACTIVE BIT(0) +#define STATUS_WRITE_IN_PROGRESS BIT(1) +#define STATUS_READ_IN_PROGRESS BIT(2) +#define STATUS_MASK GENMASK(2, 0) /* * operation modes */ -#define DW_IC_MASTER 0 -#define DW_IC_SLAVE 1 +#define DW_IC_MASTER 0 +#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 -#define ABRT_10ADDR2_NOACK 2 -#define ABRT_TXDATA_NOACK 3 -#define ABRT_GCALL_NOACK 4 -#define ABRT_GCALL_READ 5 -#define ABRT_SBYTE_ACKDET 7 -#define ABRT_SBYTE_NORSTRT 9 -#define ABRT_10B_RD_NORSTRT 10 -#define ABRT_MASTER_DIS 11 -#define ARB_LOST 12 -#define ABRT_SLAVE_FLUSH_TXFIFO 13 -#define ABRT_SLAVE_ARBLOST 14 -#define ABRT_SLAVE_RD_INTX 15 +#define ABRT_7B_ADDR_NOACK 0 +#define ABRT_10ADDR1_NOACK 1 +#define ABRT_10ADDR2_NOACK 2 +#define ABRT_TXDATA_NOACK 3 +#define ABRT_GCALL_NOACK 4 +#define ABRT_GCALL_READ 5 +#define ABRT_SBYTE_ACKDET 7 +#define ABRT_SBYTE_NORSTRT 9 +#define ABRT_10B_RD_NORSTRT 10 +#define ABRT_MASTER_DIS 11 +#define ARB_LOST 12 +#define ABRT_SLAVE_FLUSH_TXFIFO 13 +#define ABRT_SLAVE_ARBLOST 14 +#define ABRT_SLAVE_RD_INTX 15 #define DW_IC_TX_ABRT_7B_ADDR_NOACK BIT(ABRT_7B_ADDR_NOACK) #define DW_IC_TX_ABRT_10ADDR1_NOACK BIT(ABRT_10ADDR1_NOACK) @@ -171,11 +179,11 @@ #define DW_IC_RX_ABRT_SLAVE_ARBLOST BIT(ABRT_SLAVE_ARBLOST) #define DW_IC_RX_ABRT_SLAVE_FLUSH_TXFIFO BIT(ABRT_SLAVE_FLUSH_TXFIFO) -#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \ - DW_IC_TX_ABRT_10ADDR1_NOACK | \ - DW_IC_TX_ABRT_10ADDR2_NOACK | \ - DW_IC_TX_ABRT_TXDATA_NOACK | \ - DW_IC_TX_ABRT_GCALL_NOACK) +#define DW_IC_TX_ABRT_NOACK (DW_IC_TX_ABRT_7B_ADDR_NOACK | \ + DW_IC_TX_ABRT_10ADDR1_NOACK | \ + DW_IC_TX_ABRT_10ADDR2_NOACK | \ + DW_IC_TX_ABRT_TXDATA_NOACK | \ + DW_IC_TX_ABRT_GCALL_NOACK) struct clk; struct device; @@ -191,23 +199,27 @@ struct reset_control; * @cmd_complete: tx completion indicator * @clk: input reference clock * @pclk: clock required to access the registers + * @rst: optional reset for the controller * @slave: represent an I2C slave device - * @cmd_err: run time hadware error code + * @get_clk_rate_khz: callback to retrieve IP specific bus speed + * @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 + * @msg_write_idx: the element index of the current tx message in the msgs array * @tx_buf_len: the length of the current tx buffer * @tx_buf: the current tx buffer - * @msg_read_idx: the element index of the current rx message in the msgs - * array + * @msg_read_idx: the element index of the current rx message in the msgs array * @rx_buf_len: the length of the current rx buffer * @rx_buf: the current rx buffer * @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 + * @functionality: I2C_FUNC_* ORed bits to reflect what controller does support + * @master_cfg: configuration for the master device * @slave_cfg: configuration for the slave device * @tx_fifo_depth: depth of the hardware tx fifo * @rx_fifo_depth: depth of the hardware rx fifo @@ -224,12 +236,17 @@ struct reset_control; * @hs_lcnt: high speed LCNT value * @acquire_lock: function to acquire a hardware lock on the bus * @release_lock: function to release a hardware lock on the bus - * @shared_with_punit: true if this bus is shared with the SoCs PUNIT - * @disable: function to disable the controller - * @disable_int: function to disable all interrupts + * @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 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 - * @suspended: set to true if the controller is suspended + * @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. @@ -245,7 +262,7 @@ struct dw_i2c_dev { struct clk *clk; struct clk *pclk; struct reset_control *rst; - struct i2c_client *slave; + struct i2c_client *slave; u32 (*get_clk_rate_khz) (struct dw_i2c_dev *dev); int cmd_err; struct i2c_msg *msgs; @@ -258,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; @@ -280,36 +298,48 @@ struct dw_i2c_dev { u16 hs_lcnt; int (*acquire_lock)(void); void (*release_lock)(void); + int semaphore_idx; bool shared_with_punit; - void (*disable)(struct dw_i2c_dev *dev); - void (*disable_int)(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; - bool suspended; + u32 bus_capacitance_pF; + bool clk_freq_optimized; }; -#define ACCESS_INTR_MASK BIT(0) -#define ACCESS_NO_IRQ_SUSPEND BIT(1) +#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_MASK GENMASK(11, 8) +#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) /* * Enable UCSI interrupt by writing 0xd at register * offset 0x474 specified in hardware specification. */ -#define AMD_UCSI_INTR_REG 0x474 -#define AMD_UCSI_INTR_EN 0xd +#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); +}; 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); @@ -317,20 +347,41 @@ 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); -void i2c_dw_disable_int(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) { + dev->status |= STATUS_ACTIVE; regmap_write(dev->map, DW_IC_ENABLE, 1); } static inline void __i2c_dw_disable_nowait(struct dw_i2c_dev *dev) { regmap_write(dev->map, DW_IC_ENABLE, 0); + 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); @@ -343,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)) @@ -364,17 +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) -extern int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev); -#else -static inline int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) { return 0; } +int i2c_dw_baytrail_probe_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; } +#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_AMDPSP) +int i2c_dw_amdpsp_probe_lock_support(struct dw_i2c_dev *dev); #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 9b08bb5df38d..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) */ - i2c_dw_disable_int(dev); + __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); - i2c_dw_disable_int(dev); /* 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,121 +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; - } - - if (dev_WARN_ONCE(dev->dev, dev->suspended, "Transfer while suspended\n")) { - ret = -ESHUTDOWN; - 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 = STATUS_IDLE; - 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. @@ -672,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 @@ -701,7 +695,8 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) regmap_read(dev->map, DW_IC_CLR_RX_DONE, &dummy); if (stat & DW_IC_INTR_ACTIVITY) regmap_read(dev->map, DW_IC_CLR_ACTIVITY, &dummy); - if (stat & DW_IC_INTR_STOP_DET) + if ((stat & DW_IC_INTR_STOP_DET) && + ((dev->rx_outstanding == 0) || (stat & DW_IC_INTR_RX_FULL))) regmap_read(dev->map, DW_IC_CLR_STOP_DET, &dummy); if (stat & DW_IC_INTR_START_DET) regmap_read(dev->map, DW_IC_CLR_START_DET, &dummy); @@ -711,24 +706,18 @@ static u32 i2c_dw_read_clear_intrbits(struct dw_i2c_dev *dev) return stat; } -/* - * Interrupt service routine. This gets called whenever an I2C master interrupt - * occurs. - */ -static int i2c_dw_irq_handler_master(struct dw_i2c_dev *dev) +static void i2c_dw_process_transfer(struct dw_i2c_dev *dev, unsigned int stat) { - u32 stat; - - stat = i2c_dw_read_clear_intrbits(dev); if (stat & DW_IC_INTR_TX_ABRT) { dev->cmd_err |= DW_IC_ERR_TX_ABRT; - dev->status = STATUS_IDLE; + 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. */ - regmap_write(dev->map, DW_IC_INTR_MASK, 0); + __i2c_dw_write_intr_mask(dev, 0); goto tx_aborted; } @@ -745,34 +734,194 @@ static int i2c_dw_irq_handler_master(struct dw_i2c_dev *dev) */ tx_aborted: - if ((stat & (DW_IC_INTR_TX_ABRT | DW_IC_INTR_STOP_DET)) || dev->msg_err) + 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); - i2c_dw_disable_int(dev); - regmap_write(dev->map, DW_IC_INTR_MASK, stat); + __i2c_dw_read_intr_mask(dev, &stat); + __i2c_dw_write_intr_mask(dev, 0); + __i2c_dw_write_intr_mask(dev, stat); } - - return 0; } +/* + * Interrupt service routine. This gets called whenever an I2C master interrupt + * occurs. + */ 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); - dev_dbg(dev->dev, "enabled=%#x stat=%#x\n", enabled, stat); if (!enabled || !(stat & ~DW_IC_INTR_ACTIVITY)) return IRQ_NONE; + if (pm_runtime_suspended(dev->dev) || stat == GENMASK(31, 0)) + return IRQ_NONE; + dev_dbg(dev->dev, "enabled=%#x stat=%#x\n", enabled, stat); - i2c_dw_irq_handler_master(dev); + stat = i2c_dw_read_clear_intrbits(dev); + + if (!(dev->status & STATUS_ACTIVE)) { + /* + * Unexpected interrupt in driver point of view. State + * variables are either unset or stale so acknowledge and + * disable interrupts for suppressing further interrupts if + * interrupt really came from this HW (E.g. firmware has left + * the HW active). + */ + __i2c_dw_write_intr_mask(dev, 0); + return IRQ_HANDLED; + } + + i2c_dw_process_transfer(dev, stat); 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)); + } + + return ret ? 0 : -ETIMEDOUT; +} + +/* + * 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; + } + + /* + * 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"); + + /* + * 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_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; @@ -832,42 +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; - dev->disable_int = i2c_dw_disable_int; ret = i2c_dw_init_regmap(dev); if (ret) @@ -881,34 +1026,58 @@ 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 { irq_flags = IRQF_SHARED | IRQF_COND_SUSPEND; } - i2c_dw_disable_int(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); + ret = i2c_dw_acquire_lock(dev); + if (ret) return ret; + + __i2c_dw_write_intr_mask(dev, 0); + i2c_dw_release_lock(dev); + + 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); @@ -933,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 0f409a4c2da0..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,14 +18,16 @@ #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> #include "i2c-designware-core.h" +#include "i2c-ccgx-ucsi.h" #define DRIVER_NAME "i2c-designware-pci" -#define AMD_CLK_RATE_HZ 100000 enum dw_pci_ctl_id_t { medfield, @@ -38,12 +39,19 @@ enum dw_pci_ctl_id_t { navi_amd, }; +/* + * This is a legacy structure to describe the hardware counters + * to configure signal timings on the bus. For Device Tree platforms + * one should use the respective properties and for ACPI there is + * a set of ACPI methods that provide these counters. No new + * platform should use this structure. + */ struct dw_scl_sda_cfg { - u32 ss_hcnt; - u32 fs_hcnt; - u32 ss_lcnt; - u32 fs_lcnt; - u32 sda_hold; + u16 ss_hcnt; + u16 fs_hcnt; + u16 ss_lcnt; + u16 fs_lcnt; + u32 sda_hold_time; }; struct dw_pci_controller { @@ -68,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 */ @@ -77,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) @@ -92,14 +100,9 @@ static u32 mfld_get_clk_rate_khz(struct dw_i2c_dev *dev) return 25000; } -static u32 navi_amd_get_clk_rate_khz(struct dw_i2c_dev *dev) -{ - return AMD_CLK_RATE_HZ; -} - 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: @@ -118,35 +121,6 @@ static int mfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c) return -ENODEV; } - /* - * TODO find a better way how to deduplicate instantiation - * of USB PD slave device from nVidia GPU driver. - */ -static int navi_amd_register_client(struct dw_i2c_dev *dev) -{ - struct i2c_board_info info; - - memset(&info, 0, sizeof(struct i2c_board_info)); - strscpy(info.type, "ccgx-ucsi", I2C_NAME_SIZE); - info.addr = 0x08; - info.irq = dev->irq; - - dev->slave = i2c_new_client_device(&dev->adapter, &info); - if (IS_ERR(dev->slave)) - return PTR_ERR(dev->slave); - - return 0; -} - -static int navi_amd_setup(struct pci_dev *pdev, struct dw_pci_controller *c) -{ - struct dw_i2c_dev *dev = dev_get_drvdata(&pdev->dev); - - dev->flags |= MODEL_AMD_NAVI_GPU; - dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ; - return 0; -} - static int mrfld_setup(struct pci_dev *pdev, struct dw_pci_controller *c) { /* @@ -171,6 +145,20 @@ static u32 ehl_get_clk_rate_khz(struct dw_i2c_dev *dev) return 100000; } +static u32 navi_amd_get_clk_rate_khz(struct dw_i2c_dev *dev) +{ + return 100000; +} + +static int navi_amd_setup(struct pci_dev *pdev, struct dw_pci_controller *c) +{ + struct dw_i2c_dev *dev = pci_get_drvdata(pdev); + + dev->flags |= MODEL_AMD_NAVI_GPU | ACCESS_POLLING; + dev->timings.bus_freq_hz = I2C_MAX_STANDARD_MODE_FREQ; + return 0; +} + static struct dw_pci_controller dw_pci_controllers[] = { [medfield] = { .bus_num = -1, @@ -206,65 +194,43 @@ static struct dw_pci_controller dw_pci_controllers[] = { }, }; -#ifdef CONFIG_PM -static int i2c_dw_pci_suspend(struct device *dev) -{ - struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - - i_dev->suspended = true; - i_dev->disable(i_dev); - - return 0; -} - -static int i2c_dw_pci_resume(struct device *dev) -{ - struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - int ret; - - ret = i_dev->init(i_dev); - i_dev->suspended = false; - - return ret; -} -#endif +static const struct property_entry dgpu_properties[] = { + /* USB-C doesn't power the system */ + PROPERTY_ENTRY_U8("scope", POWER_SUPPLY_SCOPE_DEVICE), + {} +}; -static UNIVERSAL_DEV_PM_OPS(i2c_dw_pm_ops, i2c_dw_pci_suspend, - i2c_dw_pci_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; - if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) { - dev_err(&pdev->dev, "%s: invalid driver data %ld\n", __func__, - id->driver_data); - return -EINVAL; - } + if (id->driver_data >= ARRAY_SIZE(dw_pci_controllers)) + 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) { - dev_err(&pdev->dev, "Failed to enable I2C PCI device (%d)\n", - r); - return r; - } + if (r) + 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) { - dev_err(&pdev->dev, "I/O memory remapping failed\n"); - return r; - } + if (r) + return dev_err_probe(device, r, "I/O memory remapping failed\n"); - dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL); + dev = devm_kzalloc(device, sizeof(*dev), GFP_KERNEL); if (!dev) return -ENOMEM; @@ -273,9 +239,8 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, return r; dev->get_clk_rate_khz = controller->get_clk_rate_khz; - dev->timings.bus_freq_hz = I2C_MAX_FAST_MODE_FREQ; 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; @@ -283,22 +248,13 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev, 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); @@ -308,33 +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) { - r = navi_amd_register_client(dev); - if (r) { - dev_err(dev->dev, "register client failed with %d\n", r); - return r; + 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,20 +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; - dev->disable(dev); - pm_runtime_forbid(&pdev->dev); - pm_runtime_get_noresume(&pdev->dev); + i2c_dw_disable(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); } -/* work with hotplug and coldplug */ -MODULE_ALIAS("i2c_designware-pci"); - -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 }, @@ -394,26 +345,30 @@ static const struct pci_device_id i2_designware_pci_ids[] = { { PCI_VDEVICE(INTEL, 0x4bbe), elkhartlake }, { PCI_VDEVICE(INTEL, 0x4bbf), elkhartlake }, { PCI_VDEVICE(INTEL, 0x4bc0), elkhartlake }, + /* AMD NAVI */ { PCI_VDEVICE(ATI, 0x7314), navi_amd }, { PCI_VDEVICE(ATI, 0x73a4), navi_amd }, { PCI_VDEVICE(ATI, 0x73e4), navi_amd }, { PCI_VDEVICE(ATI, 0x73c4), navi_amd }, - { 0,} + { PCI_VDEVICE(ATI, 0x7444), navi_amd }, + { PCI_VDEVICE(ATI, 0x7464), navi_amd }, + {} }; -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); 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 4b37f28ec0c6..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,36 +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)/1000; + 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 }, - { "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) @@ -95,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, @@ -117,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) { @@ -179,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); @@ -203,66 +153,117 @@ static const struct dmi_system_id dw_i2c_hwmon_class_dmi[] = { { } /* terminate list */ }; +static const struct i2c_dw_semaphore_callbacks i2c_dw_semaphore_cb_table[] = { +#ifdef CONFIG_I2C_DESIGNWARE_BAYTRAIL + { + .probe = i2c_dw_baytrail_probe_lock_support, + }, +#endif +#ifdef CONFIG_I2C_DESIGNWARE_AMDPSP + { + .probe = i2c_dw_amdpsp_probe_lock_support, + }, +#endif + {} +}; + +static int i2c_dw_probe_lock_support(struct dw_i2c_dev *dev) +{ + const struct i2c_dw_semaphore_callbacks *ptr; + int i = 0; + int ret; + + dev->semaphore_idx = -1; + + for (ptr = i2c_dw_semaphore_cb_table; ptr->probe; ptr++) { + ret = ptr->probe(dev); + if (ret) { + /* + * If there is no semaphore device attached to this + * controller, we shouldn't abort general i2c_controller + * probe. + */ + if (ret != -ENODEV) + return ret; + + i++; + continue; + } + + dev->semaphore_idx = i; + break; + } + + return 0; +} + 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(device, NULL); + if (IS_ERR(dev->clk)) { + ret = dev_err_probe(device, PTR_ERR(dev->clk), "failed to acquire clock\n"); goto exit_reset; } - dev->clk = devm_clk_get(&pdev->dev, NULL); - if (!i2c_dw_prepare_clk(dev, true)) { + ret = i2c_dw_prepare_clk(dev, true); + if (ret) + 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; @@ -270,39 +271,33 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) if (!dev->sda_hold_time && t->sda_hold_ns) dev->sda_hold_time = - div_u64(clk_khz * t->sda_hold_ns + 500000, 1000000); + DIV_S64_ROUND_CLOSEST(clk_khz * t->sda_hold_ns, MICRO); } 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 | - DPM_FLAG_MAY_SKIP_RESUME); - } else { - dev_pm_set_driver_flags(&pdev->dev, - DPM_FLAG_SMART_PREPARE | - DPM_FLAG_SMART_SUSPEND | - DPM_FLAG_MAY_SKIP_RESUME); - } + 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(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) @@ -312,111 +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); - 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); -} - -static void dw_i2c_plat_complete(struct device *dev) -{ - /* - * The device can only be in runtime suspend at this point if it has not - * been resumed throughout the ending system suspend/resume cycle, so if - * the platform firmware might mess up with it, request the runtime PM - * framework to resume it. - */ - if (pm_runtime_suspended(dev) && pm_resume_via_firmware()) - pm_request_resume(dev); -} -#else -#define dw_i2c_plat_prepare NULL -#define dw_i2c_plat_complete NULL -#endif - -#ifdef CONFIG_PM -static int dw_i2c_plat_suspend(struct device *dev) -{ - struct dw_i2c_dev *i_dev = dev_get_drvdata(dev); - - i_dev->suspended = true; - - if (i_dev->shared_with_punit) - return 0; + i2c_dw_prepare_clk(dev, false); - i_dev->disable(i_dev); - i2c_dw_prepare_clk(i_dev, false); - - return 0; -} - -static int dw_i2c_plat_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); - i_dev->suspended = false; - - return 0; + reset_control_assert(dev->rst); } -static const struct dev_pm_ops dw_i2c_dev_pm_ops = { - .prepare = dw_i2c_plat_prepare, - .complete = dw_i2c_plat_complete, - SET_LATE_SYSTEM_SLEEP_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_resume) - SET_RUNTIME_PM_OPS(dw_i2c_plat_suspend, dw_i2c_plat_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) @@ -434,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 0d15f4c1e9f7..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) { @@ -78,13 +83,7 @@ static int i2c_dw_reg_slave(struct i2c_client *slave) __i2c_dw_enable(dev); - dev->cmd_err = 0; - dev->msg_write_idx = 0; - dev->msg_read_idx = 0; - dev->msg_err = 0; - dev->status = STATUS_IDLE; - dev->abort_source = 0; - dev->rx_outstanding = 0; + dev->status = 0; return 0; } @@ -93,18 +92,18 @@ static int i2c_dw_unreg_slave(struct i2c_client *slave) { struct dw_i2c_dev *dev = i2c_get_adapdata(slave->adapter); - dev->disable_int(dev); - dev->disable(dev); + regmap_write(dev->map, DW_IC_INTR_MASK, 0); + 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. @@ -153,10 +152,10 @@ static u32 i2c_dw_read_clear_intrbits_slave(struct dw_i2c_dev *dev) * Interrupt service routine. This gets called whenever an I2C slave interrupt * occurs. */ - -static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev) +static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id) { - u32 raw_stat, stat, enabled, tmp; + struct dw_i2c_dev *dev = dev_id; + unsigned int raw_stat, stat, enabled, tmp; u8 val = 0, slave_activity; regmap_read(dev->map, DW_IC_ENABLE, &enabled); @@ -165,7 +164,7 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev) slave_activity = ((tmp & DW_IC_STATUS_SLAVE_ACTIVITY) >> 6); if (!enabled || !(raw_stat & ~DW_IC_INTR_ACTIVITY) || !dev->slave) - return 0; + return IRQ_NONE; stat = i2c_dw_read_clear_intrbits_slave(dev); dev_dbg(dev->dev, @@ -173,55 +172,49 @@ static int i2c_dw_irq_handler_slave(struct dw_i2c_dev *dev) enabled, slave_activity, raw_stat, stat); if (stat & DW_IC_INTR_RX_FULL) { - if (dev->status != STATUS_WRITE_IN_PROGRESS) { - dev->status = STATUS_WRITE_IN_PROGRESS; + if (!(dev->status & STATUS_WRITE_IN_PROGRESS)) { + dev->status |= STATUS_WRITE_IN_PROGRESS; + dev->status &= ~STATUS_READ_IN_PROGRESS; i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_REQUESTED, &val); } - regmap_read(dev->map, DW_IC_DATA_CMD, &tmp); - val = tmp; - if (!i2c_slave_event(dev->slave, I2C_SLAVE_WRITE_RECEIVED, - &val)) - dev_vdbg(dev->dev, "Byte %X acked!", val); + 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); + regmap_read(dev->map, DW_IC_STATUS, &tmp); + } while (tmp & DW_IC_STATUS_RFNE); } if (stat & DW_IC_INTR_RD_REQ) { if (slave_activity) { regmap_read(dev->map, DW_IC_CLR_RD_REQ, &tmp); - dev->status = STATUS_READ_IN_PROGRESS; - if (!i2c_slave_event(dev->slave, - I2C_SLAVE_READ_REQUESTED, - &val)) - regmap_write(dev->map, DW_IC_DATA_CMD, val); + if (!(dev->status & STATUS_READ_IN_PROGRESS)) { + i2c_slave_event(dev->slave, + I2C_SLAVE_READ_REQUESTED, + &val); + dev->status |= STATUS_READ_IN_PROGRESS; + dev->status &= ~STATUS_WRITE_IN_PROGRESS; + } else { + i2c_slave_event(dev->slave, + I2C_SLAVE_READ_PROCESSED, + &val); + } + regmap_write(dev->map, DW_IC_DATA_CMD, val); } } - if (stat & DW_IC_INTR_RX_DONE) { - if (!i2c_slave_event(dev->slave, I2C_SLAVE_READ_PROCESSED, - &val)) - regmap_read(dev->map, DW_IC_CLR_RX_DONE, &tmp); - } - - if (stat & DW_IC_INTR_STOP_DET) { - dev->status = STATUS_IDLE; + if (stat & DW_IC_INTR_STOP_DET) i2c_slave_event(dev->slave, I2C_SLAVE_STOP, &val); - } - return 1; -} - -static irqreturn_t i2c_dw_isr_slave(int this_irq, void *dev_id) -{ - struct dw_i2c_dev *dev = dev_id; - int ret; - - ret = i2c_dw_irq_handler_slave(dev); - if (ret > 0) - complete(&dev->cmd_complete); - - return IRQ_RETVAL(ret); + return IRQ_HANDLED; } static const struct i2c_algorithm i2c_dw_algo = { @@ -232,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; @@ -246,11 +239,7 @@ int i2c_dw_probe_slave(struct dw_i2c_dev *dev) struct i2c_adapter *adap = &dev->adapter; int ret; - init_completion(&dev->cmd_complete); - dev->init = i2c_dw_init_slave; - dev->disable = i2c_dw_disable; - dev->disable_int = i2c_dw_disable_int; ret = i2c_dw_init_regmap(dev); if (ret) @@ -277,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) @@ -294,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 60c838c7c454..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) @@ -322,7 +322,7 @@ static int dc_i2c_probe(struct platform_device *pdev) if (ret < 0) return ret; - strlcpy(i2c->adap.name, "Conexant Digicolor I2C adapter", + strscpy(i2c->adap.name, "Conexant Digicolor I2C adapter", sizeof(i2c->adap.name)); i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &dc_i2c_algorithm; @@ -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 321b2770feab..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 }; @@ -773,7 +755,7 @@ static int pch_i2c_probe(struct pci_dev *pdev, pch_adap->owner = THIS_MODULE; pch_adap->class = I2C_CLASS_HWMON; - strlcpy(pch_adap->name, KBUILD_MODNAME, sizeof(pch_adap->name)); + strscpy(pch_adap->name, KBUILD_MODNAME, sizeof(pch_adap->name)); pch_adap->algo = &pch_algorithm; pch_adap->algo_data = &adap_info->pch_data[i]; 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 bdff0e6345d9..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); @@ -371,15 +371,11 @@ static int em_i2c_probe(struct platform_device *pdev) if (IS_ERR(priv->base)) return PTR_ERR(priv->base); - strlcpy(priv->adap.name, "EMEV2 I2C", sizeof(priv->adap.name)); + 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 97d4f3ac0abd..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> /* @@ -169,6 +167,8 @@ enum i2c_type_exynos { I2C_TYPE_EXYNOS5, I2C_TYPE_EXYNOS7, + I2C_TYPE_EXYNOSAUTOV9, + I2C_TYPE_EXYNOS8895, }; struct exynos5_i2c { @@ -181,7 +181,8 @@ struct exynos5_i2c { unsigned int irq; void __iomem *regs; - struct clk *clk; + struct clk *clk; /* operating clock */ + struct clk *pclk; /* bus clock */ struct device *dev; int state; @@ -194,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; @@ -230,6 +236,16 @@ static const struct exynos_hsi2c_variant exynos7_hsi2c_data = { .hw = I2C_TYPE_EXYNOS7, }; +static const struct exynos_hsi2c_variant exynosautov9_hsi2c_data = { + .fifo_depth = 64, + .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", @@ -243,6 +259,12 @@ static const struct of_device_id exynos5_i2c_match[] = { }, { .compatible = "samsung,exynos7-hsi2c", .data = &exynos7_hsi2c_data + }, { + .compatible = "samsung,exynosautov9-hsi2c", + .data = &exynosautov9_hsi2c_data + }, { + .compatible = "samsung,exynos8895-hsi2c", + .data = &exynos8895_hsi2c_data }, {}, }; MODULE_DEVICE_TABLE(of, exynos5_i2c_match); @@ -257,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 @@ -282,6 +304,31 @@ static int exynos5_i2c_set_timing(struct exynos5_i2c *i2c, bool hs_timings) int div, clk_cycle, temp; /* + * In case of HSI2C controllers in ExynosAutoV9: + * + * FSCL = IPCLK / ((CLK_DIV + 1) * 16) + * T_SCL_LOW = IPCLK * (CLK_DIV + 1) * (N + M) + * [N : number of 0's in the TSCL_H_HS] + * [M : number of 0's in the TSCL_L_HS] + * T_SCL_HIGH = IPCLK * (CLK_DIV + 1) * (N + M) + * [N : number of 1's in the TSCL_H_HS] + * [M : number of 1's in the TSCL_L_HS] + * + * Result of (N + M) is always 8. + * In general case, we don't need to control timing_s1 and timing_s2. + */ + if (i2c->variant->hw == I2C_TYPE_EXYNOSAUTOV9) { + div = ((clkin / (16 * i2c->op_clock)) - 1); + i2c_timing_s3 = div << 16; + if (hs_timings) + writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_HS3); + else + writel(i2c_timing_s3, i2c->regs + HSI2C_TIMING_FS3); + + return 0; + } + + /* * In case of HSI2C controller in Exynos5 series * FPCLK / FI2C = * (CLK_DIV + 1) * (TSCLK_L + TSCLK_H + 2) + 8 + 2 * FLT_CYCLE @@ -293,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; @@ -422,7 +513,12 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) writel(int_status, i2c->regs + HSI2C_INT_STATUS); /* handle interrupt related to the transfer status */ - if (i2c->variant->hw == I2C_TYPE_EXYNOS7) { + 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; i2c->state = 0; @@ -443,7 +539,12 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) i2c->state = -ETIMEDOUT; goto stop; } - } else if (int_status & HSI2C_INT_I2C) { + + break; + case I2C_TYPE_EXYNOS5: + if (!(int_status & HSI2C_INT_I2C)) + break; + trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS); if (trans_status & HSI2C_NO_DEV_ACK) { dev_dbg(i2c->dev, "No ACK from device\n"); @@ -465,6 +566,8 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) i2c->trans_done = 1; i2c->state = 0; } + + break; } if ((i2c->msg->flags & I2C_M_RD) && (int_status & @@ -569,13 +672,13 @@ static void exynos5_i2c_bus_check(struct exynos5_i2c *i2c) { unsigned long timeout; - if (i2c->variant->hw != I2C_TYPE_EXYNOS7) + if (i2c->variant->hw == I2C_TYPE_EXYNOS5) return; /* - * HSI2C_MASTER_ST_LOSE state in EXYNOS7 variant before transaction - * indicates that bus is stuck (SDA is low). In such case bus recovery - * can be performed. + * HSI2C_MASTER_ST_LOSE state (in Exynos7 and ExynosAutoV9 variants) + * before transaction indicates that bus is stuck (SDA is low). + * In such case bus recovery can be performed. */ timeout = jiffies + msecs_to_jiffies(100); for (;;) { @@ -611,10 +714,10 @@ static void exynos5_i2c_message_start(struct exynos5_i2c *i2c, int stop) unsigned long flags; unsigned short trig_lvl; - if (i2c->variant->hw == I2C_TYPE_EXYNOS7) - int_en |= HSI2C_INT_I2C_TRANS; - else + if (i2c->variant->hw == I2C_TYPE_EXYNOS5) int_en |= HSI2C_INT_I2C; + else + int_en |= HSI2C_INT_I2C_TRANS; i2c_ctl = readl(i2c->regs + HSI2C_CTL); i2c_ctl &= ~(HSI2C_TXCHON | HSI2C_RXCHON); @@ -668,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; @@ -682,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) @@ -713,10 +837,14 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap, struct exynos5_i2c *i2c = adap->algo_data; int i, ret; - ret = clk_enable(i2c->clk); + ret = clk_enable(i2c->pclk); if (ret) return ret; + ret = clk_enable(i2c->clk); + if (ret) + goto err_pclk; + for (i = 0; i < num; ++i) { ret = exynos5_i2c_xfer_msg(i2c, msgs + i, i + 1 == num); if (ret) @@ -724,18 +852,36 @@ static int exynos5_i2c_xfer(struct i2c_adapter *adap, } clk_disable(i2c->clk); +err_pclk: + clk_disable(i2c->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) @@ -751,7 +897,7 @@ static int exynos5_i2c_probe(struct platform_device *pdev) if (of_property_read_u32(np, "clock-frequency", &i2c->op_clock)) i2c->op_clock = I2C_MAX_STANDARD_MODE_FREQ; - strlcpy(i2c->adap.name, "exynos5-i2c", sizeof(i2c->adap.name)); + strscpy(i2c->adap.name, "exynos5-i2c", sizeof(i2c->adap.name)); i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &exynos5_i2c_algorithm; i2c->adap.retries = 3; @@ -763,10 +909,20 @@ static int exynos5_i2c_probe(struct platform_device *pdev) return -ENOENT; } - ret = clk_prepare_enable(i2c->clk); + i2c->pclk = devm_clk_get_optional(&pdev->dev, "hsi2c_pclk"); + if (IS_ERR(i2c->pclk)) { + return dev_err_probe(&pdev->dev, PTR_ERR(i2c->pclk), + "cannot get pclk"); + } + + ret = clk_prepare_enable(i2c->pclk); if (ret) return ret; + ret = clk_prepare_enable(i2c->clk); + if (ret) + goto err_pclk; + i2c->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(i2c->regs)) { ret = PTR_ERR(i2c->regs); @@ -809,32 +965,35 @@ static int exynos5_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, i2c); clk_disable(i2c->clk); + clk_disable(i2c->pclk); return 0; err_clk: clk_disable_unprepare(i2c->clk); + + err_pclk: + clk_disable_unprepare(i2c->pclk); 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); i2c_del_adapter(&i2c->adap); clk_unprepare(i2c->clk); - - return 0; + clk_unprepare(i2c->pclk); } -#ifdef CONFIG_PM_SLEEP static int exynos5_i2c_suspend_noirq(struct device *dev) { struct exynos5_i2c *i2c = dev_get_drvdata(dev); i2c_mark_adapter_suspended(&i2c->adap); clk_unprepare(i2c->clk); + clk_unprepare(i2c->pclk); return 0; } @@ -844,27 +1003,35 @@ static int exynos5_i2c_resume_noirq(struct device *dev) struct exynos5_i2c *i2c = dev_get_drvdata(dev); int ret = 0; - ret = clk_prepare_enable(i2c->clk); + ret = clk_prepare_enable(i2c->pclk); if (ret) return ret; + ret = clk_prepare_enable(i2c->clk); + if (ret) + goto err_pclk; + ret = exynos5_hsi2c_clock_setup(i2c); - if (ret) { - clk_disable_unprepare(i2c->clk); - return ret; - } + if (ret) + goto err_clk; exynos5_i2c_init(i2c); clk_disable(i2c->clk); + clk_disable(i2c->pclk); i2c_mark_adapter_resumed(&i2c->adap); return 0; + +err_clk: + clk_disable_unprepare(i2c->clk); +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 = { @@ -872,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 7a048abbf92b..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) - strlcpy(adap->name, dev_name(dev), sizeof(adap->name)); + 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,34 +450,35 @@ 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; } -#if defined(CONFIG_OF) static const struct of_device_id i2c_gpio_dt_ids[] = { { .compatible = "i2c-gpio", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, i2c_gpio_dt_ids); -#endif + +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 = of_match_ptr(i2c_gpio_dt_ids), + .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 803dad70e2a7..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); @@ -379,7 +379,7 @@ static int highlander_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); dev->irq = platform_get_irq(pdev, 0); - if (iic_force_poll) + if (dev->irq < 0 || iic_force_poll) dev->irq = 0; if (dev->irq) { @@ -402,7 +402,7 @@ static int highlander_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(adap, dev); adap->owner = THIS_MODULE; adap->class = I2C_CLASS_HWMON; - strlcpy(adap->name, "HL FPGA I2C adapter", sizeof(adap->name)); + strscpy(adap->name, "HL FPGA I2C adapter", sizeof(adap->name)); adap->algo = &highlander_i2c_algo; adap->dev.parent = &pdev->dev; adap->nr = pdev->id; @@ -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 acf394812061..4b735ad9e193 100644 --- a/drivers/i2c/busses/i2c-hisi.c +++ b/drivers/i2c/busses/i2c-hisi.c @@ -7,6 +7,7 @@ #include <linux/bits.h> #include <linux/bitfield.h> +#include <linux/clk.h> #include <linux/completion.h> #include <linux/i2c.h> #include <linux/interrupt.h> @@ -15,6 +16,7 @@ #include <linux/mod_devicetable.h> #include <linux/platform_device.h> #include <linux/property.h> +#include <linux/units.h> #define HISI_I2C_FRAME_CTRL 0x0000 #define HISI_I2C_FRAME_CTRL_SPEED_MODE GENMASK(1, 0) @@ -55,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 @@ -80,8 +84,6 @@ #define HISI_I2C_TX_F_AE_THRESH 1 #define HISI_I2C_RX_F_AF_THRESH 60 -#define HZ_PER_KHZ 1000 - #define NSEC_TO_CYCLES(ns, clk_rate_khz) \ DIV_ROUND_UP_ULL((clk_rate_khz) * (ns), NSEC_PER_MSEC) @@ -89,6 +91,7 @@ struct hisi_i2c_controller { struct i2c_adapter adapter; void __iomem *iobase; struct device *dev; + struct clk *clk; int irq; /* Intermediates for recording the transfer process */ @@ -123,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; @@ -167,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; @@ -188,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); @@ -227,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) @@ -265,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; @@ -315,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) @@ -322,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)) @@ -340,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); } @@ -450,15 +481,16 @@ 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; - } - - 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 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) + return dev_err_probe(dev, ret, "failed to get clock frequency\n"); + } else { + clk_rate_hz = clk_get_rate(ctlr->clk); } ctlr->clk_rate_khz = DIV_ROUND_UP_ULL(clk_rate_hz, HZ_PER_KHZ); @@ -490,11 +522,18 @@ static const struct acpi_device_id hisi_i2c_acpi_ids[] = { }; MODULE_DEVICE_TABLE(acpi, hisi_i2c_acpi_ids); +static const struct of_device_id hisi_i2c_dts_ids[] = { + { .compatible = "hisilicon,ascend910-i2c", }, + { } +}; +MODULE_DEVICE_TABLE(of, hisi_i2c_dts_ids); + static struct platform_driver hisi_i2c_driver = { .probe = hisi_i2c_probe, .driver = { .name = "hisi-i2c", .acpi_match_table = hisi_i2c_acpi_ids, + .of_match_table = hisi_i2c_dts_ids, }, }; module_platform_driver(hisi_i2c_driver); diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c index aa00ba8bcb70..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) @@ -413,17 +416,16 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev) return PTR_ERR(priv->regs); irq = platform_get_irq(pdev, 0); - if (irq <= 0) + 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); - strlcpy(priv->adap.name, "hix5hd2-i2c", sizeof(priv->adap.name)); + strscpy(priv->adap.name, "hix5hd2-i2c", sizeof(priv->adap.name)); priv->dev = &pdev->dev; priv->adap.owner = THIS_MODULE; priv->adap.algo = &hix5hd2_i2c_algorithm; @@ -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 aa3f60e69230..81e6e2d7ad3d 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -64,6 +64,7 @@ * Cannon Lake-LP (PCH) 0x9da3 32 hard yes yes yes * Cedar Fork (PCH) 0x18df 32 hard yes yes yes * Ice Lake-LP (PCH) 0x34a3 32 hard yes yes yes + * Ice Lake-N (PCH) 0x38a3 32 hard yes yes yes * Comet Lake (PCH) 0x02a3 32 hard yes yes yes * Comet Lake-H (PCH) 0x06a3 32 hard yes yes yes * Elkhart Lake (PCH) 0x4b23 32 hard yes yes yes @@ -74,6 +75,16 @@ * Alder Lake-S (PCH) 0x7aa3 32 hard yes yes yes * Alder Lake-P (PCH) 0x51a3 32 hard yes yes yes * 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 @@ -81,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 * @@ -99,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> @@ -109,9 +121,11 @@ #include <linux/err.h> #include <linux/platform_device.h> #include <linux/platform_data/itco_wdt.h> +#include <linux/platform_data/x86/p2sb.h> #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 @@ -132,12 +146,12 @@ #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 #define TCOCTL 0x054 -#define SBREG_BAR 0x10 #define SBREG_SMBCTRL 0xc6000c #define SBREG_SMBCTRL_DNV 0xcf000c @@ -163,7 +177,7 @@ #define I801_BYTE 0x04 #define I801_BYTE_DATA 0x08 #define I801_WORD_DATA 0x0C -#define I801_PROC_CALL 0x10 /* unimplemented */ +#define I801_PROC_CALL 0x10 #define I801_BLOCK_DATA 0x14 #define I801_I2C_BLOCK_DATA 0x18 /* ICH5 and later */ #define I801_BLOCK_PROC_CALL 0x1C @@ -189,6 +203,7 @@ #define SMBSLVSTS_HST_NTFY_STS BIT(0) /* Host Notify Command register bits */ +#define SMBSLVCMD_SMBALERT_DISABLE BIT(2) #define SMBSLVCMD_HST_NTFY_INTREN BIT(0) #define STATUS_ERROR_FLAGS (SMBHSTSTS_FAILED | SMBHSTSTS_BUS_ERR | \ @@ -197,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 @@ -217,14 +234,22 @@ #define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0 #define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4 #define PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS 0x34a3 +#define PCI_DEVICE_ID_INTEL_ICELAKE_N_SMBUS 0x38a3 #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 @@ -242,20 +267,23 @@ #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; struct pci_dev *pci_dev; unsigned int features; @@ -271,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) @@ -315,30 +342,84 @@ 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) { - dev_err(&priv->pci_dev->dev, "SMBus is busy, can't use it!\n"); + pci_err(priv->pci_dev, "SMBus is busy, can't use it!\n"); return -EBUSY; } status &= STATUS_FLAGS; if (status) { - dev_dbg(&priv->pci_dev->dev, "Clearing status flags (%02x)\n", - status); - outb_p(status, SMBHSTSTS(priv)); - status = inb_p(SMBHSTSTS(priv)) & STATUS_FLAGS; - if (status) { - dev_err(&priv->pci_dev->dev, - "Failed clearing status flags (%02x)\n", - status); - return -EBUSY; - } + pci_dbg(priv->pci_dev, "Clearing status flags (%02x)\n", status); + iowrite8(status, SMBHSTSTS(priv)); } /* @@ -348,61 +429,35 @@ 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) { - dev_dbg(&priv->pci_dev->dev, - "Clearing aux status flags (%02x)\n", status); - outb_p(status, SMBAUXSTS(priv)); - status = inb_p(SMBAUXSTS(priv)) & SMBAUXSTS_CRCE; - if (status) { - dev_err(&priv->pci_dev->dev, - "Failed clearing aux status flags (%02x)\n", - status); - return -EBUSY; - } - } - } + result = i801_check_and_clear_pec_error(priv); + if (result) + pci_dbg(priv->pci_dev, "Clearing aux status flag CRCE\n"); return 0; } -/* - * Convert the status register to an error code, and clear it. - * Note that status only contains the bits we want to clear, not the - * actual register value. - */ static int i801_check_post(struct i801_priv *priv, int status) { int result = 0; /* * If the SMBus is still busy, we give up - * Note: This timeout condition only happens when using polling - * transactions. For interrupt operation, NAK/timeout is indicated by - * DEV_ERR. */ 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"); - outb_p(STATUS_FLAGS, SMBHSTSTS(priv)); + 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) { /* @@ -420,180 +475,126 @@ 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"); } - /* Clear status flags except BYTE_DONE, to be cleared by caller */ - outb_p(status, SMBHSTSTS(priv)); - 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; } - /* the current contents of SMBHSTCNT can be overwritten, since PEC, - * SMBSCMD are passed in xact */ - 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 hwpec) + char read_write, int command) { - int i, len; - int status; - int xact = hwpec ? SMBHSTCNT_PEC_EN : 0; + int len, status, xact; switch (command) { case I2C_SMBUS_BLOCK_PROC_CALL: - xact |= I801_BLOCK_PROC_CALL; + xact = I801_BLOCK_PROC_CALL; break; case I2C_SMBUS_BLOCK_DATA: - xact |= I801_BLOCK_DATA; + xact = I801_BLOCK_DATA; break; default: return -EOPNOTSUPP; } - inb_p(SMBHSTCNT(priv)); /* reset the data buffer index */ + /* Set block buffer mode */ + iowrite8(ioread8(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv)); - /* Use 32-byte buffer to process this transaction */ 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; - } else { - dev_dbg(&priv->pci_dev->dev, - "SMBus block read size is %d\n", - priv->len); - } + 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) @@ -603,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; } @@ -616,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. @@ -635,23 +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 irq sources and 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 &= SMBHSTSTS_INTR | STATUS_ERROR_FLAGS; + status &= STATUS_FLAGS | SMBHSTSTS_SMBALERT_STS; + iowrite8(status, SMBHSTSTS(priv)); + + status &= STATUS_ERROR_FLAGS | SMBHSTSTS_INTR; if (status) { - outb_p(status, SMBHSTSTS(priv)); - priv->status = status; + priv->status = status & STATUS_ERROR_FLAGS; complete(&priv->done); } @@ -665,8 +668,7 @@ static irqreturn_t i801_isr(int irq, void *dev_id) */ static int i801_block_transaction_byte_by_byte(struct i801_priv *priv, union i2c_smbus_data *data, - char read_write, int command, - int hwpec) + char read_write, int command) { int i, len; int smbcmd; @@ -677,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 && @@ -704,115 +702,185 @@ 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); } -static int i801_set_block_buffer_mode(struct i801_priv *priv) +static void i801_set_hstadd(struct i801_priv *priv, u8 addr, char read_write) { - outb_p(inb_p(SMBAUXCTL(priv)) | SMBAUXCTL_E32B, SMBAUXCTL(priv)); - if ((inb_p(SMBAUXCTL(priv)) & SMBAUXCTL_E32B) == 0) - return -EIO; - return 0; + iowrite8((addr << 1) | (read_write & 0x01), SMBHSTADD(priv)); } -/* Block transaction function */ -static int i801_block_transaction(struct i801_priv *priv, - union i2c_smbus_data *data, char read_write, - int command, int hwpec) +/* 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 result = 0; - unsigned char hostc; + int xact, ret; - if (command == I2C_SMBUS_I2C_BLOCK_DATA) { + switch (command) { + case I2C_SMBUS_QUICK: + i801_set_hstadd(priv, addr, read_write); + xact = I801_QUICK; + break; + case I2C_SMBUS_BYTE: + i801_set_hstadd(priv, addr, read_write); + if (read_write == I2C_SMBUS_WRITE) + iowrite8(hstcmd, SMBHSTCMD(priv)); + xact = I801_BYTE; + break; + case I2C_SMBUS_BYTE_DATA: + i801_set_hstadd(priv, addr, read_write); + if (read_write == I2C_SMBUS_WRITE) + iowrite8(data->byte, SMBHSTDAT0(priv)); + iowrite8(hstcmd, SMBHSTCMD(priv)); + xact = I801_BYTE_DATA; + break; + case I2C_SMBUS_WORD_DATA: + i801_set_hstadd(priv, addr, read_write); 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; + 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: + 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; + default: + pci_err(priv->pci_dev, "Unsupported transaction %d\n", command); + return -EOPNOTSUPP; } - if (read_write == I2C_SMBUS_WRITE - || command == I2C_SMBUS_I2C_BLOCK_DATA) { - if (data->block[0] < 1) - data->block[0] = 1; - if (data->block[0] > I2C_SMBUS_BLOCK_MAX) - data->block[0] = I2C_SMBUS_BLOCK_MAX; - } else { - data->block[0] = 32; /* max for SMBus block reads */ + 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_WORD_DATA: + case I2C_SMBUS_PROC_CALL: + data->word = ioread8(SMBHSTDAT0(priv)) + + (ioread8(SMBHSTDAT1(priv)) << 8); + break; } - /* 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 - && i801_set_block_buffer_mode(priv) == 0) - result = i801_block_transaction_by_block(priv, data, - read_write, - command, hwpec); + 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 - result = i801_block_transaction_byte_by_byte(priv, data, - read_write, - command, hwpec); + i801_set_hstadd(priv, addr, read_write); + iowrite8(hstcmd, SMBHSTCMD(priv)); - 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); + if (priv->features & FEATURE_BLOCK_BUFFER) + return i801_block_transaction_by_block(priv, data, read_write, command); + else + return i801_block_transaction_byte_by_byte(priv, data, read_write, command); +} + +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 (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; } @@ -821,139 +889,50 @@ 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; - int block = 0; - int ret = 0, xact = 0; + int hwpec, ret; struct i801_priv *priv = i2c_get_adapdata(adap); - mutex_lock(&priv->acpi_lock); - if (priv->acpi_reserved) { - mutex_unlock(&priv->acpi_lock); + if (priv->acpi_reserved) return -EBUSY; - } pm_runtime_get_sync(&priv->pci_dev->dev); + ret = i801_check_pre(priv); + if (ret) + goto out; + hwpec = (priv->features & FEATURE_SMBUS_PEC) && (flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK && size != I2C_SMBUS_I2C_BLOCK_DATA; - switch (size) { - case I2C_SMBUS_QUICK: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD(priv)); - xact = I801_QUICK; - break; - case I2C_SMBUS_BYTE: - outb_p(((addr & 0x7f) << 1) | (read_write & 0x01), - SMBHSTADD(priv)); - if (read_write == I2C_SMBUS_WRITE) - outb_p(command, 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)); - if (read_write == I2C_SMBUS_WRITE) - outb_p(data->byte, SMBHSTDAT0(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)); - if (read_write == I2C_SMBUS_WRITE) { - outb_p(data->word & 0xff, SMBHSTDAT0(priv)); - outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1(priv)); - } - xact = I801_WORD_DATA; - 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; - 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; - 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)); + iowrite8(ioread8(SMBAUXCTL(priv)) | SMBAUXCTL_CRC, SMBAUXCTL(priv)); else - outb_p(inb_p(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC), + iowrite8(ioread8(SMBAUXCTL(priv)) & (~SMBAUXCTL_CRC), SMBAUXCTL(priv)); - if (block) - ret = i801_block_transaction(priv, data, read_write, size, - hwpec); + 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_transaction(priv, xact); - - /* 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)); - - if (block) - goto out; - if (ret) - goto out; - if ((read_write == I2C_SMBUS_WRITE) || (xact == I801_QUICK)) - goto out; + ret = i801_simple_transaction(priv, data, addr, command, read_write, size); - switch (xact & 0x7f) { - case I801_BYTE: /* Result put in SMBHSTDAT0 */ - case I801_BYTE_DATA: - data->byte = inb_p(SMBHSTDAT0(priv)); - break; - case I801_WORD_DATA: - data->word = inb_p(SMBHSTDAT0(priv)) + - (inb_p(SMBHSTDAT1(priv)) << 8); - break; - } + 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 */ - outb_p(SMBHSTSTS_INUSE_STS, SMBHSTSTS(priv)); + /* + * Unlock the SMBus device for use by BIOS/ACPI, + * and clear status flags if not done already. + */ + 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,6 +943,7 @@ static u32 i801_func(struct i2c_adapter *adapter) return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_WRITE_I2C_BLOCK | ((priv->features & FEATURE_SMBUS_PEC) ? I2C_FUNC_SMBUS_PEC : 0) | ((priv->features & FEATURE_BLOCK_PROC) ? @@ -981,12 +961,16 @@ static void i801_enable_host_notify(struct i2c_adapter *adapter) if (!(priv->features & FEATURE_HOST_NOTIFY)) return; - if (!(SMBSLVCMD_HST_NTFY_INTREN & priv->original_slvcmd)) - outb_p(SMBSLVCMD_HST_NTFY_INTREN | priv->original_slvcmd, - SMBSLVCMD(priv)); + /* + * Enable host notify interrupt and block the generation of interrupt + * from the SMB_ALERT signal because the driver does not support + * SMBus Alert. + */ + 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) @@ -994,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 = { @@ -1002,72 +986,88 @@ static const struct i2c_algorithm smbus_algorithm = { .functionality = i801_func, }; +#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(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AA_3) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801AB_3) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_2) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_3) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_3) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801EB_3) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_4) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH6_16) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EP80579_1) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COUGARPOINT_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_AVOTON_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CDF_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_DNV_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_EBG_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROXTON_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS) }, - { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ALDER_LAKE_M_SMBUS) }, + { 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) @@ -1125,7 +1125,7 @@ static void dmi_check_onboard_device(u8 type, const char *name, memset(&info, 0, sizeof(struct i2c_board_info)); info.addr = dmi_devices[i].i2c_addr; - strlcpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE); + strscpy(info.type, dmi_devices[i].i2c_type, I2C_NAME_SIZE); i2c_new_client_device(adap, &info); break; } @@ -1138,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; @@ -1162,132 +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); - - *((bool *)return_value) = true; - return AE_CTRL_TERMINATE; - -smo88xx_not_found: - kfree(info); - return AE_OK; -} - -static bool is_dell_system_with_lis3lv02d(void) -{ - bool found; - const char *vendor; - - vendor = dmi_get_system_info(DMI_SYS_VENDOR); - if (!vendor || strcmp(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). - */ - found = false; - acpi_get_devices(NULL, check_acpi_smo88xx_device, NULL, - (void **)&found); - - return found; -} - -/* - * 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 }, -}; - -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; - strlcpy(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) +/* Register optional targets */ +static void i801_probe_optional_targets(struct i801_priv *priv) { - /* Only register slaves on main SMBus channel */ + /* Only register targets on main SMBus channel */ if (priv->features & FEATURE_IDF) return; @@ -1303,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, }; @@ -1331,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, }; @@ -1403,25 +1276,44 @@ 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 int i801_add_mux(struct i801_priv *priv) +static void i801_add_mux(struct i801_priv *priv) { struct device *dev = &priv->adapter.dev; 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) - return 0; - mux_config = priv->mux_drvdata; + id = dmi_first_match(mux_dmi_table); + if (!id) + return; + + 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 */ @@ -1429,16 +1321,16 @@ static int i801_add_mux(struct i801_priv *priv) struct_size(lookup, table, mux_config->n_gpios + 1), GFP_KERNEL); if (!lookup) - return -ENOMEM; + return; lookup->dev_id = "i2c-mux-gpio"; - for (i = 0; i < mux_config->n_gpios; i++) { - lookup->table[i] = (struct gpiod_lookup) - GPIO_LOOKUP(mux_config->gpio_chip, - mux_config->gpios[i], "mux", 0); - } + for (i = 0; i < mux_config->n_gpios; i++) + 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 @@ -1451,117 +1343,65 @@ static int 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; } - - return PTR_ERR_OR_ZERO(priv->mux_pdev); } 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 int i801_add_mux(struct i801_priv *priv) { return 0; } +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 const struct itco_wdt_platform_data spt_tco_platform_data = { - .name = "Intel PCH", - .version = 4, -}; - -static DEFINE_SPINLOCK(p2sb_spinlock); - 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", + .version = 4, + }; struct resource *res; - unsigned int devfn; - u64 base64_addr; - u32 base_addr; - u8 hidden; + int ret; /* * We must access the NO_REBOOT bit over the Primary to Sideband - * bridge (P2SB). The BIOS prevents the P2SB device from being - * enumerated by the PCI subsystem, so we need to unhide/hide it - * to lookup the P2SB BAR. + * (P2SB) bridge. */ - spin_lock(&p2sb_spinlock); - - devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 1); - - /* Unhide the P2SB device, if it is hidden */ - pci_bus_read_config_byte(pci_dev->bus, devfn, 0xe1, &hidden); - if (hidden) - pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, 0x0); - - pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR, &base_addr); - base64_addr = base_addr & 0xfffffff0; - - pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR + 0x4, &base_addr); - base64_addr |= (u64)base_addr << 32; - - /* Hide the P2SB device, if it was hidden before */ - if (hidden) - pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden); - spin_unlock(&p2sb_spinlock); res = &tco_res[1]; + ret = p2sb_bar(pci_dev->bus, 0, res); + if (ret) + return ERR_PTR(ret); + if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS) - res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL_DNV; + res->start += SBREG_SMBCTRL_DNV; else - res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL; + res->start += SBREG_SMBCTRL; res->end = res->start + 3; - res->flags = IORESOURCE_MEM; return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1, - tco_res, 2, &spt_tco_platform_data, - sizeof(spt_tco_platform_data)); + tco_res, 2, &pldata, sizeof(pldata)); } -static const struct itco_wdt_platform_data cnl_tco_platform_data = { - .name = "Intel PCH", - .version = 6, -}; - 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) { - return platform_device_register_resndata(&pci_dev->dev, - "iTCO_wdt", -1, tco_res, 1, &cnl_tco_platform_data, - sizeof(cnl_tco_platform_data)); + static const struct itco_wdt_platform_data pldata = { + .name = "Intel PCH", + .version = 6, + }; + + return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1, + tco_res, 1, &pldata, sizeof(pldata)); } static void i801_add_tco(struct i801_priv *priv) @@ -1593,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); } @@ -1622,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 @@ -1642,43 +1482,29 @@ 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; } static int i801_acpi_probe(struct i801_priv *priv) { - struct acpi_device *adev; + acpi_handle ah = ACPI_HANDLE(&priv->pci_dev->dev); acpi_status status; - adev = ACPI_COMPANION(&priv->pci_dev->dev); - if (adev) { - status = acpi_install_address_space_handler(adev->handle, - ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler, - NULL, priv); - if (ACPI_SUCCESS(status)) - return 0; - } + status = acpi_install_address_space_handler(ah, ACPI_ADR_SPACE_SYSTEM_IO, + i801_acpi_io_handler, NULL, priv); + if (ACPI_SUCCESS(status)) + return 0; return acpi_check_resource_conflict(&priv->pci_dev->resource[SMBBAR]); } static void i801_acpi_remove(struct i801_priv *priv) { - struct acpi_device *adev; - - adev = ACPI_COMPANION(&priv->pci_dev->dev); - if (!adev) - return; + acpi_handle ah = ACPI_HANDLE(&priv->pci_dev->dev); - acpi_remove_address_space_handler(adev->handle, - ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler); - - mutex_lock(&priv->acpi_lock); - if (priv->acpi_reserved) - pm_runtime_put(&priv->pci_dev->dev); - mutex_unlock(&priv->acpi_lock); + acpi_remove_address_space_handler(ah, ACPI_ADR_SPACE_SYSTEM_IO, i801_acpi_io_handler); } #else static inline int i801_acpi_probe(struct i801_priv *priv) { return 0; } @@ -1694,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); @@ -1705,139 +1537,74 @@ 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; - switch (dev->device) { - case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS: - case PCI_DEVICE_ID_INTEL_SUNRISEPOINT_LP_SMBUS: - case PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS: - case PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS: - case PCI_DEVICE_ID_INTEL_DNV_SMBUS: - case PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS: - case PCI_DEVICE_ID_INTEL_COMETLAKE_V_SMBUS: - priv->features |= FEATURE_BLOCK_PROC; - priv->features |= FEATURE_I2C_BLOCK_READ; - priv->features |= FEATURE_IRQ; - priv->features |= FEATURE_SMBUS_PEC; - priv->features |= FEATURE_BLOCK_BUFFER; - priv->features |= FEATURE_TCO_SPT; - priv->features |= FEATURE_HOST_NOTIFY; - break; - - case PCI_DEVICE_ID_INTEL_CANNONLAKE_H_SMBUS: - case PCI_DEVICE_ID_INTEL_CANNONLAKE_LP_SMBUS: - case PCI_DEVICE_ID_INTEL_CDF_SMBUS: - case PCI_DEVICE_ID_INTEL_ICELAKE_LP_SMBUS: - case PCI_DEVICE_ID_INTEL_COMETLAKE_SMBUS: - case PCI_DEVICE_ID_INTEL_COMETLAKE_H_SMBUS: - case PCI_DEVICE_ID_INTEL_ELKHART_LAKE_SMBUS: - case PCI_DEVICE_ID_INTEL_TIGERLAKE_LP_SMBUS: - case PCI_DEVICE_ID_INTEL_TIGERLAKE_H_SMBUS: - case PCI_DEVICE_ID_INTEL_JASPER_LAKE_SMBUS: - case PCI_DEVICE_ID_INTEL_EBG_SMBUS: - case PCI_DEVICE_ID_INTEL_ALDER_LAKE_S_SMBUS: - case PCI_DEVICE_ID_INTEL_ALDER_LAKE_P_SMBUS: - case PCI_DEVICE_ID_INTEL_ALDER_LAKE_M_SMBUS: - priv->features |= FEATURE_BLOCK_PROC; - priv->features |= FEATURE_I2C_BLOCK_READ; - priv->features |= FEATURE_IRQ; - priv->features |= FEATURE_SMBUS_PEC; - priv->features |= FEATURE_BLOCK_BUFFER; - priv->features |= FEATURE_TCO_CNL; - priv->features |= FEATURE_HOST_NOTIFY; - break; - - case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF0: - case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF1: - case PCI_DEVICE_ID_INTEL_PATSBURG_SMBUS_IDF2: - case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0: - case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1: - case PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2: - priv->features |= FEATURE_IDF; - fallthrough; - default: - priv->features |= FEATURE_BLOCK_PROC; - priv->features |= FEATURE_I2C_BLOCK_READ; - priv->features |= FEATURE_IRQ; - fallthrough; - case PCI_DEVICE_ID_INTEL_82801DB_3: - priv->features |= FEATURE_SMBUS_PEC; - priv->features |= FEATURE_BLOCK_BUFFER; - fallthrough; - case PCI_DEVICE_ID_INTEL_82801CA_3: - priv->features |= FEATURE_HOST_NOTIFY; - fallthrough; - case PCI_DEVICE_ID_INTEL_82801BA_2: - case PCI_DEVICE_ID_INTEL_82801AB_3: - case PCI_DEVICE_ID_INTEL_82801AA_3: - break; - } + priv->features = id->driver_data; /* 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 Host Notify setting */ - 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; @@ -1845,19 +1612,12 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) priv->features &= ~FEATURE_IRQ; if (priv->features & FEATURE_IRQ) { - u16 pcictl, pcists; + u16 pcists; /* 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"); - - /* Check if interrupts have been disabled */ - pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pcictl); - if (pcictl & PCI_COMMAND_INTX_DISABLE) { - dev_info(&dev->dev, "Interrupts are disabled\n"); - priv->features &= ~FEATURE_IRQ; - } + pci_warn(dev, "An interrupt is pending!\n"); } if (priv->features & FEATURE_IRQ) { @@ -1866,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); @@ -1905,17 +1682,19 @@ static void i801_remove(struct pci_dev *dev) { struct i801_priv *priv = pci_get_drvdata(dev); - pm_runtime_forbid(&dev->dev); - pm_runtime_get_noresume(&dev->dev); - 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); + /* if acpi_reserved is set then usage_count is incremented already */ + 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) @@ -1926,17 +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 */ 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); - pci_write_config_byte(priv->pci_dev, SMBHSTCFG, priv->original_hstcfg); + i2c_mark_adapter_suspended(&priv->adapter); + i801_restore_regs(priv); + return 0; } @@ -1946,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, @@ -1960,20 +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>"); @@ -1981,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 9f71daf6db64..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); @@ -738,9 +730,9 @@ static int iic_probe(struct platform_device *ofdev) adap = &dev->adap; adap->dev.parent = &ofdev->dev; adap->dev.of_node = of_node_get(np); - strlcpy(adap->name, "IBM IIC", sizeof(adap->name)); + 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-icy.c b/drivers/i2c/busses/i2c-icy.c index 5dae7cab7260..febcb6f01d4d 100644 --- a/drivers/i2c/busses/i2c-icy.c +++ b/drivers/i2c/busses/i2c-icy.c @@ -141,7 +141,7 @@ static int icy_probe(struct zorro_dev *z, i2c->adapter.owner = THIS_MODULE; /* i2c->adapter.algo assigned by i2c_pcf_add_bus() */ i2c->adapter.algo_data = algo_data; - strlcpy(i2c->adapter.name, "ICY I2C Zorro adapter", + strscpy(i2c->adapter.name, "ICY I2C Zorro adapter", sizeof(i2c->adapter.name)); if (!devm_request_mem_region(&z->dev, 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 8b9ba055c418..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,13 +148,33 @@ 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; - struct clk *clk; + int num_clks; + struct clk_bulk_data *clks; void __iomem *base; __u8 *rx_buf; __u8 *tx_buf; struct completion complete; + unsigned long rate_per; unsigned int msglen; unsigned int delivered; unsigned int block_data; @@ -106,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; @@ -161,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; @@ -173,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->clk); + clk_rate = lpi2c_imx->rate_per; + if (lpi2c_imx->mode == HS || lpi2c_imx->mode == ULTRA_FAST) filt = 0; else @@ -216,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; @@ -278,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; @@ -292,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; } @@ -350,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; @@ -365,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; @@ -396,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 */ @@ -415,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, @@ -423,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; @@ -438,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); + + 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 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); - lpi2c_imx_intctrl(lpi2c_imx, MIER_RDIE | MIER_NDIE); + 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(struct i2c_adapter *adapter, - struct i2c_msg *msgs, int num) +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; @@ -454,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; @@ -462,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) @@ -499,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 | @@ -526,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; @@ -546,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); @@ -558,35 +1392,45 @@ static int lpi2c_imx_probe(struct platform_device *pdev) lpi2c_imx->adapter.algo = &lpi2c_imx_algo; lpi2c_imx->adapter.dev.parent = &pdev->dev; lpi2c_imx->adapter.dev.of_node = pdev->dev.of_node; - strlcpy(lpi2c_imx->adapter.name, pdev->name, + strscpy(lpi2c_imx->adapter.name, pdev->name, sizeof(lpi2c_imx->adapter.name)); + phy_addr = (dma_addr_t)res->start; - lpi2c_imx->clk = devm_clk_get(&pdev->dev, NULL); - if (IS_ERR(lpi2c_imx->clk)) { - dev_err(&pdev->dev, "can't get I2C peripheral clock\n"); - return PTR_ERR(lpi2c_imx->clk); - } + ret = devm_clk_bulk_get_all(&pdev->dev, &lpi2c_imx->clks); + 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, "clock-frequency", &lpi2c_imx->bitrate); 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); - ret = clk_prepare_enable(lpi2c_imx->clk); - if (ret) { - dev_err(&pdev->dev, "clk enable failed %d\n", ret); + ret = clk_bulk_prepare_enable(lpi2c_imx->num_clks, lpi2c_imx->clks); + 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); @@ -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_disable_unprepare(lpi2c_imx->clk); + 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_prepare_enable(lpi2c_imx->clk); + 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 d5b5f084a27d..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> @@ -37,9 +38,10 @@ #include <linux/io.h> #include <linux/iopoll.h> #include <linux/kernel.h> +#include <linux/spinlock.h> +#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> @@ -51,6 +53,8 @@ /* This will be the driver name the kernel reports */ #define DRIVER_NAME "imx-i2c" +#define I2C_IMX_CHECK_DELAY 30000 /* Time to check for bus idle, in NS */ + /* * Enable DMA if transfer byte size is bigger than this threshold. * As the hardware request, it must bigger than 4 bytes.\ @@ -62,7 +66,7 @@ /* IMX I2C registers: * the I2C register offset is different between SoCs, - * to provid support for all these chips, split the + * to provide support for all these chips, split the * register offset into a fixed base address and a * variable shift value, then the full register offset * will be calculated by @@ -81,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 @@ -162,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, }; @@ -175,6 +205,12 @@ struct imx_i2c_hwdata { unsigned int ndivs; unsigned int i2sr_clr_opcode; unsigned int i2cr_ien_opcode; + /* + * Errata ERR007805 or e7805: + * I2C: When the I2C clock speed is configured for 400 kHz, + * the SCL low period violates the I2C spec of 1.3 uS min. + */ + bool has_err007805; }; struct imx_i2c_dma { @@ -188,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; @@ -203,13 +250,21 @@ 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; }; static const struct imx_i2c_hwdata imx1_i2c_hwdata = { @@ -232,6 +287,16 @@ static const struct imx_i2c_hwdata imx21_i2c_hwdata = { }; +static const struct imx_i2c_hwdata imx6_i2c_hwdata = { + .devtype = IMX21_I2C, + .regshift = IMX_I2C_REGSHIFT, + .clk_div = imx_i2c_clk_div, + .ndivs = ARRAY_SIZE(imx_i2c_clk_div), + .i2sr_clr_opcode = I2SR_CLR_OPCODE_W0C, + .i2cr_ien_opcode = I2CR_IEN_OPCODE_1, + .has_err007805 = true, +}; + static struct imx_i2c_hwdata vf610_i2c_hwdata = { .devtype = VF610_I2C, .regshift = VF610_I2C_REGSHIFT, @@ -239,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[] = { @@ -258,7 +331,19 @@ MODULE_DEVICE_TABLE(platform, imx_i2c_devtype); static const struct of_device_id i2c_imx_dt_ids[] = { { .compatible = "fsl,imx1-i2c", .data = &imx1_i2c_hwdata, }, { .compatible = "fsl,imx21-i2c", .data = &imx21_i2c_hwdata, }, + { .compatible = "fsl,imx6q-i2c", .data = &imx6_i2c_hwdata, }, + { .compatible = "fsl,imx6sl-i2c", .data = &imx6_i2c_hwdata, }, + { .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); @@ -313,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)) { @@ -368,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); @@ -376,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) @@ -423,7 +509,7 @@ static int i2c_imx_dma_xfer(struct imx_i2c_struct *i2c_imx, return 0; err_submit: - dmaengine_terminate_all(dma->chan_using); + dmaengine_terminate_sync(dma->chan_using); err_desc: dma_unmap_single(chan_dev, dma->dma_buf, dma->dma_len, dma->dma_data_dir); @@ -449,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; @@ -456,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; } @@ -511,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); @@ -536,16 +623,27 @@ 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; int i; + if (i2c_imx->hwdata->has_err007805 && i2c_imx->bitrate > 384000) { + dev_dbg(&i2c_imx->adapter.dev, + "SoC errata ERR007805 or e7805 applies, bus frequency limited from %d Hz to 384000 Hz.\n", + i2c_imx->bitrate); + i2c_imx->bitrate = 384000; + } + /* 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; @@ -576,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, @@ -585,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) @@ -651,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); } @@ -680,7 +781,7 @@ static void i2c_imx_slave_event(struct imx_i2c_struct *i2c_imx, static void i2c_imx_slave_finish_op(struct imx_i2c_struct *i2c_imx) { - u8 val; + u8 val = 0; while (i2c_imx->last_slave_event != I2C_SLAVE_STOP) { switch (i2c_imx->last_slave_event) { @@ -701,10 +802,11 @@ static void i2c_imx_slave_finish_op(struct imx_i2c_struct *i2c_imx) } } -static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx, - unsigned int status, unsigned int ctl) +/* Returns true if the timer should be restarted, false if not. */ +static irqreturn_t i2c_imx_slave_handle(struct imx_i2c_struct *i2c_imx, + unsigned int status, unsigned int ctl) { - u8 value; + u8 value = 0; if (status & I2SR_IAL) { /* Arbitration lost */ i2c_imx_clear_irq(i2c_imx, I2SR_IAL); @@ -712,6 +814,16 @@ static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx, return IRQ_HANDLED; } + if (!(status & I2SR_IBB)) { + /* No master on the bus, that could mean a stop condition. */ + i2c_imx_slave_finish_op(i2c_imx); + return IRQ_HANDLED; + } + + if (!(status & I2SR_ICF)) + /* Data transfer still in progress, ignore this. */ + goto out; + if (status & I2SR_IAAS) { /* Addressed as a slave */ i2c_imx_slave_finish_op(i2c_imx); if (status & I2SR_SRW) { /* Master wants to read from us*/ @@ -737,16 +849,9 @@ static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx, imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); } } else if (!(ctl & I2CR_MTX)) { /* Receive mode */ - if (status & I2SR_IBB) { /* No STOP signal detected */ - value = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); - i2c_imx_slave_event(i2c_imx, - I2C_SLAVE_WRITE_RECEIVED, &value); - } else { /* STOP signal is detected */ - dev_dbg(&i2c_imx->adapter.dev, - "STOP signal detected"); - i2c_imx_slave_event(i2c_imx, - I2C_SLAVE_STOP, &value); - } + value = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2DR); + i2c_imx_slave_event(i2c_imx, + I2C_SLAVE_WRITE_RECEIVED, &value); } else if (!(status & I2SR_RXAK)) { /* Transmit mode received ACK */ ctl |= I2CR_MTX; imx_i2c_write_reg(ctl, i2c_imx, IMX_I2C_I2CR); @@ -755,15 +860,48 @@ static irqreturn_t i2c_imx_slave_isr(struct imx_i2c_struct *i2c_imx, I2C_SLAVE_READ_PROCESSED, &value); imx_i2c_write_reg(value, i2c_imx, IMX_I2C_I2DR); - } else { /* Transmit mode received NAK */ + } else { /* Transmit mode received NAK, operation is done */ 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; } +out: + /* + * No need to check the return value here. If it returns 0 or + * 1, then everything is fine. If it returns -1, then the + * timer is running in the handler. This will still work, + * though it may be redone (or already have been done) by the + * timer function. + */ + hrtimer_try_to_cancel(&i2c_imx->slave_timer); + hrtimer_forward_now(&i2c_imx->slave_timer, I2C_IMX_CHECK_DELAY); + hrtimer_restart(&i2c_imx->slave_timer); return IRQ_HANDLED; } +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; + + 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); + + return HRTIMER_NORESTART; +} + static void i2c_imx_slave_init(struct imx_i2c_struct *i2c_imx) { int temp; @@ -830,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; } @@ -844,23 +1128,25 @@ static irqreturn_t i2c_imx_isr(int irq, void *dev_id) struct imx_i2c_struct *i2c_imx = dev_id; unsigned int ctl, status; - 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)) { - return i2c_imx_slave_isr(i2c_imx, status, ctl); - } else if (i2c_imx->last_slave_event != - I2C_SLAVE_STOP) { - i2c_imx_slave_finish_op(i2c_imx); - } + if (!(ctl & I2CR_MSTA)) + return i2c_imx_slave_handle(i2c_imx, + status, ctl); + + i2c_imx_slave_finish_op(i2c_imx); } - return i2c_imx_master_isr(i2c_imx, status); } - return IRQ_NONE; + return i2c_imx_master_isr(i2c_imx, status); } static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, @@ -873,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; @@ -894,7 +1182,7 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx, &i2c_imx->dma->cmd_complete, msecs_to_jiffies(DMA_TIMEOUT)); if (time_left == 0) { - dmaengine_terminate_all(dma->chan_using); + dmaengine_terminate_sync(dma->chan_using); return -ETIMEDOUT; } @@ -925,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) { @@ -935,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; @@ -949,7 +1280,7 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx, &i2c_imx->dma->cmd_complete, msecs_to_jiffies(DMA_TIMEOUT)); if (time_left == 0) { - dmaengine_terminate_all(dma->chan_using); + dmaengine_terminate_sync(dma->chan_using); return -ETIMEDOUT; } @@ -1011,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; @@ -1021,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); @@ -1035,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); @@ -1045,54 +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->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; /* @@ -1123,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: @@ -1154,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) { @@ -1161,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); @@ -1213,14 +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) + 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; @@ -1252,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; @@ -1275,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 @@ -1303,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); - } + struct i2c_bus_recovery_info *bri = &i2c_imx->rinfo; - 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; - } + bri->pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR(bri->pinctrl)) + return PTR_ERR(bri->pinctrl); - dev_dbg(&pdev->dev, "using scl%s for recovery\n", - rinfo->sda_gpiod ? ",sda" : ""); - - 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; } @@ -1347,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) @@ -1366,18 +1706,21 @@ 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"); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - base = devm_ioremap_resource(&pdev->dev, res); + 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); if (!i2c_imx) return -ENOMEM; + spin_lock_init(&i2c_imx->slave_lock); + hrtimer_setup(&i2c_imx->slave_timer, i2c_imx_slave_timeout, CLOCK_MONOTONIC, + HRTIMER_MODE_ABS); + match = device_get_match_data(&pdev->dev); if (match) i2c_imx->hwdata = match; @@ -1396,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); @@ -1426,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, @@ -1441,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); @@ -1451,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); @@ -1465,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: @@ -1478,18 +1839,17 @@ 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; - ret = pm_runtime_resume_and_get(&pdev->dev); - if (ret < 0) - return ret; + ret = pm_runtime_get_sync(&pdev->dev); + + hrtimer_cancel(&i2c_imx->slave_timer); /* remove adapter */ dev_dbg(&i2c_imx->adapter.dev, "adapter removed\n"); @@ -1498,38 +1858,40 @@ static int i2c_imx_remove(struct platform_device *pdev) if (i2c_imx->dma) i2c_imx_dma_free(i2c_imx); - /* setup chip registers to defaults */ - imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR); - 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); + if (ret >= 0) { + /* setup chip registers to defaults */ + imx_i2c_write_reg(0, i2c_imx, IMX_I2C_IADR); + 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_notifier_unregister(i2c_imx->clk, &i2c_imx->clk_change_nb); irq = platform_get_irq(pdev, 0); if (irq >= 0) free_irq(irq, i2c_imx); - clk_disable_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); @@ -1537,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 = { @@ -1547,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 cfecaf18ccbb..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 @@ -469,20 +464,18 @@ iop3xx_i2c_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - ret = -ENXIO; + ret = irq; goto unmap; } ret = request_irq(irq, iop3xx_i2c_irq_handler, 0, pdev->name, adapter_data); - if (ret) { - ret = -EIO; + if (ret) goto unmap; - } 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 a6187cbec2c9..7aaefb21416a 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -82,6 +82,7 @@ #define ISMT_DESC_ENTRIES 2 /* number of descriptor entries */ #define ISMT_MAX_RETRIES 3 /* number of SMBus retries to attempt */ +#define ISMT_LOG_ENTRIES 3 /* number of interrupt cause log entries */ /* Hardware Descriptor Constants - Control Field */ #define ISMT_DESC_CWRL 0x01 /* Command/Write Length */ @@ -145,8 +146,8 @@ #define ISMT_SPGT_SPD_MASK 0xc0000000 /* SMBus Speed mask */ #define ISMT_SPGT_SPD_80K 0x00 /* 80 kHz */ #define ISMT_SPGT_SPD_100K (0x1 << 30) /* 100 kHz */ -#define ISMT_SPGT_SPD_400K (0x2 << 30) /* 400 kHz */ -#define ISMT_SPGT_SPD_1M (0x3 << 30) /* 1 MHz */ +#define ISMT_SPGT_SPD_400K (0x2U << 30) /* 400 kHz */ +#define ISMT_SPGT_SPD_1M (0x3U << 30) /* 1 MHz */ /* MSI Control Register (MSICTL) bit definitions */ @@ -175,6 +176,8 @@ struct ismt_priv { u8 head; /* ring buffer head pointer */ struct completion cmp; /* interrupt completion */ u8 buffer[I2C_SMBUS_BLOCK_MAX + 16]; /* temp R/W data buffer */ + dma_addr_t log_dma; + u32 *log; }; static const struct pci_device_id ismt_ids[] = { @@ -379,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 @@ -411,6 +423,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, memset(desc, 0, sizeof(struct ismt_desc)); desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, read_write); + /* Always clear the log entries */ + memset(priv->log, 0, ISMT_LOG_ENTRIES * sizeof(u32)); + /* Initialize common control bits */ if (likely(pci_dev_msi_enabled(priv->pci_dev))) desc->control = ISMT_DESC_INT | ISMT_DESC_FAIR; @@ -503,6 +518,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, if (read_write == I2C_SMBUS_WRITE) { /* Block Write */ dev_dbg(dev, "I2C_SMBUS_BLOCK_DATA: WRITE\n"); + if (data->block[0] < 1 || data->block[0] > I2C_SMBUS_BLOCK_MAX) + return -EINVAL; + dma_size = data->block[0] + 1; dma_direction = DMA_TO_DEVICE; desc->wr_len_cmd = dma_size; @@ -522,6 +540,9 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr, case I2C_SMBUS_BLOCK_PROC_CALL: dev_dbg(dev, "I2C_SMBUS_BLOCK_PROC_CALL\n"); + if (data->block[0] > I2C_SMBUS_BLOCK_MAX) + return -EINVAL; + dma_size = I2C_SMBUS_BLOCK_MAX; desc->tgtaddr_rw = ISMT_DESC_ADDR_RW(addr, 1); desc->wr_len_cmd = data->block[0] + 1; @@ -611,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; } @@ -708,6 +729,8 @@ static void ismt_hw_init(struct ismt_priv *priv) /* initialize the Master Descriptor Base Address (MDBA) */ writeq(priv->io_rng_dma, priv->smba + ISMT_MSTR_MDBA); + writeq(priv->log_dma, priv->smba + ISMT_GR_SMTICL); + /* initialize the Master Control Register (MCTRL) */ writel(ISMT_MCTRL_MEIE, priv->smba + ISMT_MSTR_MCTRL); @@ -795,6 +818,12 @@ static int ismt_dev_init(struct ismt_priv *priv) priv->head = 0; init_completion(&priv->cmp); + priv->log = dmam_alloc_coherent(&priv->pci_dev->dev, + ISMT_LOG_ENTRIES * sizeof(u32), + &priv->log_dma, GFP_KERNEL); + if (!priv->log) + return -ENOMEM; + return 0; } @@ -904,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", @@ -918,15 +947,10 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id) return -ENODEV; } - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) || - (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0)) { - if ((pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) || - (pci_set_consistent_dma_mask(pdev, - DMA_BIT_MASK(32)) != 0)) { - dev_err(&pdev->dev, "pci_set_dma_mask fail %p\n", - pdev); - return -ENODEV; - } + err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (err) { + dev_err(&pdev->dev, "dma_set_mask fail\n"); + return -ENODEV; } err = ismt_dev_init(priv); 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 2d60be086b1a..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,14 +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, + .class = I2C_CLASS_HWMON | I2C_CLASS_DEPRECATED, .algo = &kempld_i2c_algorithm, }; @@ -302,6 +302,7 @@ static int kempld_i2c_probe(struct platform_device *pdev) i2c->dev = &pdev->dev; i2c->adap = kempld_i2c_adapter; i2c->adap.dev.parent = i2c->dev; + ACPI_COMPANION_SET(&i2c->adap.dev, ACPI_COMPANION(&pdev->dev)); i2c_set_adapdata(&i2c->adap, i2c); platform_set_drvdata(pdev, i2c); @@ -327,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; @@ -346,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; @@ -366,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); @@ -377,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 4e30c5267142..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 */ @@ -417,35 +409,27 @@ static int i2c_lpc2k_probe(struct platform_device *pdev) i2c_set_adapdata(&i2c->adap, i2c); i2c->adap.owner = THIS_MODULE; - strlcpy(i2c->adap.name, "LPC2K I2C adapter", sizeof(i2c->adap.name)); + strscpy(i2c->adap.name, "LPC2K I2C adapter", sizeof(i2c->adap.name)); i2c->adap.algo = &i2c_lpc2k_algorithm; i2c->adap.dev.parent = &pdev->dev; i2c->adap.dev.of_node = pdev->dev.of_node; 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 new file mode 100644 index 000000000000..bc0f1a0c8ee1 --- /dev/null +++ b/drivers/i2c/busses/i2c-mchp-pci1xxxx.c @@ -0,0 +1,1212 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip PCI1XXXX I2C adapter driver for PCIe Switch + * which has I2C controller in one of its downstream functions + * + * Copyright (C) 2021 - 2022 Microchip Technology Inc. + * + * Authors: Tharun Kumar P <tharunkumar.pasumarthi@microchip.com> + * Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com> + */ + +#include <linux/bits.h> +#include <linux/delay.h> +#include <linux/i2c.h> +#include <linux/i2c-smbus.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/types.h> + +#define SMBUS_MAST_CORE_ADDR_BASE 0x00000 +#define SMBUS_MAST_SYS_REG_ADDR_BASE 0x01000 + +/* SMB register space. */ +#define SMB_CORE_CTRL_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x00) + +#define SMB_CORE_CTRL_ESO BIT(6) +#define SMB_CORE_CTRL_FW_ACK BIT(4) +#define SMB_CORE_CTRL_ACK BIT(0) + +#define SMB_CORE_CMD_REG_OFF3 (SMBUS_MAST_CORE_ADDR_BASE + 0x0F) +#define SMB_CORE_CMD_REG_OFF2 (SMBUS_MAST_CORE_ADDR_BASE + 0x0E) +#define SMB_CORE_CMD_REG_OFF1 (SMBUS_MAST_CORE_ADDR_BASE + 0x0D) + +#define SMB_CORE_CMD_READM BIT(4) +#define SMB_CORE_CMD_STOP BIT(2) +#define SMB_CORE_CMD_START BIT(0) + +#define SMB_CORE_CMD_REG_OFF0 (SMBUS_MAST_CORE_ADDR_BASE + 0x0C) + +#define SMB_CORE_CMD_M_PROCEED BIT(1) +#define SMB_CORE_CMD_M_RUN BIT(0) + +#define SMB_CORE_SR_HOLD_TIME_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x18) + +/* + * 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 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) + +#define COMPLETION_MDONE BIT(6) +#define COMPLETION_IDLE BIT(5) +#define COMPLETION_MNAKX BIT(0) + +#define SMB_CORE_IDLE_SCALING_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x24) + +/* + * FAIR_BUS_IDLE_MIN_XK_TICKS field will indicate the number of ticks of + * 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 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 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) +#define SMB_IDLE_SCALING_400K \ + ((FAIR_IDLE_DELAY_400K_TICKS << 16) | FAIR_BUS_IDLE_MIN_400K_TICKS) +#define SMB_IDLE_SCALING_1000K \ + ((FAIR_IDLE_DELAY_1000K_TICKS << 16) | FAIR_BUS_IDLE_MIN_1000K_TICKS) + +#define SMB_CORE_CONFIG_REG3 (SMBUS_MAST_CORE_ADDR_BASE + 0x2B) + +#define SMB_CONFIG3_ENMI BIT(6) +#define SMB_CONFIG3_ENIDI BIT(5) + +#define SMB_CORE_CONFIG_REG2 (SMBUS_MAST_CORE_ADDR_BASE + 0x2A) +#define SMB_CORE_CONFIG_REG1 (SMBUS_MAST_CORE_ADDR_BASE + 0x29) + +#define SMB_CONFIG1_ASR BIT(7) +#define SMB_CONFIG1_ENAB BIT(2) +#define SMB_CONFIG1_RESET BIT(1) +#define SMB_CONFIG1_FEN BIT(0) + +#define SMB_CORE_BUS_CLK_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x2C) + +/* + * BUS_CLK_XK_LOW_PERIOD_TICKS field defines the number of I2C Baud Clock + * periods that make up the low phase of the I2C/SMBus bus clock at X KHz. + */ +#define BUS_CLK_100K_LOW_PERIOD_TICKS 156 +#define BUS_CLK_400K_LOW_PERIOD_TICKS 41 +#define BUS_CLK_1000K_LOW_PERIOD_TICKS 15 + +/* + * BUS_CLK_XK_HIGH_PERIOD_TICKS field defines the number of I2C Baud Clock + * periods that make up the high phase of the I2C/SMBus bus clock at X KHz. + */ +#define BUS_CLK_100K_HIGH_PERIOD_TICKS 154 +#define BUS_CLK_400K_HIGH_PERIOD_TICKS 35 +#define BUS_CLK_1000K_HIGH_PERIOD_TICKS 14 + +#define BUS_CLK_100K \ + ((BUS_CLK_100K_HIGH_PERIOD_TICKS << 8) | BUS_CLK_100K_LOW_PERIOD_TICKS) +#define BUS_CLK_400K \ + ((BUS_CLK_400K_HIGH_PERIOD_TICKS << 8) | BUS_CLK_400K_LOW_PERIOD_TICKS) +#define BUS_CLK_1000K \ + ((BUS_CLK_1000K_HIGH_PERIOD_TICKS << 8) | BUS_CLK_1000K_LOW_PERIOD_TICKS) + +#define SMB_CORE_CLK_SYNC_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x3C) + +/* + * CLK_SYNC_XK defines the number of clock cycles to sync up to the external + * clock before comparing the internal and external clocks for clock stretching + * at X KHz. + */ +#define CLK_SYNC_100K 4 +#define CLK_SYNC_400K 4 +#define CLK_SYNC_1000K 4 + +#define SMB_CORE_DATA_TIMING_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x40) + +/* + * + * FIRST_START_HOLD_XK_TICKS will indicate the number of ticks of the baud + * clock required to program 'FIRST_START_HOLD' timer at X KHz. This timer + * determines the SCLK hold time following SDAT driven low during the first + * START bit in a transfer. + */ +#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 150 +#define STOP_SETUP_400K_TICKS 20 +#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 156 +#define RESTART_SETUP_400K_TICKS 20 +#define RESTART_SETUP_1000K_TICKS 12 + +/* + * DATA_HOLD_XK_TICKS will indicate the number of ticks of the baud clock + * 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 12 +#define DATA_HOLD_400K_TICKS 2 +#define DATA_HOLD_1000K_TICKS 2 + +#define DATA_TIMING_100K \ + ((FIRST_START_HOLD_100K_TICKS << 24) | (STOP_SETUP_100K_TICKS << 16) | \ + (RESTART_SETUP_100K_TICKS << 8) | DATA_HOLD_100K_TICKS) +#define DATA_TIMING_400K \ + ((FIRST_START_HOLD_400K_TICKS << 24) | (STOP_SETUP_400K_TICKS << 16) | \ + (RESTART_SETUP_400K_TICKS << 8) | DATA_HOLD_400K_TICKS) +#define DATA_TIMING_1000K \ + ((FIRST_START_HOLD_1000K_TICKS << 24) | (STOP_SETUP_1000K_TICKS << 16) | \ + (RESTART_SETUP_1000K_TICKS << 8) | DATA_HOLD_1000K_TICKS) + +#define SMB_CORE_TO_SCALING_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x44) + +/* + * BUS_IDLE_MIN_XK_TICKS defines Bus Idle Minimum Time. + * 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 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 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 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 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) | \ + (TARGET_CUM_TIME_OUT_100K_TICKS << 8) | CLOCK_HIGH_TIME_OUT_100K_TICKS) +#define TO_SCALING_400K \ + ((BUS_IDLE_MIN_400K_TICKS << 24) | (CTRL_CUM_TIME_OUT_400K_TICKS << 16) | \ + (TARGET_CUM_TIME_OUT_400K_TICKS << 8) | CLOCK_HIGH_TIME_OUT_400K_TICKS) +#define TO_SCALING_1000K \ + ((BUS_IDLE_MIN_1000K_TICKS << 24) | (CTRL_CUM_TIME_OUT_1000K_TICKS << 16) | \ + (TARGET_CUM_TIME_OUT_1000K_TICKS << 8) | CLOCK_HIGH_TIME_OUT_1000K_TICKS) + +#define I2C_SCL_PAD_CTRL_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x100) +#define I2C_SDA_PAD_CTRL_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x101) + +#define I2C_FOD_EN BIT(4) +#define I2C_PULL_UP_EN BIT(3) +#define I2C_PULL_DOWN_EN BIT(2) +#define I2C_INPUT_EN BIT(1) +#define I2C_OUTPUT_EN BIT(0) + +#define SMBUS_CONTROL_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x200) + +#define CTL_RESET_COUNTERS BIT(3) +#define CTL_TRANSFER_DIR BIT(2) +#define CTL_HOST_FIFO_ENTRY BIT(1) +#define CTL_RUN BIT(0) + +#define I2C_DIRN_WRITE 0 +#define I2C_DIRN_READ 1 + +#define SMBUS_STATUS_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x204) + +#define STA_DMA_TERM BIT(7) +#define STA_DMA_REQ BIT(6) +#define STA_THRESHOLD BIT(2) +#define STA_BUF_FULL BIT(1) +#define STA_BUF_EMPTY BIT(0) + +#define SMBUS_INTR_STAT_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x208) + +#define INTR_STAT_DMA_TERM BIT(7) +#define INTR_STAT_THRESHOLD BIT(2) +#define INTR_STAT_BUF_FULL BIT(1) +#define INTR_STAT_BUF_EMPTY BIT(0) + +#define SMBUS_INTR_MSK_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x20C) + +#define INTR_MSK_DMA_TERM BIT(7) +#define INTR_MSK_THRESHOLD BIT(2) +#define INTR_MSK_BUF_FULL BIT(1) +#define INTR_MSK_BUF_EMPTY BIT(0) + +#define ALL_NW_LAYER_INTERRUPTS \ + (INTR_MSK_DMA_TERM | INTR_MSK_THRESHOLD | INTR_MSK_BUF_FULL | \ + INTR_MSK_BUF_EMPTY) + +#define SMBUS_MCU_COUNTER_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x214) + +#define SMBALERT_MST_PAD_CTRL_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x230) + +#define SMBALERT_MST_PU BIT(0) + +#define SMBUS_GEN_INT_STAT_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x23C) + +#define SMBUS_GEN_INT_MASK_REG_OFF (SMBUS_MAST_CORE_ADDR_BASE + 0x240) + +#define SMBALERT_INTR_MASK BIT(10) +#define I2C_BUF_MSTR_INTR_MASK BIT(9) +#define I2C_INTR_MASK BIT(8) +#define SMBALERT_WAKE_INTR_MASK BIT(2) +#define I2C_BUF_MSTR_WAKE_INTR_MASK BIT(1) +#define I2C_WAKE_INTR_MASK BIT(0) + +#define ALL_HIGH_LAYER_INTR \ + (SMBALERT_INTR_MASK | I2C_BUF_MSTR_INTR_MASK | I2C_INTR_MASK | \ + SMBALERT_WAKE_INTR_MASK | I2C_BUF_MSTR_WAKE_INTR_MASK | \ + I2C_WAKE_INTR_MASK) + +#define SMBUS_RESET_REG (SMBUS_MAST_CORE_ADDR_BASE + 0x248) + +#define PERI_SMBUS_D3_RESET_DIS BIT(16) + +#define SMBUS_MST_BUF (SMBUS_MAST_CORE_ADDR_BASE + 0x280) + +#define SMBUS_BUF_MAX_SIZE 0x80 + +#define I2C_FLAGS_DIRECT_MODE BIT(7) +#define I2C_FLAGS_POLLING_MODE BIT(6) +#define I2C_FLAGS_STOP BIT(5) +#define I2C_FLAGS_SMB_BLK_READ BIT(4) + +#define PCI1XXXX_I2C_TIMEOUT_MS 1000 + +/* General Purpose Register. */ +#define SMB_GPR_REG (SMBUS_MAST_CORE_ADDR_BASE + 0x1000 + 0x0c00 + \ + 0x00) + +/* Lock Register. */ +#define SMB_GPR_LOCK_REG (SMBUS_MAST_CORE_ADDR_BASE + 0x1000 + 0x0000 + \ + 0x00A0) + +#define SMBUS_PERI_LOCK BIT(3) + +struct pci1xxxx_i2c { + struct completion i2c_xfer_done; + bool i2c_xfer_in_progress; + struct i2c_adapter adap; + void __iomem *i2c_base; + u32 freq; + u32 flags; +}; + +static int set_sys_lock(struct pci1xxxx_i2c *i2c) +{ + void __iomem *p = i2c->i2c_base + SMB_GPR_LOCK_REG; + u8 data; + + writel(SMBUS_PERI_LOCK, p); + data = readl(p); + if (data != SMBUS_PERI_LOCK) + return -EPERM; + + return 0; +} + +static int release_sys_lock(struct pci1xxxx_i2c *i2c) +{ + void __iomem *p = i2c->i2c_base + SMB_GPR_LOCK_REG; + u8 data; + + data = readl(p); + if (data != SMBUS_PERI_LOCK) + return 0; + + writel(0, p); + data = readl(p); + if (data & SMBUS_PERI_LOCK) + return -EPERM; + + return 0; +} + +static void pci1xxxx_ack_high_level_intr(struct pci1xxxx_i2c *i2c, u16 intr_msk) +{ + writew(intr_msk, i2c->i2c_base + SMBUS_GEN_INT_STAT_REG_OFF); +} + +static void pci1xxxx_i2c_configure_smbalert_pin(struct pci1xxxx_i2c *i2c, + bool enable) +{ + void __iomem *p = i2c->i2c_base + SMBALERT_MST_PAD_CTRL_REG_OFF; + u8 regval; + + regval = readb(p); + + if (enable) + regval |= SMBALERT_MST_PU; + else + regval &= ~SMBALERT_MST_PU; + + writeb(regval, p); +} + +static void pci1xxxx_i2c_send_start_stop(struct pci1xxxx_i2c *i2c, bool start) +{ + void __iomem *p = i2c->i2c_base + SMB_CORE_CMD_REG_OFF1; + u8 regval; + + regval = readb(p); + + if (start) + regval |= SMB_CORE_CMD_START; + else + regval |= SMB_CORE_CMD_STOP; + + writeb(regval, p); +} + +/* + * When accessing the core control reg, we should not do a read modified write + * as they are write '1' to clear bits. Instead we need to write with the + * specific bits that needs to be set. + */ +static void pci1xxxx_i2c_set_clear_FW_ACK(struct pci1xxxx_i2c *i2c, bool set) +{ + u8 regval; + + if (set) + regval = SMB_CORE_CTRL_FW_ACK | SMB_CORE_CTRL_ESO | SMB_CORE_CTRL_ACK; + else + regval = SMB_CORE_CTRL_ESO | SMB_CORE_CTRL_ACK; + + writeb(regval, i2c->i2c_base + SMB_CORE_CTRL_REG_OFF); +} + +static void pci1xxxx_i2c_buffer_write(struct pci1xxxx_i2c *i2c, u8 slaveaddr, + u8 transferlen, unsigned char *buf) +{ + void __iomem *p = i2c->i2c_base + SMBUS_MST_BUF; + + if (slaveaddr) + writeb(slaveaddr, p++); + + if (buf) + memcpy_toio(p, buf, transferlen); +} + +/* + * When accessing the core control reg, we should not do a read modified write + * as there are write '1' to clear bits. Instead we need to write with the + * specific bits that needs to be set. + */ +static void pci1xxxx_i2c_enable_ESO(struct pci1xxxx_i2c *i2c) +{ + writeb(SMB_CORE_CTRL_ESO, i2c->i2c_base + SMB_CORE_CTRL_REG_OFF); +} + +static void pci1xxxx_i2c_reset_counters(struct pci1xxxx_i2c *i2c) +{ + void __iomem *p = i2c->i2c_base + SMBUS_CONTROL_REG_OFF; + u8 regval; + + regval = readb(p); + regval |= CTL_RESET_COUNTERS; + writeb(regval, p); +} + +static void pci1xxxx_i2c_set_transfer_dir(struct pci1xxxx_i2c *i2c, u8 direction) +{ + void __iomem *p = i2c->i2c_base + SMBUS_CONTROL_REG_OFF; + u8 regval; + + regval = readb(p); + if (direction == I2C_DIRN_WRITE) + regval &= ~CTL_TRANSFER_DIR; + else + regval |= CTL_TRANSFER_DIR; + + writeb(regval, p); +} + +static void pci1xxxx_i2c_set_mcu_count(struct pci1xxxx_i2c *i2c, u8 count) +{ + writeb(count, i2c->i2c_base + SMBUS_MCU_COUNTER_REG_OFF); +} + +static void pci1xxxx_i2c_set_read_count(struct pci1xxxx_i2c *i2c, u8 readcount) +{ + writeb(readcount, i2c->i2c_base + SMB_CORE_CMD_REG_OFF3); +} + +static void pci1xxxx_i2c_set_write_count(struct pci1xxxx_i2c *i2c, u8 writecount) +{ + writeb(writecount, i2c->i2c_base + SMB_CORE_CMD_REG_OFF2); +} + +static void pci1xxxx_i2c_set_DMA_run(struct pci1xxxx_i2c *i2c) +{ + void __iomem *p = i2c->i2c_base + SMBUS_CONTROL_REG_OFF; + u8 regval; + + regval = readb(p); + regval |= CTL_RUN; + writeb(regval, p); +} + +static void pci1xxxx_i2c_set_mrun_proceed(struct pci1xxxx_i2c *i2c) +{ + void __iomem *p = i2c->i2c_base + SMB_CORE_CMD_REG_OFF0; + u8 regval; + + regval = readb(p); + regval |= SMB_CORE_CMD_M_RUN; + regval |= SMB_CORE_CMD_M_PROCEED; + writeb(regval, p); +} + +static void pci1xxxx_i2c_start_DMA(struct pci1xxxx_i2c *i2c) +{ + pci1xxxx_i2c_set_DMA_run(i2c); + pci1xxxx_i2c_set_mrun_proceed(i2c); +} + +static void pci1xxxx_i2c_config_asr(struct pci1xxxx_i2c *i2c, bool enable) +{ + void __iomem *p = i2c->i2c_base + SMB_CORE_CONFIG_REG1; + u8 regval; + + regval = readb(p); + if (enable) + regval |= SMB_CONFIG1_ASR; + else + regval &= ~SMB_CONFIG1_ASR; + writeb(regval, p); +} + +static irqreturn_t pci1xxxx_i2c_isr(int irq, void *dev) +{ + struct pci1xxxx_i2c *i2c = dev; + void __iomem *p1 = i2c->i2c_base + SMBUS_GEN_INT_STAT_REG_OFF; + void __iomem *p2 = i2c->i2c_base + SMBUS_INTR_STAT_REG_OFF; + irqreturn_t intr_handled = IRQ_NONE; + u16 reg1; + u8 reg3; + + /* + * Read the SMBus interrupt status register to see if the + * DMA_TERM interrupt has caused this callback. + */ + reg1 = readw(p1); + + if (reg1 & I2C_BUF_MSTR_INTR_MASK) { + reg3 = readb(p2); + if (reg3 & INTR_STAT_DMA_TERM) { + complete(&i2c->i2c_xfer_done); + intr_handled = IRQ_HANDLED; + writeb(INTR_STAT_DMA_TERM, p2); + } + pci1xxxx_ack_high_level_intr(i2c, I2C_BUF_MSTR_INTR_MASK); + } + + if (reg1 & SMBALERT_INTR_MASK) { + intr_handled = IRQ_HANDLED; + pci1xxxx_ack_high_level_intr(i2c, SMBALERT_INTR_MASK); + } + + return intr_handled; +} + +static void pci1xxxx_i2c_set_count(struct pci1xxxx_i2c *i2c, u8 mcucount, + u8 writecount, u8 readcount) +{ + pci1xxxx_i2c_set_mcu_count(i2c, mcucount); + pci1xxxx_i2c_set_write_count(i2c, writecount); + pci1xxxx_i2c_set_read_count(i2c, readcount); +} + +static void pci1xxxx_i2c_set_readm(struct pci1xxxx_i2c *i2c, bool enable) +{ + void __iomem *p = i2c->i2c_base + SMB_CORE_CMD_REG_OFF1; + u8 regval; + + regval = readb(p); + if (enable) + regval |= SMB_CORE_CMD_READM; + else + regval &= ~SMB_CORE_CMD_READM; + + writeb(regval, p); +} + +static void pci1xxxx_ack_nw_layer_intr(struct pci1xxxx_i2c *i2c, u8 ack_intr_msk) +{ + writeb(ack_intr_msk, i2c->i2c_base + SMBUS_INTR_STAT_REG_OFF); +} + +static void pci1xxxx_config_nw_layer_intr(struct pci1xxxx_i2c *i2c, + u8 intr_msk, bool enable) +{ + void __iomem *p = i2c->i2c_base + SMBUS_INTR_MSK_REG_OFF; + u8 regval; + + regval = readb(p); + if (enable) + regval &= ~intr_msk; + else + regval |= intr_msk; + + writeb(regval, p); +} + +static void pci1xxxx_i2c_config_padctrl(struct pci1xxxx_i2c *i2c, bool enable) +{ + void __iomem *p1 = i2c->i2c_base + I2C_SCL_PAD_CTRL_REG_OFF; + void __iomem *p2 = i2c->i2c_base + I2C_SDA_PAD_CTRL_REG_OFF; + u8 regval; + + regval = readb(p1); + if (enable) + regval |= I2C_INPUT_EN | I2C_OUTPUT_EN; + else + regval &= ~(I2C_INPUT_EN | I2C_OUTPUT_EN); + + writeb(regval, p1); + + regval = readb(p2); + if (enable) + regval |= I2C_INPUT_EN | I2C_OUTPUT_EN; + else + regval &= ~(I2C_INPUT_EN | I2C_OUTPUT_EN); + + writeb(regval, p2); +} + +static void pci1xxxx_i2c_set_mode(struct pci1xxxx_i2c *i2c) +{ + void __iomem *p = i2c->i2c_base + SMBUS_CONTROL_REG_OFF; + u8 regval; + + regval = readb(p); + if (i2c->flags & I2C_FLAGS_DIRECT_MODE) + regval &= ~CTL_HOST_FIFO_ENTRY; + else + regval |= CTL_HOST_FIFO_ENTRY; + + writeb(regval, p); +} + +static void pci1xxxx_i2c_config_high_level_intr(struct pci1xxxx_i2c *i2c, + u16 intr_msk, bool enable) +{ + void __iomem *p = i2c->i2c_base + SMBUS_GEN_INT_MASK_REG_OFF; + u16 regval; + + regval = readw(p); + if (enable) + regval &= ~intr_msk; + else + regval |= intr_msk; + writew(regval, p); +} + +static void pci1xxxx_i2c_configure_core_reg(struct pci1xxxx_i2c *i2c, bool enable) +{ + void __iomem *p1 = i2c->i2c_base + SMB_CORE_CONFIG_REG1; + void __iomem *p3 = i2c->i2c_base + SMB_CORE_CONFIG_REG3; + u8 reg1; + u8 reg3; + + reg1 = readb(p1); + reg3 = readb(p3); + if (enable) { + reg1 |= SMB_CONFIG1_ENAB | SMB_CONFIG1_FEN; + reg3 |= SMB_CONFIG3_ENMI | SMB_CONFIG3_ENIDI; + } else { + reg1 &= ~(SMB_CONFIG1_ENAB | SMB_CONFIG1_FEN); + reg3 &= ~(SMB_CONFIG3_ENMI | SMB_CONFIG3_ENIDI); + } + + writeb(reg1, p1); + writeb(reg3, p3); +} + +static void pci1xxxx_i2c_set_freq(struct pci1xxxx_i2c *i2c) +{ + void __iomem *bp = i2c->i2c_base; + void __iomem *p_idle_scaling = bp + SMB_CORE_IDLE_SCALING_REG_OFF; + void __iomem *p_data_timing = bp + SMB_CORE_DATA_TIMING_REG_OFF; + void __iomem *p_hold_time = bp + SMB_CORE_SR_HOLD_TIME_REG_OFF; + void __iomem *p_to_scaling = bp + SMB_CORE_TO_SCALING_REG_OFF; + void __iomem *p_clk_sync = bp + SMB_CORE_CLK_SYNC_REG_OFF; + void __iomem *p_clk_reg = bp + SMB_CORE_BUS_CLK_REG_OFF; + + switch (i2c->freq) { + case I2C_MAX_STANDARD_MODE_FREQ: + writeb(SR_HOLD_TIME_100K_TICKS, p_hold_time); + writel(SMB_IDLE_SCALING_100K, p_idle_scaling); + writew(BUS_CLK_100K, p_clk_reg); + writel(CLK_SYNC_100K, p_clk_sync); + writel(DATA_TIMING_100K, p_data_timing); + writel(TO_SCALING_100K, p_to_scaling); + break; + + case I2C_MAX_FAST_MODE_PLUS_FREQ: + writeb(SR_HOLD_TIME_1000K_TICKS, p_hold_time); + writel(SMB_IDLE_SCALING_1000K, p_idle_scaling); + writew(BUS_CLK_1000K, p_clk_reg); + writel(CLK_SYNC_1000K, p_clk_sync); + writel(DATA_TIMING_1000K, p_data_timing); + writel(TO_SCALING_1000K, p_to_scaling); + break; + + case I2C_MAX_FAST_MODE_FREQ: + default: + writeb(SR_HOLD_TIME_400K_TICKS, p_hold_time); + writel(SMB_IDLE_SCALING_400K, p_idle_scaling); + writew(BUS_CLK_400K, p_clk_reg); + writel(CLK_SYNC_400K, p_clk_sync); + writel(DATA_TIMING_400K, p_data_timing); + writel(TO_SCALING_400K, p_to_scaling); + break; + } +} + +static void pci1xxxx_i2c_init(struct pci1xxxx_i2c *i2c) +{ + void __iomem *p2 = i2c->i2c_base + SMBUS_STATUS_REG_OFF; + void __iomem *p1 = i2c->i2c_base + SMB_GPR_REG; + u8 regval; + int ret; + + ret = set_sys_lock(i2c); + if (ret == -EPERM) { + /* + * Configure I2C Fast Mode as default frequency if unable + * to acquire sys lock. + */ + regval = 0; + } else { + regval = readl(p1); + release_sys_lock(i2c); + } + + switch (regval) { + case 0: + i2c->freq = I2C_MAX_FAST_MODE_FREQ; + pci1xxxx_i2c_set_freq(i2c); + break; + case 1: + i2c->freq = I2C_MAX_STANDARD_MODE_FREQ; + pci1xxxx_i2c_set_freq(i2c); + break; + case 2: + i2c->freq = I2C_MAX_FAST_MODE_PLUS_FREQ; + pci1xxxx_i2c_set_freq(i2c); + break; + case 3: + default: + break; + } + + pci1xxxx_i2c_config_padctrl(i2c, true); + i2c->flags |= I2C_FLAGS_DIRECT_MODE; + pci1xxxx_i2c_set_mode(i2c); + + /* + * Added as a precaution since BUF_EMPTY in status register + * also trigered an Interrupt. + */ + writeb(STA_BUF_EMPTY, p2); + + /* Configure core I2c control registers. */ + pci1xxxx_i2c_configure_core_reg(i2c, true); + + /* + * Enable pull-up for the SMB alert pin which is just used for + * wakeup right now. + */ + pci1xxxx_i2c_configure_smbalert_pin(i2c, true); +} + +static void pci1xxxx_i2c_clear_flags(struct pci1xxxx_i2c *i2c) +{ + u8 regval; + + /* Reset the internal buffer counters. */ + pci1xxxx_i2c_reset_counters(i2c); + + /* Clear low level interrupts. */ + regval = COMPLETION_MNAKX | COMPLETION_IDLE | COMPLETION_MDONE; + writeb(regval, i2c->i2c_base + SMB_CORE_COMPLETION_REG_OFF3); + reinit_completion(&i2c->i2c_xfer_done); + pci1xxxx_ack_nw_layer_intr(i2c, ALL_NW_LAYER_INTERRUPTS); + pci1xxxx_ack_high_level_intr(i2c, ALL_HIGH_LAYER_INTR); +} + +static int pci1xxxx_i2c_read(struct pci1xxxx_i2c *i2c, u8 slaveaddr, + unsigned char *buf, u16 total_len) +{ + void __iomem *p2 = i2c->i2c_base + SMB_CORE_COMPLETION_REG_OFF3; + void __iomem *p1 = i2c->i2c_base + SMB_CORE_CMD_REG_OFF1; + void __iomem *p3 = i2c->i2c_base + SMBUS_MST_BUF; + unsigned long time_left; + u16 remainingbytes; + u8 transferlen; + int retval = 0; + u8 read_count; + u32 regval; + u16 count; + + /* Enable I2C host controller by setting the ESO bit in the CONTROL REG. */ + pci1xxxx_i2c_enable_ESO(i2c); + pci1xxxx_i2c_clear_flags(i2c); + pci1xxxx_config_nw_layer_intr(i2c, INTR_MSK_DMA_TERM, true); + pci1xxxx_i2c_config_high_level_intr(i2c, I2C_BUF_MSTR_INTR_MASK, true); + + /* + * The I2C transfer could be more than 128 bytes. Our Core is + * capable of only sending 128 at a time. + * As far as the I2C read is concerned, initailly send the + * read slave address along with the number of bytes to read in + * ReadCount. After sending the slave address the interrupt + * is generated. On seeing the ACK for the slave address, reverse the + * buffer direction and run the DMA to initiate Read from slave. + */ + for (count = 0; count < total_len; count += transferlen) { + + /* + * Before start of any transaction clear the existing + * START/STOP conditions. + */ + writeb(0, p1); + remainingbytes = total_len - count; + transferlen = min_t(u16, remainingbytes, SMBUS_BUF_MAX_SIZE); + + /* + * Send STOP bit for the last chunk in the transaction. + * For I2C read transaction of more than BUF_SIZE, NACK should + * only be sent for the last read. + * Hence a bit FW_ACK is set for all the read chunks except for + * the last chunk. For the last chunk NACK should be sent and + * FW_ACK is cleared Send STOP only when I2C_FLAGS_STOP bit is + * set in the flags and only for the last transaction. + */ + if ((count + transferlen >= total_len) && + (i2c->flags & I2C_FLAGS_STOP)) { + pci1xxxx_i2c_set_clear_FW_ACK(i2c, false); + pci1xxxx_i2c_send_start_stop(i2c, 0); + } else { + pci1xxxx_i2c_set_clear_FW_ACK(i2c, true); + } + + /* Send START bit for the first transaction. */ + if (count == 0) { + pci1xxxx_i2c_set_transfer_dir(i2c, I2C_DIRN_WRITE); + pci1xxxx_i2c_send_start_stop(i2c, 1); + + /* Write I2c buffer with just the slave addr. */ + pci1xxxx_i2c_buffer_write(i2c, slaveaddr, 0, NULL); + + /* Set the count. Readcount is the transfer bytes. */ + pci1xxxx_i2c_set_count(i2c, 1, 1, transferlen); + + /* + * Set the Auto_start_read bit so that the HW itself + * will take care of the read phase. + */ + pci1xxxx_i2c_config_asr(i2c, true); + if (i2c->flags & I2C_FLAGS_SMB_BLK_READ) + pci1xxxx_i2c_set_readm(i2c, true); + } else { + pci1xxxx_i2c_set_count(i2c, 0, 0, transferlen); + pci1xxxx_i2c_config_asr(i2c, false); + pci1xxxx_i2c_clear_flags(i2c); + pci1xxxx_i2c_set_transfer_dir(i2c, I2C_DIRN_READ); + } + + /* Start the DMA. */ + pci1xxxx_i2c_start_DMA(i2c); + + /* Wait for the DMA_TERM interrupt. */ + time_left = wait_for_completion_timeout(&i2c->i2c_xfer_done, + msecs_to_jiffies(PCI1XXXX_I2C_TIMEOUT_MS)); + if (time_left == 0) { + /* Reset the I2C core to release the bus lock. */ + pci1xxxx_i2c_init(i2c); + retval = -ETIMEDOUT; + goto cleanup; + } + + /* Read the completion reg to know the reason for DMA_TERM. */ + regval = readb(p2); + + /* Slave did not respond. */ + if (regval & COMPLETION_MNAKX) { + writeb(COMPLETION_MNAKX, p2); + retval = -ETIMEDOUT; + goto cleanup; + } + + if (i2c->flags & I2C_FLAGS_SMB_BLK_READ) { + buf[0] = readb(p3); + read_count = buf[0]; + memcpy_fromio(&buf[1], p3 + 1, read_count); + } else { + memcpy_fromio(&buf[count], p3, transferlen); + } + } + +cleanup: + /* Disable all the interrupts. */ + pci1xxxx_config_nw_layer_intr(i2c, INTR_MSK_DMA_TERM, false); + pci1xxxx_i2c_config_high_level_intr(i2c, I2C_BUF_MSTR_INTR_MASK, false); + pci1xxxx_i2c_config_asr(i2c, false); + return retval; +} + +static int pci1xxxx_i2c_write(struct pci1xxxx_i2c *i2c, u8 slaveaddr, + unsigned char *buf, u16 total_len) +{ + void __iomem *p2 = i2c->i2c_base + SMB_CORE_COMPLETION_REG_OFF3; + void __iomem *p1 = i2c->i2c_base + SMB_CORE_CMD_REG_OFF1; + unsigned long time_left; + u16 remainingbytes; + u8 actualwritelen; + u8 transferlen; + int retval = 0; + u32 regval; + u16 count; + + /* Enable I2C host controller by setting the ESO bit in the CONTROL REG. */ + pci1xxxx_i2c_enable_ESO(i2c); + + /* Set the Buffer direction. */ + pci1xxxx_i2c_set_transfer_dir(i2c, I2C_DIRN_WRITE); + pci1xxxx_config_nw_layer_intr(i2c, INTR_MSK_DMA_TERM, true); + pci1xxxx_i2c_config_high_level_intr(i2c, I2C_BUF_MSTR_INTR_MASK, true); + + /* + * The i2c transfer could be more than 128 bytes. Our Core is + * capable of only sending 128 at a time. + */ + for (count = 0; count < total_len; count += transferlen) { + /* + * Before start of any transaction clear the existing + * START/STOP conditions. + */ + writeb(0, p1); + pci1xxxx_i2c_clear_flags(i2c); + remainingbytes = total_len - count; + + /* If it is the starting of the transaction send START. */ + if (count == 0) { + pci1xxxx_i2c_send_start_stop(i2c, 1); + + /* -1 for the slave address. */ + transferlen = min_t(u16, SMBUS_BUF_MAX_SIZE - 1, + remainingbytes); + pci1xxxx_i2c_buffer_write(i2c, slaveaddr, + transferlen, &buf[count]); + /* + * The actual number of bytes written on the I2C bus + * is including the slave address. + */ + actualwritelen = transferlen + 1; + } else { + transferlen = min_t(u16, SMBUS_BUF_MAX_SIZE, remainingbytes); + pci1xxxx_i2c_buffer_write(i2c, 0, transferlen, &buf[count]); + actualwritelen = transferlen; + } + + pci1xxxx_i2c_set_count(i2c, actualwritelen, actualwritelen, 0); + + /* + * Send STOP only when I2C_FLAGS_STOP bit is set in the flags and + * only for the last transaction. + */ + if (remainingbytes <= transferlen && + (i2c->flags & I2C_FLAGS_STOP)) + pci1xxxx_i2c_send_start_stop(i2c, 0); + + pci1xxxx_i2c_start_DMA(i2c); + + /* + * Wait for the DMA_TERM interrupt. + */ + time_left = wait_for_completion_timeout(&i2c->i2c_xfer_done, + msecs_to_jiffies(PCI1XXXX_I2C_TIMEOUT_MS)); + if (time_left == 0) { + /* Reset the I2C core to release the bus lock. */ + pci1xxxx_i2c_init(i2c); + retval = -ETIMEDOUT; + goto cleanup; + } + + regval = readb(p2); + if (regval & COMPLETION_MNAKX) { + writeb(COMPLETION_MNAKX, p2); + retval = -ETIMEDOUT; + goto cleanup; + } + } +cleanup: + /* Disable all the interrupts. */ + pci1xxxx_config_nw_layer_intr(i2c, INTR_MSK_DMA_TERM, false); + pci1xxxx_i2c_config_high_level_intr(i2c, I2C_BUF_MSTR_INTR_MASK, false); + + return retval; +} + +static int pci1xxxx_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + struct pci1xxxx_i2c *i2c = i2c_get_adapdata(adap); + u8 slaveaddr; + int retval; + u32 i; + + i2c->i2c_xfer_in_progress = true; + for (i = 0; i < num; i++) { + slaveaddr = i2c_8bit_addr_from_msg(&msgs[i]); + + /* + * Send the STOP bit if the transfer is the final one or + * if the I2C_M_STOP flag is set. + */ + if ((i == num - 1) || (msgs[i].flags & I2C_M_STOP)) + i2c->flags |= I2C_FLAGS_STOP; + else + i2c->flags &= ~I2C_FLAGS_STOP; + + if (msgs[i].flags & I2C_M_RECV_LEN) + i2c->flags |= I2C_FLAGS_SMB_BLK_READ; + else + i2c->flags &= ~I2C_FLAGS_SMB_BLK_READ; + + if (msgs[i].flags & I2C_M_RD) + retval = pci1xxxx_i2c_read(i2c, slaveaddr, + msgs[i].buf, msgs[i].len); + else + retval = pci1xxxx_i2c_write(i2c, slaveaddr, + msgs[i].buf, msgs[i].len); + + if (retval < 0) + break; + } + i2c->i2c_xfer_in_progress = false; + + if (retval < 0) + return retval; + + return num; +} + +/* + * List of supported functions by the driver. + */ +static u32 pci1xxxx_i2c_get_funcs(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_PROTOCOL_MANGLING | + I2C_FUNC_SMBUS_BLOCK_PROC_CALL | + I2C_FUNC_SMBUS_BYTE | + I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_PROC_CALL | + I2C_FUNC_SMBUS_BLOCK_DATA; +} + +static const struct i2c_algorithm pci1xxxx_i2c_algo = { + .xfer = pci1xxxx_i2c_xfer, + .functionality = pci1xxxx_i2c_get_funcs, +}; + +static const struct i2c_adapter_quirks pci1xxxx_i2c_quirks = { + .flags = I2C_AQ_NO_ZERO_LEN, +}; + +static const struct i2c_adapter pci1xxxx_i2c_ops = { + .owner = THIS_MODULE, + .name = "PCI1xxxx I2C Adapter", + .algo = &pci1xxxx_i2c_algo, + .quirks = &pci1xxxx_i2c_quirks, +}; + +static int pci1xxxx_i2c_suspend(struct device *dev) +{ + struct pci1xxxx_i2c *i2c = dev_get_drvdata(dev); + void __iomem *p = i2c->i2c_base + SMBUS_RESET_REG; + struct pci_dev *pdev = to_pci_dev(dev); + u32 regval; + + i2c_mark_adapter_suspended(&i2c->adap); + + /* + * If the system is put into 'suspend' state when the I2C transfer is in + * progress, wait until the transfer completes. + */ + while (i2c->i2c_xfer_in_progress) + msleep(20); + + pci1xxxx_i2c_config_high_level_intr(i2c, SMBALERT_WAKE_INTR_MASK, true); + + /* + * Enable the PERST_DIS bit to mask the PERST from resetting the core + * registers. + */ + regval = readl(p); + regval |= PERI_SMBUS_D3_RESET_DIS; + writel(regval, p); + + /* Enable PCI wake in the PMCSR register. */ + device_set_wakeup_enable(dev, true); + pci_wake_from_d3(pdev, true); + + return 0; +} + +static int pci1xxxx_i2c_resume(struct device *dev) +{ + struct pci1xxxx_i2c *i2c = dev_get_drvdata(dev); + void __iomem *p1 = i2c->i2c_base + SMBUS_GEN_INT_STAT_REG_OFF; + void __iomem *p2 = i2c->i2c_base + SMBUS_RESET_REG; + struct pci_dev *pdev = to_pci_dev(dev); + u32 regval; + + regval = readw(p1); + writew(regval, p1); + pci1xxxx_i2c_config_high_level_intr(i2c, SMBALERT_WAKE_INTR_MASK, false); + regval = readl(p2); + regval &= ~PERI_SMBUS_D3_RESET_DIS; + writel(regval, p2); + i2c_mark_adapter_resumed(&i2c->adap); + pci_wake_from_d3(pdev, false); + return 0; +} + +static DEFINE_SIMPLE_DEV_PM_OPS(pci1xxxx_i2c_pm_ops, pci1xxxx_i2c_suspend, + pci1xxxx_i2c_resume); + +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); +} + +static int pci1xxxx_i2c_probe_pci(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct device *dev = &pdev->dev; + struct pci1xxxx_i2c *i2c; + int ret; + + i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + pci_set_drvdata(pdev, i2c); + i2c->i2c_xfer_in_progress = false; + + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + pci_set_master(pdev); + + /* + * We are getting the base address of the SMB core. SMB core uses + * BAR0 and size is 32K. + */ + ret = pcim_iomap_regions(pdev, BIT(0), pci_name(pdev)); + if (ret < 0) + return ret; + + i2c->i2c_base = pcim_iomap_table(pdev)[0]; + init_completion(&i2c->i2c_xfer_done); + pci1xxxx_i2c_init(i2c); + + ret = devm_add_action(dev, pci1xxxx_i2c_shutdown, i2c); + if (ret) + return ret; + + ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES); + if (ret < 0) + return ret; + + ret = devm_request_irq(dev, pci_irq_vector(pdev, 0), pci1xxxx_i2c_isr, + 0, pci_name(pdev), i2c); + if (ret) + return ret; + + i2c->adap = pci1xxxx_i2c_ops; + i2c->adap.dev.parent = dev; + + snprintf(i2c->adap.name, sizeof(i2c->adap.name), + "MCHP PCI1xxxx i2c adapter at %s", pci_name(pdev)); + + i2c_set_adapdata(&i2c->adap, i2c); + + ret = devm_i2c_add_adapter(dev, &i2c->adap); + if (ret) + return dev_err_probe(dev, ret, "i2c add adapter failed\n"); + + return 0; +} + +static const struct pci_device_id pci1xxxx_i2c_pci_id_table[] = { + { PCI_VDEVICE(EFAR, 0xA003) }, + { PCI_VDEVICE(EFAR, 0xA013) }, + { PCI_VDEVICE(EFAR, 0xA023) }, + { PCI_VDEVICE(EFAR, 0xA033) }, + { PCI_VDEVICE(EFAR, 0xA043) }, + { } +}; +MODULE_DEVICE_TABLE(pci, pci1xxxx_i2c_pci_id_table); + +static struct pci_driver pci1xxxx_i2c_pci_driver = { + .name = "i2c-mchp-pci1xxxx", + .id_table = pci1xxxx_i2c_pci_id_table, + .probe = pci1xxxx_i2c_probe_pci, + .driver = { + .pm = pm_sleep_ptr(&pci1xxxx_i2c_pm_ops), + }, +}; +module_pci_driver(pci1xxxx_i2c_pci_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Tharun Kumar P<tharunkumar.pasumarthi@microchip.com>"); +MODULE_AUTHOR("Kumaravel Thiagarajan <kumaravel.thiagarajan@microchip.com>"); +MODULE_DESCRIPTION("Microchip Technology Inc. pci1xxxx I2C bus driver"); diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index ef73a42577cc..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> @@ -30,18 +29,21 @@ #define REG_TOK_RDATA1 0x1c /* Control register fields */ -#define REG_CTRL_START BIT(0) -#define REG_CTRL_ACK_IGNORE BIT(1) -#define REG_CTRL_STATUS BIT(2) -#define REG_CTRL_ERROR BIT(3) -#define REG_CTRL_CLKDIV GENMASK(21, 12) -#define REG_CTRL_CLKDIVEXT GENMASK(29, 28) - -#define REG_SLV_ADDR GENMASK(7, 0) -#define REG_SLV_SDA_FILTER GENMASK(10, 8) -#define REG_SLV_SCL_FILTER GENMASK(13, 11) -#define REG_SLV_SCL_LOW GENMASK(27, 16) -#define REG_SLV_SCL_LOW_EN BIT(28) +#define REG_CTRL_START BIT(0) +#define REG_CTRL_ACK_IGNORE BIT(1) +#define REG_CTRL_STATUS BIT(2) +#define REG_CTRL_ERROR BIT(3) +#define REG_CTRL_CLKDIV_SHIFT 12 +#define REG_CTRL_CLKDIV_MASK GENMASK(21, REG_CTRL_CLKDIV_SHIFT) +#define REG_CTRL_CLKDIVEXT_SHIFT 28 +#define REG_CTRL_CLKDIVEXT_MASK GENMASK(29, REG_CTRL_CLKDIVEXT_SHIFT) + +#define REG_SLV_ADDR_MASK GENMASK(7, 0) +#define REG_SLV_SDA_FILTER_MASK GENMASK(10, 8) +#define REG_SLV_SCL_FILTER_MASK GENMASK(13, 11) +#define REG_SLV_SCL_LOW_SHIFT 16 +#define REG_SLV_SCL_LOW_MASK GENMASK(27, REG_SLV_SCL_LOW_SHIFT) +#define REG_SLV_SCL_LOW_EN BIT(28) #define I2C_TIMEOUT_MS 500 #define FILTER_DELAY 15 @@ -62,10 +64,6 @@ enum { STATE_WRITE, }; -struct meson_i2c_data { - unsigned char div_factor; -}; - /** * struct meson_i2c - Meson I2C device private data * @@ -83,7 +81,7 @@ struct meson_i2c_data { * @done: Completion used to wait for transfer termination * @tokens: Sequence of tokens to be written to the device * @num_tokens: Number of tokens - * @data: Pointer to the controlller's platform data + * @data: Pointer to the controller's platform data */ struct meson_i2c { struct i2c_adapter adap; @@ -106,6 +104,10 @@ struct meson_i2c { const struct meson_i2c_data *data; }; +struct meson_i2c_data { + void (*set_clk_div)(struct meson_i2c *i2c, unsigned int freq); +}; + static void meson_i2c_set_mask(struct meson_i2c *i2c, int reg, u32 mask, u32 val) { @@ -134,14 +136,62 @@ static void meson_i2c_add_token(struct meson_i2c *i2c, int token) i2c->num_tokens++; } -static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq) +static void meson_gxbb_axg_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq) +{ + unsigned long clk_rate = clk_get_rate(i2c->clk); + unsigned int div_h, div_l; + + /* According to I2C-BUS Spec 2.1, in FAST-MODE, the minimum LOW period is 1.3uS, and + * minimum HIGH is least 0.6us. + * For 400000 freq, the period is 2.5us. To keep within the specs, give 40% of period to + * HIGH and 60% to LOW. This means HIGH at 1.0us and LOW 1.5us. + * The same applies for Fast-mode plus, where LOW is 0.5us and HIGH is 0.26us. + * Duty = H/(H + L) = 2/5 + */ + if (freq <= I2C_MAX_STANDARD_MODE_FREQ) { + div_h = DIV_ROUND_UP(clk_rate, freq); + div_l = DIV_ROUND_UP(div_h, 4); + div_h = DIV_ROUND_UP(div_h, 2) - FILTER_DELAY; + } else { + div_h = DIV_ROUND_UP(clk_rate * 2, freq * 5) - FILTER_DELAY; + div_l = DIV_ROUND_UP(clk_rate * 3, freq * 5 * 2); + } + + /* clock divider has 12 bits */ + if (div_h > GENMASK(11, 0)) { + dev_err(i2c->dev, "requested bus frequency too low\n"); + div_h = GENMASK(11, 0); + } + if (div_l > GENMASK(11, 0)) { + dev_err(i2c->dev, "requested bus frequency too low\n"); + div_l = GENMASK(11, 0); + } + + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK, + FIELD_PREP(REG_CTRL_CLKDIV_MASK, div_h & GENMASK(9, 0))); + + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK, + FIELD_PREP(REG_CTRL_CLKDIVEXT_MASK, div_h >> 10)); + + /* set SCL low delay */ + meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_MASK, + FIELD_PREP(REG_SLV_SCL_LOW_MASK, div_l)); + + /* Enable HIGH/LOW mode */ + meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_EN, REG_SLV_SCL_LOW_EN); + + dev_dbg(i2c->dev, "%s: clk %lu, freq %u, divh %u, divl %u\n", __func__, + clk_rate, freq, div_h, div_l); +} + +static void meson6_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq) { unsigned long clk_rate = clk_get_rate(i2c->clk); unsigned int div; div = DIV_ROUND_UP(clk_rate, freq); div -= FILTER_DELAY; - div = DIV_ROUND_UP(div, i2c->data->div_factor); + div = DIV_ROUND_UP(div, 4); /* clock divider has 12 bits */ if (div > GENMASK(11, 0)) { @@ -149,11 +199,11 @@ static void meson_i2c_set_clk_div(struct meson_i2c *i2c, unsigned int freq) div = GENMASK(11, 0); } - meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV, - FIELD_PREP(REG_CTRL_CLKDIV, div & GENMASK(9, 0))); + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIV_MASK, + FIELD_PREP(REG_CTRL_CLKDIV_MASK, div & GENMASK(9, 0))); - meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT, - FIELD_PREP(REG_CTRL_CLKDIVEXT, div >> 10)); + meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_CLKDIVEXT_MASK, + FIELD_PREP(REG_CTRL_CLKDIVEXT_MASK, div >> 10)); /* Disable HIGH/LOW mode */ meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_SCL_LOW_EN, 0); @@ -292,8 +342,8 @@ static void meson_i2c_do_start(struct meson_i2c *i2c, struct i2c_msg *msg) TOKEN_SLAVE_ADDR_WRITE; - meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR, - FIELD_PREP(REG_SLV_ADDR, msg->addr << 1)); + meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, REG_SLV_ADDR_MASK, + FIELD_PREP(REG_SLV_ADDR_MASK, msg->addr << 1)); meson_i2c_add_token(i2c, TOKEN_START); meson_i2c_add_token(i2c, token); @@ -398,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, }; @@ -451,7 +501,7 @@ static int meson_i2c_probe(struct platform_device *pdev) return ret; } - strlcpy(i2c->adap.name, "Meson I2C adapter", + strscpy(i2c->adap.name, "Meson I2C adapter", sizeof(i2c->adap.name)); i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &meson_i2c_algorithm; @@ -465,41 +515,43 @@ static int meson_i2c_probe(struct platform_device *pdev) */ meson_i2c_set_mask(i2c, REG_CTRL, REG_CTRL_START, 0); + /* Disable filtering */ + meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, + REG_SLV_SDA_FILTER_MASK | REG_SLV_SCL_FILTER_MASK, 0); + + if (!i2c->data->set_clk_div) { + clk_disable_unprepare(i2c->clk); + return -EINVAL; + } + i2c->data->set_clk_div(i2c, timings.bus_freq_hz); + ret = i2c_add_adapter(&i2c->adap); if (ret < 0) { clk_disable_unprepare(i2c->clk); return ret; } - /* Disable filtering */ - meson_i2c_set_mask(i2c, REG_SLAVE_ADDR, - REG_SLV_SDA_FILTER | REG_SLV_SCL_FILTER, 0); - - meson_i2c_set_clk_div(i2c, timings.bus_freq_hz); - 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 = { - .div_factor = 4, + .set_clk_div = meson6_i2c_set_clk_div, }; static const struct meson_i2c_data i2c_gxbb_data = { - .div_factor = 4, + .set_clk_div = meson_gxbb_axg_i2c_set_clk_div, }; static const struct meson_i2c_data i2c_axg_data = { - .div_factor = 3, + .set_clk_div = meson_gxbb_axg_i2c_set_clk_div, }; static const struct of_device_id meson_i2c_match[] = { @@ -513,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 new file mode 100644 index 000000000000..c8599733633e --- /dev/null +++ b/drivers/i2c/busses/i2c-microchip-corei2c.c @@ -0,0 +1,649 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Microchip CoreI2C I2C controller driver + * + * Copyright (c) 2018-2022 Microchip Corporation. All rights reserved. + * + * Author: Daire McNamara <daire.mcnamara@microchip.com> + * Author: Conor Dooley <conor.dooley@microchip.com> + */ +#include <linux/clk.h> +#include <linux/clkdev.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> + +#define CORE_I2C_CTRL (0x00) +#define CTRL_CR0 BIT(0) +#define CTRL_CR1 BIT(1) +#define CTRL_AA BIT(2) +#define CTRL_SI BIT(3) +#define CTRL_STO BIT(4) +#define CTRL_STA BIT(5) +#define CTRL_ENS1 BIT(6) +#define CTRL_CR2 BIT(7) + +#define STATUS_BUS_ERROR (0x00) +#define STATUS_M_START_SENT (0x08) +#define STATUS_M_REPEATED_START_SENT (0x10) +#define STATUS_M_SLAW_ACK (0x18) +#define STATUS_M_SLAW_NACK (0x20) +#define STATUS_M_TX_DATA_ACK (0x28) +#define STATUS_M_TX_DATA_NACK (0x30) +#define STATUS_M_ARB_LOST (0x38) +#define STATUS_M_SLAR_ACK (0x40) +#define STATUS_M_SLAR_NACK (0x48) +#define STATUS_M_RX_DATA_ACKED (0x50) +#define STATUS_M_RX_DATA_NACKED (0x58) +#define STATUS_S_SLAW_ACKED (0x60) +#define STATUS_S_ARB_LOST_SLAW_ACKED (0x68) +#define STATUS_S_GENERAL_CALL_ACKED (0x70) +#define STATUS_S_ARB_LOST_GENERAL_CALL_ACKED (0x78) +#define STATUS_S_RX_DATA_ACKED (0x80) +#define STATUS_S_RX_DATA_NACKED (0x88) +#define STATUS_S_GENERAL_CALL_RX_DATA_ACKED (0x90) +#define STATUS_S_GENERAL_CALL_RX_DATA_NACKED (0x98) +#define STATUS_S_RX_STOP (0xA0) +#define STATUS_S_SLAR_ACKED (0xA8) +#define STATUS_S_ARB_LOST_SLAR_ACKED (0xB0) +#define STATUS_S_TX_DATA_ACK (0xB8) +#define STATUS_S_TX_DATA_NACK (0xC0) +#define STATUS_LAST_DATA_ACK (0xC8) +#define STATUS_M_SMB_MASTER_RESET (0xD0) +#define STATUS_S_SCL_LOW_TIMEOUT (0xD8) /* 25 ms */ +#define STATUS_NO_STATE_INFO (0xF8) + +#define CORE_I2C_STATUS (0x04) +#define CORE_I2C_DATA (0x08) +#define WRITE_BIT (0x0) +#define READ_BIT (0x1) +#define SLAVE_ADDR_SHIFT (1) +#define CORE_I2C_SLAVE0_ADDR (0x0c) +#define GENERAL_CALL_BIT (0x0) +#define CORE_I2C_SMBUS (0x10) +#define SMBALERT_INT_ENB (0x0) +#define SMBSUS_INT_ENB (0x1) +#define SMBUS_ENB (0x2) +#define SMBALERT_NI_STATUS (0x3) +#define SMBALERT_NO_CTRL (0x4) +#define SMBSUS_NI_STATUS (0x5) +#define SMBSUS_NO_CTRL (0x6) +#define SMBUS_RESET (0x7) +#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) +#define PCLK_DIV_224 (CTRL_CR0) +#define PCLK_DIV_192 (CTRL_CR1) +#define PCLK_DIV_160 (CTRL_CR0 | CTRL_CR1) +#define PCLK_DIV_120 (CTRL_CR0 | CTRL_CR2) +#define PCLK_DIV_60 (CTRL_CR1 | CTRL_CR2) +#define BCLK_DIV_8 (CTRL_CR0 | CTRL_CR1 | CTRL_CR2) +#define CLK_MASK (CTRL_CR0 | CTRL_CR1 | CTRL_CR2) + +/** + * struct mchp_corei2c_dev - Microchip CoreI2C device private data + * + * @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) +{ + u8 ctrl = readb(idev->base + CORE_I2C_CTRL); + + ctrl &= ~CTRL_ENS1; + writeb(ctrl, idev->base + CORE_I2C_CTRL); +} + +static void mchp_corei2c_core_enable(struct mchp_corei2c_dev *idev) +{ + u8 ctrl = readb(idev->base + CORE_I2C_CTRL); + + ctrl |= CTRL_ENS1; + writeb(ctrl, idev->base + CORE_I2C_CTRL); +} + +static void mchp_corei2c_reset(struct mchp_corei2c_dev *idev) +{ + mchp_corei2c_core_disable(idev); + mchp_corei2c_core_enable(idev); +} + +static inline void mchp_corei2c_stop(struct mchp_corei2c_dev *idev) +{ + u8 ctrl = readb(idev->base + CORE_I2C_CTRL); + + ctrl |= CTRL_STO; + writeb(ctrl, idev->base + CORE_I2C_CTRL); +} + +static inline int mchp_corei2c_set_divisor(u32 rate, + struct mchp_corei2c_dev *idev) +{ + u8 clkval, ctrl; + + if (rate >= 960) + clkval = PCLK_DIV_960; + else if (rate >= 256) + clkval = PCLK_DIV_256; + else if (rate >= 224) + clkval = PCLK_DIV_224; + else if (rate >= 192) + clkval = PCLK_DIV_192; + else if (rate >= 160) + clkval = PCLK_DIV_160; + else if (rate >= 120) + clkval = PCLK_DIV_120; + else if (rate >= 60) + clkval = PCLK_DIV_60; + else if (rate >= 8) + clkval = BCLK_DIV_8; + else + return -EINVAL; + + ctrl = readb(idev->base + CORE_I2C_CTRL); + ctrl &= ~CLK_MASK; + ctrl |= clkval; + writeb(ctrl, idev->base + CORE_I2C_CTRL); + + ctrl = readb(idev->base + CORE_I2C_CTRL); + if ((ctrl & CLK_MASK) != clkval) + return -EIO; + + return 0; +} + +static int mchp_corei2c_init(struct mchp_corei2c_dev *idev) +{ + u32 clk_rate = clk_get_rate(idev->i2c_clk); + u32 divisor = clk_rate / idev->bus_clk_rate; + int ret; + + ret = mchp_corei2c_set_divisor(divisor, idev); + if (ret) + return ret; + + mchp_corei2c_reset(idev); + + return 0; +} + +static void mchp_corei2c_empty_rx(struct mchp_corei2c_dev *idev) +{ + u8 ctrl; + + if (idev->msg_len > 0) { + *idev->buf++ = readb(idev->base + CORE_I2C_DATA); + idev->msg_len--; + } + + if (idev->msg_len <= 1) { + ctrl = readb(idev->base + CORE_I2C_CTRL); + ctrl &= ~CTRL_AA; + writeb(ctrl, idev->base + CORE_I2C_CTRL); + } +} + +static int mchp_corei2c_fill_tx(struct mchp_corei2c_dev *idev) +{ + if (idev->msg_len > 0) + writeb(*idev->buf++, idev->base + CORE_I2C_DATA); + idev->msg_len--; + + 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; + u8 ctrl; + bool last_byte = false, finished = false; + + if (!idev->buf) + return IRQ_NONE; + + switch (status) { + case STATUS_M_START_SENT: + case STATUS_M_REPEATED_START_SENT: + ctrl = readb(idev->base + CORE_I2C_CTRL); + ctrl &= ~CTRL_STA; + writeb(idev->addr, idev->base + CORE_I2C_DATA); + writeb(ctrl, idev->base + CORE_I2C_CTRL); + break; + case STATUS_M_ARB_LOST: + idev->msg_err = -EAGAIN; + finished = true; + break; + case STATUS_M_SLAW_ACK: + case STATUS_M_TX_DATA_ACK: + if (idev->msg_len > 0) { + mchp_corei2c_fill_tx(idev); + } else { + if (idev->restart_needed) + finished = true; + else + last_byte = true; + } + break; + case STATUS_M_TX_DATA_NACK: + case STATUS_M_SLAR_NACK: + case STATUS_M_SLAW_NACK: + idev->msg_err = -ENXIO; + last_byte = true; + break; + case STATUS_M_SLAR_ACK: + ctrl = readb(idev->base + CORE_I2C_CTRL); + if (idev->msg_len == 1u) { + ctrl &= ~CTRL_AA; + writeb(ctrl, idev->base + CORE_I2C_CTRL); + } else { + ctrl |= CTRL_AA; + writeb(ctrl, idev->base + CORE_I2C_CTRL); + } + if (idev->msg_len < 1u) + last_byte = true; + break; + case STATUS_M_RX_DATA_ACKED: + mchp_corei2c_empty_rx(idev); + break; + case STATUS_M_RX_DATA_NACKED: + mchp_corei2c_empty_rx(idev); + if (idev->msg_len == 0) + last_byte = true; + break; + default: + break; + } + + /* On the last byte to be transmitted, send STOP */ + if (last_byte) + mchp_corei2c_stop(idev); + + if (last_byte || finished) + mchp_corei2c_next_msg(idev); + + return IRQ_HANDLED; +} + +static irqreturn_t mchp_corei2c_isr(int irq, void *_dev) +{ + struct mchp_corei2c_dev *idev = _dev; + irqreturn_t ret = IRQ_NONE; + u8 ctrl; + + ctrl = readb(idev->base + CORE_I2C_CTRL); + if (ctrl & CTRL_SI) { + idev->isr_status = readb(idev->base + CORE_I2C_STATUS); + ret = mchp_corei2c_handle_isr(idev); + } + + ctrl = readb(idev->base + CORE_I2C_CTRL); + ctrl &= ~CTRL_SI; + writeb(ctrl, idev->base + CORE_I2C_CTRL); + + return ret; +} + +static int mchp_corei2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + 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); + + /* + * 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; + + if (idev->total_num > 1) { + struct i2c_msg *next_msg = msgs + 1; + + 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); + + time_left = wait_for_completion_timeout(&idev->msg_complete, + idev->adapter.timeout); + if (!time_left) + return -ETIMEDOUT; + + if (idev->msg_err) + return idev->msg_err; + + return 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); + u8 tx_buf[I2C_SMBUS_BLOCK_MAX + 2]; + u8 rx_buf[I2C_SMBUS_BLOCK_MAX + 1]; + int num_msgs = 1; + int 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; + } + + 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; + } + + 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 = { + .xfer = mchp_corei2c_xfer, + .functionality = mchp_corei2c_func, + .smbus_xfer = mchp_corei2c_smbus_xfer, +}; + +static int mchp_corei2c_probe(struct platform_device *pdev) +{ + struct mchp_corei2c_dev *idev; + struct resource *res; + int irq, ret; + + idev = devm_kzalloc(&pdev->dev, sizeof(*idev), GFP_KERNEL); + if (!idev) + return -ENOMEM; + + idev->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(idev->base)) + return PTR_ERR(idev->base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + idev->i2c_clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(idev->i2c_clk)) + return dev_err_probe(&pdev->dev, PTR_ERR(idev->i2c_clk), + "missing clock\n"); + + idev->dev = &pdev->dev; + init_completion(&idev->msg_complete); + + ret = device_property_read_u32(idev->dev, "clock-frequency", + &idev->bus_clk_rate); + if (ret || !idev->bus_clk_rate) { + dev_info(&pdev->dev, "default to 100kHz\n"); + idev->bus_clk_rate = 100000; + } + + if (idev->bus_clk_rate > 400000) + return dev_err_probe(&pdev->dev, -EINVAL, + "clock-frequency too high: %d\n", + idev->bus_clk_rate); + + /* + * This driver supports both the hard peripherals & soft FPGA cores. + * The hard peripherals do not have shared IRQs, but we don't have + * control over what way the interrupts are wired for the soft cores. + */ + ret = devm_request_irq(&pdev->dev, irq, mchp_corei2c_isr, IRQF_SHARED, + pdev->name, idev); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed to claim irq %d\n", irq); + + ret = clk_prepare_enable(idev->i2c_clk); + if (ret) + return dev_err_probe(&pdev->dev, ret, + "failed to enable clock\n"); + + ret = mchp_corei2c_init(idev); + if (ret) { + clk_disable_unprepare(idev->i2c_clk); + return dev_err_probe(&pdev->dev, ret, "failed to program clock divider\n"); + } + + i2c_set_adapdata(&idev->adapter, idev); + snprintf(idev->adapter.name, sizeof(idev->adapter.name), + "Microchip I2C hw bus at %08lx", (unsigned long)res->start); + idev->adapter.owner = THIS_MODULE; + idev->adapter.algo = &mchp_corei2c_algo; + idev->adapter.dev.parent = &pdev->dev; + idev->adapter.dev.of_node = pdev->dev.of_node; + idev->adapter.timeout = HZ; + + platform_set_drvdata(pdev, idev); + + ret = i2c_add_adapter(&idev->adapter); + if (ret) { + clk_disable_unprepare(idev->i2c_clk); + return ret; + } + + dev_info(&pdev->dev, "registered CoreI2C bus driver\n"); + + return 0; +} + +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); +} + +static const struct of_device_id mchp_corei2c_of_match[] = { + { .compatible = "microchip,mpfs-i2c" }, + { .compatible = "microchip,corei2c-rtl-v7" }, + {}, +}; +MODULE_DEVICE_TABLE(of, mchp_corei2c_of_match); + +static struct platform_driver mchp_corei2c_driver = { + .probe = mchp_corei2c_probe, + .remove = mchp_corei2c_remove, + .driver = { + .name = "microchip-corei2c", + .of_match_table = mchp_corei2c_of_match, + }, +}; + +module_platform_driver(mchp_corei2c_driver); + +MODULE_DESCRIPTION("Microchip CoreI2C bus driver"); +MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>"); +MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-mlxbf.c b/drivers/i2c/busses/i2c-mlxbf.c index 8716032f030a..8345f7e6385d 100644 --- a/drivers/i2c/busses/i2c-mlxbf.c +++ b/drivers/i2c/busses/i2c-mlxbf.c @@ -6,17 +6,20 @@ */ #include <linux/acpi.h> +#include <linux/bitfield.h> #include <linux/delay.h> #include <linux/err.h> #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 \ @@ -31,8 +34,6 @@ (MLXBF_I2C_FUNC_SMBUS_DEFAULT | MLXBF_I2C_FUNC_SMBUS_BLOCK | \ I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SLAVE) -#define MLXBF_I2C_SMBUS_MAX 3 - /* Shared resources info in BlueField platforms. */ #define MLXBF_I2C_COALESCE_TYU_ADDR 0x02801300 @@ -47,6 +48,9 @@ #define MLXBF_I2C_COREPLL_YU_ADDR 0x02800c30 #define MLXBF_I2C_COREPLL_YU_SIZE 0x00c +#define MLXBF_I2C_COREPLL_RSH_YU_ADDR 0x13409824 +#define MLXBF_I2C_COREPLL_RSH_YU_SIZE 0x00c + #define MLXBF_I2C_SHARED_RES_MAX 3 /* @@ -63,13 +67,14 @@ */ #define MLXBF_I2C_TYU_PLL_OUT_FREQ (400 * 1000 * 1000) /* Reference clock for Bluefield - 156 MHz. */ -#define MLXBF_I2C_PLL_IN_FREQ (156 * 1000 * 1000) +#define MLXBF_I2C_PLL_IN_FREQ 156250000ULL /* Constant used to determine the PLL frequency. */ -#define MLNXBF_I2C_COREPLL_CONST 16384 +#define MLNXBF_I2C_COREPLL_CONST 16384ULL + +#define MLXBF_I2C_FREQUENCY_1GHZ 1000000000ULL /* PLL registers. */ -#define MLXBF_I2C_CORE_PLL_REG0 0x0 #define MLXBF_I2C_CORE_PLL_REG1 0x4 #define MLXBF_I2C_CORE_PLL_REG2 0x8 @@ -129,14 +134,10 @@ /* Slave busy bit reset. */ #define MLXBF_I2C_CAUSE_S_GW_BUSY_FALL BIT(18) -#define MLXBF_I2C_CAUSE_SLAVE_ARBITER_BITS_MASK GENMASK(20, 0) - /* Cause coalesce registers. */ #define MLXBF_I2C_CAUSE_COALESCE_0 0x00 -#define MLXBF_I2C_CAUSE_COALESCE_1 0x04 -#define MLXBF_I2C_CAUSE_COALESCE_2 0x08 -#define MLXBF_I2C_CAUSE_TYU_SLAVE_BIT MLXBF_I2C_SMBUS_MAX +#define MLXBF_I2C_CAUSE_TYU_SLAVE_BIT 3 #define MLXBF_I2C_CAUSE_YU_SLAVE_BIT 1 /* Functional enable register. */ @@ -163,15 +164,6 @@ #define MLXBF_I2C_GPIO_SMBUS_GW_ASSERT_PINS(num, val) \ ((val) | (0x3 << MLXBF_I2C_GPIO_SMBUS_GW_PINS(num))) -/* SMBus timing parameters. */ -#define MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH 0x00 -#define MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE 0x04 -#define MLXBF_I2C_SMBUS_TIMER_THOLD 0x08 -#define MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP 0x0c -#define MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA 0x10 -#define MLXBF_I2C_SMBUS_THIGH_MAX_TBUF 0x14 -#define MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT 0x18 - /* * Defines SMBus operating frequency and core clock frequency. * According to ADB files, default values are compliant to 100KHz SMBus @@ -181,42 +173,47 @@ #define MLXBF_I2C_COREPLL_FREQ MLXBF_I2C_TYU_PLL_OUT_FREQ /* Core PLL TYU configuration. */ -#define MLXBF_I2C_COREPLL_CORE_F_TYU_MASK GENMASK(12, 0) -#define MLXBF_I2C_COREPLL_CORE_OD_TYU_MASK GENMASK(3, 0) -#define MLXBF_I2C_COREPLL_CORE_R_TYU_MASK GENMASK(5, 0) - -#define MLXBF_I2C_COREPLL_CORE_F_TYU_SHIFT 3 -#define MLXBF_I2C_COREPLL_CORE_OD_TYU_SHIFT 16 -#define MLXBF_I2C_COREPLL_CORE_R_TYU_SHIFT 20 +#define MLXBF_I2C_COREPLL_CORE_F_TYU_MASK GENMASK(15, 3) +#define MLXBF_I2C_COREPLL_CORE_OD_TYU_MASK GENMASK(19, 16) +#define MLXBF_I2C_COREPLL_CORE_R_TYU_MASK GENMASK(25, 20) /* Core PLL YU configuration. */ #define MLXBF_I2C_COREPLL_CORE_F_YU_MASK GENMASK(25, 0) #define MLXBF_I2C_COREPLL_CORE_OD_YU_MASK GENMASK(3, 0) -#define MLXBF_I2C_COREPLL_CORE_R_YU_MASK GENMASK(5, 0) +#define MLXBF_I2C_COREPLL_CORE_R_YU_MASK GENMASK(31, 26) -#define MLXBF_I2C_COREPLL_CORE_F_YU_SHIFT 0 -#define MLXBF_I2C_COREPLL_CORE_OD_YU_SHIFT 1 -#define MLXBF_I2C_COREPLL_CORE_R_YU_SHIFT 26 +/* SMBus timing parameters. */ +#define MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH 0x00 +#define MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE 0x04 +#define MLXBF_I2C_SMBUS_TIMER_THOLD 0x08 +#define MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP 0x0c +#define MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA 0x10 +#define MLXBF_I2C_SMBUS_THIGH_MAX_TBUF 0x14 +#define MLXBF_I2C_SMBUS_SCL_LOW_TIMEOUT 0x18 -/* Core PLL frequency. */ -static u64 mlxbf_i2c_corepll_frequency; +#define MLXBF_I2C_SHIFT_0 0 +#define MLXBF_I2C_SHIFT_8 8 +#define MLXBF_I2C_SHIFT_16 16 +#define MLXBF_I2C_SHIFT_24 24 + +#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 /* SMBus Master GW. */ -#define MLXBF_I2C_SMBUS_MASTER_GW 0x200 +#define MLXBF_I2C_SMBUS_MASTER_GW 0x0 /* Number of bytes received and sent. */ -#define MLXBF_I2C_SMBUS_RS_BYTES 0x300 +#define MLXBF_I2C_YU_SMBUS_RS_BYTES 0x100 +#define MLXBF_I2C_RSH_YU_SMBUS_RS_BYTES 0x10c /* Packet error check (PEC) value. */ -#define MLXBF_I2C_SMBUS_MASTER_PEC 0x304 +#define MLXBF_I2C_SMBUS_MASTER_PEC 0x104 /* Status bits (ACK/NACK/FW Timeout). */ -#define MLXBF_I2C_SMBUS_MASTER_STATUS 0x308 +#define MLXBF_I2C_SMBUS_MASTER_STATUS 0x108 /* SMbus Master Finite State Machine. */ -#define MLXBF_I2C_SMBUS_MASTER_FSM 0x310 - -/* - * When enabled, the master will issue a stop condition in case of - * timeout while waiting for FW response. - */ -#define MLXBF_I2C_SMBUS_EN_FW_TIMEOUT 0x31c +#define MLXBF_I2C_YU_SMBUS_MASTER_FSM 0x110 +#define MLXBF_I2C_RSH_YU_SMBUS_MASTER_FSM 0x100 /* SMBus master GW control bits offset in MLXBF_I2C_SMBUS_MASTER_GW[31:3]. */ #define MLXBF_I2C_MASTER_LOCK_BIT BIT(31) /* Lock bit. */ @@ -228,7 +225,7 @@ static u64 mlxbf_i2c_corepll_frequency; #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) @@ -236,14 +233,14 @@ static u64 mlxbf_i2c_corepll_frequency; #define MLXBF_I2C_MASTER_ENABLE_READ \ (MLXBF_I2C_MASTER_ENABLE | MLXBF_I2C_MASTER_CTL_READ_BIT) -#define MLXBF_I2C_MASTER_SLV_ADDR_SHIFT 12 /* Slave address shift. */ -#define MLXBF_I2C_MASTER_WRITE_SHIFT 21 /* Control write bytes shift. */ -#define MLXBF_I2C_MASTER_SEND_PEC_SHIFT 20 /* Send PEC byte shift. */ -#define MLXBF_I2C_MASTER_PARSE_EXP_SHIFT 11 /* Parse expected bytes shift. */ -#define MLXBF_I2C_MASTER_READ_SHIFT 4 /* Control read bytes shift. */ +#define MLXBF_I2C_MASTER_WRITE_SHIFT 21 /* Control write bytes */ +#define MLXBF_I2C_MASTER_SEND_PEC_SHIFT 20 /* Send PEC byte when set to 1 */ +#define MLXBF_I2C_MASTER_PARSE_EXP_SHIFT 11 /* Control parse expected bytes */ +#define MLXBF_I2C_MASTER_SLV_ADDR_SHIFT 12 /* Slave address */ +#define MLXBF_I2C_MASTER_READ_SHIFT 4 /* Control read bytes */ /* SMBus master GW Data descriptor. */ -#define MLXBF_I2C_MASTER_DATA_DESC_ADDR 0x280 +#define MLXBF_I2C_MASTER_DATA_DESC_ADDR 0x80 #define MLXBF_I2C_MASTER_DATA_DESC_SIZE 0x80 /* Size in bytes. */ /* Maximum bytes to read/write per SMBus transaction. */ @@ -269,19 +266,21 @@ static u64 mlxbf_i2c_corepll_frequency; #define MLXBF_I2C_SMBUS_MASTER_FSM_STOP_MASK BIT(31) #define MLXBF_I2C_SMBUS_MASTER_FSM_PS_STATE_MASK BIT(15) +#define MLXBF_I2C_SLV_ADDR_OFFSET 0x400 + /* SMBus slave GW. */ -#define MLXBF_I2C_SMBUS_SLAVE_GW 0x400 +#define MLXBF_I2C_SMBUS_SLAVE_GW 0x0 /* Number of bytes received and sent from/to master. */ -#define MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES 0x500 +#define MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES 0x100 /* Packet error check (PEC) value. */ -#define MLXBF_I2C_SMBUS_SLAVE_PEC 0x504 +#define MLXBF_I2C_SMBUS_SLAVE_PEC 0x104 /* SMBus slave Finite State Machine (FSM). */ -#define MLXBF_I2C_SMBUS_SLAVE_FSM 0x510 +#define MLXBF_I2C_SMBUS_SLAVE_FSM 0x110 /* * Should be set when all raised causes handled, and cleared by HW on * every new cause. */ -#define MLXBF_I2C_SMBUS_SLAVE_READY 0x52c +#define MLXBF_I2C_SMBUS_SLAVE_READY 0x12c /* SMBus slave GW control bits offset in MLXBF_I2C_SMBUS_SLAVE_GW[31:19]. */ #define MLXBF_I2C_SLAVE_BUSY_BIT BIT(30) /* Busy bit. */ @@ -294,23 +293,75 @@ static u64 mlxbf_i2c_corepll_frequency; #define MLXBF_I2C_SLAVE_SEND_PEC_SHIFT 21 /* Send PEC byte shift. */ /* SMBus slave GW Data descriptor. */ -#define MLXBF_I2C_SLAVE_DATA_DESC_ADDR 0x480 +#define MLXBF_I2C_SLAVE_DATA_DESC_ADDR 0x80 #define MLXBF_I2C_SLAVE_DATA_DESC_SIZE 0x80 /* Size in bytes. */ /* SMbus slave configuration registers. */ -#define MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG 0x514 +#define MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG 0x114 #define MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT 16 -#define MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT 7 +#define MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT BIT(7) #define MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK GENMASK(6, 0) -#define MLXBF_I2C_SLAVE_ADDR_ENABLED(addr) \ - ((addr) & (1 << MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT)) - /* * Timeout is given in microsends. Note also that timeout handling is not * exact. */ #define MLXBF_I2C_SMBUS_TIMEOUT (300 * 1000) /* 300ms */ +#define MLXBF_I2C_SMBUS_LOCK_POLL_TIMEOUT (300 * 1000) /* 300ms */ + +/* Polling frequency in microseconds. */ +#define MLXBF_I2C_POLL_FREQ_IN_USEC 200 + +#define MLXBF_I2C_SMBUS_OP_CNT_1 1 +#define MLXBF_I2C_SMBUS_OP_CNT_2 2 +#define MLXBF_I2C_SMBUS_OP_CNT_3 3 +#define MLXBF_I2C_SMBUS_MAX_OP_CNT MLXBF_I2C_SMBUS_OP_CNT_3 + +/* Helper macro to define an I2C resource parameters. */ +#define MLXBF_I2C_RES_PARAMS(addr, size, str) \ + { \ + .start = (addr), \ + .end = (addr) + (size) - 1, \ + .name = (str) \ + } + +enum { + MLXBF_I2C_TIMING_100KHZ = 100000, + MLXBF_I2C_TIMING_400KHZ = 400000, + MLXBF_I2C_TIMING_1000KHZ = 1000000, +}; + +enum { + MLXBF_I2C_F_READ = BIT(0), + MLXBF_I2C_F_WRITE = BIT(1), + MLXBF_I2C_F_NORESTART = BIT(3), + MLXBF_I2C_F_SMBUS_OPERATION = BIT(4), + 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. */ +enum mlxbf_i2c_chip_type { + MLXBF_I2C_CHIP_TYPE_1, /* Mellanox BlueField-1 chip. */ + MLXBF_I2C_CHIP_TYPE_2, /* Mellanox BlueField-2 chip. */ + MLXBF_I2C_CHIP_TYPE_3 /* Mellanox BlueField-3 chip. */ +}; + +/* List of chip resources that are being accessed by the driver. */ +enum { + MLXBF_I2C_SMBUS_RES, + MLXBF_I2C_MST_CAUSE_RES, + MLXBF_I2C_SLV_CAUSE_RES, + MLXBF_I2C_COALESCE_RES, + MLXBF_I2C_SMBUS_TIMER_RES, + MLXBF_I2C_SMBUS_MST_RES, + MLXBF_I2C_SMBUS_SLV_RES, + MLXBF_I2C_COREPLL_RES, + MLXBF_I2C_GPIO_RES, + MLXBF_I2C_END_RES +}; /* Encapsulates timing parameters. */ struct mlxbf_i2c_timings { @@ -331,27 +382,12 @@ struct mlxbf_i2c_timings { u32 timeout; /* Detect clock low timeout. */ }; -enum { - MLXBF_I2C_F_READ = BIT(0), - MLXBF_I2C_F_WRITE = BIT(1), - MLXBF_I2C_F_NORESTART = BIT(3), - MLXBF_I2C_F_SMBUS_OPERATION = BIT(4), - MLXBF_I2C_F_SMBUS_BLOCK = BIT(5), - MLXBF_I2C_F_SMBUS_PEC = BIT(6), - MLXBF_I2C_F_SMBUS_PROCESS_CALL = BIT(7), -}; - struct mlxbf_i2c_smbus_operation { u32 flags; u32 length; /* Buffer length in bytes. */ u8 *buffer; }; -#define MLXBF_I2C_SMBUS_OP_CNT_1 1 -#define MLXBF_I2C_SMBUS_OP_CNT_2 2 -#define MLXBF_I2C_SMBUS_OP_CNT_3 3 -#define MLXBF_I2C_SMBUS_MAX_OP_CNT MLXBF_I2C_SMBUS_OP_CNT_3 - struct mlxbf_i2c_smbus_request { u8 slave; u8 operation_cnt; @@ -365,24 +401,38 @@ struct mlxbf_i2c_resource { u8 type; }; -/* List of chip resources that are being accessed by the driver. */ -enum { - MLXBF_I2C_SMBUS_RES, - MLXBF_I2C_MST_CAUSE_RES, - MLXBF_I2C_SLV_CAUSE_RES, - MLXBF_I2C_COALESCE_RES, - MLXBF_I2C_COREPLL_RES, - MLXBF_I2C_GPIO_RES, - MLXBF_I2C_END_RES, +struct mlxbf_i2c_chip_info { + enum mlxbf_i2c_chip_type type; + /* Chip shared resources that are being used by the I2C controller. */ + struct mlxbf_i2c_resource *shared_res[MLXBF_I2C_SHARED_RES_MAX]; + + /* Callback to calculate the core PLL frequency. */ + u64 (*calculate_freq)(struct mlxbf_i2c_resource *corepll_res); + + /* Registers' address offset */ + u32 smbus_master_rs_bytes_off; + u32 smbus_master_fsm_off; }; -/* Helper macro to define an I2C resource parameters. */ -#define MLXBF_I2C_RES_PARAMS(addr, size, str) \ - { \ - .start = (addr), \ - .end = (addr) + (size) - 1, \ - .name = (str) \ - } +struct mlxbf_i2c_priv { + const struct mlxbf_i2c_chip_info *chip; + struct i2c_adapter adap; + struct mlxbf_i2c_resource *smbus; + struct mlxbf_i2c_resource *timer; + struct mlxbf_i2c_resource *mst; + struct mlxbf_i2c_resource *slv; + struct mlxbf_i2c_resource *mst_cause; + struct mlxbf_i2c_resource *slv_cause; + struct mlxbf_i2c_resource *coalesce; + u64 frequency; /* Core frequency in Hz. */ + int bus; /* Physical bus identifier. */ + int irq; + struct i2c_client *slave[MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT]; + u32 resource_version; +}; + +/* Core PLL frequency. */ +static u64 mlxbf_i2c_corepll_frequency; static struct resource mlxbf_i2c_coalesce_tyu_params = MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COALESCE_TYU_ADDR, @@ -396,6 +446,10 @@ static struct resource mlxbf_i2c_corepll_yu_params = MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COREPLL_YU_ADDR, MLXBF_I2C_COREPLL_YU_SIZE, "COREPLL_MEM"); +static struct resource mlxbf_i2c_corepll_rsh_yu_params = + MLXBF_I2C_RES_PARAMS(MLXBF_I2C_COREPLL_RSH_YU_ADDR, + MLXBF_I2C_COREPLL_RSH_YU_SIZE, + "COREPLL_MEM"); static struct resource mlxbf_i2c_gpio_tyu_params = MLXBF_I2C_RES_PARAMS(MLXBF_I2C_GPIO_TYU_ADDR, MLXBF_I2C_GPIO_TYU_SIZE, @@ -405,34 +459,6 @@ static struct mutex mlxbf_i2c_coalesce_lock; static struct mutex mlxbf_i2c_corepll_lock; static struct mutex mlxbf_i2c_gpio_lock; -/* Mellanox BlueField chip type. */ -enum mlxbf_i2c_chip_type { - MLXBF_I2C_CHIP_TYPE_1, /* Mellanox BlueField-1 chip. */ - MLXBF_I2C_CHIP_TYPE_2, /* Mallanox BlueField-2 chip. */ -}; - -struct mlxbf_i2c_chip_info { - enum mlxbf_i2c_chip_type type; - /* Chip shared resources that are being used by the I2C controller. */ - struct mlxbf_i2c_resource *shared_res[MLXBF_I2C_SHARED_RES_MAX]; - - /* Callback to calculate the core PLL frequency. */ - u64 (*calculate_freq)(struct mlxbf_i2c_resource *corepll_res); -}; - -struct mlxbf_i2c_priv { - const struct mlxbf_i2c_chip_info *chip; - struct i2c_adapter adap; - struct mlxbf_i2c_resource *smbus; - struct mlxbf_i2c_resource *mst_cause; - struct mlxbf_i2c_resource *slv_cause; - struct mlxbf_i2c_resource *coalesce; - u64 frequency; /* Core frequency in Hz. */ - int bus; /* Physical bus identifier. */ - int irq; - struct i2c_client *slave; -}; - static struct mlxbf_i2c_resource mlxbf_i2c_coalesce_res[] = { [MLXBF_I2C_CHIP_TYPE_1] = { .params = &mlxbf_i2c_coalesce_tyu_params, @@ -452,6 +478,11 @@ static struct mlxbf_i2c_resource mlxbf_i2c_corepll_res[] = { .params = &mlxbf_i2c_corepll_yu_params, .lock = &mlxbf_i2c_corepll_lock, .type = MLXBF_I2C_COREPLL_RES, + }, + [MLXBF_I2C_CHIP_TYPE_3] = { + .params = &mlxbf_i2c_corepll_rsh_yu_params, + .lock = &mlxbf_i2c_corepll_lock, + .type = MLXBF_I2C_COREPLL_RES, } }; @@ -468,59 +499,6 @@ static u8 mlxbf_i2c_bus_count; static struct mutex mlxbf_i2c_bus_lock; -/* Polling frequency in microseconds. */ -#define MLXBF_I2C_POLL_FREQ_IN_USEC 200 - -#define MLXBF_I2C_SHIFT_0 0 -#define MLXBF_I2C_SHIFT_8 8 -#define MLXBF_I2C_SHIFT_16 16 -#define MLXBF_I2C_SHIFT_24 24 - -#define MLXBF_I2C_MASK_8 GENMASK(7, 0) -#define MLXBF_I2C_MASK_16 GENMASK(15, 0) - -#define MLXBF_I2C_FREQUENCY_1GHZ 1000000000 - -/* - * 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_smbus_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_smbus_master_wait_for_idle(struct mlxbf_i2c_priv *priv) -{ - u32 mask = MLXBF_I2C_SMBUS_MASTER_FSM_STOP_MASK; - u32 addr = MLXBF_I2C_SMBUS_MASTER_FSM; - u32 timeout = MLXBF_I2C_SMBUS_TIMEOUT; - - if (mlxbf_smbus_poll(priv->smbus->io, addr, mask, true, timeout)) - return true; - - return false; -} - static bool mlxbf_i2c_smbus_transaction_success(u32 master_status, u32 cause_status) { @@ -550,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 @@ -558,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_smbus_poll(priv->smbus->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 + @@ -571,7 +550,7 @@ static int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv) * Parse both Cause and Master GW bits, then return transaction status. */ - master_status_bits = readl(priv->smbus->io + + master_status_bits = readl(priv->mst->io + MLXBF_I2C_SMBUS_MASTER_STATUS); master_status_bits &= MLXBF_I2C_SMBUS_MASTER_STATUS_MASK; @@ -596,7 +575,8 @@ static int mlxbf_i2c_smbus_check_status(struct mlxbf_i2c_priv *priv) } static void mlxbf_i2c_smbus_write_data(struct mlxbf_i2c_priv *priv, - const u8 *data, u8 length, u32 addr) + const u8 *data, u8 length, u32 addr, + bool is_master) { u8 offset, aligned_length; u32 data32; @@ -613,12 +593,16 @@ static void mlxbf_i2c_smbus_write_data(struct mlxbf_i2c_priv *priv, */ for (offset = 0; offset < aligned_length; offset += sizeof(u32)) { data32 = *((u32 *)(data + offset)); - iowrite32be(data32, priv->smbus->io + addr + offset); + if (is_master) + iowrite32be(data32, priv->mst->io + addr + offset); + else + iowrite32be(data32, priv->slv->io + addr + offset); } } static void mlxbf_i2c_smbus_read_data(struct mlxbf_i2c_priv *priv, - u8 *data, u8 length, u32 addr) + u8 *data, u8 length, u32 addr, + bool is_master) { u32 data32, mask; u8 byte, offset; @@ -634,14 +618,20 @@ static void mlxbf_i2c_smbus_read_data(struct mlxbf_i2c_priv *priv, */ for (offset = 0; offset < (length & ~mask); offset += sizeof(u32)) { - data32 = ioread32be(priv->smbus->io + addr + offset); + if (is_master) + data32 = ioread32be(priv->mst->io + addr + offset); + else + data32 = ioread32be(priv->slv->io + addr + offset); *((u32 *)(data + offset)) = data32; } if (!(length & mask)) return; - data32 = ioread32be(priv->smbus->io + addr + offset); + if (is_master) + data32 = ioread32be(priv->mst->io + addr + offset); + else + data32 = ioread32be(priv->slv->io + addr + offset); for (byte = 0; byte < (length & mask); byte++) { data[offset + byte] = data32 & GENMASK(7, 0); @@ -650,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); @@ -667,16 +660,16 @@ static int mlxbf_i2c_smbus_enable(struct mlxbf_i2c_priv *priv, u8 slave, command |= rol32(pec_en, MLXBF_I2C_MASTER_SEND_PEC_SHIFT); /* Clear status bits. */ - writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_STATUS); + writel(0x0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_STATUS); /* Set the cause data. */ - writel(~0x0, priv->smbus->io + MLXBF_I2C_CAUSE_OR_CLEAR); + writel(~0x0, priv->mst_cause->io + MLXBF_I2C_CAUSE_OR_CLEAR); /* Zero PEC byte. */ - writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_PEC); + writel(0x0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_PEC); /* Zero byte count. */ - writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_RS_BYTES); + writel(0x0, priv->mst->io + priv->chip->smbus_master_rs_bytes_off); /* GW activation. */ - writel(command, priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_GW); + writel(command, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW); /* * Poll master status and check status bits. An ACK is sent when @@ -694,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; @@ -712,10 +708,30 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, slave = request->slave & GENMASK(6, 0); addr = slave << 1; - /* First of all, check whether the HW is idle. */ - if (WARN_ON(!mlxbf_smbus_master_wait_for_idle(priv))) + /* + * Try to acquire the smbus gw lock before any reads of the GW register since + * a read sets the lock. + */ + 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; + /* + * 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; + } + /* Set first byte. */ data_desc[data_idx++] = addr; @@ -738,10 +754,24 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, if (flags & MLXBF_I2C_F_WRITE) { write_en = 1; write_len += operation->length; + if (data_idx + operation->length > + MLXBF_I2C_MASTER_DATA_DESC_SIZE) { + ret = -ENOBUFS; + goto out_unlock; + } 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 @@ -763,25 +793,25 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, * must be written to the data registers. */ mlxbf_i2c_smbus_write_data(priv, (const u8 *)data_desc, data_len, - MLXBF_I2C_MASTER_DATA_DESC_ADDR); + MLXBF_I2C_MASTER_DATA_DESC_ADDR, true); 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) - return ret; + goto out_unlock; } if (read_en) { /* Write slave address to Master GW data descriptor. */ mlxbf_i2c_smbus_write_data(priv, (const u8 *)&addr, 1, - MLXBF_I2C_MASTER_DATA_DESC_ADDR); + 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, - MLXBF_I2C_MASTER_DATA_DESC_ADDR); + MLXBF_I2C_MASTER_DATA_DESC_ADDR, true); /* Get data from Master GW data descriptor. */ memcpy(read_buf, data_desc, read_len + 1); @@ -793,9 +823,13 @@ mlxbf_i2c_smbus_start_transaction(struct mlxbf_i2c_priv *priv, * next tag integration. */ writel(MLXBF_I2C_SMBUS_MASTER_FSM_PS_STATE_MASK, - priv->smbus->io + MLXBF_I2C_SMBUS_MASTER_FSM); + priv->mst->io + priv->chip->smbus_master_fsm_off); } +out_unlock: + /* Clear the gw to clear the lock */ + writel(0, priv->mst->io + MLXBF_I2C_SMBUS_MASTER_GW); + return ret; } @@ -879,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 @@ -1019,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); @@ -1052,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. @@ -1082,7 +1113,7 @@ static void mlxbf_i2c_set_timings(struct mlxbf_i2c_priv *priv, timer |= mlxbf_i2c_set_timer(priv, timings->scl_low, false, MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16); - writel(timer, priv->smbus->io + + writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_TIMER_SCL_LOW_SCL_HIGH); timer = mlxbf_i2c_set_timer(priv, timings->sda_rise, false, @@ -1093,34 +1124,35 @@ static void mlxbf_i2c_set_timings(struct mlxbf_i2c_priv *priv, MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_16); timer |= mlxbf_i2c_set_timer(priv, timings->scl_fall, false, MLXBF_I2C_MASK_8, MLXBF_I2C_SHIFT_24); - writel(timer, priv->smbus->io + + writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_TIMER_FALL_RISE_SPIKE); timer = mlxbf_i2c_set_timer(priv, timings->hold_start, true, MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); timer |= mlxbf_i2c_set_timer(priv, timings->hold_data, true, MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16); - writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_TIMER_THOLD); + writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_TIMER_THOLD); timer = mlxbf_i2c_set_timer(priv, timings->setup_start, true, MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); timer |= mlxbf_i2c_set_timer(priv, timings->setup_stop, true, MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16); - writel(timer, priv->smbus->io + + writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_TIMER_TSETUP_START_STOP); timer = mlxbf_i2c_set_timer(priv, timings->setup_data, true, MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); - writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA); + writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_TIMER_TSETUP_DATA); timer = mlxbf_i2c_set_timer(priv, timings->buf, false, MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_0); timer |= mlxbf_i2c_set_timer(priv, timings->thigh_max, false, MLXBF_I2C_MASK_16, MLXBF_I2C_SHIFT_16); - writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_THIGH_MAX_TBUF); + writel(timer, priv->timer->io + MLXBF_I2C_SMBUS_THIGH_MAX_TBUF); - timer = timings->timeout; - writel(timer, priv->smbus->io + MLXBF_I2C_SMBUS_SCL_LOW_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); } enum mlxbf_i2c_timings_config { @@ -1129,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, @@ -1148,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, @@ -1164,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 } }; @@ -1407,24 +1435,19 @@ static int mlxbf_i2c_init_master(struct platform_device *pdev, return 0; } -static u64 mlxbf_calculate_freq_from_tyu(struct mlxbf_i2c_resource *corepll_res) +static u64 mlxbf_i2c_calculate_freq_from_tyu(struct mlxbf_i2c_resource *corepll_res) { - u64 core_frequency, pad_frequency; + u64 core_frequency; u8 core_od, core_r; u32 corepll_val; u16 core_f; - pad_frequency = MLXBF_I2C_PLL_IN_FREQ; - corepll_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG1); /* Get Core PLL configuration bits. */ - core_f = rol32(corepll_val, MLXBF_I2C_COREPLL_CORE_F_TYU_SHIFT) & - MLXBF_I2C_COREPLL_CORE_F_TYU_MASK; - core_od = rol32(corepll_val, MLXBF_I2C_COREPLL_CORE_OD_TYU_SHIFT) & - MLXBF_I2C_COREPLL_CORE_OD_TYU_MASK; - core_r = rol32(corepll_val, MLXBF_I2C_COREPLL_CORE_R_TYU_SHIFT) & - MLXBF_I2C_COREPLL_CORE_R_TYU_MASK; + core_f = FIELD_GET(MLXBF_I2C_COREPLL_CORE_F_TYU_MASK, corepll_val); + core_od = FIELD_GET(MLXBF_I2C_COREPLL_CORE_OD_TYU_MASK, corepll_val); + core_r = FIELD_GET(MLXBF_I2C_COREPLL_CORE_R_TYU_MASK, corepll_val); /* * Compute PLL output frequency as follow: @@ -1436,31 +1459,25 @@ static u64 mlxbf_calculate_freq_from_tyu(struct mlxbf_i2c_resource *corepll_res) * Where PLL_OUT_FREQ and PLL_IN_FREQ refer to CoreFrequency * and PadFrequency, respectively. */ - core_frequency = pad_frequency * (++core_f); - core_frequency /= (++core_r) * (++core_od); + core_frequency = MLXBF_I2C_PLL_IN_FREQ * (++core_f); - return core_frequency; + return div_u64(core_frequency, (++core_r) * (++core_od)); } -static u64 mlxbf_calculate_freq_from_yu(struct mlxbf_i2c_resource *corepll_res) +static u64 mlxbf_i2c_calculate_freq_from_yu(struct mlxbf_i2c_resource *corepll_res) { u32 corepll_reg1_val, corepll_reg2_val; - u64 corepll_frequency, pad_frequency; + u64 corepll_frequency; u8 core_od, core_r; u32 core_f; - pad_frequency = MLXBF_I2C_PLL_IN_FREQ; - corepll_reg1_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG1); corepll_reg2_val = readl(corepll_res->io + MLXBF_I2C_CORE_PLL_REG2); /* Get Core PLL configuration bits */ - core_f = rol32(corepll_reg1_val, MLXBF_I2C_COREPLL_CORE_F_YU_SHIFT) & - MLXBF_I2C_COREPLL_CORE_F_YU_MASK; - core_r = rol32(corepll_reg1_val, MLXBF_I2C_COREPLL_CORE_R_YU_SHIFT) & - MLXBF_I2C_COREPLL_CORE_R_YU_MASK; - core_od = rol32(corepll_reg2_val, MLXBF_I2C_COREPLL_CORE_OD_YU_SHIFT) & - MLXBF_I2C_COREPLL_CORE_OD_YU_MASK; + core_f = FIELD_GET(MLXBF_I2C_COREPLL_CORE_F_YU_MASK, corepll_reg1_val); + core_r = FIELD_GET(MLXBF_I2C_COREPLL_CORE_R_YU_MASK, corepll_reg1_val); + core_od = FIELD_GET(MLXBF_I2C_COREPLL_CORE_OD_YU_MASK, corepll_reg2_val); /* * Compute PLL output frequency as follow: @@ -1472,10 +1489,9 @@ static u64 mlxbf_calculate_freq_from_yu(struct mlxbf_i2c_resource *corepll_res) * Where PLL_OUT_FREQ and PLL_IN_FREQ refer to CoreFrequency * and PadFrequency, respectively. */ - corepll_frequency = (pad_frequency * core_f) / MLNXBF_I2C_COREPLL_CONST; - corepll_frequency /= (++core_r) * (++core_od); + corepll_frequency = (MLXBF_I2C_PLL_IN_FREQ * core_f) / MLNXBF_I2C_COREPLL_CONST; - return corepll_frequency; + return div_u64(corepll_frequency, (++core_r) * (++core_od)); } static int mlxbf_i2c_calculate_corepll_freq(struct platform_device *pdev, @@ -1523,28 +1539,26 @@ static int mlxbf_i2c_calculate_corepll_freq(struct platform_device *pdev, return 0; } -static int mlxbf_slave_enable(struct mlxbf_i2c_priv *priv, u8 addr) +static int mlxbf_i2c_slave_enable(struct mlxbf_i2c_priv *priv, + struct i2c_client *slave) { - u32 slave_reg, slave_reg_tmp, slave_reg_avail, slave_addr_mask; - u8 reg, reg_cnt, byte, addr_tmp, reg_avail, byte_avail; - bool avail, disabled; - - disabled = false; - avail = false; + u8 reg, reg_cnt, byte, addr_tmp; + u32 slave_reg, slave_reg_tmp; if (!priv) return -EPERM; reg_cnt = MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT >> 2; - slave_addr_mask = MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK; /* * Read the slave registers. There are 4 * 32-bit slave registers. - * Each slave register can hold up to 4 * 8-bit slave configuration - * (7-bit address, 1 status bit (1 if enabled, 0 if not)). + * Each slave register can hold up to 4 * 8-bit slave configuration: + * 1) A 7-bit address + * 2) And a status bit (1 if enabled, 0 if not). + * Look for the next available slave register slot. */ for (reg = 0; reg < reg_cnt; reg++) { - slave_reg = readl(priv->smbus->io + + slave_reg = readl(priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4); /* * Each register holds 4 slave addresses. So, we have to keep @@ -1556,121 +1570,87 @@ static int mlxbf_slave_enable(struct mlxbf_i2c_priv *priv, u8 addr) addr_tmp = slave_reg_tmp & GENMASK(7, 0); /* - * Mark the first available slave address slot, i.e. its - * enabled bit should be unset. This slot might be used - * later on to register our slave. - */ - if (!avail && !MLXBF_I2C_SLAVE_ADDR_ENABLED(addr_tmp)) { - avail = true; - reg_avail = reg; - byte_avail = byte; - slave_reg_avail = slave_reg; - } - - /* - * Parse slave address bytes and check whether the - * slave address already exists and it's enabled, - * i.e. most significant bit is set. + * If an enable bit is not set in the + * MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG register, then the + * slave address slot associated with that bit is + * free. So set the enable bit and write the + * slave address bits. */ - if ((addr_tmp & slave_addr_mask) == addr) { - if (MLXBF_I2C_SLAVE_ADDR_ENABLED(addr_tmp)) - return 0; - disabled = true; - break; + if (!(addr_tmp & MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT)) { + slave_reg &= ~(MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK << (byte * 8)); + slave_reg |= (slave->addr << (byte * 8)); + slave_reg |= MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT << (byte * 8); + writel(slave_reg, priv->slv->io + + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + + (reg * 0x4)); + + /* + * Set the slave at the corresponding index. + */ + priv->slave[(reg * 4) + byte] = slave; + + return 0; } /* Parse next byte. */ slave_reg_tmp >>= 8; } - - /* Exit the loop if the slave address is found. */ - if (disabled) - break; - } - - if (!avail && !disabled) - return -EINVAL; /* No room for a new slave address. */ - - if (avail && !disabled) { - reg = reg_avail; - byte = byte_avail; - /* Set the slave address. */ - slave_reg_avail &= ~(slave_addr_mask << (byte * 8)); - slave_reg_avail |= addr << (byte * 8); - slave_reg = slave_reg_avail; } - /* Enable the slave address and update the register. */ - slave_reg |= (1 << MLXBF_I2C_SMBUS_SLAVE_ADDR_EN_BIT) << (byte * 8); - writel(slave_reg, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + - reg * 0x4); - - return 0; + return -EBUSY; } -static int mlxbf_slave_disable(struct mlxbf_i2c_priv *priv) +static int mlxbf_i2c_slave_disable(struct mlxbf_i2c_priv *priv, u8 addr) { - u32 slave_reg, slave_reg_tmp, slave_addr_mask; - u8 addr, addr_tmp, reg, reg_cnt, slave_byte; - struct i2c_client *client = priv->slave; - bool exist; - - exist = false; + u8 addr_tmp, reg, reg_cnt, byte; + u32 slave_reg, slave_reg_tmp; - addr = client->addr; reg_cnt = MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT >> 2; - slave_addr_mask = MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK; /* * Read the slave registers. There are 4 * 32-bit slave registers. - * Each slave register can hold up to 4 * 8-bit slave configuration - * (7-bit address, 1 status bit (1 if enabled, 0 if not)). + * Each slave register can hold up to 4 * 8-bit slave configuration: + * 1) A 7-bit address + * 2) And a status bit (1 if enabled, 0 if not). + * Check if addr is present in the registers. */ for (reg = 0; reg < reg_cnt; reg++) { - slave_reg = readl(priv->smbus->io + + slave_reg = readl(priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + reg * 0x4); /* Check whether the address slots are empty. */ - if (slave_reg == 0) + if (!slave_reg) continue; /* - * Each register holds 4 slave addresses. So, we have to keep - * the byte order consistent with the value read in order to - * update the register correctly, if needed. + * Check if addr matches any of the 4 slave addresses + * in the register. */ slave_reg_tmp = slave_reg; - slave_byte = 0; - while (slave_reg_tmp != 0) { - addr_tmp = slave_reg_tmp & slave_addr_mask; + for (byte = 0; byte < 4; byte++) { + addr_tmp = slave_reg_tmp & MLXBF_I2C_SMBUS_SLAVE_ADDR_MASK; /* * Parse slave address bytes and check whether the * slave address already exists. */ if (addr_tmp == addr) { - exist = true; - break; + /* Clear the slave address slot. */ + slave_reg &= ~(GENMASK(7, 0) << (byte * 8)); + writel(slave_reg, priv->slv->io + + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + + (reg * 0x4)); + /* Free slave at the corresponding index */ + priv->slave[(reg * 4) + byte] = NULL; + + return 0; } /* Parse next byte. */ slave_reg_tmp >>= 8; - slave_byte += 1; } - - /* Exit the loop if the slave address is found. */ - if (exist) - break; } - if (!exist) - return 0; /* Slave is not registered, nothing to do. */ - - /* Cleanup the slave address slot. */ - slave_reg &= ~(GENMASK(7, 0) << (slave_byte * 8)); - writel(slave_reg, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_ADDR_CFG + - reg * 0x4); - - return 0; + return -ENXIO; } static int mlxbf_i2c_init_coalesce(struct platform_device *pdev, @@ -1760,7 +1740,7 @@ static int mlxbf_i2c_init_slave(struct platform_device *pdev, int ret; /* Reset FSM. */ - writel(0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_FSM); + writel(0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_FSM); /* * Enable slave cause interrupt bits. Drive @@ -1775,7 +1755,7 @@ static int mlxbf_i2c_init_slave(struct platform_device *pdev, writel(int_reg, priv->slv_cause->io + MLXBF_I2C_CAUSE_OR_EVTEN0); /* Finally, set the 'ready' bit to start handling transactions. */ - writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY); + writel(0x1, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_READY); /* Initialize the cause coalesce resource. */ ret = mlxbf_i2c_init_coalesce(pdev, priv); @@ -1820,84 +1800,81 @@ static bool mlxbf_i2c_has_coalesce(struct mlxbf_i2c_priv *priv, bool *read, return true; } -static bool mlxbf_smbus_slave_wait_for_idle(struct mlxbf_i2c_priv *priv, - u32 timeout) +static struct i2c_client *mlxbf_i2c_get_slave_from_addr( + struct mlxbf_i2c_priv *priv, u8 addr) { - u32 mask = MLXBF_I2C_CAUSE_S_GW_BUSY_FALL; - u32 addr = MLXBF_I2C_CAUSE_ARBITER; + int i; - if (mlxbf_smbus_poll(priv->slv_cause->io, addr, mask, false, timeout)) - return true; + for (i = 0; i < MLXBF_I2C_SMBUS_SLAVE_ADDR_CNT; i++) { + if (!priv->slave[i]) + continue; - return false; + if (priv->slave[i]->addr == addr) + return priv->slave[i]; + } + + return NULL; } -/* Send byte to 'external' smbus master. */ -static int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes) +/* + * Send byte to 'external' smbus master. This function is executed when + * an external smbus master wants to read data from the BlueField. + */ +static int mlxbf_i2c_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes) { u8 data_desc[MLXBF_I2C_SLAVE_DATA_DESC_SIZE] = { 0 }; - u8 write_size, pec_en, addr, byte, value, byte_cnt, desc_size; - struct i2c_client *slave = priv->slave; + u8 write_size, pec_en, addr, value, byte_cnt; + struct i2c_client *slave; u32 control32, data32; - int ret; - - if (!slave) - return -EINVAL; - - addr = 0; - byte = 0; - desc_size = MLXBF_I2C_SLAVE_DATA_DESC_SIZE; + int ret = 0; /* - * Read bytes received from the external master. These bytes should - * be located in the first data descriptor register of the slave GW. - * These bytes are the slave address byte and the internal register - * address, if supplied. + * Read the first byte received from the external master to + * determine the slave address. This byte is located in the + * first data descriptor register of the slave GW. */ - if (recv_bytes > 0) { - data32 = ioread32be(priv->smbus->io + - MLXBF_I2C_SLAVE_DATA_DESC_ADDR); - - /* Parse the received bytes. */ - switch (recv_bytes) { - case 2: - byte = (data32 >> 8) & GENMASK(7, 0); - fallthrough; - case 1: - addr = (data32 & GENMASK(7, 0)) >> 1; - } + data32 = ioread32be(priv->slv->io + + MLXBF_I2C_SLAVE_DATA_DESC_ADDR); + addr = (data32 & GENMASK(7, 0)) >> 1; - /* Check whether it's our slave address. */ - if (slave->addr != addr) - return -EINVAL; + /* + * Check if the slave address received in the data descriptor register + * matches any of the slave addresses registered. If there is a match, + * set the slave. + */ + slave = mlxbf_i2c_get_slave_from_addr(priv, addr); + if (!slave) { + ret = -ENXIO; + goto clear_csr; } /* - * I2C read transactions may start by a WRITE followed by a READ. - * Indeed, most slave devices would expect the internal address - * following the slave address byte. So, write that byte first, - * and then, send the requested data bytes to the master. + * An I2C read can consist of a WRITE bit transaction followed by + * a READ bit transaction. Indeed, slave devices often expect + * the slave address to be followed by the internal address. + * So, write the internal address byte first, and then, send the + * requested data to the master. */ if (recv_bytes > 1) { i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); - value = byte; + value = (data32 >> 8) & GENMASK(7, 0); ret = i2c_slave_event(slave, I2C_SLAVE_WRITE_RECEIVED, &value); i2c_slave_event(slave, I2C_SLAVE_STOP, &value); if (ret < 0) - return ret; + goto clear_csr; } /* - * Now, send data to the master; currently, the driver supports - * READ_BYTE, READ_WORD and BLOCK READ protocols. Note that the - * hardware can send up to 128 bytes per transfer. That is the - * size of its data registers. + * Send data to the master. Currently, the driver supports + * READ_BYTE, READ_WORD and BLOCK READ protocols. The + * hardware can send up to 128 bytes per transfer which is + * the total size of the data registers. */ i2c_slave_event(slave, I2C_SLAVE_READ_REQUESTED, &value); - for (byte_cnt = 0; byte_cnt < desc_size; byte_cnt++) { + for (byte_cnt = 0; byte_cnt < MLXBF_I2C_SLAVE_DATA_DESC_SIZE; byte_cnt++) { data_desc[byte_cnt] = value; i2c_slave_event(slave, I2C_SLAVE_READ_PROCESSED, &value); } @@ -1905,14 +1882,12 @@ static int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes) /* Send a stop condition to the backend. */ i2c_slave_event(slave, I2C_SLAVE_STOP, &value); - /* Handle the actual transfer. */ - /* Set the number of bytes to write to master. */ write_size = (byte_cnt - 1) & 0x7f; /* Write data to Slave GW data descriptor. */ mlxbf_i2c_smbus_write_data(priv, data_desc, byte_cnt, - MLXBF_I2C_SLAVE_DATA_DESC_ADDR); + MLXBF_I2C_SLAVE_DATA_DESC_ADDR, false); pec_en = 0; /* Disable PEC since it is not supported. */ @@ -1921,46 +1896,54 @@ static int mlxbf_smbus_irq_send(struct mlxbf_i2c_priv *priv, u8 recv_bytes) control32 |= rol32(write_size, MLXBF_I2C_SLAVE_WRITE_BYTES_SHIFT); control32 |= rol32(pec_en, MLXBF_I2C_SLAVE_SEND_PEC_SHIFT); - writel(control32, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_GW); + writel(control32, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_GW); /* * 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_smbus_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. */ - writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); - writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_PEC); - writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY); + writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); + writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_PEC); + writel(0x1, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_READY); - return 0; + return ret; } -/* Receive bytes from 'external' smbus master. */ -static int mlxbf_smbus_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes) +/* + * Receive bytes from 'external' smbus master. This function is executed when + * an external smbus master wants to write data to the BlueField. + */ +static int mlxbf_i2c_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes) { u8 data_desc[MLXBF_I2C_SLAVE_DATA_DESC_SIZE] = { 0 }; - struct i2c_client *slave = priv->slave; + struct i2c_client *slave; u8 value, byte, addr; int ret = 0; - if (!slave) - return -EINVAL; - /* Read data from Slave GW data descriptor. */ mlxbf_i2c_smbus_read_data(priv, data_desc, recv_bytes, - MLXBF_I2C_SLAVE_DATA_DESC_ADDR); - - /* Check whether its our slave address. */ + MLXBF_I2C_SLAVE_DATA_DESC_ADDR, false); addr = data_desc[0] >> 1; - if (slave->addr != addr) - return -EINVAL; /* - * Notify the slave backend; another I2C master wants to write data - * to us. This event is sent once the slave address and the write bit - * is detected. + * Check if the slave address received in the data descriptor register + * matches any of the slave addresses registered. + */ + slave = mlxbf_i2c_get_slave_from_addr(priv, addr); + if (!slave) { + ret = -EINVAL; + goto clear_csr; + } + + /* + * Notify the slave backend that an smbus master wants to write data + * to the BlueField. */ i2c_slave_event(slave, I2C_SLAVE_WRITE_REQUESTED, &value); @@ -1973,18 +1956,22 @@ static int mlxbf_smbus_irq_recv(struct mlxbf_i2c_priv *priv, u8 recv_bytes) break; } - /* Send a stop condition to the backend. */ + /* + * Send a stop event to the slave backend, to signal + * the end of the write transactions. + */ i2c_slave_event(slave, I2C_SLAVE_STOP, &value); +clear_csr: /* Release the Slave GW. */ - writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); - writel(0x0, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_PEC); - writel(0x1, priv->smbus->io + MLXBF_I2C_SMBUS_SLAVE_READY); + writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); + writel(0x0, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_PEC); + writel(0x1, priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_READY); return ret; } -static irqreturn_t mlxbf_smbus_irq(int irq, void *ptr) +static irqreturn_t mlxbf_i2c_irq(int irq, void *ptr) { struct mlxbf_i2c_priv *priv = ptr; bool read, write, irq_is_set; @@ -2014,7 +2001,7 @@ static irqreturn_t mlxbf_smbus_irq(int irq, void *ptr) * slave, if the higher 8 bits are sent then the slave expect N bytes * from the master. */ - rw_bytes_reg = readl(priv->smbus->io + + rw_bytes_reg = readl(priv->slv->io + MLXBF_I2C_SMBUS_SLAVE_RS_MASTER_BYTES); recv_bytes = (rw_bytes_reg >> 8) & GENMASK(7, 0); @@ -2032,9 +2019,9 @@ static irqreturn_t mlxbf_smbus_irq(int irq, void *ptr) MLXBF_I2C_SLAVE_DATA_DESC_SIZE : recv_bytes; if (read) - mlxbf_smbus_irq_send(priv, recv_bytes); + mlxbf_i2c_irq_send(priv, recv_bytes); else - mlxbf_smbus_irq_recv(priv, recv_bytes); + mlxbf_i2c_irq_recv(priv, recv_bytes); return IRQ_HANDLED; } @@ -2066,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: @@ -2088,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: @@ -2096,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: @@ -2129,23 +2116,21 @@ static s32 mlxbf_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr, static int mlxbf_i2c_reg_slave(struct i2c_client *slave) { struct mlxbf_i2c_priv *priv = i2c_get_adapdata(slave->adapter); + struct device *dev = &slave->dev; int ret; - if (priv->slave) - return -EBUSY; - /* * Do not support ten bit chip address and do not use Packet Error * Checking (PEC). */ - if (slave->flags & (I2C_CLIENT_TEN | I2C_CLIENT_PEC)) + if (slave->flags & (I2C_CLIENT_TEN | I2C_CLIENT_PEC)) { + dev_err(dev, "SMBus PEC and 10 bit address not supported\n"); return -EAFNOSUPPORT; + } - ret = mlxbf_slave_enable(priv, slave->addr); - if (ret < 0) - return ret; - - priv->slave = slave; + ret = mlxbf_i2c_slave_enable(priv, slave); + if (ret) + dev_err(dev, "Surpassed max number of registered slaves allowed\n"); return 0; } @@ -2153,18 +2138,19 @@ static int mlxbf_i2c_reg_slave(struct i2c_client *slave) static int mlxbf_i2c_unreg_slave(struct i2c_client *slave) { struct mlxbf_i2c_priv *priv = i2c_get_adapdata(slave->adapter); + struct device *dev = &slave->dev; int ret; - WARN_ON(!priv->slave); - - /* Unregister slave, i.e. disable the slave address in hardware. */ - ret = mlxbf_slave_disable(priv); - if (ret < 0) - return ret; - - priv->slave = NULL; + /* + * Unregister slave by: + * 1) Disabling the slave address in hardware + * 2) Freeing priv->slave at the corresponding index + */ + ret = mlxbf_i2c_slave_disable(priv, slave->addr); + if (ret) + dev_err(dev, "Unable to find slave 0x%x\n", slave->addr); - return 0; + return ret; } static u32 mlxbf_i2c_functionality(struct i2c_adapter *adap) @@ -2180,14 +2166,27 @@ static struct mlxbf_i2c_chip_info mlxbf_i2c_chip[] = { [1] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_1], [2] = &mlxbf_i2c_gpio_res[MLXBF_I2C_CHIP_TYPE_1] }, - .calculate_freq = mlxbf_calculate_freq_from_tyu + .calculate_freq = mlxbf_i2c_calculate_freq_from_tyu, + .smbus_master_rs_bytes_off = MLXBF_I2C_YU_SMBUS_RS_BYTES, + .smbus_master_fsm_off = MLXBF_I2C_YU_SMBUS_MASTER_FSM }, [MLXBF_I2C_CHIP_TYPE_2] = { .type = MLXBF_I2C_CHIP_TYPE_2, .shared_res = { [0] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_2] }, - .calculate_freq = mlxbf_calculate_freq_from_yu + .calculate_freq = mlxbf_i2c_calculate_freq_from_yu, + .smbus_master_rs_bytes_off = MLXBF_I2C_YU_SMBUS_RS_BYTES, + .smbus_master_fsm_off = MLXBF_I2C_YU_SMBUS_MASTER_FSM + }, + [MLXBF_I2C_CHIP_TYPE_3] = { + .type = MLXBF_I2C_CHIP_TYPE_3, + .shared_res = { + [0] = &mlxbf_i2c_corepll_res[MLXBF_I2C_CHIP_TYPE_3] + }, + .calculate_freq = mlxbf_i2c_calculate_freq_from_yu, + .smbus_master_rs_bytes_off = MLXBF_I2C_RSH_YU_SMBUS_RS_BYTES, + .smbus_master_fsm_off = MLXBF_I2C_RSH_YU_SMBUS_MASTER_FSM } }; @@ -2203,24 +2202,10 @@ static struct i2c_adapter_quirks mlxbf_i2c_quirks = { .max_write_len = MLXBF_I2C_MASTER_DATA_W_LENGTH, }; -static const struct of_device_id mlxbf_i2c_dt_ids[] = { - { - .compatible = "mellanox,i2c-mlxbf1", - .data = &mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_1] - }, - { - .compatible = "mellanox,i2c-mlxbf2", - .data = &mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_2] - }, - {}, -}; - -MODULE_DEVICE_TABLE(of, mlxbf_i2c_dt_ids); - -#ifdef CONFIG_ACPI static const struct acpi_device_id mlxbf_i2c_acpi_ids[] = { { "MLNXBF03", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_1] }, { "MLNXBF23", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_2] }, + { "MLNXBF31", (kernel_ulong_t)&mlxbf_i2c_chip[MLXBF_I2C_CHIP_TYPE_3] }, {}, }; @@ -2229,64 +2214,25 @@ MODULE_DEVICE_TABLE(acpi, mlxbf_i2c_acpi_ids); static int mlxbf_i2c_acpi_probe(struct device *dev, struct mlxbf_i2c_priv *priv) { const struct acpi_device_id *aid; - struct acpi_device *adev; - unsigned long bus_id = 0; - const char *uid; + u64 bus_id; int ret; if (acpi_disabled) return -ENOENT; - adev = ACPI_COMPANION(dev); - if (!adev) - return -ENXIO; - aid = acpi_match_device(mlxbf_i2c_acpi_ids, dev); if (!aid) return -ENODEV; priv->chip = (struct mlxbf_i2c_chip_info *)aid->driver_data; - uid = acpi_device_uid(adev); - if (!uid || !(*uid)) { + ret = acpi_dev_uid_to_integer(ACPI_COMPANION(dev), &bus_id); + if (ret) { dev_err(dev, "Cannot retrieve UID\n"); - return -ENODEV; - } - - ret = kstrtoul(uid, 0, &bus_id); - if (!ret) - priv->bus = bus_id; - - return ret; -} -#else -static int mlxbf_i2c_acpi_probe(struct device *dev, struct mlxbf_i2c_priv *priv) -{ - return -ENOENT; -} -#endif /* CONFIG_ACPI */ - -static int mlxbf_i2c_of_probe(struct device *dev, struct mlxbf_i2c_priv *priv) -{ - const struct of_device_id *oid; - int bus_id = -1; - - if (IS_ENABLED(CONFIG_OF) && dev->of_node) { - oid = of_match_node(mlxbf_i2c_dt_ids, dev->of_node); - if (!oid) - return -ENODEV; - - priv->chip = oid->data; - - bus_id = of_alias_get_id(dev->of_node, "i2c"); - if (bus_id >= 0) - priv->bus = bus_id; + return ret; } - if (bus_id < 0) { - dev_err(dev, "Cannot get bus id"); - return bus_id; - } + priv->bus = bus_id; return 0; } @@ -2296,6 +2242,7 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct mlxbf_i2c_priv *priv; struct i2c_adapter *adap; + u32 resource_version; int irq, ret; priv = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_priv), GFP_KERNEL); @@ -2303,32 +2250,66 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) return -ENOMEM; ret = mlxbf_i2c_acpi_probe(dev, priv); - if (ret < 0 && ret != -ENOENT && ret != -ENXIO) - ret = mlxbf_i2c_of_probe(dev, priv); - if (ret < 0) return ret; - 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; + /* This property allows the driver to stay backward compatible with older + * ACPI tables. + * Starting BlueField-3 SoC, the "smbus" resource was broken down into 3 + * separate resources "timer", "master" and "slave". + */ + if (device_property_read_u32(dev, "resource_version", &resource_version)) + resource_version = 0; + + priv->resource_version = resource_version; + + if (priv->chip->type < MLXBF_I2C_CHIP_TYPE_3 && resource_version == 0) { + priv->timer = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_resource), GFP_KERNEL); + if (!priv->timer) + return -ENOMEM; + + priv->mst = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_resource), GFP_KERNEL); + if (!priv->mst) + return -ENOMEM; + + priv->slv = devm_kzalloc(dev, sizeof(struct mlxbf_i2c_resource), GFP_KERNEL); + if (!priv->slv) + return -ENOMEM; + + ret = mlxbf_i2c_init_resource(pdev, &priv->smbus, + MLXBF_I2C_SMBUS_RES); + 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; + priv->slv->io = priv->smbus->io + MLXBF_I2C_SLV_ADDR_OFFSET; + } else { + ret = mlxbf_i2c_init_resource(pdev, &priv->timer, + MLXBF_I2C_SMBUS_TIMER_RES); + 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) + 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) + 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; @@ -2359,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); @@ -2372,13 +2351,11 @@ static int mlxbf_i2c_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; - ret = devm_request_irq(dev, irq, mlxbf_smbus_irq, - IRQF_ONESHOT | IRQF_SHARED | IRQF_PROBE_SHARED, + 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; @@ -2395,14 +2372,25 @@ 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; struct resource *params; - params = priv->smbus->params; - devm_release_mem_region(dev, params->start, resource_size(params)); + if (priv->chip->type < MLXBF_I2C_CHIP_TYPE_3 && priv->resource_version == 0) { + params = priv->smbus->params; + devm_release_mem_region(dev, params->start, resource_size(params)); + } else { + params = priv->timer->params; + devm_release_mem_region(dev, params->start, resource_size(params)); + + params = priv->mst->params; + devm_release_mem_region(dev, params->start, resource_size(params)); + + params = priv->slv->params; + devm_release_mem_region(dev, params->start, resource_size(params)); + } params = priv->mst_cause->params; devm_release_mem_region(dev, params->start, resource_size(params)); @@ -2425,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 = { @@ -2434,10 +2420,7 @@ static struct platform_driver mlxbf_i2c_driver = { .remove = mlxbf_i2c_remove, .driver = { .name = "i2c-mlxbf", - .of_match_table = mlxbf_i2c_dt_ids, -#ifdef CONFIG_ACPI .acpi_match_table = ACPI_PTR(mlxbf_i2c_acpi_ids), -#endif /* CONFIG_ACPI */ }, }; @@ -2467,4 +2450,5 @@ module_exit(mlxbf_i2c_exit); MODULE_DESCRIPTION("Mellanox BlueField I2C bus driver"); MODULE_AUTHOR("Khalil Blaiech <kblaiech@nvidia.com>"); +MODULE_AUTHOR("Asmaa Mnebhi <asmaa@nvidia.com>"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/i2c/busses/i2c-mlxcpld.c b/drivers/i2c/busses/i2c-mlxcpld.c index 4e0b7c2882ce..07d3cadbf510 100644 --- a/drivers/i2c/busses/i2c-mlxcpld.c +++ b/drivers/i2c/busses/i2c-mlxcpld.c @@ -22,12 +22,13 @@ #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 #define MLXCPLD_I2C_RETR_NUM 2 #define MLXCPLD_I2C_XFER_TO 500000 /* usec */ -#define MLXCPLD_I2C_POLL_TIME 400 /* usec */ +#define MLXCPLD_I2C_POLL_TIME 200 /* usec */ /* LPC I2C registers */ #define MLXCPLD_LPCI2C_CPBLTY_REG 0x0 @@ -40,7 +41,7 @@ #define MLXCPLD_LPCI2C_STATUS_REG 0x9 #define MLXCPLD_LPCI2C_DATA_REG 0xa -/* LPC I2C masks and parametres */ +/* LPC I2C masks and parameters */ #define MLXCPLD_LPCI2C_RST_SEL_MASK 0x1 #define MLXCPLD_LPCI2C_TRANS_END 0x1 #define MLXCPLD_LPCI2C_STATUS_NACK 0x10 @@ -49,7 +50,7 @@ #define MLXCPLD_LPCI2C_NACK_IND 2 #define MLXCPLD_I2C_FREQ_1000KHZ_SET 0x04 -#define MLXCPLD_I2C_FREQ_400KHZ_SET 0x0f +#define MLXCPLD_I2C_FREQ_400KHZ_SET 0x0e #define MLXCPLD_I2C_FREQ_100KHZ_SET 0x42 enum mlxcpld_i2c_frequency { @@ -73,6 +74,7 @@ struct mlxcpld_i2c_priv { struct mlxcpld_i2c_curr_xfer xfer; struct device *dev; bool smbus_block; + int polling_time; }; static void mlxcpld_i2c_lpc_write_buf(u8 *data, u8 len, u32 addr) @@ -195,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; @@ -267,8 +269,8 @@ static int mlxcpld_i2c_wait_for_free(struct mlxcpld_i2c_priv *priv) do { if (!mlxcpld_i2c_check_busy(priv)) break; - usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME); - timeout += MLXCPLD_I2C_POLL_TIME; + usleep_range(priv->polling_time / 2, priv->polling_time); + timeout += priv->polling_time; } while (timeout <= MLXCPLD_I2C_XFER_TO); if (timeout > MLXCPLD_I2C_XFER_TO) @@ -278,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). */ @@ -288,10 +290,10 @@ static int mlxcpld_i2c_wait_for_tc(struct mlxcpld_i2c_priv *priv) u8 datalen, val; do { - usleep_range(MLXCPLD_I2C_POLL_TIME / 2, MLXCPLD_I2C_POLL_TIME); + usleep_range(priv->polling_time / 2, priv->polling_time); if (!mlxcpld_i2c_check_status(priv, &status)) break; - timeout += MLXCPLD_I2C_POLL_TIME; + timeout += priv->polling_time; } while (status == 0 && timeout < MLXCPLD_I2C_XFER_TO); switch (status) { @@ -313,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. @@ -373,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; @@ -447,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 = { @@ -465,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, @@ -495,12 +504,14 @@ mlxcpld_i2c_set_frequency(struct mlxcpld_i2c_priv *priv, return err; /* Set frequency only if it is not 100KHz, which is default. */ - switch ((data->reg & data->mask) >> data->bit) { + switch ((regval & data->mask) >> data->bit) { case MLXCPLD_I2C_FREQ_1000KHZ: freq = MLXCPLD_I2C_FREQ_1000KHZ_SET; + priv->polling_time /= 4; break; case MLXCPLD_I2C_FREQ_400KHZ: freq = MLXCPLD_I2C_FREQ_400KHZ_SET; + priv->polling_time /= 4; break; default: return 0; @@ -527,6 +538,7 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) priv->dev = &pdev->dev; priv->base_addr = MLXPLAT_CPLD_LPC_I2C_BASE_ADDR; + priv->polling_time = MLXCPLD_I2C_POLL_TIME; /* Set I2C bus frequency if platform data provides this info. */ pdata = dev_get_platdata(&pdev->dev); @@ -543,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; @@ -556,6 +570,10 @@ static int mlxcpld_i2c_probe(struct platform_device *pdev) if (err) goto mlxcpld_i2_probe_failed; + /* Notify caller when adapter is added. */ + if (pdata && pdata->completion_notify) + pdata->completion_notify(pdata->handle, mlxcpld_i2c_adapter.nr); + return 0; mlxcpld_i2_probe_failed: @@ -563,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 6d5014ebaab5..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,26 +114,33 @@ 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, so it's all OK. + * the 9 pulses, each with a START then ending with STOP, so it's all OK. */ static void mpc_i2c_fixup(struct mpc_i2c *i2c) { int k; - u32 delay_val = 1000000 / i2c->real_clk + 1; - - if (delay_val < 2) - delay_val = 2; + unsigned long flags; for (k = 9; k; k--) { writeccr(i2c, 0); - writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN); + writeb(0, i2c->base + MPC_I2C_SR); /* clear any status bits */ + writeccr(i2c, CCR_MEN | CCR_MSTA); /* START */ + readb(i2c->base + MPC_I2C_DR); /* init xfer */ + udelay(15); /* let it hit the bus */ + local_irq_save(flags); /* should not be delayed further */ + writeccr(i2c, CCR_MEN | CCR_MSTA | CCR_RSTA); /* delay SDA */ readb(i2c->base + MPC_I2C_DR); - writeccr(i2c, CCR_MEN); - udelay(delay_val << 1); + if (k != 1) + udelay(5); + local_irq_restore(flags); } + writeccr(i2c, CCR_MEN); /* Initiate STOP */ + readb(i2c->base + MPC_I2C_DR); + udelay(15); /* Let STOP propagate */ + writeccr(i2c, 0); } static int i2c_mpc_wait_sr(struct mpc_i2c *i2c, int mask) @@ -232,6 +237,7 @@ static const struct mpc_i2c_divider mpc_i2c_dividers_52xx[] = { static int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, u32 *real_clk) { + struct fwnode_handle *fwnode = of_fwnode_handle(node); const struct mpc_i2c_divider *div = NULL; unsigned int pvr = mfspr(SPRN_PVR); u32 divider; @@ -239,12 +245,12 @@ static int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, if (clock == MPC_I2C_CLOCK_LEGACY) { /* see below - default fdr = 0x3f -> div = 2048 */ - *real_clk = mpc5xxx_get_bus_frequency(node) / 2048; + *real_clk = mpc5xxx_fwnode_get_bus_frequency(fwnode) / 2048; return -EINVAL; } /* Determine divider value */ - divider = mpc5xxx_get_bus_frequency(node) / clock; + divider = mpc5xxx_fwnode_get_bus_frequency(fwnode) / clock; /* * We want to choose an FDR/DFSR that generates an I2C bus speed that @@ -259,7 +265,7 @@ static int mpc_i2c_get_fdr_52xx(struct device_node *node, u32 clock, break; } - *real_clk = mpc5xxx_get_bus_frequency(node) / div->divider; + *real_clk = mpc5xxx_fwnode_get_bus_frequency(fwnode) / div->divider; return (int)div->fdr; } @@ -297,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 */ @@ -351,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) { @@ -376,7 +380,6 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void) iounmap(reg); } } - of_node_put(node); return val; } @@ -492,7 +495,7 @@ static void mpc_i2c_finish(struct mpc_i2c *i2c, int rc) static void mpc_i2c_do_action(struct mpc_i2c *i2c) { - struct i2c_msg *msg = &i2c->msgs[i2c->curr_msg]; + struct i2c_msg *msg = NULL; int dir = 0; int recv_len = 0; u8 byte; @@ -501,10 +504,13 @@ static void mpc_i2c_do_action(struct mpc_i2c *i2c) i2c->cntl_bits &= ~(CCR_RSTA | CCR_MTX | CCR_TXAK); - if (msg->flags & I2C_M_RD) - dir = 1; - if (msg->flags & I2C_M_RECV_LEN) - recv_len = 1; + if (i2c->action != MPC_I2C_ACTION_STOP) { + msg = &i2c->msgs[i2c->curr_msg]; + if (msg->flags & I2C_M_RD) + dir = 1; + if (msg->flags & I2C_M_RECV_LEN) + recv_len = 1; + } switch (i2c->action) { case MPC_I2C_ACTION_RESTART: @@ -581,7 +587,7 @@ static void mpc_i2c_do_action(struct mpc_i2c *i2c) break; } - if (msg->len == i2c->byte_posn) { + if (msg && msg->len == i2c->byte_posn) { i2c->curr_msg++; i2c->byte_posn = 0; @@ -635,8 +641,8 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id) status = readb(i2c->base + MPC_I2C_SR); if (status & CSR_MIF) { - /* Read again to allow register to stabilise */ - status = readb(i2c->base + MPC_I2C_SR); + /* Wait up to 100us for transfer to properly complete */ + readb_poll_timeout_atomic(i2c->base + MPC_I2C_SR, status, status & CSR_MCF, 0, 100); writeb(0, i2c->base + MPC_I2C_SR); mpc_i2c_do_intr(i2c, status); return IRQ_HANDLED; @@ -752,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 = { @@ -770,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) @@ -805,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); @@ -831,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")) @@ -858,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) @@ -939,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 4ca716e09149..aefdbee1f03c 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -15,12 +15,11 @@ #include <linux/init.h> #include <linux/interrupt.h> #include <linux/io.h> +#include <linux/iopoll.h> #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> @@ -41,12 +40,16 @@ #define I2C_HANDSHAKE_RST 0x0020 #define I2C_FIFO_ADDR_CLR 0x0001 #define I2C_DELAY_LEN 0x0002 +#define I2C_ST_START_CON 0x8001 +#define I2C_FS_START_CON 0x1800 #define I2C_TIME_CLR_VALUE 0x0000 #define I2C_TIME_DEFAULT_VALUE 0x0003 #define I2C_WRRD_TRANAC_VALUE 0x0002 #define I2C_RD_TRANAC_VALUE 0x0001 #define I2C_SCL_MIS_COMP_VALUE 0x0000 #define I2C_CHN_CLR_FLAG 0x0000 +#define I2C_RELIABILITY 0x0010 +#define I2C_DMAACK_ENABLE 0x0008 #define I2C_DMA_CON_TX 0x0000 #define I2C_DMA_CON_RX 0x0001 @@ -62,11 +65,12 @@ #define MAX_SAMPLE_CNT_DIV 8 #define MAX_STEP_CNT_DIV 64 -#define MAX_CLOCK_DIV 256 +#define MAX_CLOCK_DIV_8BITS 256 +#define MAX_CLOCK_DIV_5BITS 32 #define MAX_HS_STEP_CNT_DIV 8 -#define I2C_STANDARD_MODE_BUFFER (1000 / 2) -#define I2C_FAST_MODE_BUFFER (300 / 2) -#define I2C_FAST_MODE_PLUS_BUFFER (20 / 2) +#define I2C_STANDARD_MODE_BUFFER (1000 / 3) +#define I2C_FAST_MODE_BUFFER (300 / 3) +#define I2C_FAST_MODE_PLUS_BUFFER (20 / 3) #define I2C_CONTROL_RS (0x1 << 1) #define I2C_CONTROL_DMA_EN (0x1 << 2) @@ -80,6 +84,27 @@ #define I2C_DRV_NAME "i2c-mt65xx" +/** + * enum i2c_mt65xx_clks - Clocks enumeration for MT65XX I2C + * + * @I2C_MT65XX_CLK_MAIN: main clock for i2c bus + * @I2C_MT65XX_CLK_DMA: DMA clock for i2c via DMA + * @I2C_MT65XX_CLK_PMIC: PMIC clock for i2c from PMIC + * @I2C_MT65XX_CLK_ARB: Arbitrator clock for i2c + * @I2C_MT65XX_CLK_MAX: Number of supported clocks + */ +enum i2c_mt65xx_clks { + I2C_MT65XX_CLK_MAIN = 0, + I2C_MT65XX_CLK_DMA, + I2C_MT65XX_CLK_PMIC, + I2C_MT65XX_CLK_ARB, + I2C_MT65XX_CLK_MAX +}; + +static const char * const i2c_mt65xx_clk_ids[I2C_MT65XX_CLK_MAX] = { + "main", "dma", "pmic", "arb" +}; + enum DMA_REGS_OFFSET { OFFSET_INT_FLAG = 0x0, OFFSET_INT_EN = 0x04, @@ -125,6 +150,7 @@ enum I2C_REGS_OFFSET { OFFSET_HS, OFFSET_SOFTRESET, OFFSET_DCM_EN, + OFFSET_MULTI_DMA, OFFSET_PATH_DIR, OFFSET_DEBUGSTAT, OFFSET_DEBUGCTRL, @@ -192,8 +218,38 @@ static const u16 mt_i2c_regs_v2[] = { [OFFSET_TRANSFER_LEN_AUX] = 0x44, [OFFSET_CLOCK_DIV] = 0x48, [OFFSET_SOFTRESET] = 0x50, + [OFFSET_MULTI_DMA] = 0x8c, + [OFFSET_SCL_MIS_COMP_POINT] = 0x90, + [OFFSET_DEBUGSTAT] = 0xe4, + [OFFSET_DEBUGCTRL] = 0xe8, + [OFFSET_FIFO_STAT] = 0xf4, + [OFFSET_FIFO_THRESH] = 0xf8, + [OFFSET_DCM_EN] = 0xf88, +}; + +static const u16 mt_i2c_regs_v3[] = { + [OFFSET_DATA_PORT] = 0x0, + [OFFSET_INTR_MASK] = 0x8, + [OFFSET_INTR_STAT] = 0xc, + [OFFSET_CONTROL] = 0x10, + [OFFSET_TRANSFER_LEN] = 0x14, + [OFFSET_TRANSAC_LEN] = 0x18, + [OFFSET_DELAY_LEN] = 0x1c, + [OFFSET_TIMING] = 0x20, + [OFFSET_START] = 0x24, + [OFFSET_EXT_CONF] = 0x28, + [OFFSET_LTIMING] = 0x2c, + [OFFSET_HS] = 0x30, + [OFFSET_IO_CONFIG] = 0x34, + [OFFSET_FIFO_ADDR_CLR] = 0x38, + [OFFSET_SDA_TIMING] = 0x3c, + [OFFSET_TRANSFER_LEN_AUX] = 0x44, + [OFFSET_CLOCK_DIV] = 0x48, + [OFFSET_SOFTRESET] = 0x50, + [OFFSET_MULTI_DMA] = 0x8c, [OFFSET_SCL_MIS_COMP_POINT] = 0x90, - [OFFSET_DEBUGSTAT] = 0xe0, + [OFFSET_SLAVE_ADDR] = 0x94, + [OFFSET_DEBUGSTAT] = 0xe4, [OFFSET_DEBUGCTRL] = 0xe8, [OFFSET_FIFO_STAT] = 0xf4, [OFFSET_FIFO_THRESH] = 0xf8, @@ -236,10 +292,7 @@ struct mtk_i2c { /* set in i2c probe */ void __iomem *base; /* i2c base addr */ void __iomem *pdmabase; /* dma base address*/ - struct clk *clk_main; /* main clock for i2c bus */ - struct clk *clk_dma; /* DMA clock for i2c via DMA */ - struct clk *clk_pmic; /* PMIC clock for i2c from PMIC */ - struct clk *clk_arb; /* Arbitrator clock for i2c */ + struct clk_bulk_data clocks[I2C_MT65XX_CLK_MAX]; /* clocks for i2c */ bool have_pmic; /* can use i2c pins from PMIC */ bool use_push_pull; /* IO config push-pull mode */ @@ -363,6 +416,44 @@ static const struct mtk_i2c_compatible mt7622_compat = { .max_dma_support = 32, }; +static const struct mtk_i2c_compatible mt8168_compat = { + .regs = mt_i2c_regs_v1, + .pmic_i2c = 0, + .dcm = 1, + .auto_restart = 1, + .aux_len_reg = 1, + .timing_adjust = 1, + .dma_sync = 1, + .ltiming_adjust = 0, + .apdma_sync = 0, + .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, + .pmic_i2c = 0, + .dcm = 1, + .auto_restart = 1, + .aux_len_reg = 1, + .timing_adjust = 0, + .dma_sync = 1, + .ltiming_adjust = 0, + .max_dma_support = 32, +}; + static const struct mtk_i2c_compatible mt8173_compat = { .regs = mt_i2c_regs_v1, .pmic_i2c = 0, @@ -390,6 +481,32 @@ static const struct mtk_i2c_compatible mt8183_compat = { .max_dma_support = 33, }; +static const struct mtk_i2c_compatible mt8186_compat = { + .regs = mt_i2c_regs_v2, + .pmic_i2c = 0, + .dcm = 0, + .auto_restart = 1, + .aux_len_reg = 1, + .timing_adjust = 1, + .dma_sync = 0, + .ltiming_adjust = 1, + .apdma_sync = 0, + .max_dma_support = 36, +}; + +static const struct mtk_i2c_compatible mt8188_compat = { + .regs = mt_i2c_regs_v3, + .pmic_i2c = 0, + .dcm = 0, + .auto_restart = 1, + .aux_len_reg = 1, + .timing_adjust = 1, + .dma_sync = 0, + .ltiming_adjust = 1, + .apdma_sync = 1, + .max_dma_support = 36, +}; + static const struct mtk_i2c_compatible mt8192_compat = { .quirks = &mt8183_i2c_quirks, .regs = mt_i2c_regs_v2, @@ -409,8 +526,13 @@ 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 }, { .compatible = "mediatek,mt8183-i2c", .data = &mt8183_compat }, + { .compatible = "mediatek,mt8186-i2c", .data = &mt8186_compat }, + { .compatible = "mediatek,mt8188-i2c", .data = &mt8188_compat }, { .compatible = "mediatek,mt8192-i2c", .data = &mt8192_compat }, {} }; @@ -427,59 +549,11 @@ static void mtk_i2c_writew(struct mtk_i2c *i2c, u16 val, writew(val, i2c->base + i2c->dev_comp->regs[reg]); } -static int mtk_i2c_clock_enable(struct mtk_i2c *i2c) -{ - int ret; - - ret = clk_prepare_enable(i2c->clk_dma); - if (ret) - return ret; - - ret = clk_prepare_enable(i2c->clk_main); - if (ret) - goto err_main; - - if (i2c->have_pmic) { - ret = clk_prepare_enable(i2c->clk_pmic); - if (ret) - goto err_pmic; - } - - if (i2c->clk_arb) { - ret = clk_prepare_enable(i2c->clk_arb); - if (ret) - goto err_arb; - } - - return 0; - -err_arb: - if (i2c->have_pmic) - clk_disable_unprepare(i2c->clk_pmic); -err_pmic: - clk_disable_unprepare(i2c->clk_main); -err_main: - clk_disable_unprepare(i2c->clk_dma); - - return ret; -} - -static void mtk_i2c_clock_disable(struct mtk_i2c *i2c) -{ - if (i2c->clk_arb) - clk_disable_unprepare(i2c->clk_arb); - - if (i2c->have_pmic) - clk_disable_unprepare(i2c->clk_pmic); - - clk_disable_unprepare(i2c->clk_main); - clk_disable_unprepare(i2c->clk_dma); -} - static void mtk_i2c_init_hw(struct mtk_i2c *i2c) { u16 control_reg; u16 intr_stat_reg; + u16 ext_conf_val; mtk_i2c_writew(i2c, I2C_CHN_CLR_FLAG, OFFSET_START); intr_stat_reg = mtk_i2c_readw(i2c, OFFSET_INTR_STAT); @@ -518,8 +592,13 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c) if (i2c->dev_comp->ltiming_adjust) mtk_i2c_writew(i2c, i2c->ltiming_reg, OFFSET_LTIMING); + if (i2c->speed_hz <= I2C_MAX_STANDARD_MODE_FREQ) + ext_conf_val = I2C_ST_START_CON; + else + ext_conf_val = I2C_FS_START_CON; + if (i2c->dev_comp->timing_adjust) { - mtk_i2c_writew(i2c, i2c->ac_timing.ext, OFFSET_EXT_CONF); + ext_conf_val = i2c->ac_timing.ext; mtk_i2c_writew(i2c, i2c->ac_timing.inter_clk_div, OFFSET_CLOCK_DIV); mtk_i2c_writew(i2c, I2C_SCL_MIS_COMP_VALUE, @@ -544,6 +623,7 @@ static void mtk_i2c_init_hw(struct mtk_i2c *i2c) OFFSET_HS_STA_STO_AC_TIMING); } } + mtk_i2c_writew(i2c, ext_conf_val, OFFSET_EXT_CONF); /* If use i2c pin from PMIC mt6397 side, need set PATH_DIR first */ if (i2c->have_pmic) @@ -576,6 +656,31 @@ static int mtk_i2c_max_step_cnt(unsigned int target_speed) return MAX_STEP_CNT_DIV; } +static int mtk_i2c_get_clk_div_restri(struct mtk_i2c *i2c, + unsigned int sample_cnt) +{ + int clk_div_restri = 0; + + if (i2c->dev_comp->ltiming_adjust == 0) + return 0; + + if (sample_cnt == 1) { + if (i2c->ac_timing.inter_clk_div == 0) + clk_div_restri = 0; + else + clk_div_restri = 1; + } else { + if (i2c->ac_timing.inter_clk_div == 0) + clk_div_restri = -1; + else if (i2c->ac_timing.inter_clk_div == 1) + clk_div_restri = 0; + else + clk_div_restri = 1; + } + + return clk_div_restri; +} + /* * Check and Calculate i2c ac-timing * @@ -704,6 +809,7 @@ static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src, unsigned int best_mul; unsigned int cnt_mul; int ret = -EINVAL; + int clk_div_restri = 0; if (target_speed > I2C_MAX_HIGH_SPEED_MODE_FREQ) target_speed = I2C_MAX_HIGH_SPEED_MODE_FREQ; @@ -721,7 +827,8 @@ static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src, * optimizing for sample_cnt * step_cnt being minimal */ for (sample_cnt = 1; sample_cnt <= MAX_SAMPLE_CNT_DIV; sample_cnt++) { - step_cnt = DIV_ROUND_UP(opt_div, sample_cnt); + clk_div_restri = mtk_i2c_get_clk_div_restri(i2c, sample_cnt); + step_cnt = DIV_ROUND_UP(opt_div + clk_div_restri, sample_cnt); cnt_mul = step_cnt * sample_cnt; if (step_cnt > max_step_cnt) continue; @@ -735,7 +842,7 @@ static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src, best_mul = cnt_mul; base_sample_cnt = sample_cnt; base_step_cnt = step_cnt; - if (best_mul == opt_div) + if (best_mul == (opt_div + clk_div_restri)) break; } } @@ -746,7 +853,8 @@ static int mtk_i2c_calculate_speed(struct mtk_i2c *i2c, unsigned int clk_src, sample_cnt = base_sample_cnt; step_cnt = base_step_cnt; - if ((clk_src / (2 * sample_cnt * step_cnt)) > target_speed) { + if ((clk_src / (2 * (sample_cnt * step_cnt - clk_div_restri))) > + target_speed) { /* In this case, hardware can't support such * low i2c_bus_freq */ @@ -760,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; @@ -775,13 +883,16 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk) target_speed = i2c->speed_hz; parent_clk /= i2c->clk_src_div; - if (i2c->dev_comp->timing_adjust) - max_clk_div = MAX_CLOCK_DIV; + if (i2c->dev_comp->timing_adjust && i2c->dev_comp->ltiming_adjust) + max_clk_div = MAX_CLOCK_DIV_5BITS; + else if (i2c->dev_comp->timing_adjust) + max_clk_div = MAX_CLOCK_DIV_8BITS; else max_clk_div = 1; for (clk_div = 1; clk_div <= max_clk_div; clk_div++) { clk_src = parent_clk / clk_div; + i2c->ac_timing.inter_clk_div = clk_div - 1; if (target_speed > I2C_MAX_FAST_MODE_PLUS_FREQ) { /* Set master code speed register */ @@ -827,10 +938,57 @@ static int mtk_i2c_set_speed(struct mtk_i2c *i2c, unsigned int parent_clk) break; } +} - i2c->ac_timing.inter_clk_div = clk_div - 1; - - return 0; +static void i2c_dump_register(struct mtk_i2c *i2c) +{ + dev_dbg(i2c->dev, "SLAVE_ADDR: 0x%x, INTR_MASK: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_SLAVE_ADDR), + mtk_i2c_readw(i2c, OFFSET_INTR_MASK)); + dev_dbg(i2c->dev, "INTR_STAT: 0x%x, CONTROL: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_INTR_STAT), + mtk_i2c_readw(i2c, OFFSET_CONTROL)); + dev_dbg(i2c->dev, "TRANSFER_LEN: 0x%x, TRANSAC_LEN: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_TRANSFER_LEN), + mtk_i2c_readw(i2c, OFFSET_TRANSAC_LEN)); + dev_dbg(i2c->dev, "DELAY_LEN: 0x%x, HTIMING: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_DELAY_LEN), + mtk_i2c_readw(i2c, OFFSET_TIMING)); + dev_dbg(i2c->dev, "START: 0x%x, EXT_CONF: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_START), + mtk_i2c_readw(i2c, OFFSET_EXT_CONF)); + dev_dbg(i2c->dev, "HS: 0x%x, IO_CONFIG: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_HS), + mtk_i2c_readw(i2c, OFFSET_IO_CONFIG)); + dev_dbg(i2c->dev, "DCM_EN: 0x%x, TRANSFER_LEN_AUX: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_DCM_EN), + mtk_i2c_readw(i2c, OFFSET_TRANSFER_LEN_AUX)); + dev_dbg(i2c->dev, "CLOCK_DIV: 0x%x, FIFO_STAT: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_CLOCK_DIV), + mtk_i2c_readw(i2c, OFFSET_FIFO_STAT)); + dev_dbg(i2c->dev, "DEBUGCTRL : 0x%x, DEBUGSTAT: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_DEBUGCTRL), + mtk_i2c_readw(i2c, OFFSET_DEBUGSTAT)); + if (i2c->dev_comp->regs == mt_i2c_regs_v2) { + dev_dbg(i2c->dev, "LTIMING: 0x%x, MULTI_DMA: 0x%x\n", + mtk_i2c_readw(i2c, OFFSET_LTIMING), + mtk_i2c_readw(i2c, OFFSET_MULTI_DMA)); + } + dev_dbg(i2c->dev, "\nDMA_INT_FLAG: 0x%x, DMA_INT_EN: 0x%x\n", + readl(i2c->pdmabase + OFFSET_INT_FLAG), + readl(i2c->pdmabase + OFFSET_INT_EN)); + dev_dbg(i2c->dev, "DMA_EN: 0x%x, DMA_CON: 0x%x\n", + readl(i2c->pdmabase + OFFSET_EN), + readl(i2c->pdmabase + OFFSET_CON)); + dev_dbg(i2c->dev, "DMA_TX_MEM_ADDR: 0x%x, DMA_RX_MEM_ADDR: 0x%x\n", + readl(i2c->pdmabase + OFFSET_TX_MEM_ADDR), + readl(i2c->pdmabase + OFFSET_RX_MEM_ADDR)); + dev_dbg(i2c->dev, "DMA_TX_LEN: 0x%x, DMA_RX_LEN: 0x%x\n", + readl(i2c->pdmabase + OFFSET_TX_LEN), + readl(i2c->pdmabase + OFFSET_RX_LEN)); + dev_dbg(i2c->dev, "DMA_TX_4G_MODE: 0x%x, DMA_RX_4G_MODE: 0x%x", + readl(i2c->pdmabase + OFFSET_TX_4G_MODE), + readl(i2c->pdmabase + OFFSET_RX_4G_MODE)); } static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, @@ -842,6 +1000,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, u16 restart_flag = 0; u16 dma_sync = 0; u32 reg_4g_mode; + u32 reg_dma_reset; u8 *dma_rd_buf = NULL; u8 *dma_wr_buf = NULL; dma_addr_t rpaddr = 0; @@ -855,6 +1014,28 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, reinit_completion(&i2c->msg_complete); + if (i2c->dev_comp->apdma_sync && + i2c->op != I2C_MASTER_WRRD && num > 1) { + mtk_i2c_writew(i2c, 0x00, OFFSET_DEBUGCTRL); + writel(I2C_DMA_HANDSHAKE_RST | I2C_DMA_WARM_RST, + i2c->pdmabase + OFFSET_RST); + + ret = readw_poll_timeout(i2c->pdmabase + OFFSET_RST, + reg_dma_reset, + !(reg_dma_reset & I2C_DMA_WARM_RST), + 0, 100); + if (ret) { + dev_err(i2c->dev, "DMA warm reset timeout\n"); + return -ETIMEDOUT; + } + + writel(I2C_DMA_CLR_FLAG, i2c->pdmabase + OFFSET_RST); + mtk_i2c_writew(i2c, I2C_HANDSHAKE_RST, OFFSET_SOFTRESET); + mtk_i2c_writew(i2c, I2C_CHN_CLR_FLAG, OFFSET_SOFTRESET); + mtk_i2c_writew(i2c, I2C_RELIABILITY | I2C_DMAACK_ENABLE, + OFFSET_DEBUGCTRL); + } + control_reg = mtk_i2c_readw(i2c, OFFSET_CONTROL) & ~(I2C_CONTROL_DIR_CHANGE | I2C_CONTROL_RS); if ((i2c->speed_hz > I2C_MAX_FAST_MODE_PLUS_FREQ) || (left_num >= 1)) @@ -1040,6 +1221,7 @@ static int mtk_i2c_do_transfer(struct mtk_i2c *i2c, struct i2c_msg *msgs, if (ret == 0) { dev_dbg(i2c->dev, "addr: %x, transfer timeout\n", msgs->addr); + i2c_dump_register(i2c); mtk_i2c_init_hw(i2c); return -ETIMEDOUT; } @@ -1058,9 +1240,10 @@ 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 = mtk_i2c_clock_enable(i2c); + ret = clk_bulk_enable(I2C_MT65XX_CLK_MAX, i2c->clocks); if (ret) return ret; @@ -1071,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; } } @@ -1095,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. */ @@ -1108,25 +1290,25 @@ 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; err_exit: - mtk_i2c_clock_disable(i2c); + clk_bulk_disable(I2C_MT65XX_CLK_MAX, i2c->clocks); return ret; } 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); @@ -1160,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, }; @@ -1192,26 +1374,22 @@ static int mtk_i2c_probe(struct platform_device *pdev) { int ret = 0; struct mtk_i2c *i2c; - struct clk *clk; - struct resource *res; - int irq; + 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); irq = platform_get_irq(pdev, 0); - if (irq <= 0) + if (irq < 0) return irq; init_completion(&i2c->msg_complete); @@ -1240,39 +1418,46 @@ static int mtk_i2c_probe(struct platform_device *pdev) if (i2c->have_pmic && !i2c->dev_comp->pmic_i2c) return -EINVAL; - i2c->clk_main = devm_clk_get(&pdev->dev, "main"); - if (IS_ERR(i2c->clk_main)) { + /* Fill in clk-bulk IDs */ + for (i = 0; i < I2C_MT65XX_CLK_MAX; i++) + i2c->clocks[i].id = i2c_mt65xx_clk_ids[i]; + + /* Get clocks one by one, some may be optional */ + i2c->clocks[I2C_MT65XX_CLK_MAIN].clk = devm_clk_get(&pdev->dev, "main"); + if (IS_ERR(i2c->clocks[I2C_MT65XX_CLK_MAIN].clk)) { dev_err(&pdev->dev, "cannot get main clock\n"); - return PTR_ERR(i2c->clk_main); + return PTR_ERR(i2c->clocks[I2C_MT65XX_CLK_MAIN].clk); } - i2c->clk_dma = devm_clk_get(&pdev->dev, "dma"); - if (IS_ERR(i2c->clk_dma)) { + i2c->clocks[I2C_MT65XX_CLK_DMA].clk = devm_clk_get(&pdev->dev, "dma"); + if (IS_ERR(i2c->clocks[I2C_MT65XX_CLK_DMA].clk)) { dev_err(&pdev->dev, "cannot get dma clock\n"); - return PTR_ERR(i2c->clk_dma); + return PTR_ERR(i2c->clocks[I2C_MT65XX_CLK_DMA].clk); } - i2c->clk_arb = devm_clk_get(&pdev->dev, "arb"); - if (IS_ERR(i2c->clk_arb)) - i2c->clk_arb = NULL; + i2c->clocks[I2C_MT65XX_CLK_ARB].clk = devm_clk_get_optional(&pdev->dev, "arb"); + 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); + } - clk = i2c->clk_main; if (i2c->have_pmic) { - i2c->clk_pmic = devm_clk_get(&pdev->dev, "pmic"); - if (IS_ERR(i2c->clk_pmic)) { + if (!i2c->clocks[I2C_MT65XX_CLK_PMIC].clk) { dev_err(&pdev->dev, "cannot get pmic clock\n"); - return PTR_ERR(i2c->clk_pmic); + return -ENODEV; } - clk = i2c->clk_pmic; + speed_clk = I2C_MT65XX_CLK_PMIC; + } else { + speed_clk = I2C_MT65XX_CLK_MAIN; } - strlcpy(i2c->adap.name, I2C_DRV_NAME, sizeof(i2c->adap.name)); + strscpy(i2c->adap.name, I2C_DRV_NAME, sizeof(i2c->adap.name)); - ret = mtk_i2c_set_speed(i2c, clk_get_rate(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, @@ -1283,13 +1468,13 @@ static int mtk_i2c_probe(struct platform_device *pdev) } } - ret = mtk_i2c_clock_enable(i2c); + ret = clk_bulk_prepare_enable(I2C_MT65XX_CLK_MAX, i2c->clocks); if (ret) { dev_err(&pdev->dev, "clock enable failed!\n"); return ret; } mtk_i2c_init_hw(i2c); - mtk_i2c_clock_disable(i2c); + clk_bulk_disable(I2C_MT65XX_CLK_MAX, i2c->clocks); ret = devm_request_irq(&pdev->dev, irq, mtk_i2c_irq, IRQF_NO_SUSPEND | IRQF_TRIGGER_NONE, @@ -1297,34 +1482,39 @@ static int mtk_i2c_probe(struct platform_device *pdev) if (ret < 0) { dev_err(&pdev->dev, "Request I2C IRQ %d fail\n", irq); - return ret; + goto err_bulk_unprepare; } i2c_set_adapdata(&i2c->adap, i2c); ret = i2c_add_adapter(&i2c->adap); if (ret) - return ret; + goto err_bulk_unprepare; platform_set_drvdata(pdev, i2c); return 0; + +err_bulk_unprepare: + clk_bulk_unprepare(I2C_MT65XX_CLK_MAX, i2c->clocks); + + 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); - return 0; + clk_bulk_unprepare(I2C_MT65XX_CLK_MAX, i2c->clocks); } -#ifdef CONFIG_PM_SLEEP static int mtk_i2c_suspend_noirq(struct device *dev) { struct mtk_i2c *i2c = dev_get_drvdata(dev); i2c_mark_adapter_suspended(&i2c->adap); + clk_bulk_unprepare(I2C_MT65XX_CLK_MAX, i2c->clocks); return 0; } @@ -1334,7 +1524,7 @@ static int mtk_i2c_resume_noirq(struct device *dev) int ret; struct mtk_i2c *i2c = dev_get_drvdata(dev); - ret = mtk_i2c_clock_enable(i2c); + ret = clk_bulk_prepare_enable(I2C_MT65XX_CLK_MAX, i2c->clocks); if (ret) { dev_err(dev, "clock enable failed!\n"); return ret; @@ -1342,17 +1532,16 @@ static int mtk_i2c_resume_noirq(struct device *dev) mtk_i2c_init_hw(i2c); - mtk_i2c_clock_disable(i2c); + clk_bulk_disable(I2C_MT65XX_CLK_MAX, i2c->clocks); i2c_mark_adapter_resumed(&i2c->adap); 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 = { @@ -1360,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 45fe4a7fe0c0..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[] = { @@ -270,31 +267,23 @@ static void mtk_i2c_init(struct mtk_i2c *i2c) static int mtk_i2c_probe(struct platform_device *pdev) { - struct resource *res; struct mtk_i2c *i2c; struct i2c_adapter *adap; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2c = devm_kzalloc(&pdev->dev, sizeof(struct mtk_i2c), GFP_KERNEL); if (!i2c) return -ENOMEM; - 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); - 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; @@ -314,7 +303,7 @@ static int mtk_i2c_probe(struct platform_device *pdev) adap->dev.parent = &pdev->dev; i2c_set_adapdata(adap, i2c); adap->dev.of_node = pdev->dev.of_node; - strlcpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); + strscpy(adap->name, dev_name(&pdev->dev), sizeof(adap->name)); platform_set_drvdata(pdev, i2c); @@ -326,17 +315,14 @@ static int mtk_i2c_probe(struct platform_device *pdev) dev_info(&pdev->dev, "clock %u kHz\n", i2c->bus_freq / 1000); - return ret; + return 0; } -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 5c8e94b6cdb5..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 */ @@ -150,6 +148,7 @@ struct mv64xxx_i2c_data { /* Clk div is 2 to the power n, not 2 to the power n + 1 */ bool clk_n_base_0; struct i2c_bus_recovery_info rinfo; + bool atomic; }; static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = { @@ -176,19 +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_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN; + MV64XXX_I2C_REG_CONTROL_TWSIEN; - if (msg->flags & I2C_M_RD) - dir = 1; + if (!drv_data->atomic) + drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_INTEN; 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; } } @@ -276,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; @@ -304,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; @@ -409,7 +406,8 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) case MV64XXX_I2C_ACTION_RCV_DATA_STOP: drv_data->msg->buf[drv_data->byte_posn++] = readl(drv_data->reg_base + drv_data->reg_offsets.data); - drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; + if (!drv_data->atomic) + drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, drv_data->reg_base + drv_data->reg_offsets.control); drv_data->block = 0; @@ -427,7 +425,8 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) drv_data->rc = -EIO; fallthrough; case MV64XXX_I2C_ACTION_SEND_STOP: - drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; + if (!drv_data->atomic) + drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, drv_data->reg_base + drv_data->reg_offsets.control); drv_data->block = 0; @@ -514,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); @@ -575,6 +585,17 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data) spin_unlock_irqrestore(&drv_data->lock, flags); } +static void mv64xxx_i2c_wait_polling(struct mv64xxx_i2c_data *drv_data) +{ + ktime_t timeout = ktime_add_ms(ktime_get(), drv_data->adapter.timeout); + + while (READ_ONCE(drv_data->block) && + ktime_compare(ktime_get(), timeout) < 0) { + udelay(5); + mv64xxx_i2c_intr(0, drv_data); + } +} + static int mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg, int is_last) @@ -590,7 +611,11 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg, mv64xxx_i2c_send_start(drv_data); spin_unlock_irqrestore(&drv_data->lock, flags); - mv64xxx_i2c_wait_for_completion(drv_data); + if (!drv_data->atomic) + mv64xxx_i2c_wait_for_completion(drv_data); + else + mv64xxx_i2c_wait_polling(drv_data); + return drv_data->rc; } @@ -717,7 +742,7 @@ mv64xxx_i2c_functionality(struct i2c_adapter *adap) } static int -mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +mv64xxx_i2c_xfer_core(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); int rc, ret = num; @@ -730,7 +755,7 @@ mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) drv_data->msgs = msgs; drv_data->num_msgs = num; - if (mv64xxx_i2c_can_offload(drv_data)) + if (mv64xxx_i2c_can_offload(drv_data) && !drv_data->atomic) rc = mv64xxx_i2c_offload_xfer(drv_data); else rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[0], num == 1); @@ -741,14 +766,32 @@ mv64xxx_i2c_xfer(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; } +static int +mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) +{ + struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); + + drv_data->atomic = 0; + return mv64xxx_i2c_xfer_core(adap, msgs, num); +} + +static int mv64xxx_i2c_xfer_atomic(struct i2c_adapter *adap, + struct i2c_msg msgs[], int num) +{ + struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); + + drv_data->atomic = 1; + return mv64xxx_i2c_xfer_core(adap, msgs, num); +} + static const struct i2c_algorithm mv64xxx_i2c_algo = { - .master_xfer = mv64xxx_i2c_xfer, + .xfer = mv64xxx_i2c_xfer, + .xfer_atomic = mv64xxx_i2c_xfer_atomic, .functionality = mv64xxx_i2c_functionality, }; @@ -808,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; @@ -846,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 @@ -949,7 +992,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) if (IS_ERR(drv_data->reg_base)) return PTR_ERR(drv_data->reg_base); - strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter", + strscpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter", sizeof(drv_data->adapter.name)); init_waitqueue_head(&drv_data->waitq); @@ -1033,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); @@ -1043,16 +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 void -mv64xxx_i2c_shutdown(struct platform_device *pd) -{ - pm_runtime_disable(&pd->dev); - if (!pm_runtime_status_suspended(&pd->dev)) - mv64xxx_i2c_runtime_suspend(&pd->dev); } static const struct dev_pm_ops mv64xxx_i2c_pm_ops = { @@ -1064,8 +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, - .shutdown = mv64xxx_i2c_shutdown, + .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 f97243f02231..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, @@ -290,14 +289,14 @@ read_init_dma_fail: select_init_dma_fail: dma_unmap_sg(i2c->dev, &i2c->sg_io[0], 1, DMA_TO_DEVICE); select_init_pio_fail: - dmaengine_terminate_all(i2c->dmach); + dmaengine_terminate_sync(i2c->dmach); return -EINVAL; /* Write failpath. */ write_init_dma_fail: dma_unmap_sg(i2c->dev, i2c->sg_io, 2, DMA_TO_DEVICE); write_init_pio_fail: - dmaengine_terminate_all(i2c->dmach); + dmaengine_terminate_sync(i2c->dmach); return -EINVAL; } @@ -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, }; @@ -799,7 +806,7 @@ static int mxs_i2c_probe(struct platform_device *pdev) if (!i2c) return -ENOMEM; - i2c->dev_type = (enum mxs_i2c_devtype)of_device_get_match_data(&pdev->dev); + i2c->dev_type = (uintptr_t)of_device_get_match_data(&pdev->dev); i2c->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(i2c->regs)) @@ -826,8 +833,8 @@ static int mxs_i2c_probe(struct platform_device *pdev) /* Setup the DMA */ i2c->dmach = dma_request_chan(dev, "rx-tx"); if (IS_ERR(i2c->dmach)) { - dev_err(dev, "Failed to request dma\n"); - return PTR_ERR(i2c->dmach); + return dev_err_probe(dev, PTR_ERR(i2c->dmach), + "Failed to request dma\n"); } platform_set_drvdata(pdev, i2c); @@ -838,7 +845,7 @@ static int mxs_i2c_probe(struct platform_device *pdev) return err; adap = &i2c->adapter; - strlcpy(adap->name, "MXS I2C adapter", sizeof(adap->name)); + strscpy(adap->name, "MXS I2C adapter", sizeof(adap->name)); adap->owner = THIS_MODULE; adap->algo = &mxs_i2c_algo; adap->quirks = &mxs_i2c_quirks; @@ -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 2ad166355ec9..8b7e15240fb0 100644 --- a/drivers/i2c/busses/i2c-npcm7xx.c +++ b/drivers/i2c/busses/i2c-npcm7xx.c @@ -91,7 +91,6 @@ enum i2c_addr { /* init register and default value required to enable module */ #define NPCM_I2CSEGCTL 0xE4 -#define NPCM_I2CSEGCTL_INIT_VAL 0x0333F000 /* Common regs */ #define NPCM_I2CSDA 0x00 @@ -106,7 +105,7 @@ enum i2c_addr { #define NPCM_I2CCST3 0x19 #define I2C_VER 0x1F -/*BANK0 regs*/ +/* BANK 0 regs */ #define NPCM_I2CADDR3 0x10 #define NPCM_I2CADDR7 0x11 #define NPCM_I2CADDR4 0x12 @@ -115,6 +114,20 @@ enum i2c_addr { #define NPCM_I2CADDR9 0x15 #define NPCM_I2CADDR6 0x16 #define NPCM_I2CADDR10 0x17 +#define NPCM_I2CCTL4 0x1A +#define NPCM_I2CCTL5 0x1B +#define NPCM_I2CSCLLT 0x1C /* SCL Low Time */ +#define NPCM_I2CFIF_CTL 0x1D /* FIFO Control */ +#define NPCM_I2CSCLHT 0x1E /* SCL High Time */ + +/* BANK 1 regs */ +#define NPCM_I2CFIF_CTS 0x10 /* Both FIFOs Control and Status */ +#define NPCM_I2CTXF_CTL 0x12 /* Tx-FIFO Control */ +#define NPCM_I2CT_OUT 0x14 /* Bus T.O. */ +#define NPCM_I2CPEC 0x16 /* PEC Data */ +#define NPCM_I2CTXF_STS 0x1A /* Tx-FIFO Status */ +#define NPCM_I2CRXF_STS 0x1C /* Rx-FIFO Status */ +#define NPCM_I2CRXF_CTL 0x1E /* Rx-FIFO Control */ #if IS_ENABLED(CONFIG_I2C_SLAVE) /* @@ -124,6 +137,8 @@ enum i2c_addr { * use this array to get the address or each register. */ #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_I2CADDR3, NPCM_I2CADDR4, NPCM_I2CADDR5, NPCM_I2CADDR6, NPCM_I2CADDR7, NPCM_I2CADDR8, @@ -131,66 +146,51 @@ static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = { }; #endif -#define NPCM_I2CCTL4 0x1A -#define NPCM_I2CCTL5 0x1B -#define NPCM_I2CSCLLT 0x1C /* SCL Low Time */ -#define NPCM_I2CFIF_CTL 0x1D /* FIFO Control */ -#define NPCM_I2CSCLHT 0x1E /* SCL High Time */ - -/* BANK 1 regs */ -#define NPCM_I2CFIF_CTS 0x10 /* Both FIFOs Control and Status */ -#define NPCM_I2CTXF_CTL 0x12 /* Tx-FIFO Control */ -#define NPCM_I2CT_OUT 0x14 /* Bus T.O. */ -#define NPCM_I2CPEC 0x16 /* PEC Data */ -#define NPCM_I2CTXF_STS 0x1A /* Tx-FIFO Status */ -#define NPCM_I2CRXF_STS 0x1C /* Rx-FIFO Status */ -#define NPCM_I2CRXF_CTL 0x1E /* Rx-FIFO Control */ - /* NPCM_I2CST reg fields */ -#define NPCM_I2CST_XMIT BIT(0) -#define NPCM_I2CST_MASTER BIT(1) -#define NPCM_I2CST_NMATCH BIT(2) -#define NPCM_I2CST_STASTR BIT(3) -#define NPCM_I2CST_NEGACK BIT(4) -#define NPCM_I2CST_BER BIT(5) -#define NPCM_I2CST_SDAST BIT(6) -#define NPCM_I2CST_SLVSTP BIT(7) +#define NPCM_I2CST_XMIT BIT(0) /* Transmit mode */ +#define NPCM_I2CST_MASTER BIT(1) /* Master mode */ +#define NPCM_I2CST_NMATCH BIT(2) /* New match */ +#define NPCM_I2CST_STASTR BIT(3) /* Stall after start */ +#define NPCM_I2CST_NEGACK BIT(4) /* Negative ACK */ +#define NPCM_I2CST_BER BIT(5) /* Bus error */ +#define NPCM_I2CST_SDAST BIT(6) /* SDA status */ +#define NPCM_I2CST_SLVSTP BIT(7) /* Slave stop */ /* NPCM_I2CCST reg fields */ -#define NPCM_I2CCST_BUSY BIT(0) -#define NPCM_I2CCST_BB BIT(1) -#define NPCM_I2CCST_MATCH BIT(2) -#define NPCM_I2CCST_GCMATCH BIT(3) -#define NPCM_I2CCST_TSDA BIT(4) -#define NPCM_I2CCST_TGSCL BIT(5) -#define NPCM_I2CCST_MATCHAF BIT(6) -#define NPCM_I2CCST_ARPMATCH BIT(7) +#define NPCM_I2CCST_BUSY BIT(0) /* Busy */ +#define NPCM_I2CCST_BB BIT(1) /* Bus busy */ +#define NPCM_I2CCST_MATCH BIT(2) /* Address match */ +#define NPCM_I2CCST_GCMATCH BIT(3) /* Global call match */ +#define NPCM_I2CCST_TSDA BIT(4) /* Test SDA line */ +#define NPCM_I2CCST_TGSCL BIT(5) /* Toggle SCL line */ +#define NPCM_I2CCST_MATCHAF BIT(6) /* Match address field */ +#define NPCM_I2CCST_ARPMATCH BIT(7) /* ARP address match */ /* NPCM_I2CCTL1 reg fields */ -#define NPCM_I2CCTL1_START BIT(0) -#define NPCM_I2CCTL1_STOP BIT(1) -#define NPCM_I2CCTL1_INTEN BIT(2) +#define NPCM_I2CCTL1_START BIT(0) /* Generate start condition */ +#define NPCM_I2CCTL1_STOP BIT(1) /* Generate stop condition */ +#define NPCM_I2CCTL1_INTEN BIT(2) /* Interrupt enable */ #define NPCM_I2CCTL1_EOBINTE BIT(3) #define NPCM_I2CCTL1_ACK BIT(4) -#define NPCM_I2CCTL1_GCMEN BIT(5) -#define NPCM_I2CCTL1_NMINTE BIT(6) -#define NPCM_I2CCTL1_STASTRE BIT(7) +#define NPCM_I2CCTL1_GCMEN BIT(5) /* Global call match enable */ +#define NPCM_I2CCTL1_NMINTE BIT(6) /* New match interrupt enable */ +#define NPCM_I2CCTL1_STASTRE BIT(7) /* Stall after start enable */ /* RW1S fields (inside a RW reg): */ #define NPCM_I2CCTL1_RWS \ (NPCM_I2CCTL1_START | NPCM_I2CCTL1_STOP | NPCM_I2CCTL1_ACK) /* npcm_i2caddr reg fields */ -#define NPCM_I2CADDR_A GENMASK(6, 0) -#define NPCM_I2CADDR_SAEN BIT(7) +#define NPCM_I2CADDR_A GENMASK(6, 0) /* Address */ +#define NPCM_I2CADDR_SAEN BIT(7) /* Slave address enable */ /* NPCM_I2CCTL2 reg fields */ -#define I2CCTL2_ENABLE BIT(0) -#define I2CCTL2_SCLFRQ6_0 GENMASK(7, 1) +#define I2CCTL2_ENABLE BIT(0) /* Module enable */ +#define I2CCTL2_SCLFRQ6_0 GENMASK(7, 1) /* Bits 0:6 of frequency divisor */ /* NPCM_I2CCTL3 reg fields */ -#define I2CCTL3_SCLFRQ8_7 GENMASK(1, 0) -#define I2CCTL3_ARPMEN BIT(2) +#define I2CCTL3_SCLFRQ8_7 GENMASK(1, 0) /* Bits 7:8 of frequency divisor */ +#define I2CCTL3_ARPMEN BIT(2) /* ARP match enable */ #define I2CCTL3_IDL_START BIT(3) #define I2CCTL3_400K_MODE BIT(4) #define I2CCTL3_BNK_SEL BIT(5) @@ -226,8 +226,7 @@ static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = { #define NPCM_I2CFIF_CTS_CLR_FIFO BIT(6) #define NPCM_I2CFIF_CTS_SLVRSTR BIT(7) -/* NPCM_I2CTXF_CTL reg fields */ -#define NPCM_I2CTXF_CTL_TX_THR GENMASK(4, 0) +/* NPCM_I2CTXF_CTL reg field */ #define NPCM_I2CTXF_CTL_THR_TXIE BIT(6) /* NPCM_I2CT_OUT reg fields */ @@ -236,22 +235,18 @@ static const int npcm_i2caddr[I2C_NUM_OWN_ADDR] = { #define NPCM_I2CT_OUT_T_OUTST BIT(7) /* NPCM_I2CTXF_STS reg fields */ -#define NPCM_I2CTXF_STS_TX_BYTES GENMASK(4, 0) #define NPCM_I2CTXF_STS_TX_THST BIT(6) /* NPCM_I2CRXF_STS reg fields */ -#define NPCM_I2CRXF_STS_RX_BYTES GENMASK(4, 0) #define NPCM_I2CRXF_STS_RX_THST BIT(6) /* NPCM_I2CFIF_CTL reg fields */ #define NPCM_I2CFIF_CTL_FIFO_EN BIT(4) /* NPCM_I2CRXF_CTL reg fields */ -#define NPCM_I2CRXF_CTL_RX_THR GENMASK(4, 0) -#define NPCM_I2CRXF_CTL_LAST_PEC BIT(5) #define NPCM_I2CRXF_CTL_THR_RXIE BIT(6) -#define I2C_HW_FIFO_SIZE 16 +#define MAX_I2C_HW_FIFO_SIZE 32 /* I2C_VER reg fields */ #define I2C_VER_VERSION GENMASK(6, 0) @@ -268,11 +263,295 @@ 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; + u8 txf_sts_tx_bytes; + u8 rxf_sts_rx_bytes; + u8 rxf_ctl_last_pec; +}; + +static const struct npcm_i2c_data npxm7xx_i2c_data = { + .fifo_size = 16, + .segctl_init_val = 0x0333F000, + .txf_sts_tx_bytes = GENMASK(4, 0), + .rxf_sts_rx_bytes = GENMASK(4, 0), + .rxf_ctl_last_pec = BIT(5), +}; + +static const struct npcm_i2c_data npxm8xx_i2c_data = { + .fifo_size = 32, + .segctl_init_val = 0x9333F000, + .txf_sts_tx_bytes = GENMASK(5, 0), + .rxf_sts_rx_bytes = GENMASK(5, 0), + .rxf_ctl_last_pec = BIT(7), +}; + /* Status of one I2C module */ struct npcm_i2c { struct i2c_adapter adap; struct device *dev; unsigned char __iomem *reg; + const struct npcm_i2c_data *data; spinlock_t lock; /* IRQ synchronization */ struct completion cmd_complete; int cmd_err; @@ -305,15 +584,16 @@ struct npcm_i2c { int slv_rd_ind; int slv_wr_size; int slv_wr_ind; - u8 slv_rd_buf[I2C_HW_FIFO_SIZE]; - u8 slv_wr_buf[I2C_HW_FIFO_SIZE]; + 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, @@ -359,14 +639,14 @@ static int npcm_i2c_get_SCL(struct i2c_adapter *_adap) { struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap); - return !!(I2CCTL3_SCL_LVL & ioread32(bus->reg + NPCM_I2CCTL3)); + return !!(I2CCTL3_SCL_LVL & ioread8(bus->reg + NPCM_I2CCTL3)); } static int npcm_i2c_get_SDA(struct i2c_adapter *_adap) { struct npcm_i2c *bus = container_of(_adap, struct npcm_i2c, adap); - return !!(I2CCTL3_SDA_LVL & ioread32(bus->reg + NPCM_I2CCTL3)); + return !!(I2CCTL3_SDA_LVL & ioread8(bus->reg + NPCM_I2CCTL3)); } static inline u16 npcm_i2c_get_index(struct npcm_i2c *bus) @@ -391,14 +671,10 @@ static void npcm_i2c_disable(struct npcm_i2c *bus) #if IS_ENABLED(CONFIG_I2C_SLAVE) int i; - /* select bank 0 for I2C addresses */ - npcm_i2c_select_bank(bus, I2C_BANK_0); - /* Slave addresses removal */ - for (i = I2C_SLAVE_ADDR1; i < I2C_NUM_OWN_ADDR; i++) + for (i = I2C_SLAVE_ADDR1; i < I2C_NUM_OWN_ADDR_SUPPORTED; i++) iowrite8(0, bus->reg + npcm_i2caddr[i]); - npcm_i2c_select_bank(bus, I2C_BANK_1); #endif /* Disable module */ i2cctl2 = ioread8(bus->reg + NPCM_I2CCTL2); @@ -442,7 +718,7 @@ static inline bool npcm_i2c_tx_fifo_empty(struct npcm_i2c *bus) tx_fifo_sts = ioread8(bus->reg + NPCM_I2CTXF_STS); /* check if TX FIFO is not empty */ - if ((tx_fifo_sts & NPCM_I2CTXF_STS_TX_BYTES) == 0) + if ((tx_fifo_sts & bus->data->txf_sts_tx_bytes) == 0) return false; /* check if TX FIFO status bit is set: */ @@ -455,7 +731,7 @@ static inline bool npcm_i2c_rx_fifo_full(struct npcm_i2c *bus) rx_fifo_sts = ioread8(bus->reg + NPCM_I2CRXF_STS); /* check if RX FIFO is not empty: */ - if ((rx_fifo_sts & NPCM_I2CRXF_STS_RX_BYTES) == 0) + if ((rx_fifo_sts & bus->data->rxf_sts_rx_bytes) == 0) return false; /* check if rx fifo full status is set: */ @@ -563,6 +839,15 @@ static inline void npcm_i2c_nack(struct npcm_i2c *bus) iowrite8(val, bus->reg + NPCM_I2CCTL1); } +static inline void npcm_i2c_clear_master_status(struct npcm_i2c *bus) +{ + u8 val; + + /* Clear NEGACK, STASTR and BER bits */ + val = NPCM_I2CST_BER | NPCM_I2CST_NEGACK | NPCM_I2CST_STASTR; + iowrite8(val, bus->reg + NPCM_I2CST); +} + #if IS_ENABLED(CONFIG_I2C_SLAVE) static void npcm_i2c_slave_int_enable(struct npcm_i2c *bus, bool enable) { @@ -594,8 +879,7 @@ static int npcm_i2c_slave_enable(struct npcm_i2c *bus, enum i2c_addr addr_type, i2cctl1 &= ~NPCM_I2CCTL1_GCMEN; iowrite8(i2cctl1, bus->reg + NPCM_I2CCTL1); return 0; - } - if (addr_type == I2C_ARP_ADDR) { + } else if (addr_type == I2C_ARP_ADDR) { i2cctl3 = ioread8(bus->reg + NPCM_I2CCTL3); if (enable) i2cctl3 |= I2CCTL3_ARPMEN; @@ -604,16 +888,16 @@ static int npcm_i2c_slave_enable(struct npcm_i2c *bus, enum i2c_addr addr_type, iowrite8(i2cctl3, bus->reg + NPCM_I2CCTL3); return 0; } + if (addr_type > I2C_SLAVE_ADDR2 && addr_type <= I2C_SLAVE_ADDR10) + dev_err(bus->dev, "try to enable more than 2 SA not supported\n"); + if (addr_type >= I2C_ARP_ADDR) return -EFAULT; - /* select bank 0 for address 3 to 10 */ - if (addr_type > I2C_SLAVE_ADDR2) - npcm_i2c_select_bank(bus, I2C_BANK_0); + /* Set and enable the address */ iowrite8(sa_reg, bus->reg + npcm_i2caddr[addr_type]); npcm_i2c_slave_int_enable(bus, enable); - if (addr_type > I2C_SLAVE_ADDR2) - npcm_i2c_select_bank(bus, I2C_BANK_1); + return 0; } #endif @@ -642,8 +926,8 @@ static void npcm_i2c_reset(struct npcm_i2c *bus) iowrite8(NPCM_I2CCST_BB, bus->reg + NPCM_I2CCST); iowrite8(0xFF, bus->reg + NPCM_I2CST); - /* Clear EOB bit */ - iowrite8(NPCM_I2CCST3_EO_BUSY, bus->reg + NPCM_I2CCST3); + /* Clear and disable EOB */ + npcm_i2c_eob_int(bus, false); /* Clear all fifo bits: */ iowrite8(NPCM_I2CFIF_CTS_CLR_FIFO, bus->reg + NPCM_I2CFIF_CTS); @@ -655,6 +939,9 @@ static void npcm_i2c_reset(struct npcm_i2c *bus) } #endif + /* Clear status bits for spurious interrupts */ + npcm_i2c_clear_master_status(bus); + bus->state = I2C_IDLE; } @@ -668,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; @@ -684,6 +972,8 @@ static void npcm_i2c_callback(struct npcm_i2c *bus, switch (op_status) { case I2C_MASTER_DONE_IND: bus->cmd_err = bus->msgs_num; + if (bus->tx_complete_cnt < ULLONG_MAX) + bus->tx_complete_cnt++; fallthrough; case I2C_BLOCK_BYTES_ERR_IND: /* Master tx finished and all transmit bytes were sent */ @@ -694,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 */ @@ -724,16 +1008,18 @@ 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) { if (bus->operation == I2C_WRITE_OPER) - return FIELD_GET(NPCM_I2CTXF_STS_TX_BYTES, - ioread8(bus->reg + NPCM_I2CTXF_STS)); + return (bus->data->txf_sts_tx_bytes & + ioread8(bus->reg + NPCM_I2CTXF_STS)); if (bus->operation == I2C_READ_OPER) - return FIELD_GET(NPCM_I2CRXF_STS_RX_BYTES, - ioread8(bus->reg + NPCM_I2CRXF_STS)); + return (bus->data->rxf_sts_rx_bytes & + ioread8(bus->reg + NPCM_I2CRXF_STS)); return 0; } @@ -745,13 +1031,13 @@ static void npcm_i2c_write_to_fifo_master(struct npcm_i2c *bus, u16 max_bytes) * Fill the FIFO, while the FIFO is not full and there are more bytes * to write */ - size_free_fifo = I2C_HW_FIFO_SIZE - npcm_i2c_fifo_usage(bus); + size_free_fifo = bus->data->fifo_size - npcm_i2c_fifo_usage(bus); while (max_bytes-- && size_free_fifo) { if (bus->wr_ind < bus->wr_size) npcm_i2c_wr_byte(bus, bus->wr_buf[bus->wr_ind++]); else npcm_i2c_wr_byte(bus, 0xFF); - size_free_fifo = I2C_HW_FIFO_SIZE - npcm_i2c_fifo_usage(bus); + size_free_fifo = bus->data->fifo_size - npcm_i2c_fifo_usage(bus); } } @@ -772,16 +1058,16 @@ static void npcm_i2c_set_fifo(struct npcm_i2c *bus, int nread, int nwrite) /* configure RX FIFO */ if (nread > 0) { - rxf_ctl = min_t(int, nread, I2C_HW_FIFO_SIZE); + rxf_ctl = min_t(int, nread, bus->data->fifo_size); /* set LAST bit. if LAST is set next FIFO packet is nacked */ - if (nread <= I2C_HW_FIFO_SIZE) - rxf_ctl |= NPCM_I2CRXF_CTL_LAST_PEC; + if (nread <= bus->data->fifo_size) + rxf_ctl |= bus->data->rxf_ctl_last_pec; /* * if we are about to read the first byte in blk rd mode, * don't NACK it. If slave returns zero size HW can't NACK - * it immidiattly, it will read extra byte and then NACK. + * it immediately, it will read extra byte and then NACK. */ if (bus->rd_ind == 0 && bus->read_block_use) { /* set fifo to read one byte, no last: */ @@ -794,9 +1080,9 @@ static void npcm_i2c_set_fifo(struct npcm_i2c *bus, int nread, int nwrite) /* configure TX FIFO */ if (nwrite > 0) { - if (nwrite > I2C_HW_FIFO_SIZE) + if (nwrite > bus->data->fifo_size) /* data to send is more then FIFO size. */ - iowrite8(I2C_HW_FIFO_SIZE, bus->reg + NPCM_I2CTXF_CTL); + iowrite8(bus->data->fifo_size, bus->reg + NPCM_I2CTXF_CTL); else iowrite8(nwrite, bus->reg + NPCM_I2CTXF_CTL); @@ -815,15 +1101,6 @@ static void npcm_i2c_read_fifo(struct npcm_i2c *bus, u8 bytes_in_fifo) } } -static inline void npcm_i2c_clear_master_status(struct npcm_i2c *bus) -{ - u8 val; - - /* Clear NEGACK, STASTR and BER bits */ - val = NPCM_I2CST_BER | NPCM_I2CST_NEGACK | NPCM_I2CST_STASTR; - iowrite8(val, bus->reg + NPCM_I2CST); -} - static void npcm_i2c_master_abort(struct npcm_i2c *bus) { /* Only current master is allowed to issue a stop condition */ @@ -838,18 +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"); - /* select bank 0 for address 3 to 10 */ - if (addr_type > I2C_SLAVE_ADDR2) - npcm_i2c_select_bank(bus, I2C_BANK_0); - - slave_add = ioread8(bus->reg + npcm_i2caddr[(int)addr_type]); - - if (addr_type > I2C_SLAVE_ADDR2) - npcm_i2c_select_bank(bus, I2C_BANK_1); - - 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) @@ -858,12 +1127,12 @@ static int npcm_i2c_remove_slave_addr(struct npcm_i2c *bus, u8 slave_add) /* Set the enable bit */ slave_add |= 0x80; - npcm_i2c_select_bank(bus, I2C_BANK_0); - for (i = I2C_SLAVE_ADDR1; i < I2C_NUM_OWN_ADDR; i++) { + + for (i = I2C_SLAVE_ADDR1; i < I2C_NUM_OWN_ADDR_SUPPORTED; i++) { if (ioread8(bus->reg + npcm_i2caddr[i]) == slave_add) iowrite8(0, bus->reg + npcm_i2caddr[i]); } - npcm_i2c_select_bank(bus, I2C_BANK_1); + return 0; } @@ -876,13 +1145,13 @@ static void npcm_i2c_write_fifo_slave(struct npcm_i2c *bus, u16 max_bytes) npcm_i2c_clear_fifo_int(bus); npcm_i2c_clear_tx_fifo(bus); iowrite8(0, bus->reg + NPCM_I2CTXF_CTL); - while (max_bytes-- && I2C_HW_FIFO_SIZE != npcm_i2c_fifo_usage(bus)) { + while (max_bytes-- && bus->data->fifo_size != npcm_i2c_fifo_usage(bus)) { if (bus->slv_wr_size <= 0) break; - bus->slv_wr_ind = bus->slv_wr_ind % I2C_HW_FIFO_SIZE; + bus->slv_wr_ind = bus->slv_wr_ind & (bus->data->fifo_size - 1); npcm_i2c_wr_byte(bus, bus->slv_wr_buf[bus->slv_wr_ind]); bus->slv_wr_ind++; - bus->slv_wr_ind = bus->slv_wr_ind % I2C_HW_FIFO_SIZE; + bus->slv_wr_ind = bus->slv_wr_ind & (bus->data->fifo_size - 1); bus->slv_wr_size--; } } @@ -897,7 +1166,7 @@ static void npcm_i2c_read_fifo_slave(struct npcm_i2c *bus, u8 bytes_in_fifo) while (bytes_in_fifo--) { data = npcm_i2c_rd_byte(bus); - bus->slv_rd_ind = bus->slv_rd_ind % I2C_HW_FIFO_SIZE; + bus->slv_rd_ind = bus->slv_rd_ind & (bus->data->fifo_size - 1); bus->slv_rd_buf[bus->slv_rd_ind] = data; bus->slv_rd_ind++; @@ -915,16 +1184,20 @@ static int npcm_i2c_slave_get_wr_buf(struct npcm_i2c *bus) int ret = bus->slv_wr_ind; /* fill a cyclic buffer */ - for (i = 0; i < I2C_HW_FIFO_SIZE; i++) { - if (bus->slv_wr_size >= I2C_HW_FIFO_SIZE) + for (i = 0; i < bus->data->fifo_size; i++) { + if (bus->slv_wr_size >= bus->data->fifo_size) break; - i2c_slave_event(bus->slave, I2C_SLAVE_READ_REQUESTED, &value); - ind = (bus->slv_wr_ind + bus->slv_wr_size) % I2C_HW_FIFO_SIZE; + if (bus->state == I2C_SLAVE_MATCH) { + i2c_slave_event(bus->slave, I2C_SLAVE_READ_REQUESTED, &value); + bus->state = I2C_OPER_STARTED; + } else { + i2c_slave_event(bus->slave, I2C_SLAVE_READ_PROCESSED, &value); + } + ind = (bus->slv_wr_ind + bus->slv_wr_size) & (bus->data->fifo_size - 1); bus->slv_wr_buf[ind] = value; bus->slv_wr_size++; - i2c_slave_event(bus->slave, I2C_SLAVE_READ_PROCESSED, &value); } - return I2C_HW_FIFO_SIZE - ret; + return bus->data->fifo_size - ret; } static void npcm_i2c_slave_send_rd_buf(struct npcm_i2c *bus) @@ -959,7 +1232,7 @@ static void npcm_i2c_slave_receive(struct npcm_i2c *bus, u16 nread, bus->slv_rd_ind = 0; iowrite8(0, bus->reg + NPCM_I2CTXF_CTL); - iowrite8(I2C_HW_FIFO_SIZE, bus->reg + NPCM_I2CRXF_CTL); + iowrite8(bus->data->fifo_size, bus->reg + NPCM_I2CRXF_CTL); npcm_i2c_clear_tx_fifo(bus); npcm_i2c_clear_rx_fifo(bus); } @@ -970,7 +1243,6 @@ static void npcm_i2c_slave_xmit(struct npcm_i2c *bus, u16 nwrite, if (nwrite == 0) return; - bus->state = I2C_OPER_STARTED; bus->operation = I2C_WRITE_OPER; /* get the next buffer */ @@ -981,7 +1253,7 @@ static void npcm_i2c_slave_xmit(struct npcm_i2c *bus, u16 nwrite, /* * npcm_i2c_slave_wr_buf_sync: * currently slave IF only supports single byte operations. - * in order to utilyze the npcm HW FIFO, the driver will ask for 16 bytes + * in order to utilize the npcm HW FIFO, the driver will ask for 16 bytes * at a time, pack them in buffer, and then transmit them all together * to the FIFO and onward to the bus. * NACK on read will be once reached to bus->adap->quirks->max_read_len. @@ -993,12 +1265,12 @@ static void npcm_i2c_slave_wr_buf_sync(struct npcm_i2c *bus) { int left_in_fifo; - left_in_fifo = FIELD_GET(NPCM_I2CTXF_STS_TX_BYTES, - ioread8(bus->reg + NPCM_I2CTXF_STS)); + left_in_fifo = bus->data->txf_sts_tx_bytes & + ioread8(bus->reg + NPCM_I2CTXF_STS); /* fifo already full: */ - if (left_in_fifo >= I2C_HW_FIFO_SIZE || - bus->slv_wr_size >= I2C_HW_FIFO_SIZE) + if (left_in_fifo >= bus->data->fifo_size || + bus->slv_wr_size >= bus->data->fifo_size) return; /* update the wr fifo index back to the untransmitted bytes: */ @@ -1006,7 +1278,7 @@ static void npcm_i2c_slave_wr_buf_sync(struct npcm_i2c *bus) bus->slv_wr_size = bus->slv_wr_size + left_in_fifo; if (bus->slv_wr_ind < 0) - bus->slv_wr_ind += I2C_HW_FIFO_SIZE; + bus->slv_wr_ind += bus->data->fifo_size; } static void npcm_i2c_slave_rd_wr(struct npcm_i2c *bus) @@ -1152,7 +1424,7 @@ static irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus) npcm_i2c_clear_rx_fifo(bus); npcm_i2c_clear_tx_fifo(bus); iowrite8(0, bus->reg + NPCM_I2CTXF_CTL); - iowrite8(I2C_HW_FIFO_SIZE, bus->reg + NPCM_I2CRXF_CTL); + iowrite8(bus->data->fifo_size, bus->reg + NPCM_I2CRXF_CTL); if (NPCM_I2CST_XMIT & i2cst) { bus->operation = I2C_WRITE_OPER; } else { @@ -1175,7 +1447,7 @@ static irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus) /* * the i2c module can response to 10 own SA. * check which one was addressed by the master. - * repond to the first one. + * respond to the first one. */ addr = ((i2ccst3 & 0x07) << 7) | (i2ccst2 & 0x7F); @@ -1231,7 +1503,16 @@ static irqreturn_t npcm_i2c_int_slave_handler(struct npcm_i2c *bus) ret = IRQ_HANDLED; } /* SDAST */ - return ret; + /* + * If irq is not one of the above, make sure EOB is disabled and all + * status bits are cleared. + */ + if (ret == IRQ_NONE) { + npcm_i2c_eob_int(bus, false); + npcm_i2c_clear_master_status(bus); + } + + return IRQ_HANDLED; } static int npcm_i2c_reg_slave(struct i2c_client *client) @@ -1241,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; @@ -1304,8 +1582,8 @@ static void npcm_i2c_master_fifo_read(struct npcm_i2c *bus) * read == FIFO Size + C (where C < FIFO Size)then first read C bytes * and in the next int we read rest of the data. */ - if (rcount < (2 * I2C_HW_FIFO_SIZE) && rcount > I2C_HW_FIFO_SIZE) - fifo_bytes = rcount - I2C_HW_FIFO_SIZE; + if (rcount < (2 * bus->data->fifo_size) && rcount > bus->data->fifo_size) + fifo_bytes = rcount - bus->data->fifo_size; if (rcount <= fifo_bytes) { /* last bytes are about to be read - end of tx */ @@ -1467,6 +1745,9 @@ static void npcm_i2c_irq_handle_nack(struct npcm_i2c *bus) npcm_i2c_eob_int(bus, false); npcm_i2c_master_stop(bus); + /* Clear SDA Status bit (by reading dummy byte) */ + npcm_i2c_rd_byte(bus); + /* * The bus is released from stall only after the SW clears * NEGACK bit. Then a Stop condition is sent. @@ -1474,6 +1755,8 @@ static void npcm_i2c_irq_handle_nack(struct npcm_i2c *bus) npcm_i2c_clear_master_status(bus); readx_poll_timeout_atomic(ioread8, bus->reg + NPCM_I2CCST, val, !(val & NPCM_I2CCST_BUSY), 10, 200); + /* Verify no status bits are still set after bus is released */ + npcm_i2c_clear_master_status(bus); } bus->state = I2C_IDLE; @@ -1494,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 */ @@ -1601,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); - } } } @@ -1640,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; } @@ -1672,10 +1959,11 @@ static int npcm_i2c_recovery_tgclk(struct i2c_adapter *_adap) int iter = 27; if ((npcm_i2c_get_SDA(_adap) == 1) && (npcm_i2c_get_SCL(_adap) == 1)) { - dev_dbg(bus->dev, "bus%d recovery skipped, bus not stuck", - bus->num); + dev_dbg(bus->dev, "bus%d-0x%x recovery skipped, bus not stuck", + bus->num, bus->dest_addr); npcm_i2c_reset(bus); - return status; + bus->ber_state = false; + return 0; } npcm_i2c_int_enable(bus, false); @@ -1739,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; } @@ -1753,8 +2042,8 @@ static void npcm_i2c_recovery_init(struct i2c_adapter *_adap) /* * npcm i2c HW allows direct reading of SCL and SDA. * However, it does not support setting SCL and SDA directly. - * The recovery function can togle SCL when SDA is low (but not set) - * Getter functions used internally, and can be used externaly. + * The recovery function can toggle SCL when SDA is low (but not set) + * Getter functions used internally, and can be used externally. */ rinfo->get_scl = npcm_i2c_get_SCL; rinfo->get_sda = npcm_i2c_get_SDA; @@ -1768,111 +2057,54 @@ static void npcm_i2c_recovery_init(struct i2c_adapter *_adap) /* * npcm_i2c_init_clk: init HW timing parameters. - * NPCM7XX i2c module timing parameters are depenent on module core clk (APB) + * NPCM7XX i2c module timing parameters are dependent on module core clk (APB) * and bus frequency. - * 100kHz bus requires tSCL = 4 * SCLFRQ * tCLK. LT and HT are simetric. - * 400kHz bus requires assymetric HT and LT. A different equation is recomended + * 100kHz bus requires tSCL = 4 * SCLFRQ * tCLK. LT and HT are symmetric. + * 400kHz bus requires asymmetric HT and LT. A different equation is recommended * by the HW designer, given core clock range (equations in comments below). * */ 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 */ @@ -1884,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); @@ -1909,6 +2141,7 @@ static int npcm_i2c_init_module(struct npcm_i2c *bus, enum i2c_mode mode, bus_freq_hz < I2C_FREQ_MIN_HZ || bus_freq_hz > I2C_FREQ_MAX_HZ) return -EINVAL; + npcm_i2c_int_enable(bus, false); npcm_i2c_disable(bus); /* Configure FIFO mode : */ @@ -1937,10 +2170,21 @@ static int npcm_i2c_init_module(struct npcm_i2c *bus, enum i2c_mode mode, val = (val | NPCM_I2CCTL1_NMINTE) & ~NPCM_I2CCTL1_RWS; iowrite8(val, bus->reg + NPCM_I2CCTL1); - npcm_i2c_int_enable(bus, true); - npcm_i2c_reset(bus); + /* 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_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); return 0; } @@ -1988,14 +2232,18 @@ static irqreturn_t npcm_i2c_bus_irq(int irq, void *dev_id) #if IS_ENABLED(CONFIG_I2C_SLAVE) if (bus->slave) { bus->master_or_slave = I2C_SLAVE; - return npcm_i2c_int_slave_handler(bus); + if (npcm_i2c_int_slave_handler(bus)) + return IRQ_HANDLED; } #endif - return IRQ_NONE; + /* Clear status bits for spurious interrupts */ + npcm_i2c_clear_master_status(bus); + + return IRQ_HANDLED; } 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) { @@ -2003,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; @@ -2046,9 +2293,7 @@ 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; - int timeout; - int ret = 0; + unsigned long timeout; bool read_block = false; bool read_PEC = false; u8 bus_busy; @@ -2060,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; @@ -2093,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(msecs_to_jiffies(35), 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 + msecs_to_jiffies(DEFAULT_STALL_COUNT) + 1; + time_left = jiffies + bus->adap.timeout / bus->adap.retries + 1; do { /* * we must clear slave address immediately when the bus is not @@ -2123,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); @@ -2131,19 +2392,26 @@ 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; bus->read_block_use = read_block; reinit_completion(&bus->cmd_complete); - if (!npcm_i2c_master_start_xmit(bus, slave_addr, nwrite, nread, - write_data, read_data, read_PEC, - read_block)) - ret = -EBUSY; - if (ret != -EBUSY) { + npcm_i2c_int_enable(bus, true); + + 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); @@ -2157,26 +2425,31 @@ static int npcm_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, } } } - ret = bus->cmd_err; /* if there was BER, check if need to recover the bus: */ if (bus->cmd_err == -EAGAIN) - ret = i2c_recover_bus(adap); + bus->cmd_err = i2c_recover_bus(adap); /* * After any type of error, check if LAST bit is still set, * due to a HW issue. * It cannot be cleared without resetting the module. */ - if (bus->cmd_err && - (NPCM_I2CRXF_CTL_LAST_PEC & ioread8(bus->reg + NPCM_I2CRXF_CTL))) + else if (bus->cmd_err && + (bus->data->rxf_ctl_last_pec & ioread8(bus->reg + NPCM_I2CRXF_CTL))) npcm_i2c_reset(bus); + /* After any xfer, successful or not, stall and EOB must be disabled */ + npcm_i2c_stall_after_start(bus, false); + npcm_i2c_eob_int(bus, false); + #if IS_ENABLED(CONFIG_I2C_SLAVE) /* reenable slave if it was enabled */ if (bus->slave) iowrite8((bus->slave->addr & 0x7F) | NPCM_I2CADDR_SAEN, bus->reg + NPCM_I2CADDR1); +#else + npcm_i2c_int_enable(bus, false); #endif return bus->cmd_err; } @@ -2197,43 +2470,33 @@ 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); - - 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) { - struct npcm_i2c *bus; + struct device_node *np = pdev->dev.of_node; + static struct regmap *gcr_regmap; + struct device *dev = &pdev->dev; struct i2c_adapter *adap; + struct npcm_i2c *bus; struct clk *i2c_clk; - static struct regmap *gcr_regmap; - static struct regmap *clk_regmap; int irq; int ret; @@ -2243,6 +2506,12 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev) bus->dev = &pdev->dev; + bus->data = of_device_get_match_data(dev); + if (!bus->data) { + dev_err(dev, "OF data missing\n"); + return -EINVAL; + } + bus->num = of_alias_get_id(pdev->dev.of_node, "i2c"); /* core clk must be acquired to calculate module timing settings */ i2c_clk = devm_clk_get(&pdev->dev, NULL); @@ -2250,14 +2519,13 @@ static int npcm_i2c_probe_bus(struct platform_device *pdev) return PTR_ERR(i2c_clk); bus->apb_clk = clk_get_rate(i2c_clk); - gcr_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr"); + gcr_regmap = syscon_regmap_lookup_by_phandle(np, "nuvoton,sys-mgr"); if (IS_ERR(gcr_regmap)) - return PTR_ERR(gcr_regmap); - regmap_write(gcr_regmap, NPCM_I2CSEGCTL, NPCM_I2CSEGCTL_INIT_VAL); + gcr_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-gcr"); - clk_regmap = syscon_regmap_lookup_by_compatible("nuvoton,npcm750-clk"); - if (IS_ERR(clk_regmap)) - return PTR_ERR(clk_regmap); + if (IS_ERR(gcr_regmap)) + return PTR_ERR(gcr_regmap); + regmap_write(gcr_regmap, NPCM_I2CSEGCTL, bus->data->segctl_init_val); bus->reg = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(bus->reg)) @@ -2269,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 = HZ; + /* + * 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; @@ -2281,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) @@ -2305,21 +2585,20 @@ 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[] = { - { .compatible = "nuvoton,npcm750-i2c", }, + { .compatible = "nuvoton,npcm750-i2c", .data = &npxm7xx_i2c_data }, + { .compatible = "nuvoton,npcm845-i2c", .data = &npxm8xx_i2c_data }, {} }; MODULE_DEVICE_TABLE(of, npcm_i2c_bus_of_table); @@ -2333,20 +2612,7 @@ static struct platform_driver npcm_i2c_bus_driver = { } }; -static int __init npcm_i2c_init(void) -{ - npcm_i2c_debugfs_dir = debugfs_create_dir("npcm_i2c", NULL); - platform_driver_register(&npcm_i2c_bus_driver); - 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 b5055a3cbd93..14c059b03945 100644 --- a/drivers/i2c/busses/i2c-nvidia-gpu.c +++ b/drivers/i2c/busses/i2c-nvidia-gpu.c @@ -14,8 +14,11 @@ #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" /* I2C definitions */ #define I2C_MST_CNTL 0x00 @@ -160,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; @@ -214,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; } @@ -231,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, }; /* @@ -257,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), { } }; @@ -266,78 +269,56 @@ static const struct software_node ccgx_node = { .properties = ccgx_props, }; -static int gpu_populate_client(struct gpu_i2c_dev *i2cd, int irq) -{ - i2cd->gpu_ccgx_ucsi = devm_kzalloc(i2cd->dev, - sizeof(*i2cd->gpu_ccgx_ucsi), - GFP_KERNEL); - if (!i2cd->gpu_ccgx_ucsi) - return -ENOMEM; - - strlcpy(i2cd->gpu_ccgx_ucsi->type, "ccgx-ucsi", - sizeof(i2cd->gpu_ccgx_ucsi->type)); - i2cd->gpu_ccgx_ucsi->addr = 0x8; - i2cd->gpu_ccgx_ucsi->irq = irq; - i2cd->gpu_ccgx_ucsi->swnode = &ccgx_node; - i2cd->ccgx_client = i2c_new_client_device(&i2cd->adapter, i2cd->gpu_ccgx_ucsi); - return PTR_ERR_OR_ZERO(i2cd->ccgx_client); -} - static int gpu_i2c_probe(struct pci_dev *pdev, const struct pci_device_id *id) { + struct device *dev = &pdev->dev; struct gpu_i2c_dev *i2cd; int status; - i2cd = devm_kzalloc(&pdev->dev, sizeof(*i2cd), GFP_KERNEL); + i2cd = devm_kzalloc(dev, sizeof(*i2cd), GFP_KERNEL); if (!i2cd) return -ENOMEM; - i2cd->dev = &pdev->dev; - dev_set_drvdata(&pdev->dev, i2cd); + i2cd->dev = dev; + dev_set_drvdata(dev, i2cd); status = pcim_enable_device(pdev); - if (status < 0) { - dev_err(&pdev->dev, "pcim_enable_device failed %d\n", status); - return status; - } + if (status < 0) + return dev_err_probe(dev, status, "pcim_enable_device failed\n"); pci_set_master(pdev); i2cd->regs = pcim_iomap(pdev, 0, 0); - if (!i2cd->regs) { - dev_err(&pdev->dev, "pcim_iomap failed\n"); - return -ENOMEM; - } + if (!i2cd->regs) + return dev_err_probe(dev, -ENOMEM, "pcim_iomap failed\n"); status = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSI); - if (status < 0) { - dev_err(&pdev->dev, "pci_alloc_irq_vectors err %d\n", status); - return status; - } + if (status < 0) + return dev_err_probe(dev, status, "pci_alloc_irq_vectors err\n"); gpu_enable_i2c_bus(i2cd); i2c_set_adapdata(&i2cd->adapter, i2cd); i2cd->adapter.owner = THIS_MODULE; - strlcpy(i2cd->adapter.name, "NVIDIA GPU I2C adapter", + strscpy(i2cd->adapter.name, "NVIDIA GPU I2C adapter", sizeof(i2cd->adapter.name)); i2cd->adapter.algo = &gpu_i2c_algorithm; i2cd->adapter.quirks = &gpu_i2c_quirks; - i2cd->adapter.dev.parent = &pdev->dev; + i2cd->adapter.dev.parent = dev; status = i2c_add_adapter(&i2cd->adapter); if (status < 0) goto free_irq_vectors; - status = gpu_populate_client(i2cd, pdev->irq); - if (status < 0) { - dev_err(&pdev->dev, "gpu_populate_client failed %d\n", status); + i2cd->ccgx_client = i2c_new_ccgx_ucsi(&i2cd->adapter, pdev->irq, &ccgx_node); + if (IS_ERR(i2cd->ccgx_client)) { + status = dev_err_probe(dev, PTR_ERR(i2cd->ccgx_client), "register UCSI failed\n"); goto del_adapter; } - pm_runtime_set_autosuspend_delay(&pdev->dev, 3000); - pm_runtime_use_autosuspend(&pdev->dev); - pm_runtime_put_autosuspend(&pdev->dev); - pm_runtime_allow(&pdev->dev); + pm_runtime_set_autosuspend_delay(dev, 3000); + pm_runtime_use_autosuspend(dev); + pm_runtime_put_autosuspend(dev); + pm_runtime_allow(dev); return 0; @@ -350,7 +331,7 @@ free_irq_vectors: static void gpu_i2c_remove(struct pci_dev *pdev) { - struct gpu_i2c_dev *i2cd = dev_get_drvdata(&pdev->dev); + struct gpu_i2c_dev *i2cd = pci_get_drvdata(pdev); pm_runtime_get_noresume(i2cd->dev); i2c_del_adapter(&i2cd->adapter); 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 d4f6c6d60683..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); @@ -1488,7 +1493,7 @@ omap_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(adap, omap); adap->owner = THIS_MODULE; adap->class = I2C_CLASS_DEPRECATED; - strlcpy(adap->name, "OMAP I2C adapter", sizeof(adap->name)); + strscpy(adap->name, "OMAP I2C adapter", sizeof(adap->name)); adap->algo = &omap_i2c_algo; adap->quirks = &omap_i2c_quirks; adap->dev.parent = &pdev->dev; @@ -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 6eb0f50c5d28..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, }; /* @@ -220,9 +220,9 @@ static int i2c_opal_probe(struct platform_device *pdev) adapter->dev.of_node = of_node_get(pdev->dev.of_node); pname = of_get_property(pdev->dev.of_node, "ibm,port-name", NULL); if (pname) - strlcpy(adapter->name, pname, sizeof(adapter->name)); + strscpy(adapter->name, pname, sizeof(adapter->name)); else - strlcpy(adapter->name, "opal", sizeof(adapter->name)); + strscpy(adapter->name, "opal", sizeof(adapter->name)); platform_set_drvdata(pdev, adapter); rc = i2c_add_adapter(adapter); @@ -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 a535889acca6..3249bbd5eb43 100644 --- a/drivers/i2c/busses/i2c-parport.c +++ b/drivers/i2c/busses/i2c-parport.c @@ -267,6 +267,16 @@ static void i2c_parport_attach(struct parport *port) int i; struct pardev_cb i2c_parport_cb; + if (type < 0) { + pr_warn("adapter type unspecified\n"); + return; + } + + if (type >= ARRAY_SIZE(adapter_parm)) { + pr_warn("invalid type (%d)\n", type); + return; + } + for (i = 0; i < MAX_DEVICE; i++) { if (parport[i] == -1) continue; @@ -298,7 +308,7 @@ static void i2c_parport_attach(struct parport *port) /* Fill the rest of the structure */ adapter->adapter.owner = THIS_MODULE; adapter->adapter.class = I2C_CLASS_HWMON; - strlcpy(adapter->adapter.name, "Parallel port adapter", + strscpy(adapter->adapter.name, "Parallel port adapter", sizeof(adapter->adapter.name)); adapter->algo_data = parport_algo_data; /* Slow down if we can't sense SCL */ @@ -390,34 +400,9 @@ static struct parport_driver i2c_parport_driver = { .name = "i2c-parport", .match_port = i2c_parport_attach, .detach = i2c_parport_detach, - .devmodel = true, }; - -/* ----- Module loading, unloading and information ------------------------ */ - -static int __init i2c_parport_init(void) -{ - if (type < 0) { - pr_warn("adapter type unspecified\n"); - return -ENODEV; - } - - if (type >= ARRAY_SIZE(adapter_parm)) { - pr_warn("invalid type (%d)\n", type); - return -ENODEV; - } - - return parport_register_driver(&i2c_parport_driver); -} - -static void __exit i2c_parport_exit(void) -{ - parport_unregister_driver(&i2c_parport_driver); -} +module_parport_driver(i2c_parport_driver); MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>"); MODULE_DESCRIPTION("I2C bus over parallel port"); MODULE_LICENSE("GPL"); - -module_init(i2c_parport_init); -module_exit(i2c_parport_exit); diff --git a/drivers/i2c/busses/i2c-pasemi.c b/drivers/i2c/busses/i2c-pasemi-core.c index 20f2772c0e79..f4eca44ed183 100644 --- a/drivers/i2c/busses/i2c-pasemi.c +++ b/drivers/i2c/busses/i2c-pasemi-core.c @@ -5,99 +5,185 @@ * 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> - -static struct pci_driver pasemi_smb_driver; +#include <linux/stddef.h> -struct pasemi_smbus { - struct pci_dev *dev; - struct i2c_adapter adapter; - unsigned long base; - int size; -}; +#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 MRXFIFO_EMPTY 0x00000100 -#define MRXFIFO_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 SMSTA_XEN 0x08000000 -#define SMSTA_MTN 0x00200000 - -#define CTL_MRR 0x00000400 -#define CTL_MTR 0x00000200 -#define CTL_CLK_M 0x000000ff - -#define CLK_100K_DIV 84 -#define CLK_400K_DIV 21 +/* + * 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) { - dev_dbg(&smbus->dev->dev, "smbus write reg %lx val %08x\n", - smbus->base + reg, val); - outl(val, smbus->base + reg); + dev_dbg(smbus->dev, "smbus write reg %x val %08x\n", reg, val); + iowrite32(val, smbus->ioaddr + reg); } static inline int reg_read(struct pasemi_smbus *smbus, int reg) { int ret; - ret = inl(smbus->base + reg); - dev_dbg(&smbus->dev->dev, "smbus read reg %lx val %08x\n", - smbus->base + reg, ret); + ret = ioread32(smbus->ioaddr + reg); + dev_dbg(smbus->dev, "smbus read reg %x val %08x\n", reg, ret); return ret; } #define TXFIFO_WR(smbus, reg) reg_write((smbus), REG_MTXFIFO, (reg)) #define RXFIFO_RD(smbus) reg_read((smbus), REG_MRXFIFO) -static void pasemi_smb_clear(struct pasemi_smbus *smbus) +static void pasemi_reset(struct pasemi_smbus *smbus) +{ + u32 val = (CTL_MTR | CTL_MRR | CTL_UJM | (smbus->clk_div & CTL_CLK_M)); + + if (smbus->hw_rev >= 6) + val |= CTL_EN; + + reg_write(smbus, REG_CTL, val); + reinit_completion(&smbus->irq_completion); +} + +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 = 10; unsigned int status; - status = reg_read(smbus, REG_SMSTA); - - while (!(status & SMSTA_XEN) && timeout--) { - msleep(1); + if (smbus->use_irq) { + reinit_completion(&smbus->irq_completion); + reg_write(smbus, REG_IMASK, SMSTA_XEN | SMSTA_MTN); + 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 { + 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->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); @@ -137,13 +223,18 @@ static int pasemi_i2c_xfer_msg(struct i2c_adapter *adapter, TXFIFO_WR(smbus, msg->buf[msg->len-1] | (stop ? MTXFIFO_STOP : 0)); + + if (stop) { + err = pasemi_smb_waitready(smbus); + if (err) + goto reset_out; + } } return 0; reset_out: - reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | - (CLK_100K_DIV & CTL_CLK_M))); + pasemi_reset(smbus); return err; } @@ -153,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))); @@ -176,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: @@ -309,8 +402,7 @@ static int pasemi_smb_xfer(struct i2c_adapter *adapter, return 0; reset_out: - reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | - (CLK_100K_DIV & CTL_CLK_M))); + pasemi_reset(smbus); return err; } @@ -323,87 +415,51 @@ 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, }; -static int pasemi_smb_probe(struct pci_dev *dev, - const struct pci_device_id *id) +int pasemi_i2c_common_probe(struct pasemi_smbus *smbus) { - struct pasemi_smbus *smbus; int error; - if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO)) - return -ENODEV; - - smbus = kzalloc(sizeof(struct pasemi_smbus), GFP_KERNEL); - if (!smbus) - return -ENOMEM; - - smbus->dev = dev; - smbus->base = pci_resource_start(dev, 0); - smbus->size = pci_resource_len(dev, 0); - - if (!request_region(smbus->base, smbus->size, - pasemi_smb_driver.name)) { - error = -EBUSY; - goto out_kfree; - } - smbus->adapter.owner = THIS_MODULE; snprintf(smbus->adapter.name, sizeof(smbus->adapter.name), - "PA Semi SMBus adapter at 0x%lx", smbus->base); - smbus->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD; + "PA Semi SMBus adapter (%s)", dev_name(smbus->dev)); smbus->adapter.algo = &smbus_algorithm; smbus->adapter.algo_data = smbus; /* set up the sysfs linkage to our parent device */ - smbus->adapter.dev.parent = &dev->dev; + smbus->adapter.dev.parent = smbus->dev; + smbus->use_irq = 0; + init_completion(&smbus->irq_completion); - reg_write(smbus, REG_CTL, (CTL_MTR | CTL_MRR | - (CLK_100K_DIV & CTL_CLK_M))); + if (smbus->hw_rev != PASEMI_HW_REV_PCI) + smbus->hw_rev = reg_read(smbus, REG_REV); - error = i2c_add_adapter(&smbus->adapter); - if (error) - goto out_release_region; + reg_write(smbus, REG_IMASK, 0); - pci_set_drvdata(dev, smbus); + pasemi_reset(smbus); - return 0; + error = devm_i2c_add_adapter(smbus->dev, &smbus->adapter); + if (error) + return error; - out_release_region: - release_region(smbus->base, smbus->size); - out_kfree: - kfree(smbus); - return error; + return 0; } +EXPORT_SYMBOL_GPL(pasemi_i2c_common_probe); -static void pasemi_smb_remove(struct pci_dev *dev) +irqreturn_t pasemi_irq_handler(int irq, void *dev_id) { - struct pasemi_smbus *smbus = pci_get_drvdata(dev); + struct pasemi_smbus *smbus = dev_id; - i2c_del_adapter(&smbus->adapter); - release_region(smbus->base, smbus->size); - kfree(smbus); + reg_write(smbus, REG_IMASK, 0); + complete(&smbus->irq_completion); + return IRQ_HANDLED; } - -static const struct pci_device_id pasemi_smb_ids[] = { - { PCI_DEVICE(0x1959, 0xa003) }, - { 0, } -}; - -MODULE_DEVICE_TABLE(pci, pasemi_smb_ids); - -static struct pci_driver pasemi_smb_driver = { - .name = "i2c-pasemi", - .id_table = pasemi_smb_ids, - .probe = pasemi_smb_probe, - .remove = pasemi_smb_remove, -}; - -module_pci_driver(pasemi_smb_driver); +EXPORT_SYMBOL_GPL(pasemi_irq_handler); MODULE_LICENSE("GPL"); -MODULE_AUTHOR ("Olof Johansson <olof@lixom.net>"); +MODULE_AUTHOR("Olof Johansson <olof@lixom.net>"); MODULE_DESCRIPTION("PA Semi PWRficient SMBus driver"); diff --git a/drivers/i2c/busses/i2c-pasemi-core.h b/drivers/i2c/busses/i2c-pasemi-core.h new file mode 100644 index 000000000000..88821f4e8a9f --- /dev/null +++ b/drivers/i2c/busses/i2c-pasemi-core.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include <linux/atomic.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/device.h> +#include <linux/i2c.h> +#include <linux/i2c-smbus.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/completion.h> + +#define PASEMI_HW_REV_PCI -1 + +struct pasemi_smbus { + struct device *dev; + struct i2c_adapter adapter; + void __iomem *ioaddr; + unsigned int clk_div; + int hw_rev; + int use_irq; + struct completion irq_completion; +}; + +int pasemi_i2c_common_probe(struct pasemi_smbus *smbus); + +irqreturn_t pasemi_irq_handler(int irq, void *dev_id); diff --git a/drivers/i2c/busses/i2c-pasemi-pci.c b/drivers/i2c/busses/i2c-pasemi-pci.c new file mode 100644 index 000000000000..b9ccb54ec77e --- /dev/null +++ b/drivers/i2c/busses/i2c-pasemi-pci.c @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2006-2007 PA Semi, Inc + * + * 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/sched.h> +#include <linux/slab.h> +#include <linux/stddef.h> + +#include "i2c-pasemi-core.h" + +#define CLK_100K_DIV 84 +#define CLK_400K_DIV 21 + +static struct pci_driver pasemi_smb_pci_driver; + +static int pasemi_smb_pci_probe(struct pci_dev *dev, + const struct pci_device_id *id) +{ + struct pasemi_smbus *smbus; + unsigned long base; + int size; + int error; + + if (!(pci_resource_flags(dev, 0) & IORESOURCE_IO)) + return -ENODEV; + + smbus = devm_kzalloc(&dev->dev, sizeof(*smbus), GFP_KERNEL); + if (!smbus) + return -ENOMEM; + + smbus->dev = &dev->dev; + base = pci_resource_start(dev, 0); + size = pci_resource_len(dev, 0); + smbus->clk_div = CLK_100K_DIV; + + /* + * The original PASemi PCI controllers don't have a register for + * their HW revision. + */ + smbus->hw_rev = PASEMI_HW_REV_PCI; + + if (!devm_request_region(&dev->dev, base, size, + pasemi_smb_pci_driver.name)) + return -EBUSY; + + smbus->ioaddr = pcim_iomap(dev, 0, 0); + if (!smbus->ioaddr) + return -EBUSY; + + smbus->adapter.class = I2C_CLASS_HWMON; + error = pasemi_i2c_common_probe(smbus); + if (error) + return error; + + pci_set_drvdata(dev, smbus); + + return 0; +} + +static const struct pci_device_id pasemi_smb_pci_ids[] = { + { PCI_DEVICE(0x1959, 0xa003) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, pasemi_smb_pci_ids); + +static struct pci_driver pasemi_smb_pci_driver = { + .name = "i2c-pasemi", + .id_table = pasemi_smb_pci_ids, + .probe = pasemi_smb_pci_probe, +}; + +module_pci_driver(pasemi_smb_pci_driver); + +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-platform.c b/drivers/i2c/busses/i2c-pasemi-platform.c new file mode 100644 index 000000000000..a486a37d3863 --- /dev/null +++ b/drivers/i2c/busses/i2c-pasemi-platform.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2021 The Asahi Linux Contributors + * + * PA Semi PWRficient SMBus host driver for Apple SoCs + */ + +#include <linux/clk.h> +#include <linux/i2c.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/types.h> + +#include "i2c-pasemi-core.h" + +struct pasemi_platform_i2c_data { + struct pasemi_smbus smbus; + struct clk *clk_ref; +}; + +static int +pasemi_platform_i2c_calc_clk_div(struct pasemi_platform_i2c_data *data, + u32 frequency) +{ + unsigned long clk_rate = clk_get_rate(data->clk_ref); + + if (!clk_rate) + return -EINVAL; + + data->smbus.clk_div = DIV_ROUND_UP(clk_rate, 16 * frequency); + if (data->smbus.clk_div < 4) + return dev_err_probe(data->smbus.dev, -EINVAL, + "Bus frequency %d is too fast.\n", + frequency); + if (data->smbus.clk_div > 0xff) + return dev_err_probe(data->smbus.dev, -EINVAL, + "Bus frequency %d is too slow.\n", + frequency); + + return 0; +} + +static int pasemi_platform_i2c_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pasemi_platform_i2c_data *data; + struct pasemi_smbus *smbus; + u32 frequency; + int error; + int irq_num; + + data = devm_kzalloc(dev, sizeof(struct pasemi_platform_i2c_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + smbus = &data->smbus; + smbus->dev = dev; + + smbus->ioaddr = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(smbus->ioaddr)) + return PTR_ERR(smbus->ioaddr); + + if (of_property_read_u32(dev->of_node, "clock-frequency", &frequency)) + frequency = I2C_MAX_STANDARD_MODE_FREQ; + + data->clk_ref = devm_clk_get_enabled(dev, NULL); + if (IS_ERR(data->clk_ref)) + return PTR_ERR(data->clk_ref); + + error = pasemi_platform_i2c_calc_clk_div(data, frequency); + if (error) + return error; + + smbus->adapter.dev.of_node = pdev->dev.of_node; + error = pasemi_i2c_common_probe(smbus); + if (error) + 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); + + if (!error) + smbus->use_irq = 1; + platform_set_drvdata(pdev, data); + + 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" }, + { .compatible = "apple,i2c" }, + {}, +}; +MODULE_DEVICE_TABLE(of, pasemi_platform_i2c_of_match); + +static struct platform_driver pasemi_platform_i2c_driver = { + .driver = { + .name = "i2c-apple", + .of_match_table = pasemi_platform_i2c_of_match, + }, + .probe = pasemi_platform_i2c_probe, + .remove = pasemi_platform_i2c_remove, +}; +module_platform_driver(pasemi_platform_i2c_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sven Peter <sven@svenpeter.dev>"); +MODULE_DESCRIPTION("Apple/PASemi SMBus platform 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 8c1b31ed0c42..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 @@ -77,6 +65,7 @@ /* SB800 constants */ #define SB800_PIIX4_SMB_IDX 0xcd6 +#define SB800_PIIX4_SMB_MAP_SIZE 2 #define KERNCZ_IMC_IDX 0x3e #define KERNCZ_IMC_DATA 0x3f @@ -92,11 +81,14 @@ #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_SIZE 8 +#define SB800_ASF_ACPI_PATH "\\_SB.ASFC" + /* insmod parameters */ /* If force is set to anything different from 0, we forcibly enable the @@ -141,7 +133,7 @@ static const struct dmi_system_id piix4_dmi_ibm[] = { .ident = "IBM", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), }, }, - { }, + { } }; /* @@ -162,8 +154,74 @@ struct i2c_piix4_adapdata { bool sb800_main; bool notify_imc; u8 port; /* Port number, shifted */ + 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(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", + FCH_PM_BASE); + return -EBUSY; + } + + addr = ioremap(FCH_PM_BASE, + SB800_PIIX4_FCH_PM_SIZE); + if (!addr) { + release_mem_region(FCH_PM_BASE, + SB800_PIIX4_FCH_PM_SIZE); + dev_err(dev, "SMBus base address mapping failed.\n"); + return -ENOMEM; + } + + mmio_cfg->addr = addr; + + return 0; + } + + if (!request_muxed_region(SB800_PIIX4_SMB_IDX, SB800_PIIX4_SMB_MAP_SIZE, + "sb800_piix4_smb")) { + dev_err(dev, + "SMBus base address index region 0x%x already in use.\n", + SB800_PIIX4_SMB_IDX); + return -EBUSY; + } + + return 0; +} +EXPORT_SYMBOL_NS_GPL(piix4_sb800_region_request, "PIIX4_SMBUS"); + +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(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) +{ + /* + * cd6h/cd7h port I/O accesses can be disabled on AMD processors + * w/ SMBus PCI revision ID 0x51 or greater. MMIO is supported on + * the same processors and is the recommended access method. + */ + return (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD && + PIIX4_dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS && + PIIX4_dev->revision >= 0x51); +} + static int piix4_setup(struct pci_dev *PIIX4_dev, const struct pci_device_id *id) { @@ -263,12 +321,61 @@ static int piix4_setup(struct pci_dev *PIIX4_dev, return piix4_smba; } +static int piix4_setup_sb800_smba(struct pci_dev *PIIX4_dev, + u8 smb_en, + u8 aux, + u8 *smb_en_status, + unsigned short *piix4_smba) +{ + struct sb800_mmio_cfg mmio_cfg; + u8 smba_en_lo; + u8 smba_en_hi; + int retval; + + mmio_cfg.use_mmio = piix4_sb800_use_mmio(PIIX4_dev); + retval = piix4_sb800_region_request(&PIIX4_dev->dev, &mmio_cfg); + if (retval) + return retval; + + if (mmio_cfg.use_mmio) { + smba_en_lo = ioread8(mmio_cfg.addr); + smba_en_hi = ioread8(mmio_cfg.addr + 1); + } else { + outb_p(smb_en, SB800_PIIX4_SMB_IDX); + smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1); + outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX); + smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1); + } + + piix4_sb800_region_release(&PIIX4_dev->dev, &mmio_cfg); + + if (!smb_en) { + *smb_en_status = smba_en_lo & 0x10; + *piix4_smba = smba_en_hi << 8; + if (aux) + *piix4_smba |= 0x20; + } else { + *smb_en_status = smba_en_lo & 0x01; + *piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0; + } + + if (!*smb_en_status) { + dev_err(&PIIX4_dev->dev, + "SMBus Host Controller not enabled!\n"); + return -ENODEV; + } + + return 0; +} + static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, const struct pci_device_id *id, u8 aux) { unsigned short piix4_smba; - u8 smba_en_lo, smba_en_hi, smb_en, smb_en_status, port_sel; + u8 smb_en, smb_en_status, port_sel; u8 i2ccfg, i2ccfg_offset = 0x10; + struct sb800_mmio_cfg mmio_cfg; + int retval; /* SB800 and later SMBus does not support forcing address */ if (force || force_addr) { @@ -290,35 +397,11 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, else smb_en = (aux) ? 0x28 : 0x2c; - if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2, "sb800_piix4_smb")) { - dev_err(&PIIX4_dev->dev, - "SMB base address index region 0x%x already in use.\n", - SB800_PIIX4_SMB_IDX); - return -EBUSY; - } - - outb_p(smb_en, SB800_PIIX4_SMB_IDX); - smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1); - outb_p(smb_en + 1, SB800_PIIX4_SMB_IDX); - smba_en_hi = inb_p(SB800_PIIX4_SMB_IDX + 1); - - release_region(SB800_PIIX4_SMB_IDX, 2); - - if (!smb_en) { - smb_en_status = smba_en_lo & 0x10; - piix4_smba = smba_en_hi << 8; - if (aux) - piix4_smba |= 0x20; - } else { - smb_en_status = smba_en_lo & 0x01; - piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0; - } + retval = piix4_setup_sb800_smba(PIIX4_dev, smb_en, aux, &smb_en_status, + &piix4_smba); - if (!smb_en_status) { - dev_err(&PIIX4_dev->dev, - "SMBus Host Controller not enabled!\n"); - return -ENODEV; - } + if (retval) + return retval; if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name)) return -ENODEV; @@ -371,10 +454,11 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT; } } else { - if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2, - "sb800_piix4_smb")) { + mmio_cfg.use_mmio = piix4_sb800_use_mmio(PIIX4_dev); + retval = piix4_sb800_region_request(&PIIX4_dev->dev, &mmio_cfg); + if (retval) { release_region(piix4_smba, SMBIOSIZE); - return -EBUSY; + return retval; } outb_p(SB800_PIIX4_PORT_IDX_SEL, SB800_PIIX4_SMB_IDX); @@ -384,7 +468,7 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev, SB800_PIIX4_PORT_IDX; piix4_port_mask_sb800 = SB800_PIIX4_PORT_IDX_MASK; piix4_port_shift_sb800 = SB800_PIIX4_PORT_IDX_SHIFT; - release_region(SB800_PIIX4_SMB_IDX, 2); + piix4_sb800_region_release(&PIIX4_dev->dev, &mmio_cfg); } dev_info(&PIIX4_dev->dev, @@ -434,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; @@ -488,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) { @@ -509,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, @@ -573,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; @@ -662,6 +745,30 @@ static void piix4_imc_wakeup(void) release_region(KERNCZ_IMC_IDX, 2); } +int piix4_sb800_port_sel(u8 port, struct sb800_mmio_cfg *mmio_cfg) +{ + u8 smba_en_lo, val; + + if (mmio_cfg->use_mmio) { + smba_en_lo = ioread8(mmio_cfg->addr + piix4_port_sel_sb800); + val = (smba_en_lo & ~piix4_port_mask_sb800) | port; + if (smba_en_lo != val) + iowrite8(val, mmio_cfg->addr + piix4_port_sel_sb800); + + return (smba_en_lo & piix4_port_mask_sb800); + } + + outb_p(piix4_port_sel_sb800, SB800_PIIX4_SMB_IDX); + smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1); + + val = (smba_en_lo & ~piix4_port_mask_sb800) | port; + if (smba_en_lo != val) + outb_p(val, SB800_PIIX4_SMB_IDX + 1); + + 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. * The port is selected by bits 2:1 of the smb_en register (0x2c). @@ -678,12 +785,12 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr, unsigned short piix4_smba = adapdata->smba; int retries = MAX_TIMEOUT; int smbslvcnt; - u8 smba_en_lo; - u8 port; + u8 prev_port; int retval; - if (!request_muxed_region(SB800_PIIX4_SMB_IDX, 2, "sb800_piix4_smb")) - return -EBUSY; + retval = piix4_sb800_region_request(&adap->dev, &adapdata->mmio_cfg); + if (retval) + return retval; /* Request the SMBUS semaphore, avoid conflicts with the IMC */ smbslvcnt = inb_p(SMBSLVCNT); @@ -738,18 +845,12 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr, } } - outb_p(piix4_port_sel_sb800, SB800_PIIX4_SMB_IDX); - smba_en_lo = inb_p(SB800_PIIX4_SMB_IDX + 1); - - port = adapdata->port; - if ((smba_en_lo & piix4_port_mask_sb800) != port) - outb_p((smba_en_lo & ~piix4_port_mask_sb800) | port, - SB800_PIIX4_SMB_IDX + 1); + prev_port = piix4_sb800_port_sel(adapdata->port, &adapdata->mmio_cfg); retval = piix4_access(adap, addr, flags, read_write, command, size, data); - outb_p(smba_en_lo, SB800_PIIX4_SMB_IDX + 1); + piix4_sb800_port_sel(prev_port, &adapdata->mmio_cfg); /* Release the semaphore */ outb_p(smbslvcnt | 0x20, SMBSLVCNT); @@ -758,7 +859,7 @@ static s32 piix4_access_sb800(struct i2c_adapter *adap, u16 addr, piix4_imc_wakeup(); release: - release_region(SB800_PIIX4_SMB_IDX, 2); + piix4_sb800_region_release(&adap->dev, &adapdata->mmio_cfg); return retval; } @@ -825,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; @@ -836,6 +937,7 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba, return -ENOMEM; } + adapdata->mmio_cfg.use_mmio = piix4_sb800_use_mmio(dev); adapdata->smba = smba; adapdata->sb800_main = sb800_main; adapdata->port = port << piix4_port_shift_sb800; @@ -863,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; } @@ -915,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 && @@ -961,6 +1074,7 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id) "", &piix4_main_adapters[0]); if (retval < 0) return retval; + piix4_adapter_count = 1; } /* Check for auxiliary SMBus on some AMD chipsets */ @@ -976,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-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c deleted file mode 100644 index 5d89c7c1b3a8..000000000000 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ /dev/null @@ -1,600 +0,0 @@ -/* - * Specific bus support for PMC-TWI compliant implementation on MSP71xx. - * - * Copyright 2005-2007 PMC-Sierra, Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. - * - * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN - * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF - * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/platform_device.h> -#include <linux/i2c.h> -#include <linux/interrupt.h> -#include <linux/completion.h> -#include <linux/mutex.h> -#include <linux/delay.h> -#include <linux/io.h> - -#define DRV_NAME "pmcmsptwi" - -#define MSP_TWI_SF_CLK_REG_OFFSET 0x00 -#define MSP_TWI_HS_CLK_REG_OFFSET 0x04 -#define MSP_TWI_CFG_REG_OFFSET 0x08 -#define MSP_TWI_CMD_REG_OFFSET 0x0c -#define MSP_TWI_ADD_REG_OFFSET 0x10 -#define MSP_TWI_DAT_0_REG_OFFSET 0x14 -#define MSP_TWI_DAT_1_REG_OFFSET 0x18 -#define MSP_TWI_INT_STS_REG_OFFSET 0x1c -#define MSP_TWI_INT_MSK_REG_OFFSET 0x20 -#define MSP_TWI_BUSY_REG_OFFSET 0x24 - -#define MSP_TWI_INT_STS_DONE (1 << 0) -#define MSP_TWI_INT_STS_LOST_ARBITRATION (1 << 1) -#define MSP_TWI_INT_STS_NO_RESPONSE (1 << 2) -#define MSP_TWI_INT_STS_DATA_COLLISION (1 << 3) -#define MSP_TWI_INT_STS_BUSY (1 << 4) -#define MSP_TWI_INT_STS_ALL 0x1f - -#define MSP_MAX_BYTES_PER_RW 8 -#define MSP_MAX_POLL 5 -#define MSP_POLL_DELAY 10 -#define MSP_IRQ_TIMEOUT (MSP_MAX_POLL * MSP_POLL_DELAY) - -/* IO Operation macros */ -#define pmcmsptwi_readl __raw_readl -#define pmcmsptwi_writel __raw_writel - -/* TWI command type */ -enum pmcmsptwi_cmd_type { - MSP_TWI_CMD_WRITE = 0, /* Write only */ - MSP_TWI_CMD_READ = 1, /* Read only */ - MSP_TWI_CMD_WRITE_READ = 2, /* Write then Read */ -}; - -/* The possible results of the xferCmd */ -enum pmcmsptwi_xfer_result { - MSP_TWI_XFER_OK = 0, - MSP_TWI_XFER_TIMEOUT, - MSP_TWI_XFER_BUSY, - MSP_TWI_XFER_DATA_COLLISION, - MSP_TWI_XFER_NO_RESPONSE, - MSP_TWI_XFER_LOST_ARBITRATION, -}; - -/* Corresponds to a PMCTWI clock configuration register */ -struct pmcmsptwi_clock { - u8 filter; /* Bits 15:12, default = 0x03 */ - u16 clock; /* Bits 9:0, default = 0x001f */ -}; - -struct pmcmsptwi_clockcfg { - struct pmcmsptwi_clock standard; /* The standard/fast clock config */ - struct pmcmsptwi_clock highspeed; /* The highspeed clock config */ -}; - -/* Corresponds to the main TWI configuration register */ -struct pmcmsptwi_cfg { - u8 arbf; /* Bits 15:12, default=0x03 */ - u8 nak; /* Bits 11:8, default=0x03 */ - u8 add10; /* Bit 7, default=0x00 */ - u8 mst_code; /* Bits 6:4, default=0x00 */ - u8 arb; /* Bit 1, default=0x01 */ - u8 highspeed; /* Bit 0, default=0x00 */ -}; - -/* A single pmctwi command to issue */ -struct pmcmsptwi_cmd { - u16 addr; /* The slave address (7 or 10 bits) */ - enum pmcmsptwi_cmd_type type; /* The command type */ - u8 write_len; /* Number of bytes in the write buffer */ - u8 read_len; /* Number of bytes in the read buffer */ - u8 *write_data; /* Buffer of characters to send */ - u8 *read_data; /* Buffer to fill with incoming data */ -}; - -/* The private data */ -struct pmcmsptwi_data { - void __iomem *iobase; /* iomapped base for IO */ - int irq; /* IRQ to use (0 disables) */ - struct completion wait; /* Completion for xfer */ - struct mutex lock; /* Used for threadsafeness */ - enum pmcmsptwi_xfer_result last_result; /* result of last xfer */ -}; - -/* The default settings */ -static const struct pmcmsptwi_clockcfg pmcmsptwi_defclockcfg = { - .standard = { - .filter = 0x3, - .clock = 0x1f, - }, - .highspeed = { - .filter = 0x3, - .clock = 0x1f, - }, -}; - -static const struct pmcmsptwi_cfg pmcmsptwi_defcfg = { - .arbf = 0x03, - .nak = 0x03, - .add10 = 0x00, - .mst_code = 0x00, - .arb = 0x01, - .highspeed = 0x00, -}; - -static struct pmcmsptwi_data pmcmsptwi_data; - -static struct i2c_adapter pmcmsptwi_adapter; - -/* inline helper functions */ -static inline u32 pmcmsptwi_clock_to_reg( - const struct pmcmsptwi_clock *clock) -{ - return ((clock->filter & 0xf) << 12) | (clock->clock & 0x03ff); -} - -static inline u32 pmcmsptwi_cfg_to_reg(const struct pmcmsptwi_cfg *cfg) -{ - return ((cfg->arbf & 0xf) << 12) | - ((cfg->nak & 0xf) << 8) | - ((cfg->add10 & 0x1) << 7) | - ((cfg->mst_code & 0x7) << 4) | - ((cfg->arb & 0x1) << 1) | - (cfg->highspeed & 0x1); -} - -static inline void pmcmsptwi_reg_to_cfg(u32 reg, struct pmcmsptwi_cfg *cfg) -{ - cfg->arbf = (reg >> 12) & 0xf; - cfg->nak = (reg >> 8) & 0xf; - cfg->add10 = (reg >> 7) & 0x1; - cfg->mst_code = (reg >> 4) & 0x7; - cfg->arb = (reg >> 1) & 0x1; - cfg->highspeed = reg & 0x1; -} - -/* - * Sets the current clock configuration - */ -static void pmcmsptwi_set_clock_config(const struct pmcmsptwi_clockcfg *cfg, - struct pmcmsptwi_data *data) -{ - mutex_lock(&data->lock); - pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->standard), - data->iobase + MSP_TWI_SF_CLK_REG_OFFSET); - pmcmsptwi_writel(pmcmsptwi_clock_to_reg(&cfg->highspeed), - data->iobase + MSP_TWI_HS_CLK_REG_OFFSET); - mutex_unlock(&data->lock); -} - -/* - * Gets the current TWI bus configuration - */ -static void pmcmsptwi_get_twi_config(struct pmcmsptwi_cfg *cfg, - struct pmcmsptwi_data *data) -{ - mutex_lock(&data->lock); - pmcmsptwi_reg_to_cfg(pmcmsptwi_readl( - data->iobase + MSP_TWI_CFG_REG_OFFSET), cfg); - mutex_unlock(&data->lock); -} - -/* - * Sets the current TWI bus configuration - */ -static void pmcmsptwi_set_twi_config(const struct pmcmsptwi_cfg *cfg, - struct pmcmsptwi_data *data) -{ - mutex_lock(&data->lock); - pmcmsptwi_writel(pmcmsptwi_cfg_to_reg(cfg), - data->iobase + MSP_TWI_CFG_REG_OFFSET); - mutex_unlock(&data->lock); -} - -/* - * Parses the 'int_sts' register and returns a well-defined error code - */ -static enum pmcmsptwi_xfer_result pmcmsptwi_get_result(u32 reg) -{ - if (reg & MSP_TWI_INT_STS_LOST_ARBITRATION) { - dev_dbg(&pmcmsptwi_adapter.dev, - "Result: Lost arbitration\n"); - return MSP_TWI_XFER_LOST_ARBITRATION; - } else if (reg & MSP_TWI_INT_STS_NO_RESPONSE) { - dev_dbg(&pmcmsptwi_adapter.dev, - "Result: No response\n"); - return MSP_TWI_XFER_NO_RESPONSE; - } else if (reg & MSP_TWI_INT_STS_DATA_COLLISION) { - dev_dbg(&pmcmsptwi_adapter.dev, - "Result: Data collision\n"); - return MSP_TWI_XFER_DATA_COLLISION; - } else if (reg & MSP_TWI_INT_STS_BUSY) { - dev_dbg(&pmcmsptwi_adapter.dev, - "Result: Bus busy\n"); - return MSP_TWI_XFER_BUSY; - } - - dev_dbg(&pmcmsptwi_adapter.dev, "Result: Operation succeeded\n"); - return MSP_TWI_XFER_OK; -} - -/* - * In interrupt mode, handle the interrupt. - * NOTE: Assumes data->lock is held. - */ -static irqreturn_t pmcmsptwi_interrupt(int irq, void *ptr) -{ - struct pmcmsptwi_data *data = ptr; - - u32 reason = pmcmsptwi_readl(data->iobase + - MSP_TWI_INT_STS_REG_OFFSET); - pmcmsptwi_writel(reason, data->iobase + MSP_TWI_INT_STS_REG_OFFSET); - - dev_dbg(&pmcmsptwi_adapter.dev, "Got interrupt 0x%08x\n", reason); - if (!(reason & MSP_TWI_INT_STS_DONE)) - return IRQ_NONE; - - data->last_result = pmcmsptwi_get_result(reason); - complete(&data->wait); - - return IRQ_HANDLED; -} - -/* - * Probe for and register the device and return 0 if there is one. - */ -static int pmcmsptwi_probe(struct platform_device *pldev) -{ - struct resource *res; - int rc = -ENODEV; - - /* get the static platform resources */ - res = platform_get_resource(pldev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pldev->dev, "IOMEM resource not found\n"); - goto ret_err; - } - - /* reserve the memory region */ - if (!request_mem_region(res->start, resource_size(res), - pldev->name)) { - dev_err(&pldev->dev, - "Unable to get memory/io address region %pap\n", - &res->start); - rc = -EBUSY; - goto ret_err; - } - - /* remap the memory */ - pmcmsptwi_data.iobase = ioremap(res->start, - resource_size(res)); - if (!pmcmsptwi_data.iobase) { - dev_err(&pldev->dev, - "Unable to ioremap address %pap\n", &res->start); - rc = -EIO; - goto ret_unreserve; - } - - /* request the irq */ - pmcmsptwi_data.irq = platform_get_irq(pldev, 0); - if (pmcmsptwi_data.irq) { - rc = request_irq(pmcmsptwi_data.irq, &pmcmsptwi_interrupt, - IRQF_SHARED, pldev->name, &pmcmsptwi_data); - if (rc == 0) { - /* - * Enable 'DONE' interrupt only. - * - * If you enable all interrupts, you will get one on - * error and another when the operation completes. - * This way you only have to handle one interrupt, - * but you can still check all result flags. - */ - pmcmsptwi_writel(MSP_TWI_INT_STS_DONE, - pmcmsptwi_data.iobase + - MSP_TWI_INT_MSK_REG_OFFSET); - } else { - dev_warn(&pldev->dev, - "Could not assign TWI IRQ handler " - "to irq %d (continuing with poll)\n", - pmcmsptwi_data.irq); - pmcmsptwi_data.irq = 0; - } - } - - init_completion(&pmcmsptwi_data.wait); - mutex_init(&pmcmsptwi_data.lock); - - pmcmsptwi_set_clock_config(&pmcmsptwi_defclockcfg, &pmcmsptwi_data); - pmcmsptwi_set_twi_config(&pmcmsptwi_defcfg, &pmcmsptwi_data); - - printk(KERN_INFO DRV_NAME ": Registering MSP71xx I2C adapter\n"); - - pmcmsptwi_adapter.dev.parent = &pldev->dev; - platform_set_drvdata(pldev, &pmcmsptwi_adapter); - i2c_set_adapdata(&pmcmsptwi_adapter, &pmcmsptwi_data); - - rc = i2c_add_adapter(&pmcmsptwi_adapter); - if (rc) - goto ret_unmap; - - return 0; - -ret_unmap: - if (pmcmsptwi_data.irq) { - pmcmsptwi_writel(0, - pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET); - free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data); - } - - iounmap(pmcmsptwi_data.iobase); - -ret_unreserve: - release_mem_region(res->start, resource_size(res)); - -ret_err: - return rc; -} - -/* - * Release the device and return 0 if there is one. - */ -static int pmcmsptwi_remove(struct platform_device *pldev) -{ - struct resource *res; - - i2c_del_adapter(&pmcmsptwi_adapter); - - if (pmcmsptwi_data.irq) { - pmcmsptwi_writel(0, - pmcmsptwi_data.iobase + MSP_TWI_INT_MSK_REG_OFFSET); - free_irq(pmcmsptwi_data.irq, &pmcmsptwi_data); - } - - iounmap(pmcmsptwi_data.iobase); - - res = platform_get_resource(pldev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - return 0; -} - -/* - * Polls the 'busy' register until the command is complete. - * NOTE: Assumes data->lock is held. - */ -static void pmcmsptwi_poll_complete(struct pmcmsptwi_data *data) -{ - int i; - - for (i = 0; i < MSP_MAX_POLL; i++) { - u32 val = pmcmsptwi_readl(data->iobase + - MSP_TWI_BUSY_REG_OFFSET); - if (val == 0) { - u32 reason = pmcmsptwi_readl(data->iobase + - MSP_TWI_INT_STS_REG_OFFSET); - pmcmsptwi_writel(reason, data->iobase + - MSP_TWI_INT_STS_REG_OFFSET); - data->last_result = pmcmsptwi_get_result(reason); - return; - } - udelay(MSP_POLL_DELAY); - } - - dev_dbg(&pmcmsptwi_adapter.dev, "Result: Poll timeout\n"); - data->last_result = MSP_TWI_XFER_TIMEOUT; -} - -/* - * Do the transfer (low level): - * May use interrupt-driven or polling, depending on if an IRQ is - * presently registered. - * NOTE: Assumes data->lock is held. - */ -static enum pmcmsptwi_xfer_result pmcmsptwi_do_xfer( - u32 reg, struct pmcmsptwi_data *data) -{ - dev_dbg(&pmcmsptwi_adapter.dev, "Writing cmd reg 0x%08x\n", reg); - pmcmsptwi_writel(reg, data->iobase + MSP_TWI_CMD_REG_OFFSET); - if (data->irq) { - unsigned long timeleft = wait_for_completion_timeout( - &data->wait, MSP_IRQ_TIMEOUT); - if (timeleft == 0) { - dev_dbg(&pmcmsptwi_adapter.dev, - "Result: IRQ timeout\n"); - complete(&data->wait); - data->last_result = MSP_TWI_XFER_TIMEOUT; - } - } else - pmcmsptwi_poll_complete(data); - - return data->last_result; -} - -/* - * Helper routine, converts 'pmctwi_cmd' struct to register format - */ -static inline u32 pmcmsptwi_cmd_to_reg(const struct pmcmsptwi_cmd *cmd) -{ - return ((cmd->type & 0x3) << 8) | - (((cmd->write_len - 1) & 0x7) << 4) | - ((cmd->read_len - 1) & 0x7); -} - -/* - * Do the transfer (high level) - */ -static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd( - struct pmcmsptwi_cmd *cmd, - struct pmcmsptwi_data *data) -{ - enum pmcmsptwi_xfer_result retval; - - mutex_lock(&data->lock); - dev_dbg(&pmcmsptwi_adapter.dev, - "Setting address to 0x%04x\n", cmd->addr); - pmcmsptwi_writel(cmd->addr, data->iobase + MSP_TWI_ADD_REG_OFFSET); - - if (cmd->type == MSP_TWI_CMD_WRITE || - cmd->type == MSP_TWI_CMD_WRITE_READ) { - u64 tmp = be64_to_cpup((__be64 *)cmd->write_data); - tmp >>= (MSP_MAX_BYTES_PER_RW - cmd->write_len) * 8; - dev_dbg(&pmcmsptwi_adapter.dev, "Writing 0x%016llx\n", tmp); - pmcmsptwi_writel(tmp & 0x00000000ffffffffLL, - data->iobase + MSP_TWI_DAT_0_REG_OFFSET); - if (cmd->write_len > 4) - pmcmsptwi_writel(tmp >> 32, - data->iobase + MSP_TWI_DAT_1_REG_OFFSET); - } - - retval = pmcmsptwi_do_xfer(pmcmsptwi_cmd_to_reg(cmd), data); - if (retval != MSP_TWI_XFER_OK) - goto xfer_err; - - if (cmd->type == MSP_TWI_CMD_READ || - cmd->type == MSP_TWI_CMD_WRITE_READ) { - int i; - u64 rmsk = ~(0xffffffffffffffffLL << (cmd->read_len * 8)); - u64 tmp = (u64)pmcmsptwi_readl(data->iobase + - MSP_TWI_DAT_0_REG_OFFSET); - if (cmd->read_len > 4) - tmp |= (u64)pmcmsptwi_readl(data->iobase + - MSP_TWI_DAT_1_REG_OFFSET) << 32; - tmp &= rmsk; - dev_dbg(&pmcmsptwi_adapter.dev, "Read 0x%016llx\n", tmp); - - for (i = 0; i < cmd->read_len; i++) - cmd->read_data[i] = tmp >> i; - } - -xfer_err: - mutex_unlock(&data->lock); - - return retval; -} - -/* -- Algorithm functions -- */ - -/* - * Sends an i2c command out on the adapter - */ -static int pmcmsptwi_master_xfer(struct i2c_adapter *adap, - struct i2c_msg *msg, int num) -{ - struct pmcmsptwi_data *data = i2c_get_adapdata(adap); - struct pmcmsptwi_cmd cmd; - struct pmcmsptwi_cfg oldcfg, newcfg; - int ret; - - if (num == 2) { - struct i2c_msg *nextmsg = msg + 1; - - cmd.type = MSP_TWI_CMD_WRITE_READ; - cmd.write_len = msg->len; - cmd.write_data = msg->buf; - cmd.read_len = nextmsg->len; - cmd.read_data = nextmsg->buf; - } else if (msg->flags & I2C_M_RD) { - cmd.type = MSP_TWI_CMD_READ; - cmd.read_len = msg->len; - cmd.read_data = msg->buf; - cmd.write_len = 0; - cmd.write_data = NULL; - } else { - cmd.type = MSP_TWI_CMD_WRITE; - cmd.read_len = 0; - cmd.read_data = NULL; - cmd.write_len = msg->len; - cmd.write_data = msg->buf; - } - - cmd.addr = msg->addr; - - if (msg->flags & I2C_M_TEN) { - pmcmsptwi_get_twi_config(&newcfg, data); - memcpy(&oldcfg, &newcfg, sizeof(oldcfg)); - - /* Set the special 10-bit address flag */ - newcfg.add10 = 1; - - pmcmsptwi_set_twi_config(&newcfg, data); - } - - /* Execute the command */ - ret = pmcmsptwi_xfer_cmd(&cmd, data); - - if (msg->flags & I2C_M_TEN) - pmcmsptwi_set_twi_config(&oldcfg, data); - - dev_dbg(&adap->dev, "I2C %s of %d bytes %s\n", - (msg->flags & I2C_M_RD) ? "read" : "write", msg->len, - (ret == MSP_TWI_XFER_OK) ? "succeeded" : "failed"); - - if (ret != MSP_TWI_XFER_OK) { - /* - * TODO: We could potentially loop and retry in the case - * of MSP_TWI_XFER_TIMEOUT. - */ - return -EIO; - } - - return num; -} - -static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | - I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL; -} - -static const struct i2c_adapter_quirks pmcmsptwi_i2c_quirks = { - .flags = I2C_AQ_COMB_WRITE_THEN_READ | I2C_AQ_NO_ZERO_LEN, - .max_write_len = MSP_MAX_BYTES_PER_RW, - .max_read_len = MSP_MAX_BYTES_PER_RW, - .max_comb_1st_msg_len = MSP_MAX_BYTES_PER_RW, - .max_comb_2nd_msg_len = MSP_MAX_BYTES_PER_RW, -}; - -/* -- Initialization -- */ - -static const struct i2c_algorithm pmcmsptwi_algo = { - .master_xfer = pmcmsptwi_master_xfer, - .functionality = pmcmsptwi_i2c_func, -}; - -static struct i2c_adapter pmcmsptwi_adapter = { - .owner = THIS_MODULE, - .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, - .algo = &pmcmsptwi_algo, - .quirks = &pmcmsptwi_i2c_quirks, - .name = DRV_NAME, -}; - -static struct platform_driver pmcmsptwi_driver = { - .probe = pmcmsptwi_probe, - .remove = pmcmsptwi_remove, - .driver = { - .name = DRV_NAME, - }, -}; - -module_platform_driver(pmcmsptwi_driver); - -MODULE_DESCRIPTION("PMC MSP TWI/SMBus/I2C driver"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:" DRV_NAME); 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 5241e6f414e9..f99a2cc721a8 100644 --- a/drivers/i2c/busses/i2c-powermac.c +++ b/drivers/i2c/busses/i2c-powermac.c @@ -15,7 +15,7 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/of_irq.h> -#include <asm/prom.h> + #include <asm/pmac_low_i2c.h> MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); @@ -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 f614cade432b..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 @@ -105,7 +104,7 @@ static int ce4100_i2c_probe(struct pci_dev *dev, int i; struct ce4100_devices *sds; - ret = pci_enable_device_mem(dev); + ret = pcim_enable_device(dev); if (ret) return ret; @@ -114,10 +113,8 @@ static int ce4100_i2c_probe(struct pci_dev *dev, return -EINVAL; } sds = kzalloc(sizeof(*sds), GFP_KERNEL); - if (!sds) { - ret = -ENOMEM; - goto err_mem; - } + if (!sds) + return -ENOMEM; for (i = 0; i < ARRAY_SIZE(sds->pdev); i++) { sds->pdev[i] = add_i2c_device(dev, i); @@ -133,14 +130,12 @@ static int ce4100_i2c_probe(struct pci_dev *dev, err_dev_add: kfree(sds); -err_mem: - pci_disable_device(dev); return ret; } 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 a636ea0eb50a..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); @@ -1403,13 +1459,12 @@ static int i2c_pxa_probe(struct platform_device *dev) spin_lock_init(&i2c->lock); init_waitqueue_head(&i2c->wait); - strlcpy(i2c->adap.name, "pxa_i2c-i2c", sizeof(i2c->adap.name)); + 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,8 +1596,8 @@ static void __exit i2c_adap_pxa_exit(void) platform_driver_unregister(&i2c_pxa_driver); } +MODULE_DESCRIPTION("Intel PXA2XX I2C adapter"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pxa2xx-i2c"); subsys_initcall(i2c_adap_pxa_init); module_exit(i2c_adap_pxa_exit); diff --git a/drivers/i2c/busses/i2c-qcom-cci.c b/drivers/i2c/busses/i2c-qcom-cci.c index c1de8eb66169..884055df1560 100644 --- a/drivers/i2c/busses/i2c-qcom-cci.c +++ b/drivers/i2c/busses/i2c-qcom-cci.c @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2012-2016, The Linux Foundation. All rights reserved. -// Copyright (c) 2017-20 Linaro Limited. +// Copyright (c) 2017-2022 Linaro Limited. #include <linux/clk.h> #include <linux/completion.h> @@ -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; @@ -541,6 +537,7 @@ static int cci_probe(struct platform_device *pdev) return -ENOENT; for_each_available_child_of_node(dev->of_node, child) { + struct cci_master *master; u32 idx; ret = of_property_read_u32(child, "reg", &idx); @@ -555,61 +552,44 @@ static int cci_probe(struct platform_device *pdev) continue; } - cci->master[idx].adap.quirks = &cci->data->quirks; - cci->master[idx].adap.algo = &cci_algo; - cci->master[idx].adap.dev.parent = dev; - cci->master[idx].adap.dev.of_node = child; - cci->master[idx].master = idx; - cci->master[idx].cci = cci; + master = &cci->master[idx]; + master->adap.quirks = &cci->data->quirks; + master->adap.algo = &cci_algo; + master->adap.dev.parent = dev; + master->adap.dev.of_node = of_node_get(child); + master->master = idx; + master->cci = cci; - i2c_set_adapdata(&cci->master[idx].adap, &cci->master[idx]); - snprintf(cci->master[idx].adap.name, - sizeof(cci->master[idx].adap.name), "Qualcomm-CCI"); + i2c_set_adapdata(&master->adap, master); + snprintf(master->adap.name, sizeof(master->adap.name), "Qualcomm-CCI"); - cci->master[idx].mode = I2C_MODE_STANDARD; + master->mode = I2C_MODE_STANDARD; ret = of_property_read_u32(child, "clock-frequency", &val); if (!ret) { if (val == I2C_MAX_FAST_MODE_FREQ) - cci->master[idx].mode = I2C_MODE_FAST; + master->mode = I2C_MODE_FAST; else if (val == I2C_MAX_FAST_MODE_PLUS_FREQ) - cci->master[idx].mode = I2C_MODE_FAST_PLUS; + master->mode = I2C_MODE_FAST_PLUS; } - init_completion(&cci->master[idx].irq_complete); + init_completion(&master->irq_complete); } /* 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; @@ -638,26 +618,33 @@ static int cci_probe(struct platform_device *pdev) if (ret < 0) goto error; + pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC); + pm_runtime_use_autosuspend(dev); + pm_runtime_set_active(dev); + pm_runtime_enable(dev); + for (i = 0; i < cci->data->num_masters; i++) { if (!cci->master[i].cci) continue; ret = i2c_add_adapter(&cci->master[i].adap); - if (ret < 0) + if (ret < 0) { + of_node_put(cci->master[i].adap.dev.of_node); goto error_i2c; + } } - pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC); - pm_runtime_use_autosuspend(dev); - pm_runtime_set_active(dev); - pm_runtime_enable(dev); - return 0; error_i2c: - for (; i >= 0; i--) { - if (cci->master[i].cci) + pm_runtime_disable(dev); + pm_runtime_dont_use_autosuspend(dev); + + for (--i ; i >= 0; i--) { + if (cci->master[i].cci) { i2c_del_adapter(&cci->master[i].adap); + of_node_put(cci->master[i].adap.dev.of_node); + } } error: disable_irq(cci->irq); @@ -667,22 +654,22 @@ 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; for (i = 0; i < cci->data->num_masters; i++) { - if (cci->master[i].cci) + if (cci->master[i].cci) { i2c_del_adapter(&cci->master[i].adap); + of_node_put(cci->master[i].adap.dev.of_node); + } cci_halt(cci, i); } 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 = { @@ -692,7 +679,39 @@ 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, + .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 + }, +}; + +static const struct cci_data cci_v1_5_data = { + .num_masters = 2, + .queue_size = { 64, 16 }, + .quirks = { + .max_write_len = 10, + .max_read_len = 12, + }, .params[I2C_MODE_STANDARD] = { .thigh = 78, .tlow = 114, @@ -726,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, @@ -765,11 +783,66 @@ 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,msm8916-cci", .data = &cci_v1_data}, + { .compatible = "qcom,msm8226-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}, {} }; MODULE_DEVICE_TABLE(of, cci_dt_match); diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 6d635a7c104c..3a04016db2c3 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -3,7 +3,9 @@ #include <linux/acpi.h> #include <linux/clk.h> +#include <linux/dmaengine.h> #include <linux/dma-mapping.h> +#include <linux/dma/qcom-gpi-dma.h> #include <linux/err.h> #include <linux/i2c.h> #include <linux/interrupt.h> @@ -12,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 @@ -48,6 +51,9 @@ #define LOW_COUNTER_SHFT 10 #define CYCLE_COUNTER_MSK GENMASK(9, 0) +#define I2C_PACK_TX BIT(0) +#define I2C_PACK_RX BIT(1) + enum geni_i2c_err_code { GP_IRQ0, NACK, @@ -65,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; @@ -83,12 +107,27 @@ struct geni_i2c_dev { int cur_wr; int cur_rd; spinlock_t lock; + struct clk *core_clk; u32 clk_freq_out; const struct geni_i2c_clk_fld *clk_fld; int suspended; void *dma_buf; size_t xfer_len; dma_addr_t dma_addr; + struct dma_chan *tx_c; + 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 { + bool has_core_clk; + char *icc_ddr; + bool no_dma_support; + unsigned int tx_fifo_depth; }; struct geni_i2c_err_log { @@ -129,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; } @@ -195,9 +248,18 @@ static void geni_i2c_err(struct geni_i2c_dev *gi2c, int err) dev_dbg(gi2c->se.dev, "len:%d, slv-addr:0x%x, RD/WR:%d\n", gi2c->cur->len, gi2c->cur->addr, gi2c->cur->flags); - if (err != NACK && err != GENI_ABORT_DONE) { + switch (err) { + case GENI_ABORT_DONE: + gi2c->abort_done = true; + break; + case NACK: + case GENI_TIMEOUT: + dev_dbg(gi2c->se.dev, "%s\n", gi2c_log[err].msg); + break; + default: dev_err(gi2c->se.dev, "%s\n", gi2c_log[err].msg); geni_i2c_err_misc(gi2c); + break; } } @@ -303,21 +365,21 @@ static irqreturn_t geni_i2c_irq(int irq, void *dev) static void geni_i2c_abort_xfer(struct geni_i2c_dev *gi2c) { - u32 val; unsigned long time_left = ABORT_TIMEOUT; unsigned long flags; spin_lock_irqsave(&gi2c->lock, flags); geni_i2c_err(gi2c, GENI_TIMEOUT); gi2c->cur = NULL; + gi2c->abort_done = false; geni_se_abort_m_cmd(&gi2c->se); spin_unlock_irqrestore(&gi2c->lock, flags); + do { time_left = wait_for_completion_timeout(&gi2c->done, time_left); - val = readl_relaxed(gi2c->se.base + SE_GENI_M_IRQ_STATUS); - } while (!(val & M_CMD_ABORT_EN) && time_left); + } while (!gi2c->abort_done && time_left); - if (!(val & M_CMD_ABORT_EN)) + if (!time_left) dev_err(gi2c->se.dev, "Timeout abort_m_cmd\n"); } @@ -456,12 +518,383 @@ static int geni_i2c_tx_one_msg(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, return gi2c->err; } +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); + gi2c->err = -EIO; + } else if (result->residue) { + 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); +} + +static void geni_i2c_gpi_unmap(struct geni_i2c_dev *gi2c, struct i2c_msg *msg, + void *tx_buf, dma_addr_t tx_addr, + void *rx_buf, dma_addr_t rx_addr) +{ + if (tx_buf) { + dma_unmap_single(gi2c->se.dev->parent, tx_addr, msg->len, DMA_TO_DEVICE); + i2c_put_dma_safe_msg_buf(tx_buf, msg, !gi2c->err); + } + + if (rx_buf) { + dma_unmap_single(gi2c->se.dev->parent, rx_addr, msg->len, DMA_FROM_DEVICE); + i2c_put_dma_safe_msg_buf(rx_buf, msg, !gi2c->err); + } +} + +/** + * 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) +{ + struct gpi_i2c_config *peripheral; + unsigned int flags; + void *dma_buf; + dma_addr_t addr; + enum dma_data_direction map_dirn; + 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(&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, + msgs[msg_idx].len, map_dirn); + if (dma_mapping_error(gi2c->se.dev->parent, addr)) { + 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 = msgs[msg_idx].len; + peripheral->op = op; + + ret = dmaengine_slave_config(dma_chan, config); + if (ret) { + dev_err(gi2c->se.dev, "dma config error: %d for op:%d\n", ret, op); + goto err_config; + } + + peripheral->set_config = 0; + peripheral->multi_msg = true; + + 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, 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; + goto err_config; + } + + desc->callback_result = i2c_gpi_cb_result; + desc->callback_param = gi2c; + + 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, + msgs[msg_idx].len, map_dirn); + i2c_put_dma_safe_msg_buf(dma_buf, &msgs[msg_idx], false); + +out: + gi2c->err = ret; + return ret; +} + +static int geni_i2c_gpi_xfer(struct geni_i2c_dev *gi2c, struct i2c_msg msgs[], int num) +{ + struct dma_slave_config config = {}; + struct gpi_i2c_config peripheral = {}; + 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; + config.peripheral_size = sizeof(peripheral); + + peripheral.pack_enable = I2C_PACK_TX | I2C_PACK_RX; + peripheral.cycle_count = itr->t_cycle_cnt; + peripheral.high_count = itr->t_high_cnt; + peripheral.low_count = itr->t_low_cnt; + peripheral.clk_div = itr->clk_div; + 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; + dev_dbg(gi2c->se.dev, "msg[%d].len:%d\n", i, gi2c->cur->len); + + peripheral.stretch = 0; + if (i < num - 1) + 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, &config, + &rx_addr, &rx_buf, I2C_READ, gi2c->rx_c); + if (ret) + goto err; + + dma_async_issue_pending(gi2c->rx_c); + } + + 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) { + ret = gi2c->err; + goto err; + } + + 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; + +err: + dev_err(gi2c->se.dev, "GPI transfer failed: %d\n", ret); + dmaengine_terminate_sync(gi2c->rx_c); + dmaengine_terminate_sync(gi2c->tx_c); + 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; +} + +static int geni_i2c_fifo_xfer(struct geni_i2c_dev *gi2c, + struct i2c_msg msgs[], int num) +{ + int i, ret = 0; + + for (i = 0; i < num; i++) { + u32 m_param = i < (num - 1) ? STOP_STRETCH : 0; + + m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK); + + gi2c->cur = &msgs[i]; + if (msgs[i].flags & I2C_M_RD) + ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param); + else + ret = geni_i2c_tx_one_msg(gi2c, &msgs[i], m_param); + + if (ret) + return ret; + } + + return num; +} + static int geni_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct geni_i2c_dev *gi2c = i2c_get_adapdata(adap); - int i, ret; + int ret; gi2c->err = 0; reinit_completion(&gi2c->done); @@ -475,24 +908,12 @@ static int geni_i2c_xfer(struct i2c_adapter *adap, } qcom_geni_i2c_conf(gi2c); - for (i = 0; i < num; i++) { - u32 m_param = i < (num - 1) ? STOP_STRETCH : 0; - - m_param |= ((msgs[i].addr << SLV_ADDR_SHFT) & SLV_ADDR_MSK); - gi2c->cur = &msgs[i]; - if (msgs[i].flags & I2C_M_RD) - ret = geni_i2c_rx_one_msg(gi2c, &msgs[i], m_param); - else - ret = geni_i2c_tx_one_msg(gi2c, &msgs[i], m_param); - - if (ret) - break; - } - if (ret == 0) - ret = num; + if (gi2c->gpi_mode) + ret = geni_i2c_gpi_xfer(gi2c, msgs, num); + 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; @@ -505,25 +926,63 @@ 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 +static void release_gpi_dma(struct geni_i2c_dev *gi2c) +{ + if (gi2c->rx_c) + dma_release_channel(gi2c->rx_c); + + if (gi2c->tx_c) + dma_release_channel(gi2c->tx_c); +} + +static int setup_gpi_dma(struct geni_i2c_dev *gi2c) +{ + int ret; + + geni_se_select_mode(&gi2c->se, GENI_GPI_DMA); + gi2c->tx_c = dma_request_chan(gi2c->se.dev, "tx"); + if (IS_ERR(gi2c->tx_c)) { + ret = dev_err_probe(gi2c->se.dev, PTR_ERR(gi2c->tx_c), + "Failed to get tx DMA ch\n"); + goto err_tx; + } + + gi2c->rx_c = dma_request_chan(gi2c->se.dev, "rx"); + if (IS_ERR(gi2c->rx_c)) { + ret = dev_err_probe(gi2c->se.dev, PTR_ERR(gi2c->rx_c), + "Failed to get rx DMA ch\n"); + goto err_rx; + } + + dev_dbg(gi2c->se.dev, "Grabbed GPI dma channels\n"); + return 0; + +err_rx: + dma_release_channel(gi2c->tx_c); +err_tx: + return ret; +} + static int geni_i2c_probe(struct platform_device *pdev) { struct geni_i2c_dev *gi2c; - struct resource *res; - u32 proto, tx_depth; + u32 proto, tx_depth, fifo_disable; int ret; struct device *dev = &pdev->dev; + const struct geni_i2c_desc *desc = NULL; gi2c = devm_kzalloc(dev, sizeof(*gi2c), GFP_KERNEL); if (!gi2c) @@ -531,11 +990,18 @@ 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); + desc = device_get_match_data(&pdev->dev); + + if (desc && desc->has_core_clk) { + gi2c->core_clk = devm_clk_get(dev, "core"); + if (IS_ERR(gi2c->core_clk)) + return PTR_ERR(gi2c->core_clk); + } + gi2c->se.clk = devm_clk_get(dev, "se"); if (IS_ERR(gi2c->se.clk) && !has_acpi_companion(dev)) return PTR_ERR(gi2c->se.clk); @@ -544,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)) @@ -555,31 +1021,28 @@ 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; - strlcpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name)); + strscpy(gi2c->adap.name, "Geni-I2C", sizeof(gi2c->adap.name)); - ret = geni_icc_get(&gi2c->se, "qup-memory"); + ret = geni_icc_get(&gi2c->se, desc ? desc->icc_ddr : "qup-memory"); if (ret) return ret; /* @@ -589,39 +1052,79 @@ static int geni_i2c_probe(struct platform_device *pdev) */ gi2c->se.icc_paths[GENI_TO_CORE].avg_bw = GENI_DEFAULT_BW; gi2c->se.icc_paths[CPU_TO_GENI].avg_bw = GENI_DEFAULT_BW; - gi2c->se.icc_paths[GENI_TO_DDR].avg_bw = Bps_to_icc(gi2c->clk_freq_out); + if (!desc || desc->icc_ddr) + gi2c->se.icc_paths[GENI_TO_DDR].avg_bw = Bps_to_icc(gi2c->clk_freq_out); ret = geni_icc_set_bw(&gi2c->se); if (ret) return ret; + ret = clk_prepare_enable(gi2c->core_clk); + if (ret) + return ret; + 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); - tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se); - if (proto != GENI_SE_I2C) { - dev_err(dev, "Invalid proto %d\n", proto); - geni_se_resources_off(&gi2c->se); - return -ENXIO; - } - gi2c->tx_wm = tx_depth - 1; - geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth); - geni_se_config_packing(&gi2c->se, BITS_PER_BYTE, PACKING_BYTES_PW, - true, true, true); + 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) + fifo_disable = false; + else + fifo_disable = readl_relaxed(gi2c->se.base + GENI_IF_DISABLE_RO) & FIFO_IF_DISABLE; + + if (fifo_disable) { + /* FIFO is disabled, so we can only use GPI DMA */ + gi2c->gpi_mode = true; + ret = setup_gpi_dma(gi2c); + if (ret) + goto err_resources; + + dev_dbg(dev, "Using GPI DMA mode for I2C\n"); + } else { + gi2c->gpi_mode = false; + tx_depth = geni_se_get_tx_fifo_depth(&gi2c->se); + + /* I2C Master Hub Serial Elements doesn't have the HW_PARAM_0 register */ + if (!tx_depth && desc) + tx_depth = desc->tx_fifo_depth; + + if (!tx_depth) { + ret = dev_err_probe(dev, -EINVAL, + "Invalid TX FIFO depth\n"); + goto err_resources; + } + + gi2c->tx_wm = tx_depth - 1; + geni_se_init(&gi2c->se, gi2c->tx_wm, tx_depth); + geni_se_config_packing(&gi2c->se, BITS_PER_BYTE, + PACKING_BYTES_PW, true, true, true); + + dev_dbg(dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth); + } + + 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); - return ret; + dev_err_probe(dev, ret, "Error turning off resources\n"); + goto err_dma; } ret = geni_icc_disable(&gi2c->se); if (ret) - return ret; - - dev_dbg(dev, "i2c fifo/se-dma mode. fifo depth:%d\n", tx_depth); + goto err_dma; gi2c->suspended = 1; pm_runtime_set_suspended(gi2c->se.dev); @@ -631,23 +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); - return ret; + 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) @@ -673,6 +1188,8 @@ static int __maybe_unused geni_i2c_runtime_suspend(struct device *dev) gi2c->suspended = 1; } + clk_disable_unprepare(gi2c->core_clk); + return geni_icc_disable(&gi2c->se); } @@ -685,13 +1202,25 @@ static int __maybe_unused geni_i2c_runtime_resume(struct device *dev) if (ret) return ret; + ret = clk_prepare_enable(gi2c->core_clk); + if (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) @@ -723,8 +1252,16 @@ static const struct dev_pm_ops geni_i2c_pm_ops = { NULL) }; +static const struct geni_i2c_desc i2c_master_hub = { + .has_core_clk = true, + .icc_ddr = NULL, + .no_dma_support = true, + .tx_fifo_depth = 16, +}; + static const struct of_device_id geni_i2c_dt_match[] = { { .compatible = "qcom,geni-i2c" }, + { .compatible = "qcom,geni-i2c-master-hub", .data = &i2c_master_hub }, {} }; MODULE_DEVICE_TABLE(of, geni_i2c_dt_match); diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c index 61dc20fd1191..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; @@ -778,7 +805,7 @@ static int qup_i2c_bam_schedule_desc(struct qup_i2c_dev *qup) ret = -EINVAL; /* abort TX descriptors */ - dmaengine_terminate_all(qup->btx.dma); + dmaengine_terminate_sync(qup->btx.dma); goto desc_err; } @@ -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; @@ -1290,7 +1318,7 @@ static void qup_i2c_write_rx_tags_v2(struct qup_i2c_dev *qup) * 1. Check if tx_tags_sent is false i.e. the start of QUP block so write the * tags to TX FIFO and set tx_tags_sent to true. * 2. Check if send_last_word is true. It will be set when last few data bytes - * (less than 4 bytes) are reamining to be written in FIFO because of no FIFO + * (less than 4 bytes) are remaining to be written in FIFO because of no FIFO * space. All this data bytes are available in tx_fifo_data so write this * in FIFO. * 3. Write the data to TX FIFO and check for cur_blk_len. If it is non zero @@ -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, @@ -1797,12 +1838,12 @@ nodma: goto fail; ret = devm_request_irq(qup->dev, qup->irq, qup_i2c_interrupt, - IRQF_TRIGGER_HIGH, "i2c_qup", qup); + IRQF_TRIGGER_HIGH | IRQF_NO_AUTOEN, + "i2c_qup", qup); if (ret) { dev_err(qup->dev, "Request %d IRQ failed\n", qup->irq); goto fail; } - disable_irq(qup->irq); hw_ver = readl(qup->base + QUP_HW_VERSION); dev_dbg(qup->dev, "Revision %x\n", hw_ver); @@ -1878,7 +1919,7 @@ nodma: qup->adap.dev.of_node = pdev->dev.of_node; qup->is_last = true; - strlcpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name)); + strscpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name)); pm_runtime_set_autosuspend_delay(qup->dev, MSEC_PER_SEC); pm_runtime_use_autosuspend(qup->dev); @@ -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 bff9913c37b8..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,54 +41,73 @@ #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) */ /* ICSCR */ -#define SDBS (1 << 3) /* slave data buffer select */ -#define SIE (1 << 2) /* slave interface enable */ -#define GCAE (1 << 1) /* general call address enable */ -#define FNA (1 << 0) /* forced non acknowledgment */ +#define SDBS BIT(3) /* slave data buffer select */ +#define SIE BIT(2) /* slave interface enable */ +#define GCAE BIT(1) /* general call address enable */ +#define FNA BIT(0) /* forced non acknowledgment */ /* ICMCR */ -#define MDBS (1 << 7) /* non-fifo mode switch */ -#define FSCL (1 << 6) /* override SCL pin */ -#define FSDA (1 << 5) /* override SDA pin */ -#define OBPC (1 << 4) /* override pins */ -#define MIE (1 << 3) /* master if enable */ -#define TSBE (1 << 2) -#define FSB (1 << 1) /* force stop bit */ -#define ESG (1 << 0) /* enable start bit gen */ +#define MDBS BIT(7) /* non-fifo mode switch */ +#define FSCL BIT(6) /* override SCL pin */ +#define FSDA BIT(5) /* override SDA pin */ +#define OBPC BIT(4) /* override pins */ +#define MIE BIT(3) /* master if enable */ +#define TSBE BIT(2) +#define FSB BIT(1) /* force stop bit */ +#define ESG BIT(0) /* enable start bit gen */ /* ICSSR (also for ICSIER) */ -#define GCAR (1 << 6) /* general call received */ -#define STM (1 << 5) /* slave transmit mode */ -#define SSR (1 << 4) /* stop received */ -#define SDE (1 << 3) /* slave data empty */ -#define SDT (1 << 2) /* slave data transmitted */ -#define SDR (1 << 1) /* slave data received */ -#define SAR (1 << 0) /* slave addr received */ +#define GCAR BIT(6) /* general call received */ +#define STM BIT(5) /* slave transmit mode */ +#define SSR BIT(4) /* stop received */ +#define SDE BIT(3) /* slave data empty */ +#define SDT BIT(2) /* slave data transmitted */ +#define SDR BIT(1) /* slave data received */ +#define SAR BIT(0) /* slave addr received */ /* ICMSR (also for ICMIE) */ -#define MNR (1 << 6) /* nack received */ -#define MAL (1 << 5) /* arbitration lost */ -#define MST (1 << 4) /* sent a stop */ -#define MDE (1 << 3) -#define MDT (1 << 2) -#define MDR (1 << 1) -#define MAT (1 << 0) /* slave addr xfer done */ +#define MNR BIT(6) /* nack received */ +#define MAL BIT(5) /* arbitration lost */ +#define MST BIT(4) /* sent a stop */ +#define MDE BIT(3) +#define MDT BIT(2) +#define MDR BIT(1) +#define MAT BIT(0) /* slave addr xfer done */ /* ICDMAER */ -#define RSDMAE (1 << 3) /* DMA Slave Received Enable */ -#define TSDMAE (1 << 2) /* DMA Slave Transmitted Enable */ -#define RMDMAE (1 << 1) /* DMA Master Received Enable */ -#define TMDMAE (1 << 0) /* DMA Master Transmitted Enable */ +#define RSDMAE BIT(3) /* DMA Slave Received Enable */ +#define TSDMAE BIT(2) /* DMA Slave Transmitted Enable */ +#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) @@ -97,25 +116,27 @@ #define RCAR_IRQ_RECV (MNR | MAL | MST | MAT | MDR) #define RCAR_IRQ_STOP (MST) -#define RCAR_IRQ_ACK_SEND (~(MAT | MDE) & 0x7F) -#define RCAR_IRQ_ACK_RECV (~(MAT | MDR) & 0x7F) - -#define ID_LAST_MSG (1 << 0) -#define ID_FIRST_MSG (1 << 1) -#define ID_DONE (1 << 2) -#define ID_ARBLOST (1 << 3) -#define ID_NACK (1 << 4) +#define ID_LAST_MSG BIT(0) +#define ID_REP_AFTER_RD BIT(1) +#define ID_DONE BIT(2) +#define ID_ARBLOST BIT(3) +#define ID_NACK BIT(4) +#define ID_EPROTO BIT(5) /* persistent flags */ -#define ID_P_HOST_NOTIFY BIT(28) -#define ID_P_REP_AFTER_RD BIT(29) +#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 { @@ -130,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; @@ -141,10 +165,10 @@ struct rcar_i2c_priv { enum dma_data_direction dma_direction; struct reset_control *rstc; - bool atomic_xfer; int irq; struct i2c_client *host_notify_client; + u8 slave_flags; }; #define rcar_i2c_priv_to_dev(p) ((p)->adap.dev.parent) @@ -160,13 +184,17 @@ static u32 rcar_i2c_read(struct rcar_i2c_priv *priv, int reg) return readl(priv->io + reg); } +static void rcar_i2c_clear_irq(struct rcar_i2c_priv *priv, u32 val) +{ + writel(~val & 0x7f, priv->io + ICMSR); +} + 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) { @@ -178,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) { @@ -190,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, @@ -207,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 */ @@ -214,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->flags & ID_P_FMPLUS) + icccr2 |= FMPE; - if (priv->devtype == I2C_RCAR_GEN3) + 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) @@ -239,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 = { @@ -251,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 @@ -282,101 +319,145 @@ 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); -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 (scgd > 0x3f) + goto err_no_val; - /* keep icccr value */ - priv->icccr = scgd << cdf_width | cdf; + 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); + + if (x == 0 || x * RCAR_SCLD_RATIO > 0xffff) + goto err_no_val; + + 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; } +/* + * We don't have a test case but the HW engineers say that the write order of + * ICMSR and ICMCR depends on whether we issue START or REP_START. So, ICMSR + * handling is outside of this function. First messages clear ICMSR before this + * function, interrupt handlers clear the relevant bits after this function. + */ static void rcar_i2c_prepare_msg(struct rcar_i2c_priv *priv) { int read = !!rcar_i2c_is_recv(priv); + bool rep_start = !(priv->flags & ID_REP_AFTER_RD); priv->pos = 0; + priv->flags &= ID_P_MASK; + if (priv->msgs_left == 1) priv->flags |= ID_LAST_MSG; rcar_i2c_write(priv, ICMAR, i2c_8bit_addr_from_msg(priv->msg)); - /* - * We don't have a test case but the HW engineers say that the write order - * of ICMSR and ICMCR depends on whether we issue START or REP_START. Since - * it didn't cause a drawback for me, let's rather be safe than sorry. - */ - if (priv->flags & ID_FIRST_MSG) { - rcar_i2c_write(priv, ICMSR, 0); + if (priv->flags & ID_P_NOT_ATOMIC) + rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND); + + if (rep_start) rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); - } else { - if (priv->flags & ID_P_REP_AFTER_RD) - priv->flags &= ~ID_P_REP_AFTER_RD; - else - rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); - rcar_i2c_write(priv, ICMSR, 0); - } +} - if (!priv->atomic_xfer) - rcar_i2c_write(priv, ICMIER, read ? RCAR_IRQ_RECV : RCAR_IRQ_SEND); +static void rcar_i2c_first_msg(struct rcar_i2c_priv *priv, + struct i2c_msg *msgs, int num) +{ + priv->msg = msgs; + priv->msgs_left = num; + rcar_i2c_write(priv, ICMSR, 0); /* must be before preparing msg */ + rcar_i2c_prepare_msg(priv); } static void rcar_i2c_next_msg(struct rcar_i2c_priv *priv) { priv->msg++; priv->msgs_left--; - priv->flags &= ID_P_MASK; rcar_i2c_prepare_msg(priv); + /* ICMSR handling must come afterwards in the irq handler */ } -static void rcar_i2c_dma_unmap(struct rcar_i2c_priv *priv) +static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv, bool terminate) { struct dma_chan *chan = priv->dma_direction == DMA_FROM_DEVICE ? priv->dma_rx : priv->dma_tx; + /* only allowed from thread context! */ + if (terminate) + dmaengine_terminate_sync(chan); + 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; @@ -386,25 +467,13 @@ static void rcar_i2c_dma_unmap(struct rcar_i2c_priv *priv) rcar_i2c_write(priv, ICDMAER, 0); } -static void rcar_i2c_cleanup_dma(struct rcar_i2c_priv *priv) -{ - if (priv->dma_direction == DMA_NONE) - return; - else if (priv->dma_direction == DMA_FROM_DEVICE) - dmaengine_terminate_all(priv->dma_rx); - else if (priv->dma_direction == DMA_TO_DEVICE) - dmaengine_terminate_all(priv->dma_tx); - - rcar_i2c_dma_unmap(priv); -} - static void rcar_i2c_dma_callback(void *data) { struct rcar_i2c_priv *priv = data; priv->pos += sg_dma_len(&priv->sg); - rcar_i2c_dma_unmap(priv); + rcar_i2c_cleanup_dma(priv, false); } static bool rcar_i2c_dma(struct rcar_i2c_priv *priv) @@ -421,7 +490,7 @@ static bool rcar_i2c_dma(struct rcar_i2c_priv *priv) int len; /* Do various checks to see if DMA is feasible at all */ - if (priv->atomic_xfer || IS_ERR(chan) || msg->len < RCAR_MIN_DMA_LEN || + if (!(priv->flags & ID_P_NOT_ATOMIC) || IS_ERR(chan) || msg->len < RCAR_MIN_DMA_LEN || !(msg->flags & I2C_M_DMA_SAFE) || (read && priv->flags & ID_P_NO_RXDMA)) return false; @@ -456,7 +525,7 @@ static bool rcar_i2c_dma(struct rcar_i2c_priv *priv) DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!txdesc) { dev_dbg(dev, "dma prep slave sg failed, using PIO\n"); - rcar_i2c_cleanup_dma(priv); + rcar_i2c_cleanup_dma(priv, false); return false; } @@ -466,7 +535,7 @@ static bool rcar_i2c_dma(struct rcar_i2c_priv *priv) cookie = dmaengine_submit(txdesc); if (dma_submit_error(cookie)) { dev_dbg(dev, "submitting dma failed, using PIO\n"); - rcar_i2c_cleanup_dma(priv); + rcar_i2c_cleanup_dma(priv, false); return false; } @@ -483,11 +552,15 @@ static bool rcar_i2c_dma(struct rcar_i2c_priv *priv) static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) { struct i2c_msg *msg = priv->msg; + 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) + irqs_to_clear |= MAT; + /* Check if DMA can be enabled and take over */ if (priv->pos == 1 && rcar_i2c_dma(priv)) return; @@ -511,31 +584,32 @@ static void rcar_i2c_irq_send(struct rcar_i2c_priv *priv, u32 msr) * [ICRXTX] -> [SHIFT] -> [I2C bus] */ - if (priv->flags & ID_LAST_MSG) { + if (priv->flags & ID_LAST_MSG) /* * If current msg is the _LAST_ msg, * prepare stop condition here. * ID_DONE will be set on STOP irq. */ rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); - } else { + else rcar_i2c_next_msg(priv); - return; - } } - rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_SEND); + rcar_i2c_clear_irq(priv, irqs_to_clear); } static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) { struct i2c_msg *msg = priv->msg; + bool recv_len_init = priv->pos == 0 && msg->flags & I2C_M_RECV_LEN; + u32 irqs_to_clear = MDR; /* FIXME: sometimes, unknown interrupt happened. Do nothing */ if (!(msr & MDR)) return; if (msr & MAT) { + irqs_to_clear |= MAT; /* * Address transfer phase finished, but no data at this point. * Try to use DMA to receive data. @@ -543,30 +617,48 @@ static void rcar_i2c_irq_recv(struct rcar_i2c_priv *priv, u32 msr) rcar_i2c_dma(priv); } else if (priv->pos < msg->len) { /* get received data */ - msg->buf[priv->pos] = rcar_i2c_read(priv, ICRXTX); + u8 data = rcar_i2c_read(priv, ICRXTX); + + msg->buf[priv->pos] = data; + if (recv_len_init) { + if (data == 0 || data > I2C_SMBUS_BLOCK_MAX) { + priv->flags |= ID_DONE | ID_EPROTO; + return; + } + msg->len += msg->buf[0]; + /* Enough data for DMA? */ + if (rcar_i2c_dma(priv)) + return; + /* new length after RECV_LEN now properly initialized */ + recv_len_init = false; + } priv->pos++; } - /* If next received data is the _LAST_, go to new phase. */ - if (priv->pos + 1 == msg->len) { + /* + * If next received data is the _LAST_ and we are not waiting for a new + * length because of RECV_LEN, then go to a new phase. + */ + if (priv->pos + 1 == msg->len && !recv_len_init) { if (priv->flags & ID_LAST_MSG) { rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_STOP); } else { rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_START); - priv->flags |= ID_P_REP_AFTER_RD; + priv->flags |= ID_REP_AFTER_RD; } } if (priv->pos == msg->len && !(priv->flags & ID_LAST_MSG)) rcar_i2c_next_msg(priv); - else - rcar_i2c_write(priv, ICMSR, RCAR_IRQ_ACK_RECV); + + rcar_i2c_clear_irq(priv, irqs_to_clear); } 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); @@ -582,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); } @@ -595,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); } @@ -649,7 +747,7 @@ static irqreturn_t rcar_i2c_irq(int irq, struct rcar_i2c_priv *priv, u32 msr) /* Nack */ if (msr & MNR) { /* HW automatically sends STOP after received NACK */ - if (!priv->atomic_xfer) + if (priv->flags & ID_P_NOT_ATOMIC) rcar_i2c_write(priv, ICMIER, RCAR_IRQ_STOP); priv->flags |= ID_NACK; goto out; @@ -671,7 +769,7 @@ out: if (priv->flags & ID_DONE) { rcar_i2c_write(priv, ICMIER, 0); rcar_i2c_write(priv, ICMSR, 0); - if (!priv->atomic_xfer) + if (priv->flags & ID_P_NOT_ATOMIC) wake_up(&priv->wait); } @@ -684,12 +782,12 @@ static irqreturn_t rcar_i2c_gen2_irq(int irq, void *ptr) u32 msr; /* Clear START or STOP immediately, except for REPSTART after read */ - if (likely(!(priv->flags & ID_P_REP_AFTER_RD))) + if (likely(!(priv->flags & ID_REP_AFTER_RD))) rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA); /* Only handle interrupts that are currently enabled */ msr = rcar_i2c_read(priv, ICMSR); - if (!priv->atomic_xfer) + if (priv->flags & ID_P_NOT_ATOMIC) msr &= rcar_i2c_read(priv, ICMIER); return rcar_i2c_irq(irq, priv, msr); @@ -702,14 +800,14 @@ static irqreturn_t rcar_i2c_gen3_irq(int irq, void *ptr) /* Only handle interrupts that are currently enabled */ msr = rcar_i2c_read(priv, ICMSR); - if (!priv->atomic_xfer) + if (priv->flags & ID_P_NOT_ATOMIC) msr &= rcar_i2c_read(priv, ICMIER); /* * Clear START or STOP immediately, except for REPSTART after read or * if a spurious interrupt was detected. */ - if (likely(!(priv->flags & ID_P_REP_AFTER_RD) && msr)) + if (likely(!(priv->flags & ID_REP_AFTER_RD) && msr)) rcar_i2c_write(priv, ICMCR, RCAR_BUS_PHASE_DATA); return rcar_i2c_irq(irq, priv, msr); @@ -794,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; @@ -811,7 +913,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, int i, ret; long time_left; - priv->atomic_xfer = false; + priv->flags |= ID_P_NOT_ATOMIC; pm_runtime_get_sync(dev); @@ -820,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); @@ -835,18 +935,14 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, for (i = 0; i < num; i++) rcar_i2c_request_dma(priv, msgs + i); - /* init first message */ - priv->msg = msgs; - priv->msgs_left = num; - priv->flags = (priv->flags & ID_P_MASK) | ID_FIRST_MSG; - rcar_i2c_prepare_msg(priv); + rcar_i2c_first_msg(priv, msgs, num); time_left = wait_event_timeout(priv->wait, priv->flags & ID_DONE, num * adap->timeout); /* cleanup DMA if it couldn't complete properly due to an error */ if (priv->dma_direction != DMA_NONE) - rcar_i2c_cleanup_dma(priv); + rcar_i2c_cleanup_dma(priv, true); if (!time_left) { rcar_i2c_init(priv); @@ -855,6 +951,8 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap, ret = -ENXIO; } else if (priv->flags & ID_ARBLOST) { ret = -EAGAIN; + } else if (priv->flags & ID_EPROTO) { + ret = -EPROTO; } else { ret = num - priv->msgs_left; /* The number of transfer */ } @@ -877,7 +975,7 @@ static int rcar_i2c_master_xfer_atomic(struct i2c_adapter *adap, bool time_left; int ret; - priv->atomic_xfer = true; + priv->flags &= ~ID_P_NOT_ATOMIC; pm_runtime_get_sync(dev); @@ -887,12 +985,7 @@ static int rcar_i2c_master_xfer_atomic(struct i2c_adapter *adap, goto out; rcar_i2c_init(priv); - - /* init first message */ - priv->msg = msgs; - priv->msgs_left = num; - priv->flags = (priv->flags & ID_P_MASK) | ID_FIRST_MSG; - rcar_i2c_prepare_msg(priv); + rcar_i2c_first_msg(priv, msgs, num); j = jiffies + num * adap->timeout; do { @@ -917,6 +1010,8 @@ static int rcar_i2c_master_xfer_atomic(struct i2c_adapter *adap, ret = -ENXIO; } else if (priv->flags & ID_ARBLOST) { ret = -EAGAIN; + } else if (priv->flags & ID_EPROTO) { + ret = -EPROTO; } else { ret = num - priv->msgs_left; /* The number of transfer */ } @@ -959,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; @@ -983,7 +1075,7 @@ static u32 rcar_i2c_func(struct i2c_adapter *adap) * I2C_M_IGNORE_NAK (automatically sends STOP after NAK) */ u32 func = I2C_FUNC_I2C | I2C_FUNC_SLAVE | - (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK); + (I2C_FUNC_SMBUS_EMUL_ALL & ~I2C_FUNC_SMBUS_QUICK); if (priv->flags & ID_P_HOST_NOTIFY) func |= I2C_FUNC_SMBUS_HOST_NOTIFY; @@ -992,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 = { @@ -1013,9 +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_GEN4 }, {}, }; MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids); @@ -1059,7 +1154,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) adap->bus_recovery_info = &rcar_i2c_bri; adap->quirks = &rcar_i2c_quirks; i2c_set_adapdata(adap, priv); - strlcpy(adap->name, pdev->name, sizeof(adap->name)); + strscpy(adap->name, pdev->name, sizeof(adap->name)); /* Init DMA */ sg_init_table(&priv->sg, 1); @@ -1070,24 +1165,14 @@ static int rcar_i2c_probe(struct platform_device *pdev) pm_runtime_enable(dev); pm_runtime_get_sync(dev); ret = rcar_i2c_clock_calculate(priv); - if (ret < 0) - goto out_pm_put; - - 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 (ret < 0) { + pm_runtime_put(dev); + goto out_pm_disable; } - 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")) @@ -1098,21 +1183,40 @@ 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_disable; + goto out_pm_put; priv->irq = ret; ret = devm_request_irq(dev, priv->irq, irqhandler, irqflags, dev_name(dev), priv); if (ret < 0) { dev_err(dev, "cannot get irq %d\n", priv->irq); - goto out_pm_disable; + goto out_pm_put; } platform_set_drvdata(pdev, priv); ret = i2c_add_numbered_adapter(adap); if (ret < 0) - goto out_pm_disable; + goto out_pm_put; if (priv->flags & ID_P_HOST_NOTIFY) { priv->host_notify_client = i2c_new_slave_host_notify_device(adap); @@ -1129,13 +1233,14 @@ static int rcar_i2c_probe(struct platform_device *pdev) out_del_device: i2c_del_adapter(&priv->adap); out_pm_put: - pm_runtime_put(dev); + if (priv->flags & ID_P_PM_BLOCKED) + pm_runtime_put(dev); out_pm_disable: pm_runtime_disable(dev); 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; @@ -1147,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); @@ -1169,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 78b84445ee6a..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,63 +34,78 @@ * 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_type { - RIIC_RZ_A, - RIIC_RZ_G2L, +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 { @@ -100,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 { @@ -111,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; @@ -141,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) @@ -156,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; } @@ -197,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; } @@ -206,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) { @@ -217,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); @@ -236,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; } @@ -244,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); @@ -254,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--; @@ -266,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); @@ -319,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. @@ -330,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; @@ -356,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) @@ -367,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); - writeb(0, riic->base + RIIC_ICSER); - writeb(ICMR3_ACKWP | ICMR3_RDRFS, riic->base + RIIC_ICMR3); + riic_writeb(riic, 0, RIIC_ICSER); + riic_writeb(riic, ICMR3_ACKWP | ICMR3_RDRFS, 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 struct riic_irq_desc riic_irqs[] = { +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 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" }, @@ -396,70 +509,75 @@ static struct riic_irq_desc riic_irqs[] = { { .res_num = 5, .isr = riic_tend_isr, .name = "riic-nack" }, }; +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 resource *res; - struct i2c_timings i2c_t; - struct reset_control *rstc; int i, ret; - enum riic_type type; - riic = devm_kzalloc(&pdev->dev, sizeof(*riic), GFP_KERNEL); + riic = devm_kzalloc(dev, sizeof(*riic), GFP_KERNEL); if (!riic) return -ENOMEM; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - riic->base = devm_ioremap_resource(&pdev->dev, res); + riic->base = devm_platform_ioremap_resource(pdev, 0); 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"); - type = (enum riic_type)of_device_get_match_data(&pdev->dev); - if (type == RIIC_RZ_G2L) { - rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); - if (IS_ERR(rstc)) { - dev_err(&pdev->dev, "Error: missing reset ctrl\n"); - return PTR_ERR(rstc); - } + 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"); - reset_control_deassert(rstc); - } + riic->info = of_device_get_match_data(dev); - for (i = 0; i < ARRAY_SIZE(riic_irqs); i++) { - res = platform_get_resource(pdev, IORESOURCE_IRQ, riic_irqs[i].res_num); - if (!res) - return -ENODEV; + for (i = 0; i < riic->info->num_irqs; i++) { + const struct riic_irq_desc *irq_desc; + int irq; - ret = devm_request_irq(&pdev->dev, res->start, 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; - } + irq_desc = &riic->info->irqs[i]; + irq = platform_get_irq(pdev, irq_desc->res_num); + if (irq < 0) + return irq; + + 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); - strlcpy(adap->name, "Renesas RIIC adapter", sizeof(adap->name)); + 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; @@ -469,32 +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-r9a07g044", .data = (void *)RIIC_RZ_G2L }, - { .compatible = "renesas,riic-rz", .data = (void *)RIIC_RZ_A }, - { /* 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 = { @@ -503,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 819ab4ee517e..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 */ @@ -80,7 +80,7 @@ enum { #define DEFAULT_SCL_RATE (100 * 1000) /* Hz */ /** - * struct i2c_spec_values: + * struct i2c_spec_values - I2C specification values for various modes * @min_hold_start_ns: min hold time (repeated) START condition * @min_low_ns: min LOW period of the SCL clock * @min_high_ns: min HIGH period of the SCL cloc @@ -136,7 +136,7 @@ static const struct i2c_spec_values fast_mode_plus_spec = { }; /** - * struct rk3x_i2c_calced_timings: + * struct rk3x_i2c_calced_timings - calculated V1 timings * @div_low: Divider output for low * @div_high: Divider output for high * @tuning: Used to adjust setup/hold data time, @@ -159,7 +159,7 @@ enum rk3x_i2c_state { }; /** - * struct rk3x_i2c_soc_data: + * struct rk3x_i2c_soc_data - SOC-specific data * @grf_offset: offset inside the grf regmap for setting the i2c type * @calc_timings: Callback function for i2c timing information calculated */ @@ -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; @@ -239,7 +241,8 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c) } /** - * Generate a START condition, which triggers a REG_INT_START interrupt. + * rk3x_i2c_start - Generate a START condition, which triggers a REG_INT_START interrupt. + * @i2c: target controller data */ static void rk3x_i2c_start(struct rk3x_i2c *i2c) { @@ -258,8 +261,8 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c) } /** - * Generate a STOP condition, which triggers a REG_INT_STOP interrupt. - * + * rk3x_i2c_stop - Generate a STOP condition, which triggers a REG_INT_STOP interrupt. + * @i2c: target controller data * @error: Error code to return in rk3x_i2c_xfer */ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) @@ -298,7 +301,8 @@ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error) } /** - * Setup a read according to i2c->msg + * rk3x_i2c_prepare_read - Setup a read according to i2c->msg + * @i2c: target controller data */ static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c) { @@ -329,7 +333,8 @@ static void rk3x_i2c_prepare_read(struct rk3x_i2c *i2c) } /** - * Fill the transmit buffer with data from i2c->msg + * rk3x_i2c_fill_transmit_buf - Fill the transmit buffer with data from i2c->msg + * @i2c: target controller data */ static void rk3x_i2c_fill_transmit_buf(struct rk3x_i2c *i2c) { @@ -423,8 +428,8 @@ static void rk3x_i2c_handle_read(struct rk3x_i2c *i2c, unsigned int ipd) if (!(ipd & REG_INT_MBRF)) return; - /* ack interrupt */ - i2c_writel(i2c, REG_INT_MBRF, REG_IPD); + /* ack interrupt (read also produces a spurious START flag, clear it too) */ + i2c_writel(i2c, REG_INT_MBRF | REG_INT_START, REG_IPD); /* Can only handle a maximum of 32 bytes at a time */ if (len > 32) @@ -532,11 +537,10 @@ out: } /** - * Get timing values of I2C specification - * + * rk3x_i2c_get_spec - Get timing values of I2C specification * @speed: Desired SCL frequency * - * Returns: Matched i2c spec values. + * Return: Matched i2c_spec_values. */ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed) { @@ -549,13 +553,12 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed) } /** - * Calculate divider values for desired SCL frequency - * + * rk3x_i2c_v0_calc_timings - Calculate divider values for desired SCL frequency * @clk_rate: I2C input clock rate * @t: Known I2C timing information * @t_calc: Caculated rk3x private timings that would be written into regs * - * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case + * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case * a best-effort divider value is returned in divs. If the target rate is * too high, we silently use the highest possible rate. */ @@ -710,13 +713,12 @@ static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate, } /** - * Calculate timing values for desired SCL frequency - * + * rk3x_i2c_v1_calc_timings - Calculate timing values for desired SCL frequency * @clk_rate: I2C input clock rate * @t: Known I2C timing information * @t_calc: Caculated rk3x private timings that would be written into regs * - * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case + * Return: %0 on success, -%EINVAL if the goal SCL rate is too slow. In that case * a best-effort divider value is returned in divs. If the target rate is * too high, we silently use the highest possible rate. * The following formulas are v1's method to calculate timings. @@ -960,14 +962,14 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long } /** - * Setup I2C registers for an I2C operation specified by msgs, num. - * - * Must be called with i2c->lock held. - * + * rk3x_i2c_setup - Setup I2C registers for an I2C operation specified by msgs, num. + * @i2c: target controller data * @msgs: I2C msgs to process * @num: Number of msgs * - * returns: Number of I2C msgs processed or negative in case of error + * Must be called with i2c->lock held. + * + * Return: Number of I2C msgs processed or negative in case of error */ static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num) { @@ -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 = { @@ -1165,6 +1170,11 @@ static const struct rk3x_i2c_soc_data rv1108_soc_data = { .calc_timings = rk3x_i2c_v1_calc_timings, }; +static const struct rk3x_i2c_soc_data rv1126_soc_data = { + .grf_offset = 0x118, + .calc_timings = rk3x_i2c_v1_calc_timings, +}; + static const struct rk3x_i2c_soc_data rk3066_soc_data = { .grf_offset = 0x154, .calc_timings = rk3x_i2c_v0_calc_timings, @@ -1196,6 +1206,10 @@ static const struct of_device_id rk3x_i2c_match[] = { .data = &rv1108_soc_data }, { + .compatible = "rockchip,rv1126-i2c", + .data = &rv1126_soc_data + }, + { .compatible = "rockchip,rk3066-i2c", .data = &rk3066_soc_data }, @@ -1240,7 +1254,7 @@ static int rk3x_i2c_probe(struct platform_device *pdev) /* use common interface to get I2C timing properties */ i2c_parse_fw_timings(&pdev->dev, &i2c->t, true); - strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name)); + strscpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name)); i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &rk3x_i2c_algorithm; i2c->adap.retries = 3; @@ -1279,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) { @@ -1301,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) { @@ -1338,8 +1358,15 @@ static int rk3x_i2c_probe(struct platform_device *pdev) goto err_pclk; } + ret = clk_enable(i2c->clk); + if (ret < 0) { + dev_err(&pdev->dev, "Can't enable bus clk: %d\n", ret); + goto err_clk_notifier; + } + clk_rate = clk_get_rate(i2c->clk); rk3x_i2c_adapt_div(i2c, clk_rate); + clk_disable(i2c->clk); ret = i2c_add_adapter(&i2c->adap); if (ret < 0) @@ -1356,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); @@ -1365,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 new file mode 100644 index 000000000000..238714850673 --- /dev/null +++ b/drivers/i2c/busses/i2c-rzv2m.c @@ -0,0 +1,539 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for the Renesas RZ/V2M I2C unit + * + * Copyright (C) 2016-2022 Renesas Electronics Corporation + */ + +#include <linux/bits.h> +#include <linux/clk.h> +#include <linux/device.h> +#include <linux/err.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/i2c.h> +#include <linux/jiffies.h> +#include <linux/kernel.h> +#include <linux/math64.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/platform_device.h> +#include <linux/pm_runtime.h> +#include <linux/reset.h> + +/* Register offsets */ +#define IICB0DAT 0x00 /* Data Register */ +#define IICB0CTL0 0x08 /* Control Register 0 */ +#define IICB0TRG 0x0C /* Trigger Register */ +#define IICB0STR0 0x10 /* Status Register 0 */ +#define IICB0CTL1 0x20 /* Control Register 1 */ +#define IICB0WL 0x24 /* Low Level Width Setting Reg */ +#define IICB0WH 0x28 /* How Level Width Setting Reg */ + +/* IICB0CTL0 */ +#define IICB0IICE BIT(7) /* I2C Enable */ +#define IICB0SLWT BIT(1) /* Interrupt Request Timing */ +#define IICB0SLAC BIT(0) /* Acknowledge */ + +/* IICB0TRG */ +#define IICB0WRET BIT(2) /* Quit Wait Trigger */ +#define IICB0STT BIT(1) /* Create Start Condition Trigger */ +#define IICB0SPT BIT(0) /* Create Stop Condition Trigger */ + +/* IICB0STR0 */ +#define IICB0SSAC BIT(8) /* Ack Flag */ +#define IICB0SSBS BIT(6) /* Bus Flag */ +#define IICB0SSSP BIT(4) /* Stop Condition Flag */ + +/* IICB0CTL1 */ +#define IICB0MDSC BIT(7) /* Bus Mode */ +#define IICB0SLSE BIT(1) /* Start condition output */ + +struct rzv2m_i2c_priv { + void __iomem *base; + struct i2c_adapter adap; + struct clk *clk; + int bus_mode; + struct completion msg_tia_done; + u32 iicb0wl; + u32 iicb0wh; +}; + +enum bcr_index { + RZV2M_I2C_100K = 0, + RZV2M_I2C_400K, +}; + +struct bitrate_config { + unsigned int percent_low; + unsigned int min_hold_time_ns; +}; + +static const struct bitrate_config bitrate_configs[] = { + [RZV2M_I2C_100K] = { 47, 3450 }, + [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; + + complete(&priv->msg_tia_done); + + return IRQ_HANDLED; +} + +/* Calculate IICB0WL and IICB0WH */ +static int rzv2m_i2c_clock_calculate(struct device *dev, + struct rzv2m_i2c_priv *priv) +{ + const struct bitrate_config *config; + unsigned int hold_time_ns; + unsigned int total_pclks; + unsigned int trf_pclks; + unsigned long pclk_hz; + struct i2c_timings t; + u32 trf_ns; + + i2c_parse_fw_timings(dev, &t, true); + + pclk_hz = clk_get_rate(priv->clk); + total_pclks = pclk_hz / t.bus_freq_hz; + + trf_ns = t.scl_rise_ns + t.scl_fall_ns; + trf_pclks = mul_u64_u32_div(pclk_hz, trf_ns, NSEC_PER_SEC); + + /* Config setting */ + switch (t.bus_freq_hz) { + case I2C_MAX_FAST_MODE_FREQ: + priv->bus_mode = RZV2M_I2C_400K; + break; + case I2C_MAX_STANDARD_MODE_FREQ: + priv->bus_mode = RZV2M_I2C_100K; + break; + default: + dev_err(dev, "transfer speed is invalid\n"); + return -EINVAL; + } + config = &bitrate_configs[priv->bus_mode]; + + /* IICB0WL = (percent_low / Transfer clock) x PCLK */ + priv->iicb0wl = total_pclks * config->percent_low / 100; + if (priv->iicb0wl > (BIT(10) - 1)) + return -EINVAL; + + /* IICB0WH = ((percent_high / Transfer clock) x PCLK) - (tR + tF) */ + priv->iicb0wh = total_pclks - priv->iicb0wl - trf_pclks; + if (priv->iicb0wh > (BIT(10) - 1)) + return -EINVAL; + + /* + * Data hold time must be less than 0.9us in fast mode and + * 3.45us in standard mode. + * Data hold time = IICB0WL[9:2] / PCLK + */ + hold_time_ns = div64_ul((u64)(priv->iicb0wl >> 2) * NSEC_PER_SEC, pclk_hz); + if (hold_time_ns > config->min_hold_time_ns) { + dev_err(dev, "data hold time %dns is over %dns\n", + hold_time_ns, config->min_hold_time_ns); + return -EINVAL; + } + + return 0; +} + +static void rzv2m_i2c_init(struct rzv2m_i2c_priv *priv) +{ + u32 i2c_ctl0; + u32 i2c_ctl1; + + /* i2c disable */ + writel(0, priv->base + IICB0CTL0); + + /* IICB0CTL1 setting */ + i2c_ctl1 = IICB0SLSE; + if (priv->bus_mode == RZV2M_I2C_400K) + i2c_ctl1 |= IICB0MDSC; + writel(i2c_ctl1, priv->base + IICB0CTL1); + + /* IICB0WL IICB0WH setting */ + writel(priv->iicb0wl, priv->base + IICB0WL); + writel(priv->iicb0wh, priv->base + IICB0WH); + + /* i2c enable after setting */ + i2c_ctl0 = IICB0SLWT | IICB0SLAC | IICB0IICE; + writel(i2c_ctl0, priv->base + IICB0CTL0); +} + +static int rzv2m_i2c_write_with_ack(struct rzv2m_i2c_priv *priv, u32 data) +{ + unsigned long time_left; + + reinit_completion(&priv->msg_tia_done); + + writel(data, priv->base + IICB0DAT); + + time_left = wait_for_completion_timeout(&priv->msg_tia_done, + priv->adap.timeout); + if (!time_left) + return -ETIMEDOUT; + + /* Confirm ACK */ + if ((readl(priv->base + IICB0STR0) & IICB0SSAC) != IICB0SSAC) + return -ENXIO; + + return 0; +} + +static int rzv2m_i2c_read_with_ack(struct rzv2m_i2c_priv *priv, u8 *data, + bool last) +{ + unsigned long time_left; + u32 data_tmp; + + reinit_completion(&priv->msg_tia_done); + + /* Interrupt request timing : 8th clock */ + bit_clrl(priv->base + IICB0CTL0, IICB0SLWT); + + /* Exit the wait state */ + writel(IICB0WRET, priv->base + IICB0TRG); + + /* Wait for transaction */ + time_left = wait_for_completion_timeout(&priv->msg_tia_done, + priv->adap.timeout); + if (!time_left) + return -ETIMEDOUT; + + if (last) { + /* Disable ACK */ + bit_clrl(priv->base + IICB0CTL0, IICB0SLAC); + + /* Read data*/ + data_tmp = readl(priv->base + IICB0DAT); + + /* Interrupt request timing : 9th clock */ + bit_setl(priv->base + IICB0CTL0, IICB0SLWT); + + /* Exit the wait state */ + writel(IICB0WRET, priv->base + IICB0TRG); + + /* Wait for transaction */ + time_left = wait_for_completion_timeout(&priv->msg_tia_done, + priv->adap.timeout); + if (!time_left) + return -ETIMEDOUT; + + /* Enable ACK */ + bit_setl(priv->base + IICB0CTL0, IICB0SLAC); + } else { + /* Read data */ + data_tmp = readl(priv->base + IICB0DAT); + } + + *data = data_tmp; + + return 0; +} + +static int rzv2m_i2c_send(struct rzv2m_i2c_priv *priv, struct i2c_msg *msg, + unsigned int *count) +{ + unsigned int i; + int ret; + + for (i = 0; i < msg->len; i++) { + ret = rzv2m_i2c_write_with_ack(priv, msg->buf[i]); + if (ret < 0) + return ret; + } + *count = i; + + return 0; +} + +static int rzv2m_i2c_receive(struct rzv2m_i2c_priv *priv, struct i2c_msg *msg, + unsigned int *count) +{ + unsigned int i; + int ret; + + for (i = 0; i < msg->len; i++) { + ret = rzv2m_i2c_read_with_ack(priv, &msg->buf[i], + (msg->len - 1) == i); + if (ret < 0) + return ret; + } + *count = i; + + return 0; +} + +static int rzv2m_i2c_send_address(struct rzv2m_i2c_priv *priv, + struct i2c_msg *msg) +{ + u32 addr; + int ret; + + if (msg->flags & I2C_M_TEN) { + /* 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; + + /* 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); + ret = rzv2m_i2c_write_with_ack(priv, addr); + } + + return ret; +} + +static int rzv2m_i2c_stop_condition(struct rzv2m_i2c_priv *priv) +{ + u32 value; + + /* Send stop condition */ + writel(IICB0SPT, priv->base + IICB0TRG); + return readl_poll_timeout(priv->base + IICB0STR0, + value, value & IICB0SSSP, + 100, jiffies_to_usecs(priv->adap.timeout)); +} + +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); + + /* Send start condition */ + writel(IICB0STT, priv->base + IICB0TRG); + + ret = rzv2m_i2c_send_address(priv, msg); + if (!ret) { + if (read) + ret = rzv2m_i2c_receive(priv, msg, &count); + else + ret = rzv2m_i2c_send(priv, msg, &count); + + if (!ret && stop) + ret = rzv2m_i2c_stop_condition(priv); + } + + if (ret == -ENXIO) + rzv2m_i2c_stop_condition(priv); + else if (ret < 0) + rzv2m_i2c_init(priv); + else + ret = count; + + return ret; +} + +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; + unsigned int i; + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + if (readl(priv->base + IICB0STR0) & IICB0SSBS) { + ret = -EAGAIN; + goto out; + } + + /* I2C main transfer */ + for (i = 0; i < num; i++) { + ret = rzv2m_i2c_xfer_msg(priv, &msgs[i], i == (num - 1)); + if (ret < 0) + goto out; + } + ret = num; + +out: + pm_runtime_put_autosuspend(dev); + + return ret; +} + +static u32 rzv2m_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | + 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 const struct i2c_algorithm rzv2m_i2c_algo = { + .xfer = rzv2m_i2c_xfer, + .functionality = rzv2m_i2c_func, +}; + +static int rzv2m_i2c_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct rzv2m_i2c_priv *priv; + struct reset_control *rstc; + struct i2c_adapter *adap; + struct resource *res; + int irq, ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->clk = devm_clk_get(dev, NULL); + if (IS_ERR(priv->clk)) + return dev_err_probe(dev, PTR_ERR(priv->clk), "Can't get clock\n"); + + rstc = devm_reset_control_get_shared(dev, NULL); + if (IS_ERR(rstc)) + return dev_err_probe(dev, PTR_ERR(rstc), "Missing reset ctrl\n"); + /* + * The reset also affects other HW that is not under the control + * of Linux. Therefore, all we can do is deassert the reset. + */ + reset_control_deassert(rstc); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_irq(dev, irq, rzv2m_i2c_tia_irq_handler, 0, + dev_name(dev), priv); + if (ret < 0) + return dev_err_probe(dev, ret, "Unable to request irq %d\n", irq); + + adap = &priv->adap; + adap->nr = pdev->id; + adap->algo = &rzv2m_i2c_algo; + adap->quirks = &rzv2m_i2c_quirks; + adap->dev.parent = dev; + adap->owner = THIS_MODULE; + device_set_node(&adap->dev, dev_fwnode(dev)); + i2c_set_adapdata(adap, priv); + strscpy(adap->name, pdev->name, sizeof(adap->name)); + init_completion(&priv->msg_tia_done); + + ret = rzv2m_i2c_clock_calculate(dev, priv); + if (ret < 0) + return ret; + + pm_runtime_enable(dev); + + pm_runtime_get_sync(dev); + rzv2m_i2c_init(priv); + pm_runtime_put(dev); + + platform_set_drvdata(pdev, priv); + + ret = i2c_add_numbered_adapter(adap); + if (ret < 0) { + rzv2m_i2c_disable(dev, priv); + pm_runtime_disable(dev); + } + + return ret; +} + +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); + rzv2m_i2c_disable(dev, priv); + pm_runtime_disable(dev); +} + +static int rzv2m_i2c_suspend(struct device *dev) +{ + struct rzv2m_i2c_priv *priv = dev_get_drvdata(dev); + + return rzv2m_i2c_disable(dev, priv); +} + +static int rzv2m_i2c_resume(struct device *dev) +{ + struct rzv2m_i2c_priv *priv = dev_get_drvdata(dev); + int ret; + + ret = rzv2m_i2c_clock_calculate(dev, priv); + if (ret < 0) + return ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + rzv2m_i2c_init(priv); + pm_runtime_put(dev); + + return 0; +} + +static const struct of_device_id rzv2m_i2c_ids[] = { + { .compatible = "renesas,rzv2m-i2c" }, + { } +}; +MODULE_DEVICE_TABLE(of, rzv2m_i2c_ids); + +static const struct dev_pm_ops rzv2m_i2c_pm_ops = { + SYSTEM_SLEEP_PM_OPS(rzv2m_i2c_suspend, rzv2m_i2c_resume) +}; + +static struct platform_driver rzv2m_i2c_driver = { + .driver = { + .name = "rzv2m-i2c", + .of_match_table = rzv2m_i2c_ids, + .pm = pm_sleep_ptr(&rzv2m_i2c_pm_ops), + }, + .probe = rzv2m_i2c_probe, + .remove = rzv2m_i2c_remove, +}; +module_platform_driver(rzv2m_i2c_driver); + +MODULE_DESCRIPTION("RZ/V2M I2C bus driver"); +MODULE_AUTHOR("Renesas Electronics Corporation"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 4d82761e1585..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) { @@ -1076,7 +1030,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) else s3c24xx_i2c_parse_dt(pdev->dev.of_node, i2c); - strlcpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name)); + strscpy(i2c->adap.name, "s3c2410-i2c", sizeof(i2c->adap.name)); i2c->adap.owner = THIS_MODULE; i2c->adap.algo = &s3c24xx_i2c_algorithm; i2c->adap.retries = 2; @@ -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); @@ -1137,8 +1089,7 @@ 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"); + if (ret < 0) { 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 6746aa46d96c..10a5146b3aa5 100644 --- a/drivers/i2c/busses/i2c-scmi.c +++ b/drivers/i2c/busses/i2c-scmi.c @@ -6,18 +6,13 @@ */ #include <linux/module.h> +#include <linux/platform_device.h> #include <linux/slab.h> #include <linux/kernel.h> #include <linux/stddef.h> #include <linux/i2c.h> #include <linux/acpi.h> -#define ACPI_SMBUS_HC_CLASS "smbus" -#define ACPI_SMBUS_HC_DEVICE_NAME "cmi" - -/* SMBUS HID definition as supported by Microsoft Windows */ -#define ACPI_SMBUS_MS_HID "SMB0001" - struct smbus_methods_t { char *mt_info; char *mt_sbr; @@ -30,7 +25,7 @@ struct acpi_smbus_cmi { u8 cap_info:1; u8 cap_read:1; u8 cap_write:1; - struct smbus_methods_t *methods; + const struct smbus_methods_t *methods; }; static const struct smbus_methods_t smbus_methods = { @@ -358,29 +353,25 @@ static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level, return AE_OK; } -static int acpi_smbus_cmi_add(struct acpi_device *device) +static int smbus_cmi_probe(struct platform_device *device) { + struct device *dev = &device->dev; struct acpi_smbus_cmi *smbus_cmi; - const struct acpi_device_id *id; int ret; smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL); if (!smbus_cmi) return -ENOMEM; - smbus_cmi->handle = device->handle; - strcpy(acpi_device_name(device), ACPI_SMBUS_HC_DEVICE_NAME); - strcpy(acpi_device_class(device), ACPI_SMBUS_HC_CLASS); - device->driver_data = smbus_cmi; + smbus_cmi->handle = ACPI_HANDLE(dev); + smbus_cmi->methods = device_get_match_data(dev); + + platform_set_drvdata(device, smbus_cmi); + smbus_cmi->cap_info = 0; smbus_cmi->cap_read = 0; smbus_cmi->cap_write = 0; - for (id = acpi_smbus_cmi_ids; id->id[0]; id++) - if (!strcmp(id->id, acpi_device_hid(device))) - smbus_cmi->methods = - (struct smbus_methods_t *) id->driver_data; - acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1, acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL); @@ -390,12 +381,11 @@ static int acpi_smbus_cmi_add(struct acpi_device *device) } snprintf(smbus_cmi->adapter.name, sizeof(smbus_cmi->adapter.name), - "SMBus CMI adapter %s", - acpi_device_name(device)); + "SMBus CMI adapter %s", dev_name(dev)); 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); @@ -408,31 +398,26 @@ static int acpi_smbus_cmi_add(struct acpi_device *device) err: kfree(smbus_cmi); - device->driver_data = NULL; return ret; } -static int acpi_smbus_cmi_remove(struct acpi_device *device) +static void smbus_cmi_remove(struct platform_device *device) { - struct acpi_smbus_cmi *smbus_cmi = acpi_driver_data(device); + struct acpi_smbus_cmi *smbus_cmi = platform_get_drvdata(device); i2c_del_adapter(&smbus_cmi->adapter); kfree(smbus_cmi); - device->driver_data = NULL; - - return 0; } -static struct acpi_driver acpi_smbus_cmi_driver = { - .name = ACPI_SMBUS_HC_DEVICE_NAME, - .class = ACPI_SMBUS_HC_CLASS, - .ids = acpi_smbus_cmi_ids, - .ops = { - .add = acpi_smbus_cmi_add, - .remove = acpi_smbus_cmi_remove, +static struct platform_driver smbus_cmi_driver = { + .probe = smbus_cmi_probe, + .remove = smbus_cmi_remove, + .driver = { + .name = "smbus_cmi", + .acpi_match_table = acpi_smbus_cmi_ids, }, }; -module_acpi_driver(acpi_smbus_cmi_driver); +module_platform_driver(smbus_cmi_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Crane Cai <crane.cai@amd.com>"); 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 2d2e630fd438..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 */ @@ -442,34 +443,26 @@ static irqreturn_t sh_mobile_i2c_isr(int irq, void *dev_id) return IRQ_HANDLED; } -static void sh_mobile_i2c_dma_unmap(struct sh_mobile_i2c_data *pd) +static void sh_mobile_i2c_cleanup_dma(struct sh_mobile_i2c_data *pd, bool terminate) { struct dma_chan *chan = pd->dma_direction == DMA_FROM_DEVICE ? pd->dma_rx : pd->dma_tx; + /* only allowed from thread context! */ + if (terminate) + dmaengine_terminate_sync(chan); + dma_unmap_single(chan->device->dev, sg_dma_address(&pd->sg), pd->msg->len, pd->dma_direction); pd->dma_direction = DMA_NONE; } -static void sh_mobile_i2c_cleanup_dma(struct sh_mobile_i2c_data *pd) -{ - if (pd->dma_direction == DMA_NONE) - return; - else if (pd->dma_direction == DMA_FROM_DEVICE) - dmaengine_terminate_all(pd->dma_rx); - else if (pd->dma_direction == DMA_TO_DEVICE) - dmaengine_terminate_all(pd->dma_tx); - - sh_mobile_i2c_dma_unmap(pd); -} - static void sh_mobile_i2c_dma_callback(void *data) { struct sh_mobile_i2c_data *pd = data; - sh_mobile_i2c_dma_unmap(pd); + sh_mobile_i2c_cleanup_dma(pd, false); pd->pos = pd->msg->len; pd->stop_after_dma = true; @@ -549,7 +542,7 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd) DMA_PREP_INTERRUPT | DMA_CTRL_ACK); if (!txdesc) { dev_dbg(pd->dev, "dma prep slave sg failed, using PIO\n"); - sh_mobile_i2c_cleanup_dma(pd); + sh_mobile_i2c_cleanup_dma(pd, false); return; } @@ -559,7 +552,7 @@ static void sh_mobile_i2c_xfer_dma(struct sh_mobile_i2c_data *pd) cookie = dmaengine_submit(txdesc); if (dma_submit_error(cookie)) { dev_dbg(pd->dev, "submitting dma failed, using PIO\n"); - sh_mobile_i2c_cleanup_dma(pd); + sh_mobile_i2c_cleanup_dma(pd, false); return; } @@ -696,9 +689,8 @@ 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); + sh_mobile_i2c_cleanup_dma(pd, true); err = -ETIMEDOUT; break; @@ -748,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 = { @@ -781,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 = { @@ -791,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, }; @@ -807,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 }, {}, }; @@ -838,20 +825,38 @@ static void sh_mobile_i2c_release_dma(struct sh_mobile_i2c_data *pd) static int sh_mobile_i2c_hook_irqs(struct platform_device *dev, struct sh_mobile_i2c_data *pd) { - struct resource *res; - resource_size_t n; + struct device_node *np = dev_of_node(&dev->dev); int k = 0, ret; - while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) { - for (n = res->start; n <= res->end; n++) { - ret = devm_request_irq(&dev->dev, n, sh_mobile_i2c_isr, - 0, dev_name(&dev->dev), pd); + if (np) { + int irq; + + while ((irq = platform_get_irq_optional(dev, k)) != -ENXIO) { + if (irq < 0) + return irq; + ret = devm_request_irq(&dev->dev, irq, sh_mobile_i2c_isr, + 0, dev_name(&dev->dev), pd); if (ret) { - dev_err(&dev->dev, "cannot request IRQ %pa\n", &n); + dev_err(&dev->dev, "cannot request IRQ %d\n", irq); return ret; } + k++; + } + } else { + struct resource *res; + resource_size_t n; + + while ((res = platform_get_resource(dev, IORESOURCE_IRQ, k))) { + for (n = res->start; n <= res->end; n++) { + ret = devm_request_irq(&dev->dev, n, sh_mobile_i2c_isr, + 0, dev_name(&dev->dev), pd); + if (ret) { + dev_err(&dev->dev, "cannot request IRQ %pa\n", &n); + return ret; + } + } + k++; } - k++; } return k > 0 ? 0 : -ENOENT; @@ -861,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; @@ -883,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); @@ -895,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); @@ -930,7 +931,7 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) adap->nr = dev->id; adap->dev.of_node = dev->dev.of_node; - strlcpy(adap->name, dev->name, sizeof(adap->name)); + strscpy(adap->name, dev->name, sizeof(adap->name)); spin_lock_init(&pd->lock); init_waitqueue_head(&pd->wait); @@ -946,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); @@ -974,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 458c7bcf1d24..d90606048611 100644 --- a/drivers/i2c/busses/i2c-simtec.c +++ b/drivers/i2c/busses/i2c-simtec.c @@ -99,7 +99,7 @@ static int simtec_i2c_probe(struct platform_device *dev) pd->adap.algo_data = &pd->bit; pd->adap.dev.parent = &dev->dev; - strlcpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name)); + strscpy(pd->adap.name, "Simtec I2C", sizeof(pd->adap.name)); pd->bit.data = pd; pd->bit.setsda = simtec_i2c_setsda; @@ -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 cfb8e04a2a83..a19c3d251804 100644 --- a/drivers/i2c/busses/i2c-sis630.c +++ b/drivers/i2c/busses/i2c-sis630.c @@ -97,7 +97,7 @@ MODULE_PARM_DESC(high_clock, module_param(force, bool, 0); MODULE_PARM_DESC(force, "Forcibly enable the SIS630. DANGEROUS!"); -/* SMBus base adress */ +/* SMBus base address */ static unsigned short smbus_base; /* supported chips */ @@ -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 b9b19a2a2ffa..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; }; /* @@ -410,6 +418,19 @@ static const struct stm32f7_i2c_setup stm32mp15_setup = { .fmp_clr_offset = 0x40, }; +static const struct stm32f7_i2c_setup stm32mp13_setup = { + .rise_time = STM32F7_I2C_RISE_TIME_DEFAULT, + .fall_time = STM32F7_I2C_FALL_TIME_DEFAULT, + .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); @@ -702,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; @@ -719,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); } @@ -828,18 +853,14 @@ static void stm32f7_i2c_smbus_reload(struct stm32f7_i2c_dev *i2c_dev) writel_relaxed(cr2, i2c_dev->base + STM32F7_I2C_CR2); } -static int stm32f7_i2c_release_bus(struct i2c_adapter *i2c_adap) +static void stm32f7_i2c_release_bus(struct i2c_adapter *i2c_adap) { struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap); - dev_info(i2c_dev->dev, "Trying to recover bus\n"); - stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_PE); stm32f7_i2c_hw_config(i2c_dev); - - return 0; } static int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev) @@ -854,13 +875,7 @@ static int stm32f7_i2c_wait_free_bus(struct stm32f7_i2c_dev *i2c_dev) if (!ret) return 0; - dev_info(i2c_dev->dev, "bus busy\n"); - - ret = stm32f7_i2c_release_bus(&i2c_dev->adap); - if (ret) { - dev_err(i2c_dev->dev, "Failed to recover the bus (%d)\n", ret); - return ret; - } + stm32f7_i2c_release_bus(&i2c_dev->adap); return -EBUSY; } @@ -870,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; @@ -919,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) { @@ -943,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; @@ -1063,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; @@ -1153,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); @@ -1414,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, @@ -1489,22 +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; + 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); @@ -1513,41 +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_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) { - 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) { - ret = IRQ_WAKE_THREAD; } else if (f7_msg->smbus) { stm32f7_i2c_smbus_rep_start(i2c_dev); } else { @@ -1557,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_all(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); } @@ -1605,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_all(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); @@ -1693,25 +1730,60 @@ 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) + dmaengine_synchronize(dma->chan_using); + + /* + * It is possible that some unsent data have already been + * written into TXDR. To avoid sending old data in a + * further transfer, flush TXDR in case of any error + */ + writel_relaxed(STM32F7_I2C_ISR_TXE, + i2c_dev->base + STM32F7_I2C_ISR); + goto pm_free; + } if (!time_left) { dev_dbg(i2c_dev->dev, "Access to slave 0x%x timed out\n", i2c_dev->msg->addr); if (i2c_dev->use_dma) - dmaengine_terminate_all(dma->chan_using); + dmaengine_terminate_sync(dma->chan_using); + stm32f7_i2c_wait_free_bus(i2c_dev); ret = -ETIMEDOUT; } 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, @@ -1721,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; @@ -1741,16 +1813,28 @@ 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 (ret) { + if (i2c_dev->use_dma) + dmaengine_synchronize(dma->chan_using); + + /* + * It is possible that some unsent data have already been + * written into TXDR. To avoid sending old data in a + * further transfer, flush TXDR in case of any error + */ + writel_relaxed(STM32F7_I2C_ISR_TXE, + i2c_dev->base + STM32F7_I2C_ISR); 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_all(dma->chan_using); + dmaengine_terminate_sync(dma->chan_using); + stm32f7_i2c_wait_free_bus(i2c_dev); ret = -ETIMEDOUT; goto pm_free; } @@ -1785,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; } @@ -1892,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; @@ -1930,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; @@ -1939,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; } @@ -2067,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, @@ -2088,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); @@ -2132,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; @@ -2244,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; @@ -2276,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); @@ -2312,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) @@ -2323,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; } @@ -2334,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; } } @@ -2447,6 +2519,8 @@ static const struct dev_pm_ops stm32f7_i2c_pm_ops = { 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 2f6f6468214d..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,44 +215,38 @@ 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); if (IS_ERR(p2wi->regs)) return PTR_ERR(p2wi->regs); - strlcpy(p2wi->adapter.name, pdev->name, sizeof(p2wi->adapter.name)); + strscpy(p2wi->adapter.name, pdev->name, sizeof(p2wi->adapter.name)); irq = platform_get_irq(pdev, 0); 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 31be1811d5e6..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)) @@ -578,14 +570,12 @@ static int synquacer_i2c_probe(struct platform_device *pdev) i2c->irq = platform_get_irq(pdev, 0); if (i2c->irq < 0) - return -ENODEV; + return i2c->irq; 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 b4050f5b6746..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> @@ -239,7 +239,7 @@ static int taos_connect(struct serio *serio, struct serio_driver *drv) dev_err(&serio->dev, "TAOS EVM identification failed\n"); goto exit_close; } - strlcpy(adapter->name, name, sizeof(adapter->name)); + strscpy(adapter->name, name, sizeof(adapter->name)); /* Turn echo off for better performance */ taos->state = TAOS_STATE_EOFF; diff --git a/drivers/i2c/busses/i2c-tegra-bpmp.c b/drivers/i2c/busses/i2c-tegra-bpmp.c index ec0c7cad4240..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, }; @@ -305,7 +305,7 @@ static int tegra_bpmp_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&i2c->adapter, i2c); i2c->adapter.owner = THIS_MODULE; - strlcpy(i2c->adapter.name, "Tegra BPMP I2C adapter", + strscpy(i2c->adapter.name, "Tegra BPMP I2C adapter", sizeof(i2c->adapter.name)); i2c->adapter.algo = &tegra_bpmp_i2c_algo; i2c->adapter.dev.parent = &pdev->dev; @@ -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 c883044715f3..e533460bccc3 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -6,6 +6,7 @@ * Author: Colin Cross <ccross@android.com> */ +#include <linux/acpi.h> #include <linux/bitfield.h> #include <linux/clk.h> #include <linux/delay.h> @@ -21,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> @@ -133,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 @@ -183,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 @@ -212,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; @@ -241,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 - * @bus_clk_rate: current I2C bus clock rate + * @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 @@ -272,17 +280,18 @@ struct tegra_i2c_dev { unsigned int nclocks; struct clk *div_clk; - u32 bus_clk_rate; + struct i2c_timings timings; 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; void *dma_buf; @@ -294,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) { @@ -311,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; @@ -326,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)); } @@ -389,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) { @@ -411,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; } @@ -419,57 +429,53 @@ static int tegra_i2c_dma_submit(struct tegra_i2c_dev *i2c_dev, size_t len) static void tegra_i2c_release_dma(struct tegra_i2c_dev *i2c_dev) { if (i2c_dev->dma_buf) { - dma_free_coherent(i2c_dev->dev, i2c_dev->dma_buf_size, + dma_free_coherent(i2c_dev->dma_dev, i2c_dev->dma_buf_size, i2c_dev->dma_buf, i2c_dev->dma_phys); 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->hw->has_apb_dma || i2c_dev->is_vi) + if (IS_VI(i2c_dev)) return 0; - if (!IS_ENABLED(CONFIG_TEGRA20_APB_DMA)) { - dev_dbg(i2c_dev->dev, "DMA support not enabled\n"); + 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; + } + } else if (!IS_ENABLED(CONFIG_TEGRA186_GPC_DMA)) { + dev_dbg(i2c_dev->dev, "GPC DMA support not enabled\n"); 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; - + 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; - dma_buf = dma_alloc_coherent(i2c_dev->dev, i2c_dev->dma_buf_size, + dma_buf = dma_alloc_coherent(i2c_dev->dma_dev, i2c_dev->dma_buf_size, &dma_phys, GFP_KERNEL | __GFP_NOWARN); if (!dma_buf) { dev_err(i2c_dev->dev, "failed to allocate DMA buffer\n"); @@ -605,12 +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; + 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 @@ -618,10 +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. */ - 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 | @@ -633,17 +669,17 @@ 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 (i2c_dev->bus_clk_rate) { + switch (t->bus_freq_hz) { case I2C_MAX_STANDARD_MODE_FREQ + 1 ... I2C_MAX_FAST_MODE_PLUS_FREQ: default: tlow = i2c_dev->hw->tlow_fast_fastplus_mode; thigh = i2c_dev->hw->thigh_fast_fastplus_mode; tsu_thd = i2c_dev->hw->setup_hold_time_fast_fast_plus_mode; - if (i2c_dev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ) + if (t->bus_freq_hz > I2C_MAX_FAST_MODE_FREQ) non_hs_mode = i2c_dev->hw->clk_divisor_fast_plus_mode; else non_hs_mode = i2c_dev->hw->clk_divisor_fast_mode; @@ -679,13 +715,13 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) clk_multiplier = (tlow + thigh + 2) * (non_hs_mode + 1); err = clk_set_rate(i2c_dev->div_clk, - i2c_dev->bus_clk_rate * clk_multiplier); + t->bus_freq_hz * clk_multiplier); if (err) { dev_err(i2c_dev->dev, "failed to set div-clk rate: %d\n", err); 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; @@ -718,7 +754,7 @@ static int tegra_i2c_disable_packet_mode(struct tegra_i2c_dev *i2c_dev) * before disabling the controller so that the STOP condition has * been delivered properly. */ - udelay(DIV_ROUND_UP(2 * 1000000, i2c_dev->bus_clk_rate)); + udelay(DIV_ROUND_UP(2 * 1000000, i2c_dev->timings.bus_freq_hz)); cnfg = i2c_readl(i2c_dev, I2C_CNFG); if (cnfg & I2C_CNFG_PACKET_MODE_EN) @@ -828,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); @@ -915,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); /* @@ -954,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); } @@ -976,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) @@ -993,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; @@ -1005,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; @@ -1019,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"); @@ -1153,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; @@ -1226,15 +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_buf_remaining = msg->len; + i2c_dev->msg_len = 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); @@ -1248,24 +1294,16 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, * Total bits = 9 bits per byte (including ACK bit) + Start & stop bits */ xfer_time += DIV_ROUND_CLOSEST(((xfer_size * 9) + 2) * MSEC_PER_SEC, - i2c_dev->bus_clk_rate); + i2c_dev->timings.bus_freq_hz); int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST; tegra_i2c_unmask_irq(i2c_dev, int_mask); if (i2c_dev->dma_mode) { if (i2c_dev->msg_read) { - dma_sync_single_for_device(i2c_dev->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->dev, - i2c_dev->dma_phys, - xfer_size, DMA_TO_DEVICE); } } @@ -1274,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->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; @@ -1312,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->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, @@ -1341,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; } @@ -1382,6 +1403,20 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], else end_type = MSG_END_REPEAT_START; } + /* If M_RECV_LEN use ContinueXfer to read the first byte */ + if (msgs[i].flags & I2C_M_RECV_LEN) { + ret = tegra_i2c_xfer_msg(i2c_dev, &msgs[i], MSG_END_CONTINUE); + if (ret) + break; + + /* 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); if (ret) break; @@ -1409,18 +1444,18 @@ static u32 tegra_i2c_func(struct i2c_adapter *adap) { struct tegra_i2c_dev *i2c_dev = i2c_get_adapdata(adap); u32 ret = I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | - I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; + I2C_FUNC_10BIT_ADDR | I2C_FUNC_PROTOCOL_MANGLING; if (i2c_dev->hw->has_continue_xfer_support) - ret |= I2C_FUNC_NOSTART; + ret |= I2C_FUNC_NOSTART | I2C_FUNC_SMBUS_READ_BLOCK_DATA; return ret; } 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 */ @@ -1450,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, @@ -1474,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, @@ -1498,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, @@ -1522,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, @@ -1546,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, @@ -1570,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, @@ -1594,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, @@ -1607,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); @@ -1625,20 +1697,18 @@ static void tegra_i2c_parse_dt(struct tegra_i2c_dev *i2c_dev) { struct device_node *np = i2c_dev->dev->of_node; bool multi_mode; - int err; - err = of_property_read_u32(np, "clock-frequency", - &i2c_dev->bus_clk_rate); - if (err) - i2c_dev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ; + i2c_parse_fw_timings(i2c_dev->dev, &i2c_dev->timings, true); - multi_mode = of_property_read_bool(np, "multi-master"); + 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; } @@ -1646,12 +1716,15 @@ static int tegra_i2c_init_clocks(struct tegra_i2c_dev *i2c_dev) { int err; + if (ACPI_HANDLE(i2c_dev->dev)) + return 0; + i2c_dev->clocks[i2c_dev->nclocks++].id = "div-clk"; 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, @@ -1700,7 +1773,7 @@ static int tegra_i2c_init_hardware(struct tegra_i2c_dev *i2c_dev) else ret = tegra_i2c_init(i2c_dev); - pm_runtime_put(i2c_dev->dev); + pm_runtime_put_sync(i2c_dev->dev); return ret; } @@ -1720,7 +1793,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) init_completion(&i2c_dev->msg_complete); init_completion(&i2c_dev->dma_complete); - i2c_dev->hw = of_device_get_match_data(&pdev->dev); + i2c_dev->hw = device_get_match_data(&pdev->dev); i2c_dev->cont_id = pdev->id; i2c_dev->dev = &pdev->dev; @@ -1746,13 +1819,6 @@ static int tegra_i2c_probe(struct platform_device *pdev) if (err) return err; - i2c_dev->rst = devm_reset_control_get_exclusive(i2c_dev->dev, "i2c"); - if (IS_ERR(i2c_dev->rst)) { - dev_err_probe(i2c_dev->dev, PTR_ERR(i2c_dev->rst), - "failed to get reset control\n"); - return PTR_ERR(i2c_dev->rst); - } - tegra_i2c_parse_dt(i2c_dev); err = tegra_i2c_init_clocks(i2c_dev); @@ -1770,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); @@ -1791,11 +1857,12 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->adapter.class = I2C_CLASS_DEPRECATED; i2c_dev->adapter.algo = &tegra_i2c_algo; i2c_dev->adapter.nr = pdev->id; + ACPI_COMPANION_SET(&i2c_dev->adapter.dev, ACPI_COMPANION(&pdev->dev)); if (i2c_dev->hw->supports_bus_clear) i2c_dev->adapter.bus_recovery_info = &tegra_i2c_recovery_info; - strlcpy(i2c_dev->adapter.name, dev_name(i2c_dev->dev), + strscpy(i2c_dev->adapter.name, dev_name(i2c_dev->dev), sizeof(i2c_dev->adapter.name)); err = i2c_add_numbered_adapter(&i2c_dev->adapter); @@ -1814,17 +1881,15 @@ 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); i2c_del_adapter(&i2c_dev->adapter); - pm_runtime_disable(i2c_dev->dev); + pm_runtime_force_suspend(i2c_dev->dev); 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) @@ -1845,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; @@ -1923,12 +1988,21 @@ static const struct dev_pm_ops tegra_i2c_pm = { NULL) }; +static const struct acpi_device_id tegra_i2c_acpi_match[] = { + {.id = "NVDA0101", .driver_data = (kernel_ulong_t)&tegra210_i2c_hw}, + {.id = "NVDA0201", .driver_data = (kernel_ulong_t)&tegra186_i2c_hw}, + {.id = "NVDA0301", .driver_data = (kernel_ulong_t)&tegra194_i2c_hw}, + { } +}; +MODULE_DEVICE_TABLE(acpi, tegra_i2c_acpi_match); + static struct platform_driver tegra_i2c_driver = { .probe = tegra_i2c_probe, .remove = tegra_i2c_remove, .driver = { .name = "tegra-i2c", .of_match_table = tegra_i2c_of_match, + .acpi_match_table = tegra_i2c_acpi_match, .pm = &tegra_i2c_pm, }, }; diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c index 12c90aa0900e..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; @@ -213,6 +225,7 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev, i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info; i2c->adap.dev.parent = dev; i2c->adap.dev.of_node = pdev->dev.of_node; + i2c->adap.dev.fwnode = dev->fwnode; snprintf(i2c->adap.name, sizeof(i2c->adap.name), "Cavium ThunderX i2c adapter at %s", dev_name(dev)); i2c_set_adapdata(&i2c->adap, i2c); 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 cb4666c54a23..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); @@ -564,7 +550,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) priv->adap.algo = &uniphier_fi2c_algo; priv->adap.dev.parent = dev; priv->adap.dev.of_node = dev->of_node; - strlcpy(priv->adap.name, "UniPhier FI2C", sizeof(priv->adap.name)); + strscpy(priv->adap.name, "UniPhier FI2C", sizeof(priv->adap.name)); priv->adap.bus_recovery_info = &uniphier_fi2c_bus_recovery_info; i2c_set_adapdata(&priv->adap, priv); platform_set_drvdata(pdev, priv); @@ -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 ee00a44bf4c7..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); @@ -358,7 +344,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev) priv->adap.algo = &uniphier_i2c_algo; priv->adap.dev.parent = dev; priv->adap.dev.of_node = dev->of_node; - strlcpy(priv->adap.name, "UniPhier I2C", sizeof(priv->adap.name)); + strscpy(priv->adap.name, "UniPhier I2C", sizeof(priv->adap.name)); priv->adap.bus_recovery_info = &uniphier_i2c_bus_recovery_info; i2c_set_adapdata(&priv->adap, priv); platform_set_drvdata(pdev, priv); @@ -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 8d980b1374a8..a1ab6ef6f071 100644 --- a/drivers/i2c/busses/i2c-versatile.c +++ b/drivers/i2c/busses/i2c-versatile.c @@ -64,22 +64,20 @@ 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); writel(SCL | SDA, i2c->base + I2C_CONTROLS); i2c->adap.owner = THIS_MODULE; - strlcpy(i2c->adap.name, "Versatile I2C adapter", sizeof(i2c->adap.name)); + strscpy(i2c->adap.name, "Versatile I2C adapter", sizeof(i2c->adap.name)); i2c->adap.algo_data = &i2c->algo; i2c->adap.dev.parent = &dev->dev; i2c->adap.dev.of_node = dev->dev.of_node; @@ -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 new file mode 100644 index 000000000000..af1381949f50 --- /dev/null +++ b/drivers/i2c/busses/i2c-virtio.c @@ -0,0 +1,278 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Virtio I2C Bus Driver + * + * The Virtio I2C Specification: + * https://raw.githubusercontent.com/oasis-tcs/virtio-spec/master/virtio-i2c.tex + * + * Copyright (c) 2021 Intel Corporation. All rights reserved. + */ + +#include <linux/acpi.h> +#include <linux/completion.h> +#include <linux/err.h> +#include <linux/i2c.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/virtio.h> +#include <linux/virtio_ids.h> +#include <linux/virtio_config.h> +#include <linux/virtio_i2c.h> + +/** + * struct virtio_i2c - virtio I2C data + * @vdev: virtio device for this controller + * @adap: I2C adapter for this controller + * @vq: the virtio virtqueue for communication + */ +struct virtio_i2c { + struct virtio_device *vdev; + struct i2c_adapter adap; + struct virtqueue *vq; +}; + +/** + * struct virtio_i2c_req - the virtio I2C request structure + * @completion: completion of virtio I2C message + * @out_hdr: the OUT header of the virtio I2C message + * @buf: the buffer into which data is read, or from which it's written + * @in_hdr: the IN header of the virtio I2C message + */ +struct virtio_i2c_req { + struct completion completion; + struct virtio_i2c_out_hdr out_hdr ____cacheline_aligned; + uint8_t *buf ____cacheline_aligned; + struct virtio_i2c_in_hdr in_hdr ____cacheline_aligned; +}; + +static void virtio_i2c_msg_done(struct virtqueue *vq) +{ + struct virtio_i2c_req *req; + unsigned int len; + + while ((req = virtqueue_get_buf(vq, &len))) + complete(&req->completion); +} + +static int virtio_i2c_prepare_reqs(struct virtqueue *vq, + struct virtio_i2c_req *reqs, + struct i2c_msg *msgs, int num) +{ + struct scatterlist *sgs[3], out_hdr, msg_buf, in_hdr; + int i; + + for (i = 0; i < num; i++) { + int outcnt = 0, incnt = 0; + + init_completion(&reqs[i].completion); + + /* + * Only 7-bit mode supported for this moment. For the address + * format, Please check the Virtio I2C Specification. + */ + reqs[i].out_hdr.addr = cpu_to_le16(msgs[i].addr << 1); + + if (msgs[i].flags & I2C_M_RD) + reqs[i].out_hdr.flags |= cpu_to_le32(VIRTIO_I2C_FLAGS_M_RD); + + if (i != num - 1) + reqs[i].out_hdr.flags |= cpu_to_le32(VIRTIO_I2C_FLAGS_FAIL_NEXT); + + sg_init_one(&out_hdr, &reqs[i].out_hdr, sizeof(reqs[i].out_hdr)); + sgs[outcnt++] = &out_hdr; + + if (msgs[i].len) { + reqs[i].buf = i2c_get_dma_safe_msg_buf(&msgs[i], 1); + if (!reqs[i].buf) + break; + + sg_init_one(&msg_buf, reqs[i].buf, msgs[i].len); + + if (msgs[i].flags & I2C_M_RD) + sgs[outcnt + incnt++] = &msg_buf; + else + sgs[outcnt++] = &msg_buf; + } + + sg_init_one(&in_hdr, &reqs[i].in_hdr, sizeof(reqs[i].in_hdr)); + sgs[outcnt + incnt++] = &in_hdr; + + if (virtqueue_add_sgs(vq, sgs, outcnt, incnt, &reqs[i], GFP_KERNEL)) { + i2c_put_dma_safe_msg_buf(reqs[i].buf, &msgs[i], false); + break; + } + } + + return i; +} + +static int virtio_i2c_complete_reqs(struct virtqueue *vq, + struct virtio_i2c_req *reqs, + struct i2c_msg *msgs, int num) +{ + bool failed = false; + int i, j = 0; + + for (i = 0; i < num; i++) { + struct virtio_i2c_req *req = &reqs[i]; + + 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); + } + + return j; +} + +static int virtio_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct virtio_i2c *vi = i2c_get_adapdata(adap); + struct virtqueue *vq = vi->vq; + struct virtio_i2c_req *reqs; + int count; + + reqs = kcalloc(num, sizeof(*reqs), GFP_KERNEL); + if (!reqs) + return -ENOMEM; + + count = virtio_i2c_prepare_reqs(vq, reqs, msgs, num); + if (!count) + goto err_free; + + /* + * For the case where count < num, i.e. we weren't able to queue all the + * msgs, ideally we should abort right away and return early, but some + * of the messages are already sent to the remote I2C controller and the + * virtqueue will be left in undefined state in that case. We kick the + * remote here to clear the virtqueue, so we can try another set of + * messages later on. + */ + virtqueue_kick(vq); + + count = virtio_i2c_complete_reqs(vq, reqs, msgs, count); + +err_free: + kfree(reqs); + return count; +} + +static void virtio_i2c_del_vqs(struct virtio_device *vdev) +{ + virtio_reset_device(vdev); + vdev->config->del_vqs(vdev); +} + +static int virtio_i2c_setup_vqs(struct virtio_i2c *vi) +{ + struct virtio_device *vdev = vi->vdev; + + vi->vq = virtio_find_single_vq(vdev, virtio_i2c_msg_done, "msg"); + return PTR_ERR_OR_ZERO(vi->vq); +} + +static u32 virtio_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm virtio_algorithm = { + .xfer = virtio_i2c_xfer, + .functionality = virtio_i2c_func, +}; + +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)) + 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) + return -ENOMEM; + + vdev->priv = vi; + vi->vdev = vdev; + + ret = virtio_i2c_setup_vqs(vi); + if (ret) + return ret; + + vi->adap.owner = THIS_MODULE; + snprintf(vi->adap.name, sizeof(vi->adap.name), + "i2c_virtio at virtio bus %d", vdev->index); + vi->adap.algo = &virtio_algorithm; + vi->adap.dev.parent = &vdev->dev; + vi->adap.dev.of_node = vdev->dev.of_node; + i2c_set_adapdata(&vi->adap, vi); + + /* + * Setup ACPI node for controlled devices which will be probed through + * ACPI. + */ + ACPI_COMPANION_SET(&vi->adap.dev, ACPI_COMPANION(vdev->dev.parent)); + + ret = i2c_add_adapter(&vi->adap); + if (ret) + virtio_i2c_del_vqs(vdev); + + return ret; +} + +static void virtio_i2c_remove(struct virtio_device *vdev) +{ + struct virtio_i2c *vi = vdev->priv; + + i2c_del_adapter(&vi->adap); + virtio_i2c_del_vqs(vdev); +} + +static const struct virtio_device_id id_table[] = { + { VIRTIO_ID_I2C_ADAPTER, VIRTIO_DEV_ANY_ID }, + {} +}; +MODULE_DEVICE_TABLE(virtio, id_table); + +static int virtio_i2c_freeze(struct virtio_device *vdev) +{ + virtio_i2c_del_vqs(vdev); + return 0; +} + +static int virtio_i2c_restore(struct virtio_device *vdev) +{ + return virtio_i2c_setup_vqs(vdev->priv); +} + +static const unsigned int features[] = { + VIRTIO_I2C_F_ZERO_LENGTH_REQUEST, +}; + +static struct virtio_driver virtio_i2c_driver = { + .feature_table = features, + .feature_table_size = ARRAY_SIZE(features), + .id_table = id_table, + .probe = virtio_i2c_probe, + .remove = virtio_i2c_remove, + .driver = { + .name = "i2c_virtio", + }, + .freeze = pm_sleep_ptr(virtio_i2c_freeze), + .restore = pm_sleep_ptr(virtio_i2c_restore), +}; +module_virtio_driver(virtio_i2c_driver); + +MODULE_AUTHOR("Jie Deng <jie.deng@intel.com>"); +MODULE_AUTHOR("Conghui Chen <conghui.chen@intel.com>"); +MODULE_DESCRIPTION("Virtio i2c bus driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c deleted file mode 100644 index 88f5aafdce5b..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); - strlcpy(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 bba08cbce6e1..b29dec66b2c3 100644 --- a/drivers/i2c/busses/i2c-xgene-slimpro.c +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -91,25 +91,16 @@ #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; struct mbox_chan *mbox_chan; + struct pcc_mbox_chan *pcc_chan; struct mbox_client mbox_client; int mbox_idx; 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) \ @@ -155,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. */ @@ -176,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; @@ -185,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 */ @@ -307,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); @@ -461,81 +457,38 @@ 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 acpi_pcct_hw_reduced *cppc_ss; + 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; cl->tx_block = false; cl->rx_callback = slimpro_i2c_pcc_rx_cb; - ctx->mbox_chan = pcc_mbox_request_channel(cl, ctx->mbox_idx); - if (IS_ERR(ctx->mbox_chan)) { - dev_err(&pdev->dev, "PCC mailbox channel request failed\n"); - return PTR_ERR(ctx->mbox_chan); - } + pcc_chan = pcc_mbox_request_channel(cl, ctx->mbox_idx); + if (IS_ERR(pcc_chan)) + return dev_err_probe(&pdev->dev, PTR_ERR(pcc_chan), + "PCC mailbox channel request failed\n"); - /* - * The PCC mailbox controller driver should - * have parsed the PCCT (global table of all - * PCC channels) and stored pointers to the - * subspace communication region in con_priv. - */ - cppc_ss = ctx->mbox_chan->con_priv; - if (!cppc_ss) { - dev_err(&pdev->dev, "PPC subspace not found\n"); - rc = -ENOENT; - goto mbox_err; - } + 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 = cppc_ss->base_address; - if (ctx->comm_base_addr) { - if (version == XGENE_SLIMPRO_I2C_V2) - ctx->pcc_comm_addr = memremap( - ctx->comm_base_addr, - cppc_ss->length, - MEMREMAP_WT); - else - ctx->pcc_comm_addr = memremap( - ctx->comm_base_addr, - cppc_ss->length, - 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) @@ -561,12 +514,12 @@ mbox_err: if (acpi_disabled) mbox_free_channel(ctx->mbox_chan); else - pcc_mbox_free_channel(ctx->mbox_chan); + pcc_mbox_free_channel(ctx->pcc_chan); 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); @@ -575,9 +528,7 @@ static int xgene_slimpro_i2c_remove(struct platform_device *pdev) if (acpi_disabled) mbox_free_channel(ctx->mbox_chan); else - pcc_mbox_free_channel(ctx->mbox_chan); - - return 0; + pcc_mbox_free_channel(ctx->pcc_chan); } static const struct of_device_id xgene_slimpro_i2c_dt_ids[] = { @@ -597,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 bb93db98404e..28015d77599d 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -23,15 +23,19 @@ #include <linux/platform_device.h> #include <linux/i2c.h> #include <linux/interrupt.h> -#include <linux/wait.h> +#include <linux/completion.h> #include <linux/platform_data/i2c-xiic.h> #include <linux/io.h> #include <linux/slab.h> #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,11 +48,17 @@ 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 * @base: Memory base of the HW registers - * @wait: Wait queue for callers + * @completion: Completion for callers * @adap: Kernel adapter representation * @tx_msg: Messages from above to be sent * @lock: Mutual exclusion @@ -60,11 +70,20 @@ 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; void __iomem *base; - wait_queue_head_t wait; + struct completion completion; struct i2c_adapter adap; struct i2c_msg *tx_msg; struct mutex lock; @@ -76,26 +95,74 @@ 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 -#define XIIC_REG_OFFSET (0x100+XIIC_MSB_OFFSET) +#define XIIC_REG_OFFSET (0x100 + XIIC_MSB_OFFSET) /* * Register offsets in bytes from RegisterBase. Three is added to the * base offset to access LSB (IBM style) of the word */ -#define XIIC_CR_REG_OFFSET (0x00+XIIC_REG_OFFSET) /* Control Register */ -#define XIIC_SR_REG_OFFSET (0x04+XIIC_REG_OFFSET) /* Status Register */ -#define XIIC_DTR_REG_OFFSET (0x08+XIIC_REG_OFFSET) /* Data Tx Register */ -#define XIIC_DRR_REG_OFFSET (0x0C+XIIC_REG_OFFSET) /* Data Rx Register */ -#define XIIC_ADR_REG_OFFSET (0x10+XIIC_REG_OFFSET) /* Address Register */ -#define XIIC_TFO_REG_OFFSET (0x14+XIIC_REG_OFFSET) /* Tx FIFO Occupancy */ -#define XIIC_RFO_REG_OFFSET (0x18+XIIC_REG_OFFSET) /* Rx FIFO Occupancy */ -#define XIIC_TBA_REG_OFFSET (0x1C+XIIC_REG_OFFSET) /* 10 Bit Address reg */ -#define XIIC_RFD_REG_OFFSET (0x20+XIIC_REG_OFFSET) /* Rx FIFO Depth reg */ -#define XIIC_GPO_REG_OFFSET (0x24+XIIC_REG_OFFSET) /* Output Register */ +#define XIIC_CR_REG_OFFSET (0x00 + XIIC_REG_OFFSET) /* Control Register */ +#define XIIC_SR_REG_OFFSET (0x04 + XIIC_REG_OFFSET) /* Status Register */ +#define XIIC_DTR_REG_OFFSET (0x08 + XIIC_REG_OFFSET) /* Data Tx Register */ +#define XIIC_DRR_REG_OFFSET (0x0C + XIIC_REG_OFFSET) /* Data Rx Register */ +#define XIIC_ADR_REG_OFFSET (0x10 + XIIC_REG_OFFSET) /* Address Register */ +#define XIIC_TFO_REG_OFFSET (0x14 + XIIC_REG_OFFSET) /* Tx FIFO Occupancy */ +#define XIIC_RFO_REG_OFFSET (0x18 + XIIC_REG_OFFSET) /* Rx FIFO Occupancy */ +#define XIIC_TBA_REG_OFFSET (0x1C + XIIC_REG_OFFSET) /* 10 Bit Address reg */ +#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 */ @@ -144,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 @@ -160,6 +230,11 @@ struct xiic_i2c { #define XIIC_PM_TIMEOUT 1000 /* ms */ /* timeout waiting for the controller to respond */ #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 * register, to enable all interrupts for the device, this is the only bit @@ -170,9 +245,32 @@ struct xiic_i2c { #define xiic_tx_space(i2c) ((i2c)->tx_msg->len - (i2c)->tx_pos) #define xiic_rx_space(i2c) ((i2c)->rx_msg->len - (i2c)->rx_pos) -static int xiic_start_xfer(struct xiic_i2c *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. @@ -230,18 +328,21 @@ static inline int xiic_getreg32(struct xiic_i2c *i2c, int reg) static inline void xiic_irq_dis(struct xiic_i2c *i2c, u32 mask) { u32 ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET); + xiic_setreg32(i2c, XIIC_IIER_OFFSET, ier & ~mask); } static inline void xiic_irq_en(struct xiic_i2c *i2c, u32 mask) { u32 ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET); + xiic_setreg32(i2c, XIIC_IIER_OFFSET, ier | mask); } static inline void xiic_irq_clr(struct xiic_i2c *i2c, u32 mask) { u32 isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET); + xiic_setreg32(i2c, XIIC_IISR_OFFSET, isr & mask); } @@ -270,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); @@ -291,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); @@ -309,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; - 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); + /* 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; + + 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) @@ -347,27 +681,48 @@ 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) == 0) && (i2c->nmsgs == 1)) { + + 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; } } -static void xiic_wakeup(struct xiic_i2c *i2c, int code) +static void xiic_wakeup(struct xiic_i2c *i2c, enum xilinx_i2c_state code) { i2c->tx_msg = NULL; i2c->rx_msg = NULL; i2c->nmsgs = 0; i2c->state = code; - wake_up(&i2c->wait); + complete(&i2c->completion); } static irqreturn_t xiic_process(int irq, void *dev_id) @@ -375,6 +730,10 @@ static irqreturn_t xiic_process(int irq, void *dev_id) struct xiic_i2c *i2c = dev_id; u32 pend, isr, ier; u32 clr = 0; + int xfer_more = 0; + int wakeup_req = 0; + enum xilinx_i2c_state wakeup_code = STATE_DONE; + int ret; /* Get the interrupt Status from the IPIF. There is no clearing of * interrupts in the IPIF. Interrupts must be cleared at the source. @@ -391,12 +750,14 @@ 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) || - ((pend & XIIC_INTR_TX_ERROR_MASK) && - !(pend & XIIC_INTR_RX_FULL_MASK))) { + ((pend & XIIC_INTR_TX_ERROR_MASK) && + !(pend & XIIC_INTR_RX_FULL_MASK))) { /* bus arbritration lost, or... * Transmit error _OR_ RX completed * if this happens when RX_FULL is not set @@ -409,12 +770,20 @@ static irqreturn_t xiic_process(int irq, void *dev_id) * fifos and the next message is a TX with len 0 (only addr) * reset the IP instead of just flush fifos */ - xiic_reinit(i2c); + ret = xiic_reinit(i2c); + if (ret < 0) + dev_dbg(i2c->adap.dev.parent, "reinit failed\n"); - if (i2c->rx_msg) - xiic_wakeup(i2c, STATE_ERROR); - if (i2c->tx_msg) - xiic_wakeup(i2c, STATE_ERROR); + if (i2c->rx_msg) { + wakeup_req = 1; + wakeup_code = STATE_ERROR; + } + if (i2c->tx_msg) { + 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 */ @@ -448,27 +817,10 @@ static irqreturn_t xiic_process(int irq, void *dev_id) i2c->tx_msg++; dev_dbg(i2c->adap.dev.parent, "%s will start next...\n", __func__); - - __xiic_start_xfer(i2c); + xfer_more = 1; } } } - if (pend & XIIC_INTR_BNB_MASK) { - /* IIC bus has transitioned to not busy */ - clr |= XIIC_INTR_BNB_MASK; - - /* The bus is not busy, disable BusNotBusy interrupt */ - xiic_irq_dis(i2c, XIIC_INTR_BNB_MASK); - - if (!i2c->tx_msg) - goto out; - - if ((i2c->nmsgs == 1) && !i2c->rx_msg && - xiic_tx_space(i2c) == 0) - xiic_wakeup(i2c, STATE_DONE); - else - xiic_wakeup(i2c, STATE_ERROR); - } if (pend & (XIIC_INTR_TX_EMPTY_MASK | XIIC_INTR_TX_HALF_MASK)) { /* Transmit register/FIFO is empty or ½ empty */ @@ -481,17 +833,20 @@ 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++; - __xiic_start_xfer(i2c); + xfer_more = 1; } else { xiic_irq_dis(i2c, XIIC_INTR_TX_HALF_MASK); @@ -499,16 +854,45 @@ 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) { + /* IIC bus has transitioned to not busy */ + clr |= XIIC_INTR_BNB_MASK; + + /* 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; + + wakeup_req = 1; + + if (i2c->nmsgs == 1 && !i2c->rx_msg && + xiic_tx_space(i2c) == 0) + wakeup_code = STATE_DONE; + else + wakeup_code = STATE_ERROR; + } + out: dev_dbg(i2c->adap.dev.parent, "%s clr: 0x%x\n", __func__, clr); xiic_setreg32(i2c, XIIC_IISR_OFFSET, clr); + if (xfer_more) + __xiic_start_xfer(i2c); + if (wakeup_req) + xiic_wakeup(i2c, wakeup_code); + + WARN_ON(xfer_more && wakeup_req); + mutex_unlock(&i2c->lock); return IRQ_HANDLED; } @@ -520,67 +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) - 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) { - u8 rx_watermark; + u16 rx_watermark; + u8 cr = 0, rfd_set = 0; struct i2c_msg *msg = i2c->rx_msg = i2c->tx_msg; - unsigned long flags; - /* 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, rx_watermark - 1); + if (rx_watermark > 0) + bytes--; + xiic_setreg8(i2c, XIIC_RFD_REG_OFFSET, bytes); - local_irq_save(flags); - 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); + + /* If last message, include dynamic stop bit with length */ + val = (i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0; + val |= msg->len; - xiic_irq_clr_en(i2c, XIIC_INTR_BNB_MASK); + xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, val); - xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, - msg->len | ((i2c->nmsgs == 1) ? XIIC_TX_DYN_STOP_MASK : 0)); - local_irq_restore(flags); + 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 */ @@ -588,112 +1069,253 @@ 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; - xiic_irq_clr(i2c, XIIC_INTR_TX_ERROR_MASK); - - 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); - } - xiic_fill_tx_fifo(i2c); + /* 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)); - /* 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); -} + 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; -static irqreturn_t xiic_isr(int irq, void *dev_id) -{ - struct xiic_i2c *i2c = dev_id; - u32 pend, isr, ier; - irqreturn_t ret = IRQ_NONE; - /* Do not processes a devices interrupts if the device has no - * interrupts pending - */ + 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)); + } - dev_dbg(i2c->adap.dev.parent, "%s entry\n", __func__); + /* Write address to FIFO */ + data = i2c_8bit_addr_from_msg(msg); + xiic_setreg16(i2c, XIIC_DTR_REG_OFFSET, data); - isr = xiic_getreg32(i2c, XIIC_IISR_OFFSET); - ier = xiic_getreg32(i2c, XIIC_IIER_OFFSET); - pend = isr & ier; - if (pend) - ret = IRQ_WAKE_THREAD; + /* Fill fifo */ + xiic_fill_tx_fifo(i2c); - return ret; + 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); + } + + i2c->prev_msg_tx = true; + + if (i2c->atomic && !i2c->atomic_xfer_state) + xiic_send_rem_atomic(i2c); } static void __xiic_start_xfer(struct xiic_i2c *i2c) { - int first = 1; 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; - while ((fifo_space >= 2) && (first || (i2c->nmsgs > 1))) { - if (!first) { - i2c->nmsgs--; - i2c->tx_msg++; - i2c->tx_pos = 0; - } else - first = 0; - - if (i2c->tx_msg->flags & I2C_M_RD) { - /* we dont date putting several reads in the FIFO */ - xiic_start_recv(i2c); - return; - } else { - xiic_start_send(i2c); - if (xiic_tx_space(i2c) != 0) { - /* the message could not be completely sent */ - break; - } - } + if (i2c->tx_msg->flags & I2C_M_RD) { + /* we dont date putting several reads in the FIFO */ + xiic_start_recv(i2c); + } else { + xiic_start_send(i2c); + } +} + +static int xiic_start_xfer(struct xiic_i2c *i2c, struct i2c_msg *msgs, int num) +{ + bool broken_read, max_read_len, smbus_blk_read; + int ret, count; - fifo_space = xiic_tx_fifo_space(i2c); + if (i2c->atomic) + spin_lock(&i2c->atomic_lock); + else + mutex_lock(&i2c->lock); + + if (i2c->tx_msg || i2c->rx_msg) { + dev_err(i2c->adap.dev.parent, + "cannot start a transfer while busy\n"); + ret = -EBUSY; + goto out; } - /* there are more messages or the current one could not be completely - * put into the FIFO, also enable the half empty interrupt + 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->nmsgs > 1 || xiic_tx_space(i2c)) - xiic_irq_clr_en(i2c, XIIC_INTR_TX_HALF_MASK); + 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; -static int xiic_start_xfer(struct xiic_i2c *i2c) -{ - int ret; - mutex_lock(&i2c->lock); + 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); - mutex_unlock(&i2c->lock); +out: + if (i2c->atomic) + spin_unlock(&i2c->atomic_lock); + else + mutex_unlock(&i2c->lock); return ret; } @@ -710,63 +1332,100 @@ static int xiic_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (err < 0) return err; - err = xiic_busy(i2c); - if (err) - goto out; - - i2c->tx_msg = msgs; - i2c->nmsgs = num; - - err = xiic_start_xfer(i2c); - if (err < 0) { - dev_err(adap->dev.parent, "Error xiic_start_xfer\n"); + err = xiic_start_xfer(i2c, msgs, num); + if (err < 0) goto out; - } - if (wait_event_timeout(i2c->wait, (i2c->state == STATE_ERROR) || - (i2c->state == STATE_DONE), HZ)) { - err = (i2c->state == STATE_DONE) ? num : -EIO; - goto out; - } else { + err = wait_for_completion_timeout(&i2c->completion, XIIC_XFER_TIMEOUT); + mutex_lock(&i2c->lock); + if (err == 0) { /* Timeout */ i2c->tx_msg = NULL; i2c->rx_msg = NULL; i2c->nmsgs = 0; err = -ETIMEDOUT; - goto out; + } else { + err = (i2c->state == STATE_DONE) ? num : -EIO; } + mutex_unlock(&i2c->lock); + out: - pm_runtime_mark_last_busy(i2c->dev); 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, - .name = DRIVER_NAME, .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; @@ -776,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); @@ -793,32 +1458,38 @@ static int xiic_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&i2c->adap, i2c); i2c->adap.dev.parent = &pdev->dev; i2c->adap.dev.of_node = pdev->dev.of_node; + snprintf(i2c->adap.name, sizeof(i2c->adap.name), + DRIVER_NAME " %s", pdev->name); mutex_init(&i2c->lock); - init_waitqueue_head(&i2c->wait); + 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); - ret = devm_request_threaded_irq(&pdev->dev, irq, xiic_isr, + + /* 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 = @@ -838,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) { @@ -855,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; @@ -872,58 +1546,28 @@ static int xiic_i2c_remove(struct platform_device *pdev) /* remove adapter & data */ i2c_del_adapter(&i2c->adap); - ret = pm_runtime_resume_and_get(i2c->dev); + ret = pm_runtime_get_sync(i2c->dev); + if (ret < 0) - return ret; + dev_warn(&pdev->dev, "Failed to activate device for removal (%pe)\n", + ERR_PTR(ret)); + else + xiic_deinit(i2c); - 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 = { SET_RUNTIME_PM_OPS(xiic_i2c_runtime_suspend, xiic_i2c_runtime_resume, NULL) }; + 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), @@ -933,7 +1577,7 @@ static struct platform_driver xiic_i2c_driver = { module_platform_driver(xiic_i2c_driver); +MODULE_ALIAS("platform:" DRIVER_NAME); MODULE_AUTHOR("info@mocean-labs.com"); MODULE_DESCRIPTION("Xilinx I2C bus driver"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:"DRIVER_NAME); diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index f2241cedf5d3..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, }; @@ -517,7 +517,7 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev) return PTR_ERR(priv->base); priv->irq = platform_get_irq(pdev, 0); - if (priv->irq <= 0) + if (priv->irq < 0) return priv->irq; /* SMBAlert irq */ priv->alert_data.irq = platform_get_irq(pdev, 1); @@ -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,16 +566,8 @@ 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; } -static const struct of_device_id xlp9xx_i2c_of_match[] = { - { .compatible = "netlogic,xlp980-i2c", }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, xlp9xx_i2c_of_match); - #ifdef CONFIG_ACPI static const struct acpi_device_id xlp9xx_i2c_acpi_ids[] = { {"BRCM9007", 0}, @@ -592,7 +582,6 @@ static struct platform_driver xlp9xx_i2c_driver = { .remove = xlp9xx_i2c_remove, .driver = { .name = "xlp9xx-i2c", - .of_match_table = xlp9xx_i2c_of_match, .acpi_match_table = ACPI_PTR(xlp9xx_i2c_acpi_ids), }, }; diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c deleted file mode 100644 index 126d1393e548..000000000000 --- a/drivers/i2c/busses/i2c-xlr.c +++ /dev/null @@ -1,466 +0,0 @@ -/* - * Copyright 2011, Netlogic Microsystems Inc. - * Copyright 2004, Matt Porter <mporter@kernel.crashing.org> - * - * This file is licensed under the terms of the GNU General Public - * License version 2. This program is licensed "as is" without any - * warranty of any kind, whether express or implied. - */ - -#include <linux/err.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/ioport.h> -#include <linux/delay.h> -#include <linux/errno.h> -#include <linux/i2c.h> -#include <linux/io.h> -#include <linux/platform_device.h> -#include <linux/of_device.h> -#include <linux/clk.h> -#include <linux/interrupt.h> -#include <linux/wait.h> - -/* XLR I2C REGISTERS */ -#define XLR_I2C_CFG 0x00 -#define XLR_I2C_CLKDIV 0x01 -#define XLR_I2C_DEVADDR 0x02 -#define XLR_I2C_ADDR 0x03 -#define XLR_I2C_DATAOUT 0x04 -#define XLR_I2C_DATAIN 0x05 -#define XLR_I2C_STATUS 0x06 -#define XLR_I2C_STARTXFR 0x07 -#define XLR_I2C_BYTECNT 0x08 -#define XLR_I2C_HDSTATIM 0x09 - -/* Sigma Designs additional registers */ -#define XLR_I2C_INT_EN 0x09 -#define XLR_I2C_INT_STAT 0x0a - -/* XLR I2C REGISTERS FLAGS */ -#define XLR_I2C_BUS_BUSY 0x01 -#define XLR_I2C_SDOEMPTY 0x02 -#define XLR_I2C_RXRDY 0x04 -#define XLR_I2C_ACK_ERR 0x08 -#define XLR_I2C_ARB_STARTERR 0x30 - -/* Register Values */ -#define XLR_I2C_CFG_ADDR 0xF8 -#define XLR_I2C_CFG_NOADDR 0xFA -#define XLR_I2C_STARTXFR_ND 0x02 /* No Data */ -#define XLR_I2C_STARTXFR_RD 0x01 /* Read */ -#define XLR_I2C_STARTXFR_WR 0x00 /* Write */ - -#define XLR_I2C_TIMEOUT 10 /* timeout per byte in msec */ - -/* - * On XLR/XLS, we need to use __raw_ IO to read the I2C registers - * because they are in the big-endian MMIO area on the SoC. - * - * The readl/writel implementation on XLR/XLS byteswaps, because - * those are for its little-endian PCI space (see arch/mips/Kconfig). - */ -static inline void xlr_i2c_wreg(u32 __iomem *base, unsigned int reg, u32 val) -{ - __raw_writel(val, base + reg); -} - -static inline u32 xlr_i2c_rdreg(u32 __iomem *base, unsigned int reg) -{ - return __raw_readl(base + reg); -} - -#define XLR_I2C_FLAG_IRQ 1 - -struct xlr_i2c_config { - u32 flags; /* optional feature support */ - u32 status_busy; /* value of STATUS[0] when busy */ - u32 cfg_extra; /* extra CFG bits to set */ -}; - -struct xlr_i2c_private { - struct i2c_adapter adap; - u32 __iomem *iobase; - int irq; - int pos; - struct i2c_msg *msg; - const struct xlr_i2c_config *cfg; - wait_queue_head_t wait; - struct clk *clk; -}; - -static int xlr_i2c_busy(struct xlr_i2c_private *priv, u32 status) -{ - return (status & XLR_I2C_BUS_BUSY) == priv->cfg->status_busy; -} - -static int xlr_i2c_idle(struct xlr_i2c_private *priv) -{ - return !xlr_i2c_busy(priv, xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS)); -} - -static int xlr_i2c_wait(struct xlr_i2c_private *priv, unsigned long timeout) -{ - int status; - int t; - - t = wait_event_timeout(priv->wait, xlr_i2c_idle(priv), - msecs_to_jiffies(timeout)); - if (!t) - return -ETIMEDOUT; - - status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS); - - return status & XLR_I2C_ACK_ERR ? -EIO : 0; -} - -static void xlr_i2c_tx_irq(struct xlr_i2c_private *priv, u32 status) -{ - struct i2c_msg *msg = priv->msg; - - if (status & XLR_I2C_SDOEMPTY) - xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, - msg->buf[priv->pos++]); -} - -static void xlr_i2c_rx_irq(struct xlr_i2c_private *priv, u32 status) -{ - struct i2c_msg *msg = priv->msg; - - if (status & XLR_I2C_RXRDY) - msg->buf[priv->pos++] = - xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN); -} - -static irqreturn_t xlr_i2c_irq(int irq, void *dev_id) -{ - struct xlr_i2c_private *priv = dev_id; - struct i2c_msg *msg = priv->msg; - u32 int_stat, status; - - int_stat = xlr_i2c_rdreg(priv->iobase, XLR_I2C_INT_STAT); - if (!int_stat) - return IRQ_NONE; - - xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_STAT, int_stat); - - if (!msg) - return IRQ_HANDLED; - - status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS); - - if (priv->pos < msg->len) { - if (msg->flags & I2C_M_RD) - xlr_i2c_rx_irq(priv, status); - else - xlr_i2c_tx_irq(priv, status); - } - - if (!xlr_i2c_busy(priv, status)) - wake_up(&priv->wait); - - return IRQ_HANDLED; -} - -static int xlr_i2c_tx(struct xlr_i2c_private *priv, u16 len, - u8 *buf, u16 addr) -{ - struct i2c_adapter *adap = &priv->adap; - unsigned long timeout, stoptime, checktime; - u32 i2c_status; - int pos, timedout; - u8 offset; - u32 xfer; - - offset = buf[0]; - xlr_i2c_wreg(priv->iobase, XLR_I2C_ADDR, offset); - xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr); - xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, - XLR_I2C_CFG_ADDR | priv->cfg->cfg_extra); - - timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT); - stoptime = jiffies + timeout; - timedout = 0; - - if (len == 1) { - xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1); - xfer = XLR_I2C_STARTXFR_ND; - pos = 1; - } else { - xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 2); - xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[1]); - xfer = XLR_I2C_STARTXFR_WR; - pos = 2; - } - - priv->pos = pos; - -retry: - /* retry can only happen on the first byte */ - xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, xfer); - - if (priv->irq > 0) - return xlr_i2c_wait(priv, XLR_I2C_TIMEOUT * len); - - while (!timedout) { - checktime = jiffies; - i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS); - - if ((i2c_status & XLR_I2C_SDOEMPTY) && pos < len) { - xlr_i2c_wreg(priv->iobase, XLR_I2C_DATAOUT, buf[pos++]); - - /* reset timeout on successful xmit */ - stoptime = jiffies + timeout; - } - timedout = time_after(checktime, stoptime); - - if (i2c_status & XLR_I2C_ARB_STARTERR) { - if (timedout) - break; - goto retry; - } - - if (i2c_status & XLR_I2C_ACK_ERR) - return -EIO; - - if (!xlr_i2c_busy(priv, i2c_status) && pos >= len) - return 0; - } - dev_err(&adap->dev, "I2C transmit timeout\n"); - return -ETIMEDOUT; -} - -static int xlr_i2c_rx(struct xlr_i2c_private *priv, u16 len, u8 *buf, u16 addr) -{ - struct i2c_adapter *adap = &priv->adap; - u32 i2c_status; - unsigned long timeout, stoptime, checktime; - int nbytes, timedout; - - xlr_i2c_wreg(priv->iobase, XLR_I2C_CFG, - XLR_I2C_CFG_NOADDR | priv->cfg->cfg_extra); - xlr_i2c_wreg(priv->iobase, XLR_I2C_BYTECNT, len - 1); - xlr_i2c_wreg(priv->iobase, XLR_I2C_DEVADDR, addr); - - priv->pos = 0; - - timeout = msecs_to_jiffies(XLR_I2C_TIMEOUT); - stoptime = jiffies + timeout; - timedout = 0; - nbytes = 0; -retry: - xlr_i2c_wreg(priv->iobase, XLR_I2C_STARTXFR, XLR_I2C_STARTXFR_RD); - - if (priv->irq > 0) - return xlr_i2c_wait(priv, XLR_I2C_TIMEOUT * len); - - while (!timedout) { - checktime = jiffies; - i2c_status = xlr_i2c_rdreg(priv->iobase, XLR_I2C_STATUS); - if (i2c_status & XLR_I2C_RXRDY) { - if (nbytes >= len) - return -EIO; /* should not happen */ - - buf[nbytes++] = - xlr_i2c_rdreg(priv->iobase, XLR_I2C_DATAIN); - - /* reset timeout on successful read */ - stoptime = jiffies + timeout; - } - - timedout = time_after(checktime, stoptime); - if (i2c_status & XLR_I2C_ARB_STARTERR) { - if (timedout) - break; - goto retry; - } - - if (i2c_status & XLR_I2C_ACK_ERR) - return -EIO; - - if (!xlr_i2c_busy(priv, i2c_status)) - return 0; - } - - dev_err(&adap->dev, "I2C receive timeout\n"); - return -ETIMEDOUT; -} - -static int xlr_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg *msgs, int num) -{ - struct i2c_msg *msg; - int i; - int ret = 0; - struct xlr_i2c_private *priv = i2c_get_adapdata(adap); - - ret = clk_enable(priv->clk); - if (ret) - return ret; - - if (priv->irq) - xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_EN, 0xf); - - - for (i = 0; ret == 0 && i < num; i++) { - msg = &msgs[i]; - priv->msg = msg; - if (msg->flags & I2C_M_RD) - ret = xlr_i2c_rx(priv, msg->len, &msg->buf[0], - msg->addr); - else - ret = xlr_i2c_tx(priv, msg->len, &msg->buf[0], - msg->addr); - } - - if (priv->irq) - xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_EN, 0); - - clk_disable(priv->clk); - priv->msg = NULL; - - return (ret != 0) ? ret : num; -} - -static u32 xlr_func(struct i2c_adapter *adap) -{ - /* Emulate SMBUS over I2C */ - return (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | I2C_FUNC_I2C; -} - -static const struct i2c_algorithm xlr_i2c_algo = { - .master_xfer = xlr_i2c_xfer, - .functionality = xlr_func, -}; - -static const struct i2c_adapter_quirks xlr_i2c_quirks = { - .flags = I2C_AQ_NO_ZERO_LEN, -}; - -static const struct xlr_i2c_config xlr_i2c_config_default = { - .status_busy = XLR_I2C_BUS_BUSY, - .cfg_extra = 0, -}; - -static const struct xlr_i2c_config xlr_i2c_config_tangox = { - .flags = XLR_I2C_FLAG_IRQ, - .status_busy = 0, - .cfg_extra = 1 << 8, -}; - -static const struct of_device_id xlr_i2c_dt_ids[] = { - { - .compatible = "sigma,smp8642-i2c", - .data = &xlr_i2c_config_tangox, - }, - { } -}; -MODULE_DEVICE_TABLE(of, xlr_i2c_dt_ids); - -static int xlr_i2c_probe(struct platform_device *pdev) -{ - const struct of_device_id *match; - struct xlr_i2c_private *priv; - struct clk *clk; - unsigned long clk_rate; - unsigned long clk_div; - u32 busfreq; - int irq; - int ret; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - match = of_match_device(xlr_i2c_dt_ids, &pdev->dev); - if (match) - priv->cfg = match->data; - else - priv->cfg = &xlr_i2c_config_default; - - priv->iobase = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(priv->iobase)) - return PTR_ERR(priv->iobase); - - irq = platform_get_irq(pdev, 0); - - if (irq > 0 && (priv->cfg->flags & XLR_I2C_FLAG_IRQ)) { - priv->irq = irq; - - xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_EN, 0); - xlr_i2c_wreg(priv->iobase, XLR_I2C_INT_STAT, 0xf); - - ret = devm_request_irq(&pdev->dev, priv->irq, xlr_i2c_irq, - IRQF_SHARED, dev_name(&pdev->dev), - priv); - if (ret) - return ret; - - init_waitqueue_head(&priv->wait); - } - - if (of_property_read_u32(pdev->dev.of_node, "clock-frequency", - &busfreq)) - busfreq = I2C_MAX_STANDARD_MODE_FREQ; - - clk = devm_clk_get(&pdev->dev, NULL); - if (!IS_ERR(clk)) { - ret = clk_prepare_enable(clk); - if (ret) - return ret; - - clk_rate = clk_get_rate(clk); - clk_div = DIV_ROUND_UP(clk_rate, 2 * busfreq); - xlr_i2c_wreg(priv->iobase, XLR_I2C_CLKDIV, clk_div); - - clk_disable(clk); - priv->clk = clk; - } - - priv->adap.dev.parent = &pdev->dev; - priv->adap.dev.of_node = pdev->dev.of_node; - priv->adap.owner = THIS_MODULE; - priv->adap.algo_data = priv; - priv->adap.algo = &xlr_i2c_algo; - priv->adap.quirks = &xlr_i2c_quirks; - priv->adap.nr = pdev->id; - priv->adap.class = I2C_CLASS_HWMON; - snprintf(priv->adap.name, sizeof(priv->adap.name), "xlr-i2c"); - - i2c_set_adapdata(&priv->adap, priv); - ret = i2c_add_numbered_adapter(&priv->adap); - if (ret < 0) - return ret; - - platform_set_drvdata(pdev, priv); - dev_info(&priv->adap.dev, "Added I2C Bus.\n"); - return 0; -} - -static int xlr_i2c_remove(struct platform_device *pdev) -{ - struct xlr_i2c_private *priv; - - priv = platform_get_drvdata(pdev); - i2c_del_adapter(&priv->adap); - clk_unprepare(priv->clk); - - return 0; -} - -static struct platform_driver xlr_i2c_driver = { - .probe = xlr_i2c_probe, - .remove = xlr_i2c_remove, - .driver = { - .name = "xlr-i2cbus", - .of_match_table = xlr_i2c_dt_ids, - }, -}; - -module_platform_driver(xlr_i2c_driver); - -MODULE_AUTHOR("Ganesan Ramalingam <ganesanr@netlogicmicro.com>"); -MODULE_DESCRIPTION("XLR/XLS SoC I2C Controller driver"); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:xlr-i2cbus"); 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 6f0aa0ed3241..ed90858a27b7 100644 --- a/drivers/i2c/i2c-core-acpi.c +++ b/drivers/i2c/i2c-core-acpi.c @@ -26,7 +26,7 @@ struct gsb_buffer { union { u16 wdata; u8 bdata; - u8 data[0]; + DECLARE_FLEX_ARRAY(u8, data); }; } __packed; @@ -69,6 +69,38 @@ bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares, } EXPORT_SYMBOL_GPL(i2c_acpi_get_i2c_resource); +static int i2c_acpi_resource_count(struct acpi_resource *ares, void *data) +{ + struct acpi_resource_i2c_serialbus *sb; + int *count = data; + + if (i2c_acpi_get_i2c_resource(ares, &sb)) + *count = *count + 1; + + return 1; +} + +/** + * i2c_acpi_client_count - Count the number of I2cSerialBus resources + * @adev: ACPI device + * + * Returns the number of I2cSerialBus resources in the ACPI-device's + * resource-list; or a negative error code. + */ +int i2c_acpi_client_count(struct acpi_device *adev) +{ + int ret, count = 0; + LIST_HEAD(r); + + ret = acpi_dev_get_resources(adev, &r, i2c_acpi_resource_count, &count); + if (ret < 0) + return ret; + + acpi_dev_free_resource_list(&r); + return count; +} +EXPORT_SYMBOL_GPL(i2c_acpi_client_count); + static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data) { struct i2c_acpi_lookup *lookup = data; @@ -105,6 +137,11 @@ static const struct acpi_device_id i2c_acpi_ignored_device_ids[] = { {} }; +struct i2c_acpi_irq_context { + int irq; + bool wake_capable; +}; + static int i2c_acpi_do_lookup(struct acpi_device *adev, struct i2c_acpi_lookup *lookup) { @@ -112,9 +149,12 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev, struct list_head resource_list; int ret; - if (acpi_bus_get_status(adev) || !adev->status.present) + if (acpi_bus_get_status(adev)) return -EINVAL; + if (!acpi_dev_ready_for_enumeration(adev)) + return -ENODEV; + if (acpi_match_device_ids(adev, i2c_acpi_ignored_device_ids) == 0) return -ENODEV; @@ -133,13 +173,19 @@ static int i2c_acpi_do_lookup(struct acpi_device *adev, return 0; } -static int i2c_acpi_add_resource(struct acpi_resource *ares, void *data) +static int i2c_acpi_add_irq_resource(struct acpi_resource *ares, void *data) { - int *irq = data; + struct i2c_acpi_irq_context *irq_ctx = data; struct resource r; - if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r)) - *irq = i2c_dev_irq_from_resources(&r, 1); + if (irq_ctx->irq > 0) + return 1; + + if (!acpi_dev_resource_interrupt(ares, 0, &r)) + return 1; + + irq_ctx->irq = i2c_dev_irq_from_resources(&r, 1); + irq_ctx->wake_capable = r.flags & IORESOURCE_IRQ_WAKECAPABLE; return 1; /* No need to add resource to the list */ } @@ -147,31 +193,40 @@ static int i2c_acpi_add_resource(struct acpi_resource *ares, void *data) /** * i2c_acpi_get_irq - get device IRQ number from ACPI * @client: Pointer to the I2C client device + * @wake_capable: Set to true if the IRQ is wake capable * * Find the IRQ number used by a specific client device. * * Return: The IRQ number or an error code. */ -int i2c_acpi_get_irq(struct i2c_client *client) +int i2c_acpi_get_irq(struct i2c_client *client, bool *wake_capable) { struct acpi_device *adev = ACPI_COMPANION(&client->dev); struct list_head resource_list; - int irq = -ENOENT; + struct i2c_acpi_irq_context irq_ctx = { + .irq = -ENOENT, + }; int ret; INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, - i2c_acpi_add_resource, &irq); + i2c_acpi_add_irq_resource, &irq_ctx); if (ret < 0) return ret; acpi_dev_free_resource_list(&resource_list); - if (irq == -ENOENT) - irq = acpi_dev_gpio_irq_get(adev, 0); + if (irq_ctx.irq == -ENOENT) + irq_ctx.irq = acpi_dev_gpio_irq_wake_get(adev, 0, &irq_ctx.wake_capable); + + if (irq_ctx.irq < 0) + return irq_ctx.irq; + + if (wake_capable) + *wake_capable = irq_ctx.wake_capable; - return irq; + return irq_ctx.irq; } static int i2c_acpi_get_info(struct acpi_device *adev, @@ -195,13 +250,14 @@ 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; /* The adapter must be present */ - if (acpi_bus_get_device(lookup.adapter_handle, &adapter_adev)) + adapter_adev = acpi_fetch_acpi_dev(lookup.adapter_handle); + if (!adapter_adev) return -ENODEV; if (acpi_bus_get_status(adapter_adev) || !adapter_adev->status.present) @@ -222,6 +278,13 @@ static void i2c_acpi_register_device(struct i2c_adapter *adapter, struct acpi_device *adev, struct i2c_board_info *info) { + /* + * Skip registration on boards where the ACPI tables are + * known to contain bogus I2C devices. + */ + if (acpi_quirk_skip_i2c_client_enumeration(adev)) + return; + adev->power.flags.ignore_parent = true; acpi_device_set_enumerated(adev); @@ -233,13 +296,10 @@ static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, void *data, void **return_value) { struct i2c_adapter *adapter = data; - struct acpi_device *adev; + struct acpi_device *adev = acpi_fetch_acpi_dev(handle); struct i2c_board_info info; - if (acpi_bus_get_device(handle, &adev)) - return AE_OK; - - if (i2c_acpi_get_info(adev, &info, adapter, NULL)) + if (!adev || i2c_acpi_get_info(adev, &info, adapter, NULL)) return AE_OK; i2c_acpi_register_device(adapter, adev, &info); @@ -295,16 +355,33 @@ 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) { struct i2c_acpi_lookup *lookup = data; - struct acpi_device *adev; - - if (acpi_bus_get_device(handle, &adev)) - return AE_OK; + struct acpi_device *adev = acpi_fetch_acpi_dev(handle); - if (i2c_acpi_do_lookup(adev, lookup)) + if (!adev || i2c_acpi_do_lookup(adev, lookup)) return AE_OK; if (lookup->search_handle != lookup->adapter_handle) @@ -316,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; } @@ -366,41 +446,31 @@ u32 i2c_acpi_find_bus_speed(struct device *dev) } EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed); -static int i2c_acpi_find_match_adapter(struct device *dev, const void *data) -{ - struct i2c_adapter *adapter = i2c_verify_adapter(dev); - - if (!adapter) - return 0; - - return ACPI_HANDLE(dev) == (acpi_handle)data; -} - struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle) { + struct i2c_adapter *adapter; struct device *dev; - dev = bus_find_device(&i2c_bus_type, NULL, handle, - i2c_acpi_find_match_adapter); + dev = bus_find_device(&i2c_bus_type, NULL, handle, device_match_acpi_handle); + if (!dev) + return NULL; + + adapter = i2c_verify_adapter(dev); + if (!adapter) + put_device(dev); - return dev ? i2c_verify_adapter(dev) : NULL; + return adapter; } 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, @@ -422,17 +492,24 @@ static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, break; i2c_acpi_register_device(adapter, adev, &info); + put_device(&adapter->dev); break; case ACPI_RECONFIG_DEVICE_REMOVE: if (!acpi_device_enumerated(adev)) 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; } @@ -444,8 +521,8 @@ struct notifier_block i2c_acpi_notifier = { }; /** - * i2c_acpi_new_device - Create i2c-client for the Nth I2cSerialBus resource - * @dev: Device owning the ACPI resources to get the client from + * i2c_acpi_new_device_by_fwnode - Create i2c-client for the Nth I2cSerialBus resource + * @fwnode: fwnode with the ACPI resources to get the client from * @index: Index of ACPI resource to get * @info: describes the I2C device; note this is modified (addr gets set) * Context: can sleep @@ -461,15 +538,20 @@ struct notifier_block i2c_acpi_notifier = { * Returns a pointer to the new i2c-client, or error pointer in case of failure. * Specifically, -EPROBE_DEFER is returned if the adapter is not found. */ -struct i2c_client *i2c_acpi_new_device(struct device *dev, int index, - struct i2c_board_info *info) +struct i2c_client *i2c_acpi_new_device_by_fwnode(struct fwnode_handle *fwnode, + int index, + struct i2c_board_info *info) { - struct acpi_device *adev = ACPI_COMPANION(dev); struct i2c_acpi_lookup lookup; struct i2c_adapter *adapter; + struct acpi_device *adev; LIST_HEAD(resource_list); int ret; + adev = to_acpi_device_node(fwnode); + if (!adev) + return ERR_PTR(-ENODEV); + memset(&lookup, 0, sizeof(lookup)); lookup.info = info; lookup.device_handle = acpi_device_handle(adev); @@ -491,7 +573,17 @@ struct i2c_client *i2c_acpi_new_device(struct device *dev, int index, return i2c_new_client_device(adapter, info); } -EXPORT_SYMBOL_GPL(i2c_acpi_new_device); +EXPORT_SYMBOL_GPL(i2c_acpi_new_device_by_fwnode); + +bool i2c_acpi_waive_d0_probe(struct device *dev) +{ + struct i2c_driver *driver = to_i2c_driver(dev->driver); + struct acpi_device *adev = ACPI_COMPANION(dev); + + return driver->flags & I2C_DRV_ACPI_WAIVE_D0_PROBE && + adev && adev->power.state_for_enumeration >= adev->power.state; +} +EXPORT_SYMBOL_GPL(i2c_acpi_waive_d0_probe); #ifdef CONFIG_ACPI_I2C_OPREGION static int acpi_gsb_i2c_read_bytes(struct i2c_client *client, diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 84f12bf90644..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,15 +490,15 @@ 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_adapter *adap; struct i2c_driver *driver; + bool do_power_on; int status; if (!client) return 0; - adap = client->adapter; client->irq = client->init_irq; if (!client->irq) { @@ -484,15 +509,19 @@ 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 = i2c_acpi_get_irq(client); + irq = fwnode_irq_get(fwnode, 0); + } else if (is_acpi_device_node(fwnode)) { + bool wake_capable; + + irq = i2c_acpi_get_irq(client, &wake_capable); + if (irq > 0 && wake_capable) + 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; } @@ -518,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; } @@ -539,19 +568,13 @@ static int i2c_device_probe(struct device *dev) dev_dbg(dev, "probe\n"); - if (adap->bus_regulator) { - status = regulator_enable(adap->bus_regulator); - if (status < 0) { - dev_err(&adap->dev, "Failed to enable bus regulator\n"); - goto err_clear_wakeup_irq; - } - } - - 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; - status = dev_pm_domain_attach(&client->dev, true); + do_power_on = !i2c_acpi_waive_d0_probe(dev); + 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; @@ -559,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; @@ -588,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, true); err_clear_wakeup_irq: dev_pm_clear_wake_irq(&client->dev); device_init_wakeup(&client->dev, false); @@ -601,29 +619,21 @@ put_sync_adapter: return status; } -static int i2c_device_remove(struct device *dev) +static void i2c_device_remove(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - struct i2c_adapter *adap; struct i2c_driver *driver; - adap = client->adapter; driver = to_i2c_driver(dev->driver); if (driver->remove) { - int status; - dev_dbg(dev, "remove\n"); - status = driver->remove(client); - if (status) - dev_warn(dev, "remove failed (%pe), will be ignored\n", ERR_PTR(status)); + driver->remove(client); } - devres_release_group(&client->dev, client->devres_group_id); + debugfs_remove_recursive(client->debugfs); - dev_pm_domain_detach(&client->dev, true); - if (!pm_runtime_status_suspended(&client->dev) && adap->bus_regulator) - regulator_disable(adap->bus_regulator); + devres_release_group(&client->dev, client->devres_group_id); dev_pm_clear_wake_irq(&client->dev); device_init_wakeup(&client->dev, false); @@ -631,91 +641,8 @@ static int i2c_device_remove(struct device *dev) client->irq = 0; if (client->flags & I2C_CLIENT_HOST_NOTIFY) pm_runtime_put(&client->adapter->dev); - - /* return always 0 because there is WIP to make remove-functions void */ - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int i2c_resume_early(struct device *dev) -{ - struct i2c_client *client = i2c_verify_client(dev); - int err; - - if (!client) - return 0; - - if (pm_runtime_status_suspended(&client->dev) && - client->adapter->bus_regulator) { - err = regulator_enable(client->adapter->bus_regulator); - if (err) - return err; - } - - return pm_generic_resume_early(&client->dev); -} - -static int i2c_suspend_late(struct device *dev) -{ - struct i2c_client *client = i2c_verify_client(dev); - int err; - - if (!client) - return 0; - - err = pm_generic_suspend_late(&client->dev); - if (err) - return err; - - if (!pm_runtime_status_suspended(&client->dev) && - client->adapter->bus_regulator) - return regulator_disable(client->adapter->bus_regulator); - - return 0; -} -#endif - -#ifdef CONFIG_PM -static int i2c_runtime_resume(struct device *dev) -{ - struct i2c_client *client = i2c_verify_client(dev); - int err; - - if (!client) - return 0; - - if (client->adapter->bus_regulator) { - err = regulator_enable(client->adapter->bus_regulator); - if (err) - return err; - } - - return pm_generic_runtime_resume(&client->dev); } -static int i2c_runtime_suspend(struct device *dev) -{ - struct i2c_client *client = i2c_verify_client(dev); - int err; - - if (!client) - return 0; - - err = pm_generic_runtime_suspend(&client->dev); - if (err) - return err; - - if (client->adapter->bus_regulator) - return regulator_disable(client->adapter->bus_regulator); - return 0; -} -#endif - -static const struct dev_pm_ops i2c_device_pm = { - SET_LATE_SYSTEM_SLEEP_PM_OPS(i2c_suspend_late, i2c_resume_early) - SET_RUNTIME_PM_OPS(i2c_runtime_suspend, i2c_runtime_resume, NULL) -}; - static void i2c_device_shutdown(struct device *dev) { struct i2c_client *client = i2c_verify_client(dev); @@ -769,17 +696,16 @@ 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, .remove = i2c_device_remove, .shutdown = i2c_device_shutdown, - .pm = &i2c_device_pm, }; 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, @@ -993,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 @@ -1012,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) @@ -1030,7 +979,7 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf client->init_irq = i2c_dev_irq_from_resources(info->resources, info->num_resources); - strlcpy(client->name, info->type, sizeof(client->name)); + strscpy(client->name, info->type, sizeof(client->name)); status = i2c_check_addr_validity(client->addr, client->flags); if (status) { @@ -1039,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) @@ -1047,10 +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; - i2c_dev_set_name(adap, client, info); + device_enable_async_suspend(&client->dev); + + device_set_node(&client->dev, fwnode_handle_get(fwnode)); if (info->swnode) { status = device_add_software_node(&client->dev, info->swnode); @@ -1058,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; @@ -1069,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); @@ -1092,34 +1053,66 @@ 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; -static const struct i2c_device_id dummy_id[] = { - { "dummy", 0 }, - { }, -}; + if (!fwnode) + return NULL; -static int dummy_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - return 0; + 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 int dummy_remove(struct i2c_client *client) +static const struct i2c_device_id dummy_id[] = { + { "dummy", }, + { "smbus_host_notify", }, + { } +}; + +static int dummy_probe(struct i2c_client *client) { return 0; } @@ -1127,7 +1120,6 @@ static int dummy_remove(struct i2c_client *client) static struct i2c_driver dummy_driver = { .driver.name = "dummy", .probe = dummy_probe, - .remove = dummy_remove, .id_table = dummy_id, }; @@ -1223,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); @@ -1247,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"); @@ -1391,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, }; @@ -1414,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; @@ -1516,11 +1504,13 @@ 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; - generic_handle_irq(irq); + generic_handle_irq_safe(irq); return 0; } @@ -1569,34 +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; } - res = of_i2c_setup_smbus_alert(adap); + adap->debugfs = debugfs_create_dir(dev_name(&adap->dev), i2c_debugfs_root); + + res = i2c_setup_smbus_alert(adap); if (res) goto out_reg; - 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); @@ -1613,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); @@ -1662,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); @@ -1802,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); @@ -1814,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 @@ -1862,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) { @@ -2042,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; @@ -2061,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; @@ -2077,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(); } @@ -2102,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; } @@ -2170,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; @@ -2243,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, @@ -2337,6 +2383,20 @@ int i2c_get_device_id(const struct i2c_client *client, } EXPORT_SYMBOL_GPL(i2c_get_device_id); +/** + * i2c_client_get_device_id - get the driver match table entry of a device + * @client: the device to query. The device must be bound to a driver + * + * Returns a pointer to the matching entry if found, NULL otherwise. + */ +const struct i2c_device_id *i2c_client_get_device_id(const struct i2c_client *client) +{ + const struct i2c_driver *drv = to_i2c_driver(client->dev.driver); + + return i2c_match_id(drv->id_table, client); +} +EXPORT_SYMBOL_GPL(i2c_client_get_device_id); + /* ---------------------------------------------------- * the i2c address scanning function * Will not work for 10-bit addresses! @@ -2469,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) { @@ -2485,6 +2546,7 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) } kfree(temp_client); + return err; } @@ -2562,8 +2624,9 @@ void i2c_put_adapter(struct i2c_adapter *adap) if (!adap) return; - put_device(&adap->dev); module_put(adap->owner); + /* Should be last, otherwise we risk use-after-free with 'adap' */ + put_device(&adap->dev); } EXPORT_SYMBOL(i2c_put_adapter); 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 1589179d5eb9..02ca55c2246b 100644 --- a/drivers/i2c/i2c-core-slave.c +++ b/drivers/i2c/i2c-core-slave.c @@ -11,9 +11,13 @@ #include <linux/err.h> #include <linux/i2c.h> #include <linux/of.h> +#include <linux/property.h> #include "i2c-core.h" +#define CREATE_TRACE_POINTS +#include <trace/events/i2c_slave.h> + int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb) { int ret; @@ -79,6 +83,18 @@ int i2c_slave_unregister(struct i2c_client *client) } EXPORT_SYMBOL_GPL(i2c_slave_unregister); +int i2c_slave_event(struct i2c_client *client, + enum i2c_slave_event event, u8 *val) +{ + int ret = client->slave_cb(client, event, val); + + if (trace_i2c_slave_enabled()) + trace_i2c_slave(client, event, val, ret); + + return ret; +} +EXPORT_SYMBOL_GPL(i2c_slave_event); + /** * i2c_detect_slave_mode - detect operation mode * @dev: The device owning the bus @@ -93,18 +109,17 @@ EXPORT_SYMBOL_GPL(i2c_slave_unregister); */ 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 e5b2d1465e7e..71eb1ef56f0c 100644 --- a/drivers/i2c/i2c-core-smbus.c +++ b/drivers/i2c/i2c-core-smbus.c @@ -14,7 +14,9 @@ #include <linux/err.h> #include <linux/i2c.h> #include <linux/i2c-smbus.h> +#include <linux/property.h> #include <linux/slab.h> +#include <linux/string_choices.h> #include "i2c-core.h" @@ -121,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); @@ -432,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; } @@ -701,19 +703,25 @@ struct i2c_client *i2c_new_smbus_alert_device(struct i2c_adapter *adapter, } EXPORT_SYMBOL_GPL(i2c_new_smbus_alert_device); -#if IS_ENABLED(CONFIG_I2C_SMBUS) && IS_ENABLED(CONFIG_OF) -int of_i2c_setup_smbus_alert(struct i2c_adapter *adapter) +#if IS_ENABLED(CONFIG_I2C_SMBUS) +int i2c_setup_smbus_alert(struct i2c_adapter *adapter) { + struct device *parent = adapter->dev.parent; int irq; - irq = of_property_match_string(adapter->dev.of_node, "interrupt-names", - "smbus_alert"); - if (irq == -EINVAL || irq == -ENODATA) + /* Adapter instantiated without parent, skip the SMBus alert setup */ + if (!parent) return 0; - else if (irq < 0) + + /* Report serious errors */ + irq = device_property_match_string(parent, "interrupt-names", "smbus_alert"); + 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)); } -EXPORT_SYMBOL_GPL(of_i2c_setup_smbus_alert); #endif diff --git a/drivers/i2c/i2c-core.h b/drivers/i2c/i2c-core.h index 8ce261167a2d..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) @@ -61,11 +63,11 @@ static inline int __i2c_check_suspended(struct i2c_adapter *adap) #ifdef CONFIG_ACPI void i2c_acpi_register_devices(struct i2c_adapter *adap); -int i2c_acpi_get_irq(struct i2c_client *client); +int i2c_acpi_get_irq(struct i2c_client *client, bool *wake_capable); #else /* CONFIG_ACPI */ static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { } -static inline int i2c_acpi_get_irq(struct i2c_client *client) +static inline int i2c_acpi_get_irq(struct i2c_client *client, bool *wake_capable) { return 0; } @@ -82,7 +84,25 @@ 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; + +#if IS_ENABLED(CONFIG_I2C_SMBUS) +int i2c_setup_smbus_alert(struct i2c_adapter *adap); +#else +static inline int i2c_setup_smbus_alert(struct i2c_adapter *adap) +{ + return 0; +} +#endif diff --git a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c index cb64fe649390..e9577f920286 100644 --- a/drivers/i2c/i2c-dev.c +++ b/drivers/i2c/i2c-dev.c @@ -14,6 +14,8 @@ /* The I2C_RDWR ioctl code is written by Kolja Waschk <waschk@telos.de> */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/cdev.h> #include <linux/compat.h> #include <linux/device.h> @@ -68,8 +70,7 @@ static struct i2c_dev *get_free_i2c_dev(struct i2c_adapter *adap) struct i2c_dev *i2c_dev; if (adap->nr >= I2C_MINORS) { - printk(KERN_ERR "i2c-dev: Out of device minors (%d)\n", - adap->nr); + pr_err("Out of device minors (%d)\n", adap->nr); return ERR_PTR(-ENODEV); } @@ -101,7 +102,7 @@ static ssize_t name_show(struct device *dev, if (!i2c_dev) return -ENODEV; - return sprintf(buf, "%s\n", i2c_dev->adap->name); + return sysfs_emit(buf, "%s\n", i2c_dev->adap->name); } static DEVICE_ATTR_RO(name); @@ -138,19 +139,23 @@ 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; - tmp = kmalloc(count, GFP_KERNEL); + tmp = kzalloc(count, GFP_KERNEL); if (tmp == NULL) return -ENOMEM; - pr_debug("i2c-dev: i2c-%d reading %zu bytes.\n", - iminor(file_inode(file)), count); + pr_debug("i2c-%d reading %zu bytes.\n", iminor(file_inode(file)), count); ret = i2c_master_recv(client, tmp, count); if (ret >= 0) - ret = copy_to_user(buf, tmp, count) ? -EFAULT : ret; + if (copy_to_user(buf, tmp, ret)) + ret = -EFAULT; kfree(tmp); return ret; } @@ -162,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; @@ -169,8 +178,7 @@ static ssize_t i2cdev_write(struct file *file, const char __user *buf, if (IS_ERR(tmp)) return PTR_ERR(tmp); - pr_debug("i2c-dev: i2c-%d writing %zu bytes.\n", - iminor(file_inode(file)), count); + pr_debug("i2c-%d writing %zu bytes.\n", iminor(file_inode(file)), count); ret = i2c_master_send(client, tmp, count); kfree(tmp); @@ -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,13 +539,16 @@ 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, sizeof(rdwr_arg))) return -EFAULT; + if (!rdwr_arg.msgs || rdwr_arg.nmsgs == 0) + return -EINVAL; + if (rdwr_arg.nmsgs > I2C_RDWR_IOCTL_MAX_MSGS) return -EINVAL; @@ -554,11 +568,13 @@ static long compat_i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned lo .addr = umsg.addr, .flags = umsg.flags, .len = umsg.len, - .buf = compat_ptr(umsg.buf) + .buf = (__force __u8 *)compat_ptr(umsg.buf), }; } - 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; @@ -622,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, @@ -633,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) { @@ -643,58 +661,62 @@ 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; - dev_set_name(&i2c_dev->dev, "i2c-%d", adap->nr); + + res = dev_set_name(&i2c_dev->dev, "i2c-%d", adap->nr); + if (res) + goto err_put_i2c_dev; res = cdev_device_add(&i2c_dev->cdev, &i2c_dev->dev); - if (res) { - put_i2c_dev(i2c_dev, false); - return res; - } + if (res) + goto err_put_i2c_dev; - pr_debug("i2c-dev: adapter [%s] registered as minor %d\n", - adap->name, adap->nr); - return 0; + pr_debug("adapter [%s] registered as minor %d\n", adap->name, adap->nr); + return NOTIFY_OK; + +err_put_i2c_dev: + put_i2c_dev(i2c_dev, false); + 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("i2c-dev: adapter [%s] unregistered\n", adap->name); - return 0; + pr_debug("adapter [%s] unregistered\n", adap->name); + return NOTIFY_OK; } static int i2cdev_notifier_call(struct notifier_block *nb, unsigned long action, @@ -704,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 = { @@ -718,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 */ @@ -726,18 +760,15 @@ static int __init i2c_dev_init(void) { int res; - printk(KERN_INFO "i2c /dev entries driver\n"); + pr_info("i2c /dev entries driver\n"); res = register_chrdev_region(MKDEV(I2C_MAJOR, 0), I2C_MINORS, "i2c"); 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); @@ -745,24 +776,24 @@ 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: - printk(KERN_ERR "%s: Driver Initialisation failed\n", __FILE__); + pr_err("Driver Initialisation failed\n"); return res; } 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 774507b54b57..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; @@ -243,9 +230,10 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent, int (*deselect)(struct i2c_mux_core *, u32)) { struct i2c_mux_core *muxc; + size_t mux_size; - muxc = devm_kzalloc(dev, struct_size(muxc, adapter, max_adapters) - + sizeof_priv, GFP_KERNEL); + mux_size = struct_size(muxc, adapter, max_adapters); + muxc = devm_kzalloc(dev, size_add(mux_size, sizeof_priv), GFP_KERNEL); if (!muxc) return NULL; if (sizeof_priv) @@ -253,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; @@ -280,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; @@ -306,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) @@ -339,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 5c7ae421cacf..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; @@ -140,8 +140,9 @@ static int i2c_slave_init_eeprom_data(struct eeprom_data *eeprom, struct i2c_cli return 0; } -static int i2c_slave_eeprom_probe(struct i2c_client *client, const struct i2c_device_id *id) +static int i2c_slave_eeprom_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct eeprom_data *eeprom; int ret; unsigned int size = FIELD_GET(I2C_SLAVE_BYTELEN, id->driver_data) + 1; @@ -181,14 +182,12 @@ static int i2c_slave_eeprom_probe(struct i2c_client *client, const struct i2c_de return 0; }; -static int i2c_slave_eeprom_remove(struct i2c_client *client) +static void i2c_slave_eeprom_remove(struct i2c_client *client) { struct eeprom_data *eeprom = i2c_get_clientdata(client); i2c_slave_unregister(client); sysfs_remove_bin_file(&client->dev.kobj, &eeprom->bin); - - return 0; } static const struct i2c_device_id i2c_slave_eeprom_id[] = { diff --git a/drivers/i2c/i2c-slave-testunit.c b/drivers/i2c/i2c-slave-testunit.c index 56dae08dfd48..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; - - msg.addr = I2C_CLIENT_END; - msg.buf = msgbuf; +static char tu_version_info[] = "v" UTS_RELEASE "\n\0"; - 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,22 +243,34 @@ 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); }; -static int i2c_slave_testunit_remove(struct i2c_client *client) +static void i2c_slave_testunit_remove(struct i2c_client *client) { struct testunit_data *tu = i2c_get_clientdata(client); cancel_delayed_work_sync(&tu->worker); i2c_slave_unregister(client); - return 0; } static const struct i2c_device_id i2c_slave_testunit_id[] = { - { "slave-testunit", 0 }, + { "slave-testunit" }, { } }; MODULE_DEVICE_TABLE(i2c, i2c_slave_testunit_id); @@ -172,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 d3d06e3b4f3b..0316b347f9e7 100644 --- a/drivers/i2c/i2c-smbus.c +++ b/drivers/i2c/i2c-smbus.c @@ -8,12 +8,13 @@ #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> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/of_irq.h> +#include <linux/property.h> #include <linux/slab.h> #include <linux/workqueue.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); - /* Stop iterating after we find the device */ - return -EBUSY; + 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); + + 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; @@ -112,12 +163,13 @@ static void smbalert_work(struct work_struct *work) } /* Setup SMBALERT# infrastructure */ -static int smbalert_probe(struct i2c_client *ara, - const struct i2c_device_id *id) +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), @@ -128,19 +180,27 @@ static int smbalert_probe(struct i2c_client *ara, if (setup) { irq = setup->irq; } else { - irq = of_irq_get_byname(adapter->dev.of_node, "smbus_alert"); - if (irq <= 0) - return irq; + irq = fwnode_irq_get_byname(dev_fwnode(adapter->dev.parent), + "smbus_alert"); + 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; } @@ -152,16 +212,15 @@ static int smbalert_probe(struct i2c_client *ara, } /* IRQ and memory resources are managed so they are freed automatically */ -static int smbalert_remove(struct i2c_client *ara) +static void smbalert_remove(struct i2c_client *ara) { struct i2c_smbus_alert *alert = i2c_get_clientdata(ara); cancel_work_sync(&alert->alert); - return 0; } static const struct i2c_device_id smbalert_ids[] = { - { "smbus_alert", 0 }, + { "smbus_alert" }, { /* LIST END */ } }; MODULE_DEVICE_TABLE(i2c, smbalert_ids); @@ -309,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) { @@ -352,18 +412,22 @@ 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 + * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.6.0.pdf + */ switch (common_mem_type) { + case 0x12: /* DDR */ case 0x13: /* DDR2 */ case 0x18: /* DDR3 */ + case 0x1B: /* LPDDR */ case 0x1C: /* LPDDR2 */ case 0x1D: /* LPDDR3 */ name = "spd"; @@ -372,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", @@ -390,10 +459,13 @@ void i2c_register_spd(struct i2c_adapter *adap) unsigned short addr_list[2]; memset(&info, 0, sizeof(struct i2c_board_info)); - strlcpy(info.type, name, I2C_NAME_SIZE); + strscpy(info.type, name, I2C_NAME_SIZE); 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", @@ -402,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 1708b1a82da2..6d2f66810cdc 100644 --- a/drivers/i2c/muxes/Kconfig +++ b/drivers/i2c/muxes/Kconfig @@ -9,7 +9,7 @@ menu "Multiplexer I2C Chip support" config I2C_ARB_GPIO_CHALLENGE tristate "GPIO-based I2C arbitration" depends on GPIOLIB || COMPILE_TEST - depends on OF || COMPILE_TEST + depends on OF help If you say yes to this option, support will be included for an I2C multimaster arbitration scheme using GPIOs and a challenge & @@ -34,7 +34,7 @@ config I2C_MUX_GPIO config I2C_MUX_GPMUX tristate "General Purpose I2C multiplexer" select MULTIPLEXER - depends on OF || COMPILE_TEST + depends on OF help If you say yes to this option, support will be included for a general purpose I2C multiplexer. This driver provides access to @@ -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. @@ -77,7 +77,7 @@ config I2C_MUX_PCA954x config I2C_MUX_PINCTRL tristate "pinctrl-based I2C multiplexer" depends on PINCTRL - depends on OF || COMPILE_TEST + depends on OF help If you say yes to this option, support will be included for an I2C multiplexer that uses the pinctrl subsystem, i.e. pin multiplexing. @@ -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 5365199a31f4..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,25 +245,29 @@ 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) - goto err_rollback; + goto err_rollback_activation; err = device_create_file(&pdev->dev, &dev_attr_current_master); if (err) @@ -271,8 +277,9 @@ static int i2c_demux_pinctrl_probe(struct platform_device *pdev) err_rollback_available: device_remove_file(&pdev->dev, &dev_attr_available_masters); -err_rollback: +err_rollback_activation: i2c_demux_deactivate_master(priv); +err_rollback: for (j = 0; j < i; j++) { of_node_put(priv->chan[j].parent_np); of_changeset_destroy(&priv->chan[j].chgset); @@ -281,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; @@ -295,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[] = { @@ -311,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 bac415a52b78..9b46b84e84fb 100644 --- a/drivers/i2c/muxes/i2c-mux-gpio.c +++ b/drivers/i2c/muxes/i2c-mux-gpio.c @@ -5,16 +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; @@ -22,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)); @@ -37,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; } @@ -49,57 +53,19 @@ static int i2c_mux_gpio_deselect(struct i2c_mux_core *muxc, u32 chan) return 0; } -#ifdef CONFIG_ACPI - -static int i2c_mux_gpio_get_acpi_adr(struct device *dev, - struct fwnode_handle *fwdev, - unsigned int *adr) - -{ - unsigned long long adr64; - acpi_status status; - - status = acpi_evaluate_integer(ACPI_HANDLE_FWNODE(fwdev), - METHOD_NAME__ADR, - NULL, &adr64); - - if (!ACPI_SUCCESS(status)) { - dev_err(dev, "Cannot get address\n"); - return -EINVAL; - } - - *adr = adr64; - if (*adr != adr64) { - dev_err(dev, "Address out of range\n"); - return -ERANGE; - } - - return 0; -} - -#else - -static int i2c_mux_gpio_get_acpi_adr(struct device *dev, - struct fwnode_handle *fwdev, - unsigned int *adr) -{ - return -EINVAL; -} - -#endif - static int i2c_mux_gpio_probe_fw(struct gpiomux *mux, struct platform_device *pdev) { struct device *dev = &pdev->dev; + struct fwnode_handle *fwnode = dev_fwnode(dev); struct device_node *np = dev->of_node; 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(dev->fwnode)) { + if (is_of_node(fwnode)) { if (!np) return -ENODEV; @@ -111,7 +77,7 @@ static int i2c_mux_gpio_probe_fw(struct gpiomux *mux, adapter = of_find_i2c_adapter_by_node(adapter_np); of_node_put(adapter_np); - } else if (is_acpi_node(dev->fwnode)) { + } else if (is_acpi_node(fwnode)) { /* * In ACPI land the mux should be a direct child of the i2c * bus it muxes. @@ -139,20 +105,23 @@ 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 = i2c_mux_gpio_get_acpi_adr(dev, child, values + i); - if (rc) - return rc; + rc = acpi_get_local_address(ACPI_HANDLE_FWNODE(child), values + i); + if (rc) { + fwnode_handle_put(child); + return dev_err_probe(dev, rc, "Cannot get address\n"); + } } i++; } mux->data.values = values; - if (fwnode_property_read_u32(dev->fwnode, "idle-state", &mux->data.idle)) + 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; } @@ -162,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); @@ -190,7 +159,7 @@ static int i2c_mux_gpio_probe(struct platform_device *pdev) return -EPROBE_DEFER; muxc = i2c_mux_alloc(parent, &pdev->dev, mux->data.n_values, - ngpios * sizeof(*mux->gpios), 0, + array_size(ngpios, sizeof(*mux->gpios)), 0, i2c_mux_gpio_select, NULL); if (!muxc) { ret = -ENOMEM; @@ -213,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; @@ -232,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) @@ -242,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; } @@ -262,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[] = { @@ -280,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 d3acd8d66c32..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; } @@ -134,6 +134,7 @@ static int i2c_mux_probe(struct platform_device *pdev) return 0; err_children: + of_node_put(child); i2c_mux_del_adapters(muxc); err_parent: i2c_put_adapter(parent); @@ -141,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 704f1e50f6f4..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; @@ -294,21 +293,19 @@ static int ltc4306_probe(struct i2c_client *client) return 0; } -static int ltc4306_remove(struct i2c_client *client) +static void ltc4306_remove(struct i2c_client *client) { struct i2c_mux_core *muxc = i2c_get_clientdata(client); i2c_mux_del_adapters(muxc); - - return 0; } 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 6daec8d3d331..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; } @@ -283,8 +283,7 @@ static int pca9541_release_chan(struct i2c_mux_core *muxc, u32 chan) /* * I2C init/probing/exit functions */ -static int pca9541_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int pca9541_probe(struct i2c_client *client) { struct i2c_adapter *adap = client->adapter; struct i2c_mux_core *muxc; @@ -315,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; @@ -325,12 +324,11 @@ static int pca9541_probe(struct i2c_client *client, return 0; } -static int pca9541_remove(struct i2c_client *client) +static void pca9541_remove(struct i2c_client *client) { struct i2c_mux_core *muxc = i2c_get_clientdata(client); i2c_mux_del_adapters(muxc); - return 0; } static struct i2c_driver pca9541_driver = { diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 4ad665757dd8..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,22 +487,77 @@ 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 */ -static int pca954x_probe(struct i2c_client *client, - const struct i2c_device_id *id) +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; } @@ -521,17 +674,15 @@ fail_cleanup: return ret; } -static int pca954x_remove(struct i2c_client *client) +static void pca954x_remove(struct i2c_client *client) { struct i2c_mux_core *muxc = i2c_get_clientdata(client); device_remove_file(&client->dev, &dev_attr_idle_state); pca954x_cleanup(muxc); - return 0; } -#ifdef CONFIG_PM_SLEEP static int pca954x_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); @@ -545,14 +696,13 @@ 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 = pca954x_probe, diff --git a/drivers/i2c/muxes/i2c-mux-pinctrl.c b/drivers/i2c/muxes/i2c-mux-pinctrl.c index f1bb00a11ad6..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[] = { @@ -185,10 +183,10 @@ MODULE_DEVICE_TABLE(of, i2c_mux_pinctrl_of_match); static struct platform_driver i2c_mux_pinctrl_driver = { .driver = { .name = "i2c-mux-pinctrl", - .of_match_table = of_match_ptr(i2c_mux_pinctrl_of_match), + .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 0e0679f65cf7..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); @@ -183,13 +182,12 @@ static int i2c_mux_reg_probe(struct platform_device *pdev) if (!mux->data.reg) { dev_info(&pdev->dev, "Register not set, using platform resource\n"); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - mux->data.reg_size = resource_size(res); - mux->data.reg = devm_ioremap_resource(&pdev->dev, res); + mux->data.reg = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(mux->data.reg)) { ret = PTR_ERR(mux->data.reg); goto err_put_parent; } + mux->data.reg_size = resource_size(res); } if (mux->data.reg_size != 4 && mux->data.reg_size != 2 && @@ -214,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; } @@ -234,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[] = { @@ -252,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, }, }; |
