diff --git a/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt b/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt index 71191ff0e781..248a155414c2 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-arb-gpio-challenge.txt @@ -44,8 +44,7 @@ Required properties: - our-claim-gpio: The GPIO that we use to claim the bus. - their-claim-gpios: The GPIOs that the other sides use to claim the bus. Note that some implementations may only support a single other master. -- Standard I2C mux properties. See i2c-mux.txt in this directory. -- Single I2C child bus node at reg 0. See i2c-mux.txt in this directory. +- I2C arbitration bus node. See i2c-arb.txt in this directory. Optional properties: - slew-delay-us: microseconds to wait for a GPIO to go high. Default is 10 us. @@ -63,8 +62,6 @@ Example: i2c-arbitrator { compatible = "i2c-arb-gpio-challenge"; - #address-cells = <1>; - #size-cells = <0>; i2c-parent = <&{/i2c@12CA0000}>; @@ -74,8 +71,7 @@ Example: wait-retry-us = <3000>; wait-free-us = <50000>; - i2c@0 { - reg = <0>; + i2c-arb { #address-cells = <1>; #size-cells = <0>; diff --git a/Documentation/devicetree/bindings/i2c/i2c-arb.txt b/Documentation/devicetree/bindings/i2c/i2c-arb.txt new file mode 100644 index 000000000000..59abf9277bdc --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-arb.txt @@ -0,0 +1,35 @@ +Common i2c arbitration bus properties. + +- i2c-arb child node + +Required properties for the i2c-arb child node: +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties for i2c-arb child node: +- Child nodes conforming to i2c bus binding + + +Example : + + /* + An NXP pca9541 I2C bus master selector at address 0x74 + with a NXP pca8574 GPIO expander attached. + */ + + arb@74 { + compatible = "nxp,pca9541"; + reg = <0x74>; + + i2c-arb { + #address-cells = <1>; + #size-cells = <0>; + + gpio@38 { + compatible = "nxp,pca8574"; + reg = <0x38>; + #gpio-cells = <2>; + gpio-controller; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/i2c/i2c-gate.txt b/Documentation/devicetree/bindings/i2c/i2c-gate.txt new file mode 100644 index 000000000000..1846d236e656 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-gate.txt @@ -0,0 +1,41 @@ +An i2c gate is useful to e.g. reduce the digital noise for RF tuners connected +to the i2c bus. Gates are similar to arbitrators in that you need to perform +some kind of operation to access the i2c bus past the arbitrator/gate, but +there are no competing masters to consider for gates and therefore there is +no arbitration happening for gates. + +Common i2c gate properties. + +- i2c-gate child node + +Required properties for the i2c-gate child node: +- #address-cells = <1>; +- #size-cells = <0>; + +Optional properties for i2c-gate child node: +- Child nodes conforming to i2c bus binding + + +Example : + + /* + An Invensense mpu9150 at address 0x68 featuring an on-chip Asahi + Kasei ak8975 compass behind a gate. + */ + + mpu9150@68 { + compatible = "invensense,mpu9150"; + reg = <0x68>; + interrupt-parent = <&gpio1>; + interrupts = <18 1>; + + i2c-gate { + #address-cells = <1>; + #size-cells = <0>; + + ax8975@c { + compatible = "ak,ak8975"; + reg = <0x0c>; + }; + }; + }; diff --git a/Documentation/devicetree/bindings/i2c/i2c-meson.txt b/Documentation/devicetree/bindings/i2c/i2c-meson.txt index 682f9a6f766e..386357d1aab0 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-meson.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-meson.txt @@ -1,7 +1,7 @@ Amlogic Meson I2C controller Required properties: - - compatible: must be "amlogic,meson6-i2c" + - compatible: must be "amlogic,meson6-i2c" or "amlogic,meson-gxbb-i2c" - reg: physical address and length of the device registers - interrupts: a single interrupt specifier - clocks: clock for the device diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux.txt b/Documentation/devicetree/bindings/i2c/i2c-mux.txt index af84cce5cd7b..212e6779dc5c 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mux.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mux.txt @@ -2,19 +2,32 @@ Common i2c bus multiplexer/switch properties. An i2c bus multiplexer/switch will have several child busses that are numbered uniquely in a device dependent manner. The nodes for an i2c bus -multiplexer/switch will have one child node for each child -bus. +multiplexer/switch will have one child node for each child bus. -Required properties: +Optional properties: +- #address-cells = <1>; + This property is required is the i2c-mux child node does not exist. + +- #size-cells = <0>; + This property is required is the i2c-mux child node does not exist. + +- i2c-mux + For i2c multiplexers/switches that have child nodes that are a mixture + of both i2c child busses and other child nodes, the 'i2c-mux' subnode + can be used for populating the i2c child busses. If an 'i2c-mux' + subnode is present, only subnodes of this will be considered as i2c + child busses. + +Required properties for the i2c-mux child node: - #address-cells = <1>; - #size-cells = <0>; -Required properties for child nodes: +Required properties for i2c child bus nodes: - #address-cells = <1>; - #size-cells = <0>; - reg : The sub-bus number. -Optional properties for child nodes: +Optional properties for i2c child bus nodes: - Other properties specific to the multiplexer/switch hardware. - Child nodes conforming to i2c bus binding diff --git a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt index 5f0cb502b1db..239632a0d709 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-rcar.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-rcar.txt @@ -11,6 +11,7 @@ Required properties: "renesas,i2c-r8a7793" "renesas,i2c-r8a7794" "renesas,i2c-r8a7795" + "renesas,i2c-r8a7796" - reg: physical base address of the controller and length of memory mapped region. - interrupts: interrupt specifier. diff --git a/Documentation/devicetree/bindings/i2c/nxp,pca9541.txt b/Documentation/devicetree/bindings/i2c/nxp,pca9541.txt new file mode 100644 index 000000000000..0fbbc6970ec5 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/nxp,pca9541.txt @@ -0,0 +1,29 @@ +* NXP PCA9541 I2C bus master selector + +Required Properties: + + - compatible: Must be "nxp,pca9541" + + - reg: The I2C address of the device. + + The following required properties are defined externally: + + - I2C arbitration bus node. See i2c-arb.txt in this directory. + + +Example: + + i2c-arbitrator@74 { + compatible = "nxp,pca9541"; + reg = <0x74>; + + i2c-arb { + #address-cells = <1>; + #size-cells = <0>; + + eeprom@54 { + compatible = "at,24c08"; + reg = <0x54>; + }; + }; + }; diff --git a/MAINTAINERS b/MAINTAINERS index 33d77794a1f2..255655880881 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2908,6 +2908,14 @@ S: Maintained F: drivers/iio/light/cm* F: Documentation/devicetree/bindings/i2c/trivial-devices.txt +CAVIUM I2C DRIVER +M: Jan Glauber +M: David Daney +W: http://www.cavium.com +S: Supported +F: drivers/i2c/busses/i2c-octeon* +F: drivers/i2c/busses/i2c-thunderx* + CAVIUM LIQUIDIO NETWORK DRIVER M: Derek Chickles M: Satanand Burla @@ -5788,6 +5796,8 @@ S: Maintained F: Documentation/i2c/i2c-topology F: Documentation/i2c/muxes/ F: Documentation/devicetree/bindings/i2c/i2c-mux* +F: Documentation/devicetree/bindings/i2c/i2c-arb* +F: Documentation/devicetree/bindings/i2c/i2c-gate* F: drivers/i2c/i2c-mux.c F: drivers/i2c/muxes/ F: include/linux/i2c-mux.h diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 5d059866d17a..45c8817d068c 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -732,7 +732,7 @@ out: static const struct of_device_id pca953x_dt_ids[]; static int pca953x_probe(struct i2c_client *client, - const struct i2c_device_id *id) + const struct i2c_device_id *i2c_id) { struct pca953x_platform_data *pdata; struct pca953x_chip *chip; @@ -773,27 +773,29 @@ static int pca953x_probe(struct i2c_client *client, } chip->regulator = reg; - if (id) { - chip->driver_data = id->driver_data; + if (i2c_id) { + chip->driver_data = i2c_id->driver_data; } else { - const struct acpi_device_id *id; + const struct acpi_device_id *acpi_id; const struct of_device_id *match; match = of_match_device(pca953x_dt_ids, &client->dev); if (match) { chip->driver_data = (int)(uintptr_t)match->data; } else { - id = acpi_match_device(pca953x_acpi_ids, &client->dev); - if (!id) { + acpi_id = acpi_match_device(pca953x_acpi_ids, &client->dev); + if (!acpi_id) { ret = -ENODEV; goto err_exit; } - chip->driver_data = id->driver_data; + chip->driver_data = acpi_id->driver_data; } } mutex_init(&chip->i2c_lock); + lockdep_set_subclass(&chip->i2c_lock, + i2c_adapter_depth(client->adapter)); /* initialize cached registers from their original values. * we can't share this chip with another i2c master. diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c index eae5ef963cb7..2bd064493ae7 100644 --- a/drivers/gpu/drm/drm_dp_helper.c +++ b/drivers/gpu/drm/drm_dp_helper.c @@ -790,6 +790,12 @@ static void unlock_bus(struct i2c_adapter *i2c, unsigned int flags) mutex_unlock(&i2c_to_aux(i2c)->hw_mutex); } +static const struct i2c_lock_operations drm_dp_i2c_lock_ops = { + .lock_bus = lock_bus, + .trylock_bus = trylock_bus, + .unlock_bus = unlock_bus, +}; + /** * drm_dp_aux_init() - minimally initialise an aux channel * @aux: DisplayPort AUX channel @@ -807,9 +813,7 @@ void drm_dp_aux_init(struct drm_dp_aux *aux) aux->ddc.algo_data = aux; aux->ddc.retries = 3; - aux->ddc.lock_bus = lock_bus; - aux->ddc.trylock_bus = trylock_bus; - aux->ddc.unlock_bus = unlock_bus; + aux->ddc.lock_ops = &drm_dp_i2c_lock_ops; } EXPORT_SYMBOL(drm_dp_aux_init); diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 5c3993b26129..6d94e2ec5b4f 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -836,7 +836,7 @@ config I2C_SH7760 config I2C_SH_MOBILE tristate "SuperH Mobile I2C Controller" depends on HAS_DMA - depends on SUPERH || ARCH_RENESAS || COMPILE_TEST + depends on ARCH_SHMOBILE || ARCH_RENESAS || COMPILE_TEST help If you say yes to this option, support will be included for the built-in I2C interface on the Renesas SH-Mobile processor. @@ -956,6 +956,17 @@ config I2C_OCTEON This driver can also be built as a module. If so, the module will be called i2c-octeon. +config I2C_THUNDERX + tristate "Cavium ThunderX I2C bus support" + depends on 64BIT && PCI && (ARM64 || COMPILE_TEST) + select I2C_SMBUS + help + Say yes if you want to support the I2C serial bus on Cavium + ThunderX SOC. + + This driver can also be built as a module. If so, the module + will be called i2c-thunderx. + config I2C_XILINX tristate "Xilinx I2C Controller" depends on HAS_IOMEM diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 37f2819b4560..29764cc20a44 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -91,7 +91,10 @@ 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_OCTEON) += i2c-octeon.o +i2c-thunderx-objs := i2c-octeon-core.o i2c-thunderx-pcidrv.o +obj-$(CONFIG_I2C_THUNDERX) += i2c-thunderx.o obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o obj-$(CONFIG_I2C_XLR) += i2c-xlr.o obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o diff --git a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c index 6c7113d990f8..274908cd1fde 100644 --- a/drivers/i2c/busses/i2c-amd756.c +++ b/drivers/i2c/busses/i2c-amd756.c @@ -378,11 +378,8 @@ static int amd756_probe(struct pci_dev *pdev, const struct pci_device_id *id) amd756_ioport); error = i2c_add_adapter(&amd756_smbus); - if (error) { - dev_err(&pdev->dev, - "Adapter registration failed, module not inserted\n"); + if (error) goto out_err; - } return 0; diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 1bb97f658b47..0b86c6173e07 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -1122,8 +1122,6 @@ static int at91_twi_probe(struct platform_device *pdev) rc = i2c_add_numbered_adapter(&dev->adapter); if (rc) { - dev_err(dev->dev, "Adapter %s registration failed\n", - dev->adapter.name); clk_disable_unprepare(dev->clk); pm_runtime_disable(dev->dev); diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c index c335cc7852f9..4351a9343058 100644 --- a/drivers/i2c/busses/i2c-axxia.c +++ b/drivers/i2c/busses/i2c-axxia.c @@ -545,7 +545,11 @@ static int axxia_i2c_probe(struct platform_device *pdev) return ret; } - clk_prepare_enable(idev->i2c_clk); + ret = clk_prepare_enable(idev->i2c_clk); + if (ret) { + dev_err(&pdev->dev, "failed to enable clock\n"); + return ret; + } i2c_set_adapdata(&idev->adapter, idev); strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name)); @@ -560,7 +564,7 @@ static int axxia_i2c_probe(struct platform_device *pdev) ret = i2c_add_adapter(&idev->adapter); if (ret) { - dev_err(&pdev->dev, "failed to add adapter\n"); + clk_disable_unprepare(idev->i2c_clk); return ret; } diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c index 95f7cac76f89..326b3db02c48 100644 --- a/drivers/i2c/busses/i2c-bcm-iproc.c +++ b/drivers/i2c/busses/i2c-bcm-iproc.c @@ -488,13 +488,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev) adap->dev.parent = &pdev->dev; adap->dev.of_node = pdev->dev.of_node; - ret = i2c_add_adapter(adap); - if (ret) { - dev_err(iproc_i2c->device, "failed to add adapter\n"); - return ret; - } - - return 0; + return i2c_add_adapter(adap); } static int bcm_iproc_i2c_remove(struct platform_device *pdev) diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c index 258cb9a40ab3..4e489a9d16fb 100644 --- a/drivers/i2c/busses/i2c-bcm-kona.c +++ b/drivers/i2c/busses/i2c-bcm-kona.c @@ -858,10 +858,8 @@ static int bcm_kona_i2c_probe(struct platform_device *pdev) adap->dev.of_node = pdev->dev.of_node; rc = i2c_add_adapter(adap); - if (rc) { - dev_err(dev->device, "failed to add adapter\n"); + if (rc) return rc; - } dev_info(dev->device, "device registered successfully\n"); diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 025686d41640..29d00c4f7824 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -685,10 +685,8 @@ static int i2c_bfin_twi_probe(struct platform_device *pdev) write_CONTROL(iface, read_CONTROL(iface) | TWI_ENA); rc = i2c_add_numbered_adapter(p_adap); - if (rc < 0) { - dev_err(&pdev->dev, "Can't add i2c adapter!\n"); + if (rc < 0) goto out_error; - } platform_set_drvdata(pdev, iface); diff --git a/drivers/i2c/busses/i2c-brcmstb.c b/drivers/i2c/busses/i2c-brcmstb.c index 385b57bfcb38..0652281662a8 100644 --- a/drivers/i2c/busses/i2c-brcmstb.c +++ b/drivers/i2c/busses/i2c-brcmstb.c @@ -648,10 +648,8 @@ static int brcmstb_i2c_probe(struct platform_device *pdev) adap->dev.parent = &pdev->dev; adap->dev.of_node = pdev->dev.of_node; rc = i2c_add_adapter(adap); - if (rc) { - dev_err(dev->device, "failed to add adapter\n"); + if (rc) goto probe_errorout; - } dev_info(dev->device, "%s@%dhz registered in %s mode\n", int_name ? int_name : " ", dev->clk_freq_hz, diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c index 3c16a2f7c673..686971263bef 100644 --- a/drivers/i2c/busses/i2c-cadence.c +++ b/drivers/i2c/busses/i2c-cadence.c @@ -963,10 +963,8 @@ static int cdns_i2c_probe(struct platform_device *pdev) } ret = i2c_add_adapter(&id->adap); - if (ret < 0) { - dev_err(&pdev->dev, "reg adap failed: %d\n", ret); + if (ret < 0) goto err_clk_dis; - } /* * Cadence I2C controller has a bug wherein it generates diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index ee57c1e865e2..d89bde2c5da2 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -665,10 +665,8 @@ static int cpm_i2c_probe(struct platform_device *ofdev) cpm->adap.nr = (data && len == 4) ? be32_to_cpup(data) : -1; result = i2c_add_numbered_adapter(&cpm->adap); - if (result < 0) { - dev_err(&ofdev->dev, "Unable to register with I2C\n"); + if (result < 0) goto out_shut; - } dev_dbg(&ofdev->dev, "hw routines for %s registered.\n", cpm->adap.name); diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c index 2d5ff86398d0..9b36a7b3befd 100644 --- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c +++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c @@ -281,10 +281,8 @@ static int ec_i2c_probe(struct platform_device *pdev) bus->adap.retries = I2C_MAX_RETRIES; err = i2c_add_adapter(&bus->adap); - if (err) { - dev_err(dev, "cannot register i2c adapter\n"); + if (err) return err; - } platform_set_drvdata(pdev, bus); return err; diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index a8bdcb5292f5..9e7ef5cf5d49 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -846,10 +846,8 @@ static int davinci_i2c_probe(struct platform_device *pdev) adap->nr = pdev->id; r = i2c_add_numbered_adapter(adap); - if (r) { - dev_err(&pdev->dev, "failure adding adapter\n"); + if (r) goto err_unuse_clocks; - } return 0; diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index fcd973d5131e..1fe93c43215c 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -42,6 +42,8 @@ #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 @@ -89,12 +91,17 @@ DW_IC_INTR_TX_ABRT | \ DW_IC_INTR_STOP_DET) -#define DW_IC_STATUS_ACTIVITY 0x1 +#define DW_IC_STATUS_ACTIVITY 0x1 +#define DW_IC_STATUS_TFE BIT(2) +#define DW_IC_STATUS_MST_ACTIVITY BIT(5) #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 */ @@ -251,11 +258,16 @@ static u32 i2c_dw_scl_lcnt(u32 ic_clk, u32 tLOW, u32 tf, int offset) } static void __i2c_dw_enable(struct dw_i2c_dev *dev, bool enable) +{ + dw_writel(dev, enable, DW_IC_ENABLE); +} + +static void __i2c_dw_enable_and_wait(struct dw_i2c_dev *dev, bool enable) { int timeout = 100; do { - dw_writel(dev, enable, DW_IC_ENABLE); + __i2c_dw_enable(dev, enable); if ((dw_readl(dev, DW_IC_ENABLE_STATUS) & 1) == enable) return; @@ -282,6 +294,28 @@ static unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) return dev->get_clk_rate_khz(dev); } +static int i2c_dw_acquire_lock(struct dw_i2c_dev *dev) +{ + int ret; + + if (!dev->acquire_lock) + return 0; + + ret = dev->acquire_lock(dev); + if (!ret) + return 0; + + dev_err(dev->dev, "couldn't acquire bus ownership\n"); + + return ret; +} + +static void i2c_dw_release_lock(struct dw_i2c_dev *dev) +{ + if (dev->release_lock) + dev->release_lock(dev); +} + /** * i2c_dw_init() - initialize the designware i2c master hardware * @dev: device private data @@ -293,17 +327,13 @@ static unsigned long i2c_dw_clk_rate(struct dw_i2c_dev *dev) int i2c_dw_init(struct dw_i2c_dev *dev) { u32 hcnt, lcnt; - u32 reg; + u32 reg, comp_param1; u32 sda_falling_time, scl_falling_time; int ret; - if (dev->acquire_lock) { - ret = dev->acquire_lock(dev); - if (ret) { - dev_err(dev->dev, "couldn't acquire bus ownership\n"); - return ret; - } - } + ret = i2c_dw_acquire_lock(dev); + if (ret) + return ret; reg = dw_readl(dev, DW_IC_COMP_TYPE); if (reg == ___constant_swab32(DW_IC_COMP_TYPE_VALUE)) { @@ -315,13 +345,14 @@ int i2c_dw_init(struct dw_i2c_dev *dev) } else if (reg != DW_IC_COMP_TYPE_VALUE) { dev_err(dev->dev, "Unknown Synopsys component type: " "0x%08x\n", reg); - if (dev->release_lock) - dev->release_lock(dev); + i2c_dw_release_lock(dev); return -ENODEV; } + comp_param1 = dw_readl(dev, DW_IC_COMP_PARAM_1); + /* Disable the adapter */ - __i2c_dw_enable(dev, false); + __i2c_dw_enable_and_wait(dev, false); /* set standard and fast speed deviders for high/low periods */ @@ -347,8 +378,11 @@ int i2c_dw_init(struct dw_i2c_dev *dev) dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT); dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); - /* Set SCL timing parameters for fast-mode */ - if (dev->fs_hcnt && dev->fs_lcnt) { + /* Set SCL timing parameters for fast-mode or fast-mode plus */ + if ((dev->clk_freq == 1000000) && dev->fp_hcnt && dev->fp_lcnt) { + hcnt = dev->fp_hcnt; + lcnt = dev->fp_lcnt; + } else if (dev->fs_hcnt && dev->fs_lcnt) { hcnt = dev->fs_hcnt; lcnt = dev->fs_lcnt; } else { @@ -366,6 +400,23 @@ int i2c_dw_init(struct dw_i2c_dev *dev) dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT); dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); + if ((dev->master_cfg & DW_IC_CON_SPEED_MASK) == + DW_IC_CON_SPEED_HIGH) { + if ((comp_param1 & DW_IC_COMP_PARAM_1_SPEED_MODE_MASK) + != DW_IC_COMP_PARAM_1_SPEED_MODE_HIGH) { + dev_err(dev->dev, "High Speed not supported!\n"); + dev->master_cfg &= ~DW_IC_CON_SPEED_MASK; + dev->master_cfg |= DW_IC_CON_SPEED_FAST; + } else if (dev->hs_hcnt && dev->hs_lcnt) { + hcnt = dev->hs_hcnt; + lcnt = dev->hs_lcnt; + dw_writel(dev, hcnt, DW_IC_HS_SCL_HCNT); + dw_writel(dev, lcnt, DW_IC_HS_SCL_LCNT); + dev_dbg(dev->dev, "HighSpeed-mode HCNT:LCNT = %d:%d\n", + hcnt, lcnt); + } + } + /* Configure SDA Hold Time if required */ reg = dw_readl(dev, DW_IC_COMP_VERSION); if (reg >= DW_IC_SDA_HOLD_MIN_VERS) { @@ -387,8 +438,8 @@ int i2c_dw_init(struct dw_i2c_dev *dev) /* configure the i2c master */ dw_writel(dev, dev->master_cfg , DW_IC_CON); - if (dev->release_lock) - dev->release_lock(dev); + i2c_dw_release_lock(dev); + return 0; } EXPORT_SYMBOL_GPL(i2c_dw_init); @@ -415,27 +466,45 @@ static int i2c_dw_wait_bus_not_busy(struct dw_i2c_dev *dev) static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) { struct i2c_msg *msgs = dev->msgs; - u32 ic_con, ic_tar = 0; + u32 ic_tar = 0; + bool enabled; - /* Disable the adapter */ - __i2c_dw_enable(dev, false); + enabled = dw_readl(dev, DW_IC_ENABLE_STATUS) & 1; + + if (enabled) { + u32 ic_status; - /* if the slave address is ten bit address, enable 10BITADDR */ - ic_con = dw_readl(dev, DW_IC_CON); - if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) { - ic_con |= DW_IC_CON_10BITADDR_MASTER; /* - * If I2C_DYNAMIC_TAR_UPDATE is set, the 10-bit addressing - * mode has to be enabled via bit 12 of IC_TAR register. - * We set it always as I2C_DYNAMIC_TAR_UPDATE can't be - * detected from registers. + * Only disable adapter if ic_tar and ic_con can't be + * dynamically updated */ - ic_tar = DW_IC_TAR_10BITADDR_MASTER; - } else { - ic_con &= ~DW_IC_CON_10BITADDR_MASTER; + ic_status = dw_readl(dev, DW_IC_STATUS); + if (!dev->dynamic_tar_update_enabled || + (ic_status & DW_IC_STATUS_MST_ACTIVITY) || + !(ic_status & DW_IC_STATUS_TFE)) { + __i2c_dw_enable_and_wait(dev, false); + enabled = false; + } } - dw_writel(dev, ic_con, DW_IC_CON); + /* if the slave address is ten bit address, enable 10BITADDR */ + if (dev->dynamic_tar_update_enabled) { + /* + * If I2C_DYNAMIC_TAR_UPDATE is set, the 10-bit addressing + * mode has to be enabled via bit 12 of IC_TAR register, + * otherwise bit 4 of IC_CON is used. + */ + if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) + ic_tar = DW_IC_TAR_10BITADDR_MASTER; + } else { + u32 ic_con = dw_readl(dev, DW_IC_CON); + + if (msgs[dev->msg_write_idx].flags & I2C_M_TEN) + ic_con |= DW_IC_CON_10BITADDR_MASTER; + else + ic_con &= ~DW_IC_CON_10BITADDR_MASTER; + dw_writel(dev, ic_con, DW_IC_CON); + } /* * Set the slave (target) address and enable 10-bit addressing mode @@ -446,8 +515,8 @@ static void i2c_dw_xfer_init(struct dw_i2c_dev *dev) /* enforce disabled interrupts (due to HW issues) */ i2c_dw_disable_int(dev); - /* Enable the adapter */ - __i2c_dw_enable(dev, true); + if (!enabled) + __i2c_dw_enable(dev, true); /* Clear and enable interrupts */ dw_readl(dev, DW_IC_CLR_INTR); @@ -628,7 +697,8 @@ static int i2c_dw_handle_tx_abort(struct dw_i2c_dev *dev) } /* - * Prepare controller for a transaction and call i2c_dw_xfer_msg + * Prepare controller for a transaction and start transfer by calling + * i2c_dw_xfer_init() */ static int i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) @@ -651,13 +721,9 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) dev->abort_source = 0; dev->rx_outstanding = 0; - if (dev->acquire_lock) { - ret = dev->acquire_lock(dev); - if (ret) { - dev_err(dev->dev, "couldn't acquire bus ownership\n"); - goto done_nolock; - } - } + ret = i2c_dw_acquire_lock(dev); + if (ret) + goto done_nolock; ret = i2c_dw_wait_bus_not_busy(dev); if (ret < 0) @@ -675,16 +741,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) 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_enable(dev, false); - if (dev->msg_err) { ret = dev->msg_err; goto done; @@ -704,8 +760,7 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ret = -EIO; done: - if (dev->release_lock) - dev->release_lock(dev); + i2c_dw_release_lock(dev); done_nolock: pm_runtime_mark_last_busy(dev->dev); @@ -822,9 +877,19 @@ static irqreturn_t i2c_dw_isr(int this_irq, void *dev_id) */ 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) { + /* + * We must disable interruts before returning and signaling + * the end of the current transfer. Otherwise the hardware + * might continue generating interrupts for non-existent + * transfers. + */ + i2c_dw_disable_int(dev); + dw_readl(dev, DW_IC_CLR_INTR); + complete(&dev->cmd_complete); - else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) { + } else if (unlikely(dev->accessor_flags & ACCESS_INTR_MASK)) { /* workaround to trigger pending interrupt */ stat = dw_readl(dev, DW_IC_INTR_MASK); i2c_dw_disable_int(dev); @@ -837,7 +902,7 @@ tx_aborted: void i2c_dw_disable(struct dw_i2c_dev *dev) { /* Disable controller */ - __i2c_dw_enable(dev, false); + __i2c_dw_enable_and_wait(dev, false); /* Disable all interupts */ dw_writel(dev, 0, DW_IC_INTR_MASK); @@ -861,6 +926,7 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) { struct i2c_adapter *adap = &dev->adapter; int r; + u32 reg; init_completion(&dev->cmd_complete); @@ -868,6 +934,26 @@ int i2c_dw_probe(struct dw_i2c_dev *dev) if (r) return r; + r = i2c_dw_acquire_lock(dev); + if (r) + return r; + + /* + * Test if dynamic TAR update is enabled in this controller by writing + * to IC_10BITADDR_MASTER field in IC_CON: when it is enabled this + * field is read-only so it should not succeed + */ + reg = dw_readl(dev, DW_IC_CON); + dw_writel(dev, reg ^ DW_IC_CON_10BITADDR_MASTER, DW_IC_CON); + + if ((dw_readl(dev, DW_IC_CON) & DW_IC_CON_10BITADDR_MASTER) == + (reg & DW_IC_CON_10BITADDR_MASTER)) { + dev->dynamic_tar_update_enabled = true; + dev_dbg(dev->dev, "Dynamic TAR update enabled"); + } + + i2c_dw_release_lock(dev); + snprintf(adap->name, sizeof(adap->name), "Synopsys DesignWare I2C adapter"); adap->retries = 3; diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index 38493a7142ad..0d44d2ae7d4c 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -26,6 +26,7 @@ #define DW_IC_CON_MASTER 0x1 #define DW_IC_CON_SPEED_STD 0x2 #define DW_IC_CON_SPEED_FAST 0x4 +#define DW_IC_CON_SPEED_HIGH 0x6 #define DW_IC_CON_SPEED_MASK 0x6 #define DW_IC_CON_10BITADDR_MASTER 0x10 #define DW_IC_CON_RESTART_EN 0x20 @@ -57,10 +58,15 @@ * @tx_fifo_depth: depth of the hardware tx fifo * @rx_fifo_depth: depth of the hardware rx fifo * @rx_outstanding: current master-rx elements in tx fifo + * @clk_freq: bus clock frequency * @ss_hcnt: standard speed HCNT value * @ss_lcnt: standard speed LCNT value * @fs_hcnt: fast speed HCNT value * @fs_lcnt: fast speed LCNT value + * @fp_hcnt: fast plus HCNT value + * @fp_lcnt: fast plus LCNT value + * @hs_hcnt: high speed HCNT value + * @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 * @pm_runtime_disabled: true if pm runtime is disabled @@ -96,6 +102,7 @@ struct dw_i2c_dev { unsigned int tx_fifo_depth; unsigned int rx_fifo_depth; int rx_outstanding; + u32 clk_freq; u32 sda_hold_time; u32 sda_falling_time; u32 scl_falling_time; @@ -103,9 +110,14 @@ struct dw_i2c_dev { u16 ss_lcnt; u16 fs_hcnt; u16 fs_lcnt; + u16 fp_hcnt; + u16 fp_lcnt; + u16 hs_hcnt; + u16 hs_lcnt; int (*acquire_lock)(struct dw_i2c_dev *dev); void (*release_lock)(struct dw_i2c_dev *dev); bool pm_runtime_disabled; + bool dynamic_tar_update_enabled; }; #define ACCESS_SWAP 0x00000001 diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index d656657b805c..0b42a12171f3 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -107,6 +107,8 @@ static int dw_i2c_acpi_configure(struct platform_device *pdev) dw_i2c_acpi_params(pdev, "SSCN", &dev->ss_hcnt, &dev->ss_lcnt, NULL); dw_i2c_acpi_params(pdev, "FMCN", &dev->fs_hcnt, &dev->fs_lcnt, &dev->sda_hold_time); + dw_i2c_acpi_params(pdev, "FPCN", &dev->fp_hcnt, &dev->fp_lcnt, NULL); + dw_i2c_acpi_params(pdev, "HSCN", &dev->hs_hcnt, &dev->hs_lcnt, NULL); id = acpi_match_device(pdev->dev.driver->acpi_match_table, &pdev->dev); if (id && id->driver_data) @@ -155,7 +157,7 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) struct i2c_adapter *adap; struct resource *mem; int irq, r; - u32 clk_freq, ht = 0; + u32 acpi_speed, ht = 0; irq = platform_get_irq(pdev, 0); if (irq < 0) @@ -175,10 +177,10 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); /* fast mode by default because of legacy reasons */ - clk_freq = 400000; + dev->clk_freq = 400000; if (pdata) { - clk_freq = pdata->i2c_scl_freq; + dev->clk_freq = pdata->i2c_scl_freq; } else { device_property_read_u32(&pdev->dev, "i2c-sda-hold-time-ns", &ht); @@ -187,17 +189,24 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) device_property_read_u32(&pdev->dev, "i2c-scl-falling-time-ns", &dev->scl_falling_time); device_property_read_u32(&pdev->dev, "clock-frequency", - &clk_freq); + &dev->clk_freq); } + acpi_speed = i2c_acpi_find_bus_speed(&pdev->dev); + if (acpi_speed) + dev->clk_freq = acpi_speed; + if (has_acpi_companion(&pdev->dev)) dw_i2c_acpi_configure(pdev); /* - * Only standard mode at 100kHz and fast mode at 400kHz are supported. + * Only standard mode at 100kHz, fast mode at 400kHz, + * fast mode plus at 1MHz and high speed mode at 3.4MHz are supported. */ - if (clk_freq != 100000 && clk_freq != 400000) { - dev_err(&pdev->dev, "Only 100kHz and 400kHz supported"); + if (dev->clk_freq != 100000 && dev->clk_freq != 400000 + && dev->clk_freq != 1000000 && dev->clk_freq != 3400000) { + dev_err(&pdev->dev, + "Only 100kHz, 400kHz, 1MHz and 3.4MHz supported"); return -EINVAL; } @@ -212,12 +221,20 @@ static int dw_i2c_plat_probe(struct platform_device *pdev) I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK; - if (clk_freq == 100000) - dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | - DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_STD; - else - dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | - DW_IC_CON_RESTART_EN | DW_IC_CON_SPEED_FAST; + + dev->master_cfg = DW_IC_CON_MASTER | DW_IC_CON_SLAVE_DISABLE | + DW_IC_CON_RESTART_EN; + + switch (dev->clk_freq) { + case 100000: + dev->master_cfg |= DW_IC_CON_SPEED_STD; + break; + case 3400000: + dev->master_cfg |= DW_IC_CON_SPEED_HIGH; + break; + default: + dev->master_cfg |= DW_IC_CON_SPEED_FAST; + } dev->clk = devm_clk_get(&pdev->dev, NULL); if (!i2c_dw_plat_prepare_clk(dev, true)) { diff --git a/drivers/i2c/busses/i2c-diolan-u2c.c b/drivers/i2c/busses/i2c-diolan-u2c.c index b19a310bf9b3..f718ee4e3332 100644 --- a/drivers/i2c/busses/i2c-diolan-u2c.c +++ b/drivers/i2c/busses/i2c-diolan-u2c.c @@ -487,10 +487,8 @@ static int diolan_u2c_probe(struct usb_interface *interface, /* and finally attach to i2c layer */ ret = i2c_add_adapter(&dev->adapter); - if (ret < 0) { - dev_err(&interface->dev, "failed to add I2C adapter\n"); + if (ret < 0) goto error_free; - } dev_dbg(&interface->dev, "connected " DRIVER_NAME "\n"); diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c index f2eb4f76591f..8acda2aa1558 100644 --- a/drivers/i2c/busses/i2c-dln2.c +++ b/drivers/i2c/busses/i2c-dln2.c @@ -228,10 +228,8 @@ static int dln2_i2c_probe(struct platform_device *pdev) /* and finally attach to i2c layer */ ret = i2c_add_adapter(&dln2->adapter); - if (ret < 0) { - dev_err(dev, "failed to add I2C adapter: %d\n", ret); + if (ret < 0) goto out_disable; - } return 0; diff --git a/drivers/i2c/busses/i2c-efm32.c b/drivers/i2c/busses/i2c-efm32.c index e253598d764c..aa336ba89aa3 100644 --- a/drivers/i2c/busses/i2c-efm32.c +++ b/drivers/i2c/busses/i2c-efm32.c @@ -438,7 +438,6 @@ static int efm32_i2c_probe(struct platform_device *pdev) ret = i2c_add_adapter(&ddata->adapter); if (ret) { - dev_err(&pdev->dev, "failed to add i2c adapter (%d)\n", ret); free_irq(ddata->irq, ddata); err_disable_clk: diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index c0e3ada02876..bea607149972 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -796,10 +796,8 @@ static int exynos5_i2c_probe(struct platform_device *pdev) exynos5_i2c_reset(i2c); ret = i2c_add_adapter(&i2c->adap); - if (ret < 0) { - dev_err(&pdev->dev, "failed to add bus to i2c core\n"); + if (ret < 0) goto err_clk; - } platform_set_drvdata(pdev, i2c); diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c index 7c6966434ee7..ae7f3180f7e8 100644 --- a/drivers/i2c/busses/i2c-hix5hd2.c +++ b/drivers/i2c/busses/i2c-hix5hd2.c @@ -478,10 +478,8 @@ static int hix5hd2_i2c_probe(struct platform_device *pdev) pm_runtime_enable(priv->dev); ret = i2c_add_adapter(&priv->adap); - if (ret < 0) { - dev_err(&pdev->dev, "failed to add bus to i2c core\n"); + if (ret < 0) goto err_runtime; - } return ret; diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 26298af73232..08847e8b8998 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -64,6 +64,7 @@ * Broxton (SOC) 0x5ad4 32 hard yes yes yes * Lewisburg (PCH) 0xa1a3 32 hard yes yes yes * Lewisburg Supersku (PCH) 0xa223 32 hard yes yes yes + * Kaby Lake PCH-H (PCH) 0xa2a3 32 hard yes yes yes * * Features supported by this driver: * Software PEC no @@ -226,6 +227,7 @@ #define PCI_DEVICE_ID_INTEL_SUNRISEPOINT_H_SMBUS 0xa123 #define PCI_DEVICE_ID_INTEL_LEWISBURG_SMBUS 0xa1a3 #define PCI_DEVICE_ID_INTEL_LEWISBURG_SSKU_SMBUS 0xa223 +#define PCI_DEVICE_ID_INTEL_KABYLAKE_PCH_H_SMBUS 0xa2a3 struct i801_mux_config { char *gpio_chip; @@ -1006,6 +1008,7 @@ static const struct pci_device_id i801_ids[] = { { 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) }, { 0, } }; @@ -1482,6 +1485,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) 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: priv->features |= FEATURE_I2C_BLOCK_READ; priv->features |= FEATURE_IRQ; priv->features |= FEATURE_SMBUS_PEC; @@ -1615,7 +1619,6 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id) "SMBus I801 adapter at %04lx", priv->smba); err = i2c_add_adapter(&priv->adapter); if (err) { - dev_err(&dev->dev, "Failed to add SMBus adapter\n"); i801_acpi_remove(priv); return err; } diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index cdaa7be2cd1b..412b91d255ad 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -751,10 +751,8 @@ static int iic_probe(struct platform_device *ofdev) adap->timeout = HZ; ret = i2c_add_adapter(adap); - if (ret < 0) { - dev_err(&ofdev->dev, "failed to register i2c adapter\n"); + if (ret < 0) goto error_cleanup; - } dev_info(&ofdev->dev, "using %s mode\n", dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)"); diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c index ea20425b6972..db8e8b40569d 100644 --- a/drivers/i2c/busses/i2c-img-scb.c +++ b/drivers/i2c/busses/i2c-img-scb.c @@ -1394,10 +1394,8 @@ static int img_i2c_probe(struct platform_device *pdev) goto disable_clk; ret = i2c_add_numbered_adapter(&i2c->adap); - if (ret < 0) { - dev_err(&pdev->dev, "failed to add adapter\n"); + if (ret < 0) goto disable_clk; - } return 0; diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 1844bc9f7cd5..592a8f26a708 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -984,11 +984,24 @@ static void i2c_imx_unprepare_recovery(struct i2c_adapter *adap) pinctrl_select_state(i2c_imx->pinctrl, i2c_imx->pinctrl_pins_default); } -static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, +/* + * We switch SCL and SDA to their GPIO function and do some bitbanging + * for bus recovery. These alternative pinmux settings can be + * described in the device tree by a separate pinctrl state "gpio". If + * this is missing this is not a big problem, the only implication is + * that we can't do bus recovery. + */ +static int i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, struct platform_device *pdev) { struct i2c_bus_recovery_info *rinfo = &i2c_imx->rinfo; + i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev); + if (!i2c_imx->pinctrl || IS_ERR(i2c_imx->pinctrl)) { + dev_info(&pdev->dev, "can't get pinctrl, bus recovery not supported\n"); + return PTR_ERR(i2c_imx->pinctrl); + } + i2c_imx->pinctrl_pins_default = pinctrl_lookup_state(i2c_imx->pinctrl, PINCTRL_STATE_DEFAULT); i2c_imx->pinctrl_pins_gpio = pinctrl_lookup_state(i2c_imx->pinctrl, @@ -1001,7 +1014,7 @@ static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, IS_ERR(i2c_imx->pinctrl_pins_default) || IS_ERR(i2c_imx->pinctrl_pins_gpio)) { dev_dbg(&pdev->dev, "recovery information incomplete\n"); - return; + return 0; } dev_dbg(&pdev->dev, "using scl-gpio %d and sda-gpio %d for recovery\n", @@ -1011,6 +1024,8 @@ static void i2c_imx_init_recovery_info(struct imx_i2c_struct *i2c_imx, rinfo->unprepare_recovery = i2c_imx_unprepare_recovery; rinfo->recover_bus = i2c_generic_gpio_recovery; i2c_imx->adapter.bus_recovery_info = rinfo; + + return 0; } static u32 i2c_imx_func(struct i2c_adapter *adapter) @@ -1081,12 +1096,6 @@ static int i2c_imx_probe(struct platform_device *pdev) return ret; } - i2c_imx->pinctrl = devm_pinctrl_get(&pdev->dev); - if (IS_ERR(i2c_imx->pinctrl)) { - ret = PTR_ERR(i2c_imx->pinctrl); - goto clk_disable; - } - /* Request IRQ */ ret = devm_request_irq(&pdev->dev, irq, i2c_imx_isr, 0, pdev->name, i2c_imx); @@ -1125,14 +1134,16 @@ static int i2c_imx_probe(struct platform_device *pdev) i2c_imx, IMX_I2C_I2CR); imx_i2c_write_reg(i2c_imx->hwdata->i2sr_clr_opcode, i2c_imx, IMX_I2C_I2SR); - i2c_imx_init_recovery_info(i2c_imx, pdev); + /* Init optional bus recovery function */ + ret = i2c_imx_init_recovery_info(i2c_imx, pdev); + /* Give it another chance if pinctrl used is not ready yet */ + if (ret == -EPROBE_DEFER) + goto rpm_disable; /* Add I2C adapter */ ret = i2c_add_numbered_adapter(&i2c_imx->adapter); - if (ret < 0) { - dev_err(&pdev->dev, "registration failed\n"); + if (ret < 0) goto rpm_disable; - } pm_runtime_mark_last_busy(&pdev->dev); pm_runtime_put_autosuspend(&pdev->dev); diff --git a/drivers/i2c/busses/i2c-isch.c b/drivers/i2c/busses/i2c-isch.c index c2f25f19d76f..0cf1379f4e80 100644 --- a/drivers/i2c/busses/i2c-isch.c +++ b/drivers/i2c/busses/i2c-isch.c @@ -288,10 +288,8 @@ static int smbus_sch_probe(struct platform_device *dev) "SMBus SCH adapter at %04x", sch_smba); retval = i2c_add_adapter(&sch_adapter); - if (retval) { - dev_err(&dev->dev, "Couldn't register adapter!\n"); + if (retval) sch_smba = 0; - } return retval; } diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c index 1c8707710098..f573448d2132 100644 --- a/drivers/i2c/busses/i2c-ismt.c +++ b/drivers/i2c/busses/i2c-ismt.c @@ -922,10 +922,8 @@ ismt_probe(struct pci_dev *pdev, const struct pci_device_id *id) return err; err = i2c_add_adapter(&priv->adapter); - if (err) { - dev_err(&pdev->dev, "Failed to add SMBus iSMT adapter\n"); + if (err) return -ENODEV; - } return 0; } diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c index cd9872594fe2..b8ea62105f42 100644 --- a/drivers/i2c/busses/i2c-jz4780.c +++ b/drivers/i2c/busses/i2c-jz4780.c @@ -798,10 +798,8 @@ static int jz4780_i2c_probe(struct platform_device *pdev) goto err; ret = i2c_add_adapter(&i2c->adap); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to add bus\n"); + if (ret < 0) goto err; - } return 0; diff --git a/drivers/i2c/busses/i2c-lpc2k.c b/drivers/i2c/busses/i2c-lpc2k.c index 586a15205e61..9b1fef455a89 100644 --- a/drivers/i2c/busses/i2c-lpc2k.c +++ b/drivers/i2c/busses/i2c-lpc2k.c @@ -432,10 +432,8 @@ static int i2c_lpc2k_probe(struct platform_device *pdev) i2c->adap.dev.of_node = pdev->dev.of_node; ret = i2c_add_adapter(&i2c->adap); - if (ret < 0) { - dev_err(&pdev->dev, "failed to add adapter!\n"); + if (ret < 0) goto fail_clk; - } dev_info(&pdev->dev, "LPC2K I2C adapter\n"); diff --git a/drivers/i2c/busses/i2c-meson.c b/drivers/i2c/busses/i2c-meson.c index 76e28980904f..2aa61bbbd307 100644 --- a/drivers/i2c/busses/i2c-meson.c +++ b/drivers/i2c/busses/i2c-meson.c @@ -453,7 +453,6 @@ static int meson_i2c_probe(struct platform_device *pdev) ret = i2c_add_adapter(&i2c->adap); if (ret < 0) { - dev_err(&pdev->dev, "can't register adapter\n"); clk_unprepare(i2c->clk); return ret; } @@ -473,6 +472,7 @@ static int meson_i2c_remove(struct platform_device *pdev) static const struct of_device_id meson_i2c_match[] = { { .compatible = "amlogic,meson6-i2c" }, + { .compatible = "amlogic,meson-gxbb-i2c" }, { }, }; MODULE_DEVICE_TABLE(of, meson_i2c_match); diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 48ecffecc0ed..565a49a0c564 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -737,10 +737,8 @@ static int fsl_i2c_probe(struct platform_device *op) i2c->adap.dev.of_node = of_node_get(op->dev.of_node); result = i2c_add_adapter(&i2c->adap); - if (result < 0) { - dev_err(i2c->dev, "failed to add adapter\n"); + if (result < 0) goto fail_add; - } return result; diff --git a/drivers/i2c/busses/i2c-mt65xx.c b/drivers/i2c/busses/i2c-mt65xx.c index d9373e60be8a..4a7d9bc2142b 100644 --- a/drivers/i2c/busses/i2c-mt65xx.c +++ b/drivers/i2c/busses/i2c-mt65xx.c @@ -786,10 +786,8 @@ static int mtk_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&i2c->adap, i2c); ret = i2c_add_adapter(&i2c->adap); - if (ret) { - dev_err(&pdev->dev, "Failed to add i2c bus to i2c core\n"); + if (ret) return ret; - } platform_set_drvdata(pdev, i2c); diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 033846cdf266..5738556b6aac 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -868,7 +868,6 @@ static int mxs_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(adap, i2c); err = i2c_add_numbered_adapter(adap); if (err) { - dev_err(dev, "Failed to add adapter (%d)\n", err); writel(MXS_I2C_CTRL0_SFTRST, i2c->regs + MXS_I2C_CTRL0_SET); return err; diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 42fcc9458432..374b35e7e450 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -366,7 +366,6 @@ static int nforce2_probe_smb(struct pci_dev *dev, int bar, int alt_reg, error = i2c_add_adapter(&smbus->adapter); if (error) { - dev_err(&smbus->adapter.dev, "Failed to register adapter.\n"); release_region(smbus->base, smbus->size); return error; } diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index bcd17e8cbcb4..da6609d62848 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -1046,10 +1046,8 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) adap->name, dev->virtbase); ret = i2c_add_adapter(adap); - if (ret) { - dev_err(&adev->dev, "failed to add adapter\n"); + if (ret) goto err_no_adap; - } pm_runtime_put(&adev->dev); diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c index ac88a524143e..34f1889a4073 100644 --- a/drivers/i2c/busses/i2c-ocores.c +++ b/drivers/i2c/busses/i2c-ocores.c @@ -494,10 +494,8 @@ static int ocores_i2c_probe(struct platform_device *pdev) /* add i2c adapter to i2c tree */ ret = i2c_add_adapter(&i2c->adap); - if (ret) { - dev_err(&pdev->dev, "Failed to add adapter\n"); + if (ret) goto err_clk; - } /* add in known devices to the bus */ if (pdata) { diff --git a/drivers/i2c/busses/i2c-octeon.c b/drivers/i2c/busses/i2c-octeon-core.c similarity index 56% rename from drivers/i2c/busses/i2c-octeon.c rename to drivers/i2c/busses/i2c-octeon-core.c index 30ae35146723..419b54bfc7c7 100644 --- a/drivers/i2c/busses/i2c-octeon.c +++ b/drivers/i2c/busses/i2c-octeon-core.c @@ -4,280 +4,127 @@ * * Portions Copyright (C) 2010 - 2016 Cavium, Inc. * - * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors. + * This file contains the shared part of the driver for the i2c adapter in + * Cavium Networks' OCTEON processors and ThunderX SOCs. * * 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 -#include +#include +#include #include #include #include -#include -#include -#include -#include -#include -#include -#include +#include "i2c-octeon-core.h" -#define DRV_NAME "i2c-octeon" - -/* Register offsets */ -#define SW_TWSI 0x00 -#define TWSI_INT 0x10 -#define SW_TWSI_EXT 0x18 - -/* Controller command patterns */ -#define SW_TWSI_V BIT_ULL(63) /* Valid bit */ -#define SW_TWSI_EIA BIT_ULL(61) /* Extended internal address */ -#define SW_TWSI_R BIT_ULL(56) /* Result or read bit */ -#define SW_TWSI_SOVR BIT_ULL(55) /* Size override */ -#define SW_TWSI_SIZE_SHIFT 52 -#define SW_TWSI_ADDR_SHIFT 40 -#define SW_TWSI_IA_SHIFT 32 /* Internal address */ - -/* Controller opcode word (bits 60:57) */ -#define SW_TWSI_OP_SHIFT 57 -#define SW_TWSI_OP_7 (0ULL << SW_TWSI_OP_SHIFT) -#define SW_TWSI_OP_7_IA (1ULL << SW_TWSI_OP_SHIFT) -#define SW_TWSI_OP_10 (2ULL << SW_TWSI_OP_SHIFT) -#define SW_TWSI_OP_10_IA (3ULL << SW_TWSI_OP_SHIFT) -#define SW_TWSI_OP_TWSI_CLK (4ULL << SW_TWSI_OP_SHIFT) -#define SW_TWSI_OP_EOP (6ULL << SW_TWSI_OP_SHIFT) /* Extended opcode */ - -/* Controller extended opcode word (bits 34:32) */ -#define SW_TWSI_EOP_SHIFT 32 -#define SW_TWSI_EOP_TWSI_DATA (SW_TWSI_OP_EOP | 1ULL << SW_TWSI_EOP_SHIFT) -#define SW_TWSI_EOP_TWSI_CTL (SW_TWSI_OP_EOP | 2ULL << SW_TWSI_EOP_SHIFT) -#define SW_TWSI_EOP_TWSI_CLKCTL (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT) -#define SW_TWSI_EOP_TWSI_STAT (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT) -#define SW_TWSI_EOP_TWSI_RST (SW_TWSI_OP_EOP | 7ULL << SW_TWSI_EOP_SHIFT) - -/* 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_IFLG 0x08 /* HW event, SW writes 0 to ACK */ -#define TWSI_CTL_AAK 0x04 /* Assert ACK */ - -/* Status values */ -#define STAT_ERROR 0x00 -#define STAT_START 0x08 -#define STAT_REP_START 0x10 -#define STAT_TXADDR_ACK 0x18 -#define STAT_TXADDR_NAK 0x20 -#define STAT_TXDATA_ACK 0x28 -#define STAT_TXDATA_NAK 0x30 -#define STAT_LOST_ARB_38 0x38 -#define STAT_RXADDR_ACK 0x40 -#define STAT_RXADDR_NAK 0x48 -#define STAT_RXDATA_ACK 0x50 -#define STAT_RXDATA_NAK 0x58 -#define STAT_SLAVE_60 0x60 -#define STAT_LOST_ARB_68 0x68 -#define STAT_SLAVE_70 0x70 -#define STAT_LOST_ARB_78 0x78 -#define STAT_SLAVE_80 0x80 -#define STAT_SLAVE_88 0x88 -#define STAT_GENDATA_ACK 0x90 -#define STAT_GENDATA_NAK 0x98 -#define STAT_SLAVE_A0 0xA0 -#define STAT_SLAVE_A8 0xA8 -#define STAT_LOST_ARB_B0 0xB0 -#define STAT_SLAVE_LOST 0xB8 -#define STAT_SLAVE_NAK 0xC0 -#define STAT_SLAVE_ACK 0xC8 -#define STAT_AD2W_ACK 0xD0 -#define STAT_AD2W_NAK 0xD8 -#define STAT_IDLE 0xF8 - -/* TWSI_INT values */ -#define TWSI_INT_ST_INT BIT_ULL(0) -#define TWSI_INT_TS_INT BIT_ULL(1) -#define TWSI_INT_CORE_INT BIT_ULL(2) -#define TWSI_INT_ST_EN BIT_ULL(4) -#define TWSI_INT_TS_EN BIT_ULL(5) -#define TWSI_INT_CORE_EN BIT_ULL(6) -#define TWSI_INT_SDA_OVR BIT_ULL(8) -#define TWSI_INT_SCL_OVR BIT_ULL(9) -#define TWSI_INT_SDA BIT_ULL(10) -#define TWSI_INT_SCL BIT_ULL(11) - -#define I2C_OCTEON_EVENT_WAIT 80 /* microseconds */ - -struct octeon_i2c { - wait_queue_head_t queue; - struct i2c_adapter adap; - int irq; - int hlc_irq; /* For cn7890 only */ - u32 twsi_freq; - int sys_freq; - void __iomem *twsi_base; - struct device *dev; - bool hlc_enabled; - bool broken_irq_mode; - bool broken_irq_check; - void (*int_enable)(struct octeon_i2c *); - void (*int_disable)(struct octeon_i2c *); - void (*hlc_int_enable)(struct octeon_i2c *); - void (*hlc_int_disable)(struct octeon_i2c *); - atomic_t int_enable_cnt; - atomic_t hlc_int_enable_cnt; -}; - -static void octeon_i2c_writeq_flush(u64 val, void __iomem *addr) +/* interrupt service routine */ +irqreturn_t octeon_i2c_isr(int irq, void *dev_id) { - __raw_writeq(val, addr); - __raw_readq(addr); /* wait for write to land */ + struct octeon_i2c *i2c = dev_id; + + i2c->int_disable(i2c); + wake_up(&i2c->queue); + + return IRQ_HANDLED; } -/** - * octeon_i2c_reg_write - write an I2C core register - * @i2c: The struct octeon_i2c - * @eop_reg: Register selector - * @data: Value to be written - * - * The I2C core registers are accessed indirectly via the SW_TWSI CSR. - */ -static void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data) +static bool octeon_i2c_test_iflg(struct octeon_i2c *i2c) { - u64 tmp; - - __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI); - do { - tmp = __raw_readq(i2c->twsi_base + SW_TWSI); - } while ((tmp & SW_TWSI_V) != 0); + return (octeon_i2c_ctl_read(i2c) & TWSI_CTL_IFLG); } -#define octeon_i2c_ctl_write(i2c, val) \ - octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL, val) -#define octeon_i2c_data_write(i2c, val) \ - octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_DATA, val) - -/** - * octeon_i2c_reg_read - read lower bits of an I2C core register - * @i2c: The struct octeon_i2c - * @eop_reg: Register selector - * - * Returns the data. - * - * The I2C core registers are accessed indirectly via the SW_TWSI CSR. - */ -static u8 octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg) +static bool octeon_i2c_test_ready(struct octeon_i2c *i2c, bool *first) { - u64 tmp; + if (octeon_i2c_test_iflg(i2c)) + return true; - __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI); - do { - tmp = __raw_readq(i2c->twsi_base + SW_TWSI); - } while ((tmp & SW_TWSI_V) != 0); - - return tmp & 0xFF; -} - -#define octeon_i2c_ctl_read(i2c) \ - octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL) -#define octeon_i2c_data_read(i2c) \ - octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA) -#define octeon_i2c_stat_read(i2c) \ - octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT) - -/** - * octeon_i2c_read_int - read the TWSI_INT register - * @i2c: The struct octeon_i2c - * - * Returns the value of the register. - */ -static u64 octeon_i2c_read_int(struct octeon_i2c *i2c) -{ - return __raw_readq(i2c->twsi_base + TWSI_INT); -} - -/** - * octeon_i2c_write_int - write the TWSI_INT register - * @i2c: The struct octeon_i2c - * @data: Value to be written - */ -static void octeon_i2c_write_int(struct octeon_i2c *i2c, u64 data) -{ - octeon_i2c_writeq_flush(data, i2c->twsi_base + TWSI_INT); -} - -/** - * octeon_i2c_int_enable - enable the CORE interrupt - * @i2c: The struct octeon_i2c - * - * The interrupt will be asserted when there is non-STAT_IDLE state in - * the SW_TWSI_EOP_TWSI_STAT register. - */ -static void octeon_i2c_int_enable(struct octeon_i2c *i2c) -{ - octeon_i2c_write_int(i2c, TWSI_INT_CORE_EN); -} - -/* disable the CORE interrupt */ -static void octeon_i2c_int_disable(struct octeon_i2c *i2c) -{ - /* clear TS/ST/IFLG events */ - octeon_i2c_write_int(i2c, 0); -} - -/** - * octeon_i2c_int_enable78 - enable the CORE interrupt - * @i2c: The struct octeon_i2c - * - * The interrupt will be asserted when there is non-STAT_IDLE state in the - * SW_TWSI_EOP_TWSI_STAT register. - */ -static void octeon_i2c_int_enable78(struct octeon_i2c *i2c) -{ - atomic_inc_return(&i2c->int_enable_cnt); - enable_irq(i2c->irq); -} - -static void __octeon_i2c_irq_disable(atomic_t *cnt, int irq) -{ - int count; + if (*first) { + *first = false; + return false; + } /* - * The interrupt can be disabled in two places, but we only - * want to make the disable_irq_nosync() call once, so keep - * track with the atomic variable. + * IRQ has signaled an event but IFLG hasn't changed. + * Sleep and retry once. */ - count = atomic_dec_if_positive(cnt); - if (count >= 0) - disable_irq_nosync(irq); -} - -/* disable the CORE interrupt */ -static void octeon_i2c_int_disable78(struct octeon_i2c *i2c) -{ - __octeon_i2c_irq_disable(&i2c->int_enable_cnt, i2c->irq); + usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT); + return octeon_i2c_test_iflg(i2c); } /** - * octeon_i2c_hlc_int_enable78 - enable the ST interrupt + * octeon_i2c_wait - wait for the IFLG to be set * @i2c: The struct octeon_i2c * - * The interrupt will be asserted when there is non-STAT_IDLE state in - * the SW_TWSI_EOP_TWSI_STAT register. + * Returns 0 on success, otherwise a negative errno. */ -static void octeon_i2c_hlc_int_enable78(struct octeon_i2c *i2c) +static int octeon_i2c_wait(struct octeon_i2c *i2c) { - atomic_inc_return(&i2c->hlc_int_enable_cnt); - enable_irq(i2c->hlc_irq); + long time_left; + bool first = true; + + /* + * Some chip revisions don't assert the irq in the interrupt + * controller. So we must poll for the IFLG change. + */ + if (i2c->broken_irq_mode) { + u64 end = get_jiffies_64() + i2c->adap.timeout; + + while (!octeon_i2c_test_iflg(i2c) && + time_before64(get_jiffies_64(), end)) + usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT); + + return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT; + } + + i2c->int_enable(i2c); + time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_ready(i2c, &first), + i2c->adap.timeout); + i2c->int_disable(i2c); + + if (i2c->broken_irq_check && !time_left && + octeon_i2c_test_iflg(i2c)) { + dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n"); + i2c->broken_irq_mode = true; + return 0; + } + + if (!time_left) + return -ETIMEDOUT; + + return 0; } -/* disable the ST interrupt */ -static void octeon_i2c_hlc_int_disable78(struct octeon_i2c *i2c) +static bool octeon_i2c_hlc_test_valid(struct octeon_i2c *i2c) { - __octeon_i2c_irq_disable(&i2c->hlc_int_enable_cnt, i2c->hlc_irq); + return (__raw_readq(i2c->twsi_base + SW_TWSI(i2c)) & SW_TWSI_V) == 0; +} + +static bool octeon_i2c_hlc_test_ready(struct octeon_i2c *i2c, bool *first) +{ + /* check if valid bit is cleared */ + if (octeon_i2c_hlc_test_valid(i2c)) + return true; + + if (*first) { + *first = false; + return false; + } + + /* + * IRQ has signaled an event but valid bit isn't cleared. + * Sleep and retry once. + */ + usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT); + return octeon_i2c_hlc_test_valid(i2c); +} + +static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c) +{ + /* clear ST/TS events, listen for neither */ + octeon_i2c_write_int(i2c, TWSI_INT_ST_INT | TWSI_INT_TS_INT); } /* @@ -321,83 +168,41 @@ static void octeon_i2c_hlc_disable(struct octeon_i2c *i2c) octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); } -/* interrupt service routine */ -static irqreturn_t octeon_i2c_isr(int irq, void *dev_id) -{ - struct octeon_i2c *i2c = dev_id; - - i2c->int_disable(i2c); - wake_up(&i2c->queue); - - return IRQ_HANDLED; -} - -/* HLC interrupt service routine */ -static irqreturn_t octeon_i2c_hlc_isr78(int irq, void *dev_id) -{ - struct octeon_i2c *i2c = dev_id; - - i2c->hlc_int_disable(i2c); - wake_up(&i2c->queue); - - return IRQ_HANDLED; -} - -static bool octeon_i2c_test_iflg(struct octeon_i2c *i2c) -{ - return (octeon_i2c_ctl_read(i2c) & TWSI_CTL_IFLG); -} - -static bool octeon_i2c_test_ready(struct octeon_i2c *i2c, bool *first) -{ - if (octeon_i2c_test_iflg(i2c)) - return true; - - if (*first) { - *first = false; - return false; - } - - /* - * IRQ has signaled an event but IFLG hasn't changed. - * Sleep and retry once. - */ - usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT); - return octeon_i2c_test_iflg(i2c); -} - /** - * octeon_i2c_wait - wait for the IFLG to be set + * octeon_i2c_hlc_wait - wait for an HLC operation to complete * @i2c: The struct octeon_i2c * - * Returns 0 on success, otherwise a negative errno. + * Returns 0 on success, otherwise -ETIMEDOUT. */ -static int octeon_i2c_wait(struct octeon_i2c *i2c) +static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c) { - long time_left; - bool first = 1; + bool first = true; + int time_left; /* - * Some chip revisions don't assert the irq in the interrupt - * controller. So we must poll for the IFLG change. + * Some cn38xx boards don't assert the irq in the interrupt + * controller. So we must poll for the valid bit change. */ if (i2c->broken_irq_mode) { u64 end = get_jiffies_64() + i2c->adap.timeout; - while (!octeon_i2c_test_iflg(i2c) && + while (!octeon_i2c_hlc_test_valid(i2c) && time_before64(get_jiffies_64(), end)) usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT); - return octeon_i2c_test_iflg(i2c) ? 0 : -ETIMEDOUT; + return octeon_i2c_hlc_test_valid(i2c) ? 0 : -ETIMEDOUT; } - i2c->int_enable(i2c); - time_left = wait_event_timeout(i2c->queue, octeon_i2c_test_ready(i2c, &first), + i2c->hlc_int_enable(i2c); + time_left = wait_event_timeout(i2c->queue, + octeon_i2c_hlc_test_ready(i2c, &first), i2c->adap.timeout); - i2c->int_disable(i2c); + i2c->hlc_int_disable(i2c); + if (!time_left) + octeon_i2c_hlc_int_clear(i2c); if (i2c->broken_irq_check && !time_left && - octeon_i2c_test_iflg(i2c)) { + octeon_i2c_hlc_test_valid(i2c)) { dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n"); i2c->broken_irq_mode = true; return 0; @@ -405,13 +210,21 @@ static int octeon_i2c_wait(struct octeon_i2c *i2c) if (!time_left) return -ETIMEDOUT; - return 0; } static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read) { - u8 stat = octeon_i2c_stat_read(i2c); + u8 stat; + + /* + * This is ugly... in HLC mode the status is not in the status register + * but in the lower 8 bits of SW_TWSI. + */ + if (i2c->hlc_enabled) + stat = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + else + stat = octeon_i2c_stat_read(i2c); switch (stat) { /* Everything is fine */ @@ -470,354 +283,6 @@ static int octeon_i2c_check_status(struct octeon_i2c *i2c, int final_read) } } -static bool octeon_i2c_hlc_test_valid(struct octeon_i2c *i2c) -{ - return (__raw_readq(i2c->twsi_base + SW_TWSI) & SW_TWSI_V) == 0; -} - -static bool octeon_i2c_hlc_test_ready(struct octeon_i2c *i2c, bool *first) -{ - /* check if valid bit is cleared */ - if (octeon_i2c_hlc_test_valid(i2c)) - return true; - - if (*first) { - *first = false; - return false; - } - - /* - * IRQ has signaled an event but valid bit isn't cleared. - * Sleep and retry once. - */ - usleep_range(I2C_OCTEON_EVENT_WAIT, 2 * I2C_OCTEON_EVENT_WAIT); - return octeon_i2c_hlc_test_valid(i2c); -} - -static void octeon_i2c_hlc_int_enable(struct octeon_i2c *i2c) -{ - octeon_i2c_write_int(i2c, TWSI_INT_ST_EN); -} - -static void octeon_i2c_hlc_int_clear(struct octeon_i2c *i2c) -{ - /* clear ST/TS events, listen for neither */ - octeon_i2c_write_int(i2c, TWSI_INT_ST_INT | TWSI_INT_TS_INT); -} - -/** - * octeon_i2c_hlc_wait - wait for an HLC operation to complete - * @i2c: The struct octeon_i2c - * - * Returns 0 on success, otherwise -ETIMEDOUT. - */ -static int octeon_i2c_hlc_wait(struct octeon_i2c *i2c) -{ - bool first = 1; - int time_left; - - /* - * Some cn38xx boards don't assert the irq in the interrupt - * controller. So we must poll for the valid bit change. - */ - if (i2c->broken_irq_mode) { - u64 end = get_jiffies_64() + i2c->adap.timeout; - - while (!octeon_i2c_hlc_test_valid(i2c) && - time_before64(get_jiffies_64(), end)) - usleep_range(I2C_OCTEON_EVENT_WAIT / 2, I2C_OCTEON_EVENT_WAIT); - - return octeon_i2c_hlc_test_valid(i2c) ? 0 : -ETIMEDOUT; - } - - i2c->hlc_int_enable(i2c); - time_left = wait_event_timeout(i2c->queue, - octeon_i2c_hlc_test_ready(i2c, &first), - i2c->adap.timeout); - i2c->hlc_int_disable(i2c); - if (!time_left) - octeon_i2c_hlc_int_clear(i2c); - - if (i2c->broken_irq_check && !time_left && - octeon_i2c_hlc_test_valid(i2c)) { - dev_err(i2c->dev, "broken irq connection detected, switching to polling mode.\n"); - i2c->broken_irq_mode = true; - return 0; - } - - if (!time_left) - return -ETIMEDOUT; - return 0; -} - -/* high-level-controller pure read of up to 8 bytes */ -static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs) -{ - int i, j, ret = 0; - u64 cmd; - - octeon_i2c_hlc_enable(i2c); - octeon_i2c_hlc_int_clear(i2c); - - cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR; - /* 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); - ret = octeon_i2c_hlc_wait(i2c); - if (ret) - goto err; - - cmd = __raw_readq(i2c->twsi_base + SW_TWSI); - if ((cmd & SW_TWSI_R) == 0) - return -EAGAIN; - - for (i = 0, j = msgs[0].len - 1; i < msgs[0].len && i < 4; i++, j--) - msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff; - - if (msgs[0].len > 4) { - cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT); - for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--) - msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff; - } - -err: - return ret; -} - -/* high-level-controller pure write of up to 8 bytes */ -static int octeon_i2c_hlc_write(struct octeon_i2c *i2c, struct i2c_msg *msgs) -{ - int i, j, ret = 0; - u64 cmd; - - octeon_i2c_hlc_enable(i2c); - octeon_i2c_hlc_int_clear(i2c); - - cmd = SW_TWSI_V | SW_TWSI_SOVR; - /* 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); - - if (msgs[0].len > 4) { - u64 ext = 0; - - 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); - } - - octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI); - ret = octeon_i2c_hlc_wait(i2c); - if (ret) - goto err; - - cmd = __raw_readq(i2c->twsi_base + SW_TWSI); - if ((cmd & SW_TWSI_R) == 0) - return -EAGAIN; - - ret = octeon_i2c_check_status(i2c, false); - -err: - return ret; -} - -/* 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) -{ - int i, j, ret = 0; - u64 cmd; - - octeon_i2c_hlc_enable(i2c); - - cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR; - /* 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); - } 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); - - ret = octeon_i2c_hlc_wait(i2c); - if (ret) - goto err; - - cmd = __raw_readq(i2c->twsi_base + SW_TWSI); - if ((cmd & SW_TWSI_R) == 0) - return -EAGAIN; - - for (i = 0, j = msgs[1].len - 1; i < msgs[1].len && i < 4; i++, j--) - msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff; - - if (msgs[1].len > 4) { - cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT); - for (i = 0; i < msgs[1].len - 4 && i < 4; i++, j--) - msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff; - } - -err: - return ret; -} - -/* high-level-controller composite write+write, m[0]len<=2, m[1]len<=8 */ -static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msgs) -{ - bool set_ext = false; - int i, j, ret = 0; - u64 cmd, ext = 0; - - octeon_i2c_hlc_enable(i2c); - - cmd = SW_TWSI_V | SW_TWSI_SOVR; - /* 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; - } - - for (i = 0, j = msgs[1].len - 1; i < msgs[1].len && i < 4; i++, j--) - cmd |= (u64)msgs[1].buf[j] << (8 * i); - - if (msgs[1].len > 4) { - for (i = 0; i < msgs[1].len - 4 && i < 4; i++, j--) - ext |= (u64)msgs[1].buf[j] << (8 * i); - set_ext = true; - } - if (set_ext) - octeon_i2c_writeq_flush(ext, i2c->twsi_base + SW_TWSI_EXT); - - octeon_i2c_hlc_int_clear(i2c); - octeon_i2c_writeq_flush(cmd, i2c->twsi_base + SW_TWSI); - - ret = octeon_i2c_hlc_wait(i2c); - if (ret) - goto err; - - cmd = __raw_readq(i2c->twsi_base + SW_TWSI); - if ((cmd & SW_TWSI_R) == 0) - return -EAGAIN; - - ret = octeon_i2c_check_status(i2c, false); - -err: - return ret; -} - -/* calculate and set clock divisors */ -static 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; - - 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 given ndiv and mdiv values check the - * two closest thp values. - */ - tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10; - tclk *= (1 << ndiv_idx); - 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)); - foscl = foscl / (1 << ndiv_idx); - foscl = foscl / (mdiv_idx + 1) / 10; - diff = abs(foscl - i2c->twsi_freq); - if (diff < delta_hz) { - delta_hz = diff; - thp = thp_idx; - mdiv = mdiv_idx; - ndiv = ndiv_idx; - } - } - } - } - octeon_i2c_reg_write(i2c, SW_TWSI_OP_TWSI_CLK, thp); - octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv); -} - -static int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c) -{ - u8 status = 0; - int tries; - - /* reset controller */ - octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_RST, 0); - - for (tries = 10; tries && status != STAT_IDLE; tries--) { - udelay(1); - status = octeon_i2c_stat_read(i2c); - if (status == STAT_IDLE) - break; - } - - if (status != STAT_IDLE) { - dev_err(i2c->dev, "%s: TWSI_RST failed! (0x%x)\n", - __func__, status); - return -EIO; - } - - /* toggle twice to force both teardowns */ - octeon_i2c_hlc_enable(i2c); - octeon_i2c_hlc_disable(i2c); - return 0; -} - static int octeon_i2c_recovery(struct octeon_i2c *i2c) { int ret; @@ -864,45 +329,6 @@ static void octeon_i2c_stop(struct octeon_i2c *i2c) octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB | TWSI_CTL_STP); } -/** - * octeon_i2c_write - send data to the bus via low-level controller - * @i2c: The struct octeon_i2c - * @target: Target address - * @data: Pointer to the data to be sent - * @length: Length of the data - * - * The address is sent over the bus, then the data. - * - * Returns 0 on success, otherwise a negative errno. - */ -static int octeon_i2c_write(struct octeon_i2c *i2c, int target, - const u8 *data, int length) -{ - int i, result; - - octeon_i2c_data_write(i2c, target << 1); - octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); - - result = octeon_i2c_wait(i2c); - if (result) - return result; - - for (i = 0; i < length; i++) { - result = octeon_i2c_check_status(i2c, false); - if (result) - return result; - - octeon_i2c_data_write(i2c, data[i]); - octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); - - result = octeon_i2c_wait(i2c); - if (result) - return result; - } - - return 0; -} - /** * octeon_i2c_read - receive data from the bus via low-level controller * @i2c: The struct octeon_i2c @@ -955,7 +381,9 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target, if (result) return result; - data[i] = octeon_i2c_data_read(i2c); + data[i] = octeon_i2c_data_read(i2c, &result); + if (result) + return result; if (recv_len && i == 0) { if (data[i] > I2C_SMBUS_BLOCK_MAX + 1) return -EPROTO; @@ -970,6 +398,240 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target, return 0; } +/** + * octeon_i2c_write - send data to the bus via low-level controller + * @i2c: The struct octeon_i2c + * @target: Target address + * @data: Pointer to the data to be sent + * @length: Length of the data + * + * The address is sent over the bus, then the data. + * + * Returns 0 on success, otherwise a negative errno. + */ +static int octeon_i2c_write(struct octeon_i2c *i2c, int target, + const u8 *data, int length) +{ + int i, result; + + octeon_i2c_data_write(i2c, target << 1); + octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); + + result = octeon_i2c_wait(i2c); + if (result) + return result; + + for (i = 0; i < length; i++) { + result = octeon_i2c_check_status(i2c, false); + if (result) + return result; + + octeon_i2c_data_write(i2c, data[i]); + octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); + + result = octeon_i2c_wait(i2c); + if (result) + return result; + } + + return 0; +} + +/* high-level-controller pure read of up to 8 bytes */ +static int octeon_i2c_hlc_read(struct octeon_i2c *i2c, struct i2c_msg *msgs) +{ + int i, j, ret = 0; + u64 cmd; + + octeon_i2c_hlc_enable(i2c); + octeon_i2c_hlc_int_clear(i2c); + + cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR; + /* 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)); + ret = octeon_i2c_hlc_wait(i2c); + if (ret) + goto err; + + cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + if ((cmd & SW_TWSI_R) == 0) + return octeon_i2c_check_status(i2c, false); + + for (i = 0, j = msgs[0].len - 1; i < msgs[0].len && i < 4; i++, j--) + msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff; + + if (msgs[0].len > 4) { + cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c)); + for (i = 0; i < msgs[0].len - 4 && i < 4; i++, j--) + msgs[0].buf[j] = (cmd >> (8 * i)) & 0xff; + } + +err: + return ret; +} + +/* high-level-controller pure write of up to 8 bytes */ +static int octeon_i2c_hlc_write(struct octeon_i2c *i2c, struct i2c_msg *msgs) +{ + int i, j, ret = 0; + u64 cmd; + + octeon_i2c_hlc_enable(i2c); + octeon_i2c_hlc_int_clear(i2c); + + cmd = SW_TWSI_V | SW_TWSI_SOVR; + /* 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); + + if (msgs[0].len > 4) { + u64 ext = 0; + + 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(cmd, i2c->twsi_base + SW_TWSI(i2c)); + ret = octeon_i2c_hlc_wait(i2c); + if (ret) + goto err; + + cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + if ((cmd & SW_TWSI_R) == 0) + return octeon_i2c_check_status(i2c, false); + +err: + return ret; +} + +/* 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) +{ + int i, j, ret = 0; + u64 cmd; + + octeon_i2c_hlc_enable(i2c); + + cmd = SW_TWSI_V | SW_TWSI_R | SW_TWSI_SOVR; + /* 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); + if (ret) + goto err; + + cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + if ((cmd & SW_TWSI_R) == 0) + return octeon_i2c_check_status(i2c, false); + + for (i = 0, j = msgs[1].len - 1; i < msgs[1].len && i < 4; i++, j--) + msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff; + + if (msgs[1].len > 4) { + cmd = __raw_readq(i2c->twsi_base + SW_TWSI_EXT(i2c)); + for (i = 0; i < msgs[1].len - 4 && i < 4; i++, j--) + msgs[1].buf[j] = (cmd >> (8 * i)) & 0xff; + } + +err: + return ret; +} + +/* high-level-controller composite write+write, m[0]len<=2, m[1]len<=8 */ +static int octeon_i2c_hlc_comp_write(struct octeon_i2c *i2c, struct i2c_msg *msgs) +{ + bool set_ext = false; + int i, j, ret = 0; + u64 cmd, ext = 0; + + octeon_i2c_hlc_enable(i2c); + + cmd = SW_TWSI_V | SW_TWSI_SOVR; + /* 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; + } + + for (i = 0, j = msgs[1].len - 1; i < msgs[1].len && i < 4; i++, j--) + cmd |= (u64)msgs[1].buf[j] << (8 * i); + + if (msgs[1].len > 4) { + for (i = 0; i < msgs[1].len - 4 && i < 4; i++, j--) + ext |= (u64)msgs[1].buf[j] << (8 * i); + 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)); + + ret = octeon_i2c_hlc_wait(i2c); + if (ret) + goto err; + + cmd = __raw_readq(i2c->twsi_base + SW_TWSI(i2c)); + if ((cmd & SW_TWSI_R) == 0) + return octeon_i2c_check_status(i2c, false); + +err: + return ret; +} + /** * octeon_i2c_xfer - The driver's master_xfer function * @adap: Pointer to the i2c_adapter structure @@ -978,8 +640,7 @@ static int octeon_i2c_read(struct octeon_i2c *i2c, int target, * * Returns the number of messages processed, or a negative errno on failure. */ -static int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, - int num) +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; @@ -1031,6 +692,75 @@ out: return (ret != 0) ? ret : num; } +/* calculate and set clock divisors */ +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; + + 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 given ndiv and mdiv values check the + * two closest thp values. + */ + tclk = i2c->twsi_freq * (mdiv_idx + 1) * 10; + tclk *= (1 << ndiv_idx); + 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)); + foscl = foscl / (1 << ndiv_idx); + foscl = foscl / (mdiv_idx + 1) / 10; + diff = abs(foscl - i2c->twsi_freq); + if (diff < delta_hz) { + delta_hz = diff; + thp = thp_idx; + mdiv = mdiv_idx; + ndiv = ndiv_idx; + } + } + } + } + octeon_i2c_reg_write(i2c, SW_TWSI_OP_TWSI_CLK, thp); + octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CLKCTL, (mdiv << 3) | ndiv); +} + +int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c) +{ + u8 status = 0; + int tries; + + /* reset controller */ + octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_RST, 0); + + for (tries = 10; tries && status != STAT_IDLE; tries--) { + udelay(1); + status = octeon_i2c_stat_read(i2c); + if (status == STAT_IDLE) + break; + } + + if (status != STAT_IDLE) { + dev_err(i2c->dev, "%s: TWSI_RST failed! (0x%x)\n", + __func__, status); + return -EIO; + } + + /* toggle twice to force both teardowns */ + octeon_i2c_hlc_enable(i2c); + octeon_i2c_hlc_disable(i2c); + return 0; +} + static int octeon_i2c_get_scl(struct i2c_adapter *adap) { struct octeon_i2c *i2c = i2c_get_adapdata(adap); @@ -1044,7 +774,7 @@ static void octeon_i2c_set_scl(struct i2c_adapter *adap, int val) { struct octeon_i2c *i2c = i2c_get_adapdata(adap); - octeon_i2c_write_int(i2c, TWSI_INT_SCL_OVR); + octeon_i2c_write_int(i2c, val ? 0 : TWSI_INT_SCL_OVR); } static int octeon_i2c_get_sda(struct i2c_adapter *adap) @@ -1060,13 +790,14 @@ static void octeon_i2c_prepare_recovery(struct i2c_adapter *adap) { struct octeon_i2c *i2c = i2c_get_adapdata(adap); - /* - * The stop resets the state machine, does not _transmit_ STOP unless - * engine was active. - */ - octeon_i2c_stop(i2c); - octeon_i2c_hlc_disable(i2c); + + /* + * Bring control register to a good state regardless + * of HLC state. + */ + octeon_i2c_ctl_write(i2c, TWSI_CTL_ENAB); + octeon_i2c_write_int(i2c, 0); } @@ -1074,10 +805,19 @@ static void octeon_i2c_unprepare_recovery(struct i2c_adapter *adap) { struct octeon_i2c *i2c = i2c_get_adapdata(adap); + /* + * Generate STOP to finish the unfinished transaction. + * Can't generate STOP via the TWSI CTL register + * since it could bring the TWSI controller into an inoperable state. + */ + octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR | TWSI_INT_SCL_OVR); + udelay(5); + octeon_i2c_write_int(i2c, TWSI_INT_SDA_OVR); + udelay(5); octeon_i2c_write_int(i2c, 0); } -static struct i2c_bus_recovery_info octeon_i2c_recovery_info = { +struct i2c_bus_recovery_info octeon_i2c_recovery_info = { .recover_bus = i2c_generic_scl_recovery, .get_scl = octeon_i2c_get_scl, .set_scl = octeon_i2c_set_scl, @@ -1085,171 +825,3 @@ static struct i2c_bus_recovery_info octeon_i2c_recovery_info = { .prepare_recovery = octeon_i2c_prepare_recovery, .unprepare_recovery = octeon_i2c_unprepare_recovery, }; - -static u32 octeon_i2c_functionality(struct i2c_adapter *adap) -{ - return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | - I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL; -} - -static const struct i2c_algorithm octeon_i2c_algo = { - .master_xfer = octeon_i2c_xfer, - .functionality = octeon_i2c_functionality, -}; - -static struct i2c_adapter octeon_i2c_ops = { - .owner = THIS_MODULE, - .name = "OCTEON adapter", - .algo = &octeon_i2c_algo, -}; - -static int octeon_i2c_probe(struct platform_device *pdev) -{ - struct device_node *node = pdev->dev.of_node; - int irq, result = 0, hlc_irq = 0; - struct resource *res_mem; - struct octeon_i2c *i2c; - bool cn78xx_style; - - cn78xx_style = of_device_is_compatible(node, "cavium,octeon-7890-twsi"); - if (cn78xx_style) { - hlc_irq = platform_get_irq(pdev, 0); - if (hlc_irq < 0) - return hlc_irq; - - irq = platform_get_irq(pdev, 2); - if (irq < 0) - return irq; - } else { - /* All adaptors have an irq. */ - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - } - - i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); - if (!i2c) { - result = -ENOMEM; - goto out; - } - i2c->dev = &pdev->dev; - - res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - i2c->twsi_base = devm_ioremap_resource(&pdev->dev, res_mem); - if (IS_ERR(i2c->twsi_base)) { - result = PTR_ERR(i2c->twsi_base); - goto out; - } - - /* - * "clock-rate" is a legacy binding, the official binding is - * "clock-frequency". Try the official one first and then - * fall back if it doesn't exist. - */ - if (of_property_read_u32(node, "clock-frequency", &i2c->twsi_freq) && - of_property_read_u32(node, "clock-rate", &i2c->twsi_freq)) { - dev_err(i2c->dev, - "no I2C 'clock-rate' or 'clock-frequency' property\n"); - result = -ENXIO; - goto out; - } - - i2c->sys_freq = octeon_get_io_clock_rate(); - - init_waitqueue_head(&i2c->queue); - - i2c->irq = irq; - - if (cn78xx_style) { - i2c->hlc_irq = hlc_irq; - - i2c->int_enable = octeon_i2c_int_enable78; - i2c->int_disable = octeon_i2c_int_disable78; - i2c->hlc_int_enable = octeon_i2c_hlc_int_enable78; - i2c->hlc_int_disable = octeon_i2c_hlc_int_disable78; - - irq_set_status_flags(i2c->irq, IRQ_NOAUTOEN); - irq_set_status_flags(i2c->hlc_irq, IRQ_NOAUTOEN); - - result = devm_request_irq(&pdev->dev, i2c->hlc_irq, - octeon_i2c_hlc_isr78, 0, - DRV_NAME, i2c); - if (result < 0) { - dev_err(i2c->dev, "failed to attach interrupt\n"); - goto out; - } - } else { - i2c->int_enable = octeon_i2c_int_enable; - i2c->int_disable = octeon_i2c_int_disable; - i2c->hlc_int_enable = octeon_i2c_hlc_int_enable; - i2c->hlc_int_disable = octeon_i2c_int_disable; - } - - result = devm_request_irq(&pdev->dev, i2c->irq, - octeon_i2c_isr, 0, DRV_NAME, i2c); - if (result < 0) { - dev_err(i2c->dev, "failed to attach interrupt\n"); - goto out; - } - - if (OCTEON_IS_MODEL(OCTEON_CN38XX)) - i2c->broken_irq_check = true; - - result = octeon_i2c_init_lowlevel(i2c); - if (result) { - dev_err(i2c->dev, "init low level failed\n"); - goto out; - } - - octeon_i2c_set_clock(i2c); - - i2c->adap = octeon_i2c_ops; - i2c->adap.timeout = msecs_to_jiffies(2); - i2c->adap.retries = 5; - i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info; - i2c->adap.dev.parent = &pdev->dev; - i2c->adap.dev.of_node = node; - i2c_set_adapdata(&i2c->adap, i2c); - platform_set_drvdata(pdev, i2c); - - result = i2c_add_adapter(&i2c->adap); - if (result < 0) { - dev_err(i2c->dev, "failed to add adapter\n"); - goto out; - } - dev_info(i2c->dev, "probed\n"); - return 0; - -out: - return result; -}; - -static int 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[] = { - { .compatible = "cavium,octeon-3860-twsi", }, - { .compatible = "cavium,octeon-7890-twsi", }, - {}, -}; -MODULE_DEVICE_TABLE(of, octeon_i2c_match); - -static struct platform_driver octeon_i2c_driver = { - .probe = octeon_i2c_probe, - .remove = octeon_i2c_remove, - .driver = { - .name = DRV_NAME, - .of_match_table = octeon_i2c_match, - }, -}; - -module_platform_driver(octeon_i2c_driver); - -MODULE_AUTHOR("Michael Lawnick "); -MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors"); -MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h new file mode 100644 index 000000000000..1db7c835a454 --- /dev/null +++ b/drivers/i2c/busses/i2c-octeon-core.h @@ -0,0 +1,216 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Controller command patterns */ +#define SW_TWSI_V BIT_ULL(63) /* Valid bit */ +#define SW_TWSI_EIA BIT_ULL(61) /* Extended internal address */ +#define SW_TWSI_R BIT_ULL(56) /* Result or read bit */ +#define SW_TWSI_SOVR BIT_ULL(55) /* Size override */ +#define SW_TWSI_SIZE_SHIFT 52 +#define SW_TWSI_ADDR_SHIFT 40 +#define SW_TWSI_IA_SHIFT 32 /* Internal address */ + +/* Controller opcode word (bits 60:57) */ +#define SW_TWSI_OP_SHIFT 57 +#define SW_TWSI_OP_7 (0ULL << SW_TWSI_OP_SHIFT) +#define SW_TWSI_OP_7_IA (1ULL << SW_TWSI_OP_SHIFT) +#define SW_TWSI_OP_10 (2ULL << SW_TWSI_OP_SHIFT) +#define SW_TWSI_OP_10_IA (3ULL << SW_TWSI_OP_SHIFT) +#define SW_TWSI_OP_TWSI_CLK (4ULL << SW_TWSI_OP_SHIFT) +#define SW_TWSI_OP_EOP (6ULL << SW_TWSI_OP_SHIFT) /* Extended opcode */ + +/* Controller extended opcode word (bits 34:32) */ +#define SW_TWSI_EOP_SHIFT 32 +#define SW_TWSI_EOP_TWSI_DATA (SW_TWSI_OP_EOP | 1ULL << SW_TWSI_EOP_SHIFT) +#define SW_TWSI_EOP_TWSI_CTL (SW_TWSI_OP_EOP | 2ULL << SW_TWSI_EOP_SHIFT) +#define SW_TWSI_EOP_TWSI_CLKCTL (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT) +#define SW_TWSI_EOP_TWSI_STAT (SW_TWSI_OP_EOP | 3ULL << SW_TWSI_EOP_SHIFT) +#define SW_TWSI_EOP_TWSI_RST (SW_TWSI_OP_EOP | 7ULL << SW_TWSI_EOP_SHIFT) + +/* 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_IFLG 0x08 /* HW event, SW writes 0 to ACK */ +#define TWSI_CTL_AAK 0x04 /* Assert ACK */ + +/* Status values */ +#define STAT_ERROR 0x00 +#define STAT_START 0x08 +#define STAT_REP_START 0x10 +#define STAT_TXADDR_ACK 0x18 +#define STAT_TXADDR_NAK 0x20 +#define STAT_TXDATA_ACK 0x28 +#define STAT_TXDATA_NAK 0x30 +#define STAT_LOST_ARB_38 0x38 +#define STAT_RXADDR_ACK 0x40 +#define STAT_RXADDR_NAK 0x48 +#define STAT_RXDATA_ACK 0x50 +#define STAT_RXDATA_NAK 0x58 +#define STAT_SLAVE_60 0x60 +#define STAT_LOST_ARB_68 0x68 +#define STAT_SLAVE_70 0x70 +#define STAT_LOST_ARB_78 0x78 +#define STAT_SLAVE_80 0x80 +#define STAT_SLAVE_88 0x88 +#define STAT_GENDATA_ACK 0x90 +#define STAT_GENDATA_NAK 0x98 +#define STAT_SLAVE_A0 0xA0 +#define STAT_SLAVE_A8 0xA8 +#define STAT_LOST_ARB_B0 0xB0 +#define STAT_SLAVE_LOST 0xB8 +#define STAT_SLAVE_NAK 0xC0 +#define STAT_SLAVE_ACK 0xC8 +#define STAT_AD2W_ACK 0xD0 +#define STAT_AD2W_NAK 0xD8 +#define STAT_IDLE 0xF8 + +/* TWSI_INT values */ +#define TWSI_INT_ST_INT BIT_ULL(0) +#define TWSI_INT_TS_INT BIT_ULL(1) +#define TWSI_INT_CORE_INT BIT_ULL(2) +#define TWSI_INT_ST_EN BIT_ULL(4) +#define TWSI_INT_TS_EN BIT_ULL(5) +#define TWSI_INT_CORE_EN BIT_ULL(6) +#define TWSI_INT_SDA_OVR BIT_ULL(8) +#define TWSI_INT_SCL_OVR BIT_ULL(9) +#define TWSI_INT_SDA BIT_ULL(10) +#define TWSI_INT_SCL BIT_ULL(11) + +#define I2C_OCTEON_EVENT_WAIT 80 /* microseconds */ + +/* Register offsets */ +struct octeon_i2c_reg_offset { + unsigned int sw_twsi; + unsigned int twsi_int; + unsigned int sw_twsi_ext; +}; + +#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) + +struct octeon_i2c { + wait_queue_head_t queue; + struct i2c_adapter adap; + struct octeon_i2c_reg_offset roff; + struct clk *clk; + int irq; + int hlc_irq; /* For cn7890 only */ + u32 twsi_freq; + int sys_freq; + void __iomem *twsi_base; + struct device *dev; + bool hlc_enabled; + bool broken_irq_mode; + bool broken_irq_check; + void (*int_enable)(struct octeon_i2c *); + void (*int_disable)(struct octeon_i2c *); + void (*hlc_int_enable)(struct octeon_i2c *); + void (*hlc_int_disable)(struct octeon_i2c *); + atomic_t int_enable_cnt; + atomic_t hlc_int_enable_cnt; +#if IS_ENABLED(CONFIG_I2C_THUNDERX) + struct msix_entry i2c_msix; +#endif + struct i2c_smbus_alert_setup alert_data; + struct i2c_client *ara; +}; + +static inline void octeon_i2c_writeq_flush(u64 val, void __iomem *addr) +{ + __raw_writeq(val, addr); + __raw_readq(addr); /* wait for write to land */ +} + +/** + * octeon_i2c_reg_write - write an I2C core register + * @i2c: The struct octeon_i2c + * @eop_reg: Register selector + * @data: Value to be written + * + * The I2C core registers are accessed indirectly via the SW_TWSI CSR. + */ +static inline void octeon_i2c_reg_write(struct octeon_i2c *i2c, u64 eop_reg, u8 data) +{ + u64 tmp; + + __raw_writeq(SW_TWSI_V | eop_reg | data, i2c->twsi_base + SW_TWSI(i2c)); + + readq_poll_timeout(i2c->twsi_base + SW_TWSI(i2c), tmp, tmp & SW_TWSI_V, + I2C_OCTEON_EVENT_WAIT, i2c->adap.timeout); +} + +#define octeon_i2c_ctl_write(i2c, val) \ + octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_CTL, val) +#define octeon_i2c_data_write(i2c, val) \ + octeon_i2c_reg_write(i2c, SW_TWSI_EOP_TWSI_DATA, val) + +/** + * octeon_i2c_reg_read - read lower bits of an I2C core register + * @i2c: The struct octeon_i2c + * @eop_reg: Register selector + * + * Returns the data. + * + * The I2C core registers are accessed indirectly via the SW_TWSI CSR. + */ +static inline int octeon_i2c_reg_read(struct octeon_i2c *i2c, u64 eop_reg, + int *error) +{ + u64 tmp; + int ret; + + __raw_writeq(SW_TWSI_V | eop_reg | SW_TWSI_R, i2c->twsi_base + SW_TWSI(i2c)); + + ret = readq_poll_timeout(i2c->twsi_base + SW_TWSI(i2c), tmp, + tmp & SW_TWSI_V, I2C_OCTEON_EVENT_WAIT, + i2c->adap.timeout); + if (error) + *error = ret; + return tmp & 0xFF; +} + +#define octeon_i2c_ctl_read(i2c) \ + octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_CTL, NULL) +#define octeon_i2c_data_read(i2c, error) \ + octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_DATA, error) +#define octeon_i2c_stat_read(i2c) \ + octeon_i2c_reg_read(i2c, SW_TWSI_EOP_TWSI_STAT, NULL) + +/** + * octeon_i2c_read_int - read the 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)); +} + +/** + * octeon_i2c_write_int - write the 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)); +} + +/* Prototypes */ +irqreturn_t octeon_i2c_isr(int irq, void *dev_id); +int octeon_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num); +int octeon_i2c_init_lowlevel(struct octeon_i2c *i2c); +void octeon_i2c_set_clock(struct octeon_i2c *i2c); +extern struct i2c_bus_recovery_info octeon_i2c_recovery_info; diff --git a/drivers/i2c/busses/i2c-octeon-platdrv.c b/drivers/i2c/busses/i2c-octeon-platdrv.c new file mode 100644 index 000000000000..917524ce6890 --- /dev/null +++ b/drivers/i2c/busses/i2c-octeon-platdrv.c @@ -0,0 +1,286 @@ +/* + * (C) Copyright 2009-2010 + * Nokia Siemens Networks, michael.lawnick.ext@nsn.com + * + * Portions Copyright (C) 2010 - 2016 Cavium, Inc. + * + * This is a driver for the i2c adapter in Cavium Networks' OCTEON processors. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "i2c-octeon-core.h" + +#define DRV_NAME "i2c-octeon" + +/** + * octeon_i2c_int_enable - enable the CORE interrupt + * @i2c: The struct octeon_i2c + * + * The interrupt will be asserted when there is non-STAT_IDLE state in + * the SW_TWSI_EOP_TWSI_STAT register. + */ +static void octeon_i2c_int_enable(struct octeon_i2c *i2c) +{ + octeon_i2c_write_int(i2c, TWSI_INT_CORE_EN); +} + +/* disable the CORE interrupt */ +static void octeon_i2c_int_disable(struct octeon_i2c *i2c) +{ + /* clear TS/ST/IFLG events */ + octeon_i2c_write_int(i2c, 0); +} + +/** + * octeon_i2c_int_enable78 - enable the CORE interrupt + * @i2c: The struct octeon_i2c + * + * The interrupt will be asserted when there is non-STAT_IDLE state in the + * SW_TWSI_EOP_TWSI_STAT register. + */ +static void octeon_i2c_int_enable78(struct octeon_i2c *i2c) +{ + atomic_inc_return(&i2c->int_enable_cnt); + enable_irq(i2c->irq); +} + +static void __octeon_i2c_irq_disable(atomic_t *cnt, int irq) +{ + int count; + + /* + * The interrupt can be disabled in two places, but we only + * want to make the disable_irq_nosync() call once, so keep + * track with the atomic variable. + */ + count = atomic_dec_if_positive(cnt); + if (count >= 0) + disable_irq_nosync(irq); +} + +/* disable the CORE interrupt */ +static void octeon_i2c_int_disable78(struct octeon_i2c *i2c) +{ + __octeon_i2c_irq_disable(&i2c->int_enable_cnt, i2c->irq); +} + +/** + * octeon_i2c_hlc_int_enable78 - enable the ST interrupt + * @i2c: The struct octeon_i2c + * + * The interrupt will be asserted when there is non-STAT_IDLE state in + * the SW_TWSI_EOP_TWSI_STAT register. + */ +static void octeon_i2c_hlc_int_enable78(struct octeon_i2c *i2c) +{ + atomic_inc_return(&i2c->hlc_int_enable_cnt); + enable_irq(i2c->hlc_irq); +} + +/* disable the ST interrupt */ +static void octeon_i2c_hlc_int_disable78(struct octeon_i2c *i2c) +{ + __octeon_i2c_irq_disable(&i2c->hlc_int_enable_cnt, i2c->hlc_irq); +} + +/* HLC interrupt service routine */ +static irqreturn_t octeon_i2c_hlc_isr78(int irq, void *dev_id) +{ + struct octeon_i2c *i2c = dev_id; + + i2c->hlc_int_disable(i2c); + wake_up(&i2c->queue); + + return IRQ_HANDLED; +} + +static void octeon_i2c_hlc_int_enable(struct octeon_i2c *i2c) +{ + octeon_i2c_write_int(i2c, TWSI_INT_ST_EN); +} + +static u32 octeon_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | + I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL; +} + +static const struct i2c_algorithm octeon_i2c_algo = { + .master_xfer = octeon_i2c_xfer, + .functionality = octeon_i2c_functionality, +}; + +static struct i2c_adapter octeon_i2c_ops = { + .owner = THIS_MODULE, + .name = "OCTEON adapter", + .algo = &octeon_i2c_algo, +}; + +static int octeon_i2c_probe(struct platform_device *pdev) +{ + struct device_node *node = pdev->dev.of_node; + int irq, result = 0, hlc_irq = 0; + struct resource *res_mem; + struct octeon_i2c *i2c; + bool cn78xx_style; + + cn78xx_style = of_device_is_compatible(node, "cavium,octeon-7890-twsi"); + if (cn78xx_style) { + hlc_irq = platform_get_irq(pdev, 0); + if (hlc_irq < 0) + return hlc_irq; + + irq = platform_get_irq(pdev, 2); + if (irq < 0) + return irq; + } else { + /* All adaptors have an irq. */ + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + } + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) { + result = -ENOMEM; + goto out; + } + i2c->dev = &pdev->dev; + + i2c->roff.sw_twsi = 0x00; + i2c->roff.twsi_int = 0x10; + i2c->roff.sw_twsi_ext = 0x18; + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + i2c->twsi_base = devm_ioremap_resource(&pdev->dev, res_mem); + if (IS_ERR(i2c->twsi_base)) { + result = PTR_ERR(i2c->twsi_base); + goto out; + } + + /* + * "clock-rate" is a legacy binding, the official binding is + * "clock-frequency". Try the official one first and then + * fall back if it doesn't exist. + */ + if (of_property_read_u32(node, "clock-frequency", &i2c->twsi_freq) && + of_property_read_u32(node, "clock-rate", &i2c->twsi_freq)) { + dev_err(i2c->dev, + "no I2C 'clock-rate' or 'clock-frequency' property\n"); + result = -ENXIO; + goto out; + } + + i2c->sys_freq = octeon_get_io_clock_rate(); + + init_waitqueue_head(&i2c->queue); + + i2c->irq = irq; + + if (cn78xx_style) { + i2c->hlc_irq = hlc_irq; + + i2c->int_enable = octeon_i2c_int_enable78; + i2c->int_disable = octeon_i2c_int_disable78; + i2c->hlc_int_enable = octeon_i2c_hlc_int_enable78; + i2c->hlc_int_disable = octeon_i2c_hlc_int_disable78; + + irq_set_status_flags(i2c->irq, IRQ_NOAUTOEN); + irq_set_status_flags(i2c->hlc_irq, IRQ_NOAUTOEN); + + result = devm_request_irq(&pdev->dev, i2c->hlc_irq, + octeon_i2c_hlc_isr78, 0, + DRV_NAME, i2c); + if (result < 0) { + dev_err(i2c->dev, "failed to attach interrupt\n"); + goto out; + } + } else { + i2c->int_enable = octeon_i2c_int_enable; + i2c->int_disable = octeon_i2c_int_disable; + i2c->hlc_int_enable = octeon_i2c_hlc_int_enable; + i2c->hlc_int_disable = octeon_i2c_int_disable; + } + + result = devm_request_irq(&pdev->dev, i2c->irq, + octeon_i2c_isr, 0, DRV_NAME, i2c); + if (result < 0) { + dev_err(i2c->dev, "failed to attach interrupt\n"); + goto out; + } + + if (OCTEON_IS_MODEL(OCTEON_CN38XX)) + i2c->broken_irq_check = true; + + result = octeon_i2c_init_lowlevel(i2c); + if (result) { + dev_err(i2c->dev, "init low level failed\n"); + goto out; + } + + octeon_i2c_set_clock(i2c); + + i2c->adap = octeon_i2c_ops; + i2c->adap.timeout = msecs_to_jiffies(2); + i2c->adap.retries = 5; + i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info; + i2c->adap.dev.parent = &pdev->dev; + i2c->adap.dev.of_node = node; + i2c_set_adapdata(&i2c->adap, i2c); + platform_set_drvdata(pdev, i2c); + + result = i2c_add_adapter(&i2c->adap); + if (result < 0) + goto out; + dev_info(i2c->dev, "probed\n"); + return 0; + +out: + return result; +}; + +static int 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[] = { + { .compatible = "cavium,octeon-3860-twsi", }, + { .compatible = "cavium,octeon-7890-twsi", }, + {}, +}; +MODULE_DEVICE_TABLE(of, octeon_i2c_match); + +static struct platform_driver octeon_i2c_driver = { + .probe = octeon_i2c_probe, + .remove = octeon_i2c_remove, + .driver = { + .name = DRV_NAME, + .of_match_table = octeon_i2c_match, + }, +}; + +module_platform_driver(octeon_i2c_driver); + +MODULE_AUTHOR("Michael Lawnick "); +MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors"); +MODULE_LICENSE("GPL"); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index ab1279b8e240..c7da0c42baee 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1425,10 +1425,8 @@ omap_i2c_probe(struct platform_device *pdev) /* i2c device drivers may be active on return from add_adapter() */ adap->nr = pdev->id; r = i2c_add_numbered_adapter(adap); - if (r) { - dev_err(omap->dev, "failure adding adapter\n"); + if (r) goto err_unuse_clocks; - } dev_info(omap->dev, "bus %d rev%d.%d at %d kHz\n", adap->nr, major, minor, omap->speed); diff --git a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c index 23d1c167b5d7..c2268cdf38e8 100644 --- a/drivers/i2c/busses/i2c-piix4.c +++ b/drivers/i2c/busses/i2c-piix4.c @@ -694,7 +694,6 @@ static int piix4_add_adapter(struct pci_dev *dev, unsigned short smba, retval = i2c_add_adapter(adap); if (retval) { - dev_err(&dev->dev, "Couldn't register adapter!\n"); kfree(adapdata); kfree(adap); release_region(smba, SMBIOSIZE); diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c index 2c40edbf6224..217c78711d65 100644 --- a/drivers/i2c/busses/i2c-pmcmsp.c +++ b/drivers/i2c/busses/i2c-pmcmsp.c @@ -329,10 +329,8 @@ static int pmcmsptwi_probe(struct platform_device *pldev) i2c_set_adapdata(&pmcmsptwi_adapter, &pmcmsptwi_data); rc = i2c_add_adapter(&pmcmsptwi_adapter); - if (rc) { - dev_err(&pldev->dev, "Unable to register I2C adapter\n"); + if (rc) goto ret_unmap; - } return 0; diff --git a/drivers/i2c/busses/i2c-pnx.c b/drivers/i2c/busses/i2c-pnx.c index 7ea67aa46fb7..fd5f9d2bf6d9 100644 --- a/drivers/i2c/busses/i2c-pnx.c +++ b/drivers/i2c/busses/i2c-pnx.c @@ -714,10 +714,8 @@ static int i2c_pnx_probe(struct platform_device *pdev) /* Register this adapter with the I2C subsystem */ ret = i2c_add_numbered_adapter(&alg_data->adapter); - if (ret < 0) { - dev_err(&pdev->dev, "I2C: Failed to add bus\n"); + if (ret < 0) goto out_clock; - } dev_dbg(&pdev->dev, "%s: Master at %#8x, irq %d.\n", alg_data->adapter.name, res->start, alg_data->irq); diff --git a/drivers/i2c/busses/i2c-puv3.c b/drivers/i2c/busses/i2c-puv3.c index 82b6f02544da..0c8b1571886d 100644 --- a/drivers/i2c/busses/i2c-puv3.c +++ b/drivers/i2c/busses/i2c-puv3.c @@ -212,11 +212,8 @@ static int puv3_i2c_probe(struct platform_device *pdev) adapter->nr = pdev->id; rc = i2c_add_numbered_adapter(adapter); - if (rc) { - dev_err(&pdev->dev, "Adapter '%s' registration failed\n", - adapter->name); + if (rc) goto fail_add_adapter; - } dev_info(&pdev->dev, "PKUnity v3 i2c bus adapter.\n"); return 0; diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 0d351954db02..e28b825b0433 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1292,10 +1292,8 @@ static int i2c_pxa_probe(struct platform_device *dev) #endif ret = i2c_add_numbered_adapter(&i2c->adap); - if (ret < 0) { - dev_err(&dev->dev, "failed to add bus: %d\n", ret); + if (ret < 0) goto ereqirq; - } platform_set_drvdata(dev, i2c); diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 9bd849dacee8..726615e54f2a 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -802,6 +802,7 @@ static const struct of_device_id rcar_i2c_dt_ids[] = { { .compatible = "renesas,i2c-r8a7793", .data = (void *)I2C_RCAR_GEN2 }, { .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 }, {}, }; MODULE_DEVICE_TABLE(of, rcar_i2c_dt_ids); @@ -875,10 +876,8 @@ static int rcar_i2c_probe(struct platform_device *pdev) platform_set_drvdata(pdev, priv); ret = i2c_add_numbered_adapter(adap); - if (ret < 0) { - dev_err(dev, "reg adap failed: %d\n", ret); + if (ret < 0) goto out_pm_disable; - } dev_info(dev, "probed\n"); diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index d7e3af671543..6263ea82d6ac 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -383,10 +383,8 @@ static int riic_i2c_probe(struct platform_device *pdev) ret = i2c_add_adapter(adap); - if (ret) { - dev_err(&pdev->dev, "failed to add adapter\n"); + if (ret) return ret; - } platform_set_drvdata(pdev, riic); diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index 5c5b7cada8be..50702c7bb244 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -58,7 +58,7 @@ enum { #define REG_CON_LASTACK BIT(5) /* 1: send NACK after last received byte */ #define REG_CON_ACTACK BIT(6) /* 1: stop if NACK is received */ -#define REG_CON_TUNING_MASK GENMASK(15, 8) +#define REG_CON_TUNING_MASK GENMASK_ULL(15, 8) #define REG_CON_SDA_CFG(cfg) ((cfg) << 8) #define REG_CON_STA_CFG(cfg) ((cfg) << 12) @@ -742,7 +742,7 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate, struct i2c_timings *t, struct rk3x_i2c_calced_timings *t_calc) { - unsigned long min_low_ns, min_high_ns, min_total_ns; + unsigned long min_low_ns, min_high_ns; unsigned long min_setup_start_ns, min_setup_data_ns; unsigned long min_setup_stop_ns, max_hold_data_ns; @@ -793,7 +793,6 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate, /* These are the min dividers needed for min hold times. */ min_div_for_hold = (min_low_div + min_high_div); - min_total_ns = min_low_ns + min_high_ns; /* * This is the maximum divider so we don't go over the maximum. @@ -1312,10 +1311,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev) rk3x_i2c_adapt_div(i2c, clk_rate); ret = i2c_add_adapter(&i2c->adap); - if (ret < 0) { - dev_err(&pdev->dev, "Could not register adapter\n"); + if (ret < 0) goto err_clk_notifier; - } dev_info(&pdev->dev, "Initialized RK3xxx I2C bus at %p\n", i2c->regs); diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c index 38dc1cacfd8b..499af26e736e 100644 --- a/drivers/i2c/busses/i2c-s3c2410.c +++ b/drivers/i2c/busses/i2c-s3c2410.c @@ -1215,7 +1215,6 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev) ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) { - dev_err(&pdev->dev, "failed to add bus to i2c core\n"); pm_runtime_disable(&pdev->dev); s3c24xx_i2c_deregister_cpufreq(i2c); clk_unprepare(i2c->clk); diff --git a/drivers/i2c/busses/i2c-sh7760.c b/drivers/i2c/busses/i2c-sh7760.c index 24968384b401..c2005c789d2b 100644 --- a/drivers/i2c/busses/i2c-sh7760.c +++ b/drivers/i2c/busses/i2c-sh7760.c @@ -510,10 +510,8 @@ static int sh7760_i2c_probe(struct platform_device *pdev) } ret = i2c_add_numbered_adapter(&id->adap); - if (ret < 0) { - dev_err(&pdev->dev, "reg adap failed: %d\n", ret); + if (ret < 0) goto out4; - } platform_set_drvdata(pdev, id); diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 05b1eeab9cf5..192f36f00e4d 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -981,7 +981,6 @@ static int sh_mobile_i2c_probe(struct platform_device *dev) ret = i2c_add_numbered_adapter(adap); if (ret < 0) { sh_mobile_i2c_release_dma(pd); - dev_err(&dev->dev, "cannot add numbered adapter\n"); return ret; } diff --git a/drivers/i2c/busses/i2c-sirf.c b/drivers/i2c/busses/i2c-sirf.c index 792a42bdd335..95e81d0f72b4 100644 --- a/drivers/i2c/busses/i2c-sirf.c +++ b/drivers/i2c/busses/i2c-sirf.c @@ -387,10 +387,8 @@ static int i2c_sirfsoc_probe(struct platform_device *pdev) writel(regval, siic->base + SIRFSOC_I2C_SDA_DELAY); err = i2c_add_numbered_adapter(adap); - if (err < 0) { - dev_err(&pdev->dev, "Can't add new i2c adapter\n"); + if (err < 0) goto out; - } clk_disable(clk); diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 944ec4205084..1371547ce1a3 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -874,10 +874,8 @@ static int st_i2c_probe(struct platform_device *pdev) init_completion(&i2c_dev->complete); ret = i2c_add_adapter(adap); - if (ret) { - dev_err(&pdev->dev, "Failed to add adapter\n"); + if (ret) return ret; - } platform_set_drvdata(pdev, i2c_dev); diff --git a/drivers/i2c/busses/i2c-stu300.c b/drivers/i2c/busses/i2c-stu300.c index 460c134832ac..dc63236b45b2 100644 --- a/drivers/i2c/busses/i2c-stu300.c +++ b/drivers/i2c/busses/i2c-stu300.c @@ -920,11 +920,8 @@ static int stu300_probe(struct platform_device *pdev) /* i2c device drivers may be active on return from add_adapter() */ ret = i2c_add_numbered_adapter(adap); - if (ret) { - dev_err(&pdev->dev, "failure adding ST Micro DDC " - "I2C adapter\n"); + if (ret) return ret; - } platform_set_drvdata(pdev, dev); dev_info(&pdev->dev, "ST DDC I2C @ %p, irq %d\n", diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c index b126dbaa47e3..4af9bbae20df 100644 --- a/drivers/i2c/busses/i2c-tegra.c +++ b/drivers/i2c/busses/i2c-tegra.c @@ -28,6 +28,9 @@ #include #include #include +#include +#include +#include #include @@ -36,21 +39,21 @@ #define I2C_CNFG 0x000 #define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12 -#define I2C_CNFG_PACKET_MODE_EN (1<<10) -#define I2C_CNFG_NEW_MASTER_FSM (1<<11) -#define I2C_CNFG_MULTI_MASTER_MODE (1<<17) +#define I2C_CNFG_PACKET_MODE_EN BIT(10) +#define I2C_CNFG_NEW_MASTER_FSM BIT(11) +#define I2C_CNFG_MULTI_MASTER_MODE BIT(17) #define I2C_STATUS 0x01C #define I2C_SL_CNFG 0x020 -#define I2C_SL_CNFG_NACK (1<<1) -#define I2C_SL_CNFG_NEWSL (1<<2) +#define I2C_SL_CNFG_NACK BIT(1) +#define I2C_SL_CNFG_NEWSL BIT(2) #define I2C_SL_ADDR1 0x02c #define I2C_SL_ADDR2 0x030 #define I2C_TX_FIFO 0x050 #define I2C_RX_FIFO 0x054 #define I2C_PACKET_TRANSFER_STATUS 0x058 #define I2C_FIFO_CONTROL 0x05c -#define I2C_FIFO_CONTROL_TX_FLUSH (1<<1) -#define I2C_FIFO_CONTROL_RX_FLUSH (1<<0) +#define I2C_FIFO_CONTROL_TX_FLUSH BIT(1) +#define I2C_FIFO_CONTROL_RX_FLUSH BIT(0) #define I2C_FIFO_CONTROL_TX_TRIG_SHIFT 5 #define I2C_FIFO_CONTROL_RX_TRIG_SHIFT 2 #define I2C_FIFO_STATUS 0x060 @@ -60,26 +63,26 @@ #define I2C_FIFO_STATUS_RX_SHIFT 0 #define I2C_INT_MASK 0x064 #define I2C_INT_STATUS 0x068 -#define I2C_INT_PACKET_XFER_COMPLETE (1<<7) -#define I2C_INT_ALL_PACKETS_XFER_COMPLETE (1<<6) -#define I2C_INT_TX_FIFO_OVERFLOW (1<<5) -#define I2C_INT_RX_FIFO_UNDERFLOW (1<<4) -#define I2C_INT_NO_ACK (1<<3) -#define I2C_INT_ARBITRATION_LOST (1<<2) -#define I2C_INT_TX_FIFO_DATA_REQ (1<<1) -#define I2C_INT_RX_FIFO_DATA_REQ (1<<0) +#define I2C_INT_PACKET_XFER_COMPLETE BIT(7) +#define I2C_INT_ALL_PACKETS_XFER_COMPLETE BIT(6) +#define I2C_INT_TX_FIFO_OVERFLOW BIT(5) +#define I2C_INT_RX_FIFO_UNDERFLOW BIT(4) +#define I2C_INT_NO_ACK BIT(3) +#define I2C_INT_ARBITRATION_LOST BIT(2) +#define I2C_INT_TX_FIFO_DATA_REQ BIT(1) +#define I2C_INT_RX_FIFO_DATA_REQ BIT(0) #define I2C_CLK_DIVISOR 0x06c #define I2C_CLK_DIVISOR_STD_FAST_MODE_SHIFT 16 #define I2C_CLK_MULTIPLIER_STD_FAST_MODE 8 #define DVC_CTRL_REG1 0x000 -#define DVC_CTRL_REG1_INTR_EN (1<<10) +#define DVC_CTRL_REG1_INTR_EN BIT(10) #define DVC_CTRL_REG2 0x004 #define DVC_CTRL_REG3 0x008 -#define DVC_CTRL_REG3_SW_PROG (1<<26) -#define DVC_CTRL_REG3_I2C_DONE_INTR_EN (1<<30) +#define DVC_CTRL_REG3_SW_PROG BIT(26) +#define DVC_CTRL_REG3_I2C_DONE_INTR_EN BIT(30) #define DVC_STATUS 0x00c -#define DVC_STATUS_I2C_DONE_INTR (1<<30) +#define DVC_STATUS_I2C_DONE_INTR BIT(30) #define I2C_ERR_NONE 0x00 #define I2C_ERR_NO_ACK 0x01 @@ -89,26 +92,28 @@ #define PACKET_HEADER0_HEADER_SIZE_SHIFT 28 #define PACKET_HEADER0_PACKET_ID_SHIFT 16 #define PACKET_HEADER0_CONT_ID_SHIFT 12 -#define PACKET_HEADER0_PROTOCOL_I2C (1<<4) +#define PACKET_HEADER0_PROTOCOL_I2C BIT(4) -#define I2C_HEADER_HIGHSPEED_MODE (1<<22) -#define I2C_HEADER_CONT_ON_NAK (1<<21) -#define I2C_HEADER_SEND_START_BYTE (1<<20) -#define I2C_HEADER_READ (1<<19) -#define I2C_HEADER_10BIT_ADDR (1<<18) -#define I2C_HEADER_IE_ENABLE (1<<17) -#define I2C_HEADER_REPEAT_START (1<<16) -#define I2C_HEADER_CONTINUE_XFER (1<<15) +#define I2C_HEADER_HIGHSPEED_MODE BIT(22) +#define I2C_HEADER_CONT_ON_NAK BIT(21) +#define I2C_HEADER_SEND_START_BYTE BIT(20) +#define I2C_HEADER_READ BIT(19) +#define I2C_HEADER_10BIT_ADDR BIT(18) +#define I2C_HEADER_IE_ENABLE BIT(17) +#define I2C_HEADER_REPEAT_START BIT(16) +#define I2C_HEADER_CONTINUE_XFER BIT(15) #define I2C_HEADER_MASTER_ADDR_SHIFT 12 #define I2C_HEADER_SLAVE_ADDR_SHIFT 1 #define I2C_CONFIG_LOAD 0x08C -#define I2C_MSTR_CONFIG_LOAD (1 << 0) -#define I2C_SLV_CONFIG_LOAD (1 << 1) -#define I2C_TIMEOUT_CONFIG_LOAD (1 << 2) +#define I2C_MSTR_CONFIG_LOAD BIT(0) +#define I2C_SLV_CONFIG_LOAD BIT(1) +#define I2C_TIMEOUT_CONFIG_LOAD BIT(2) #define I2C_CLKEN_OVERRIDE 0x090 -#define I2C_MST_CORE_CLKEN_OVR (1 << 0) +#define I2C_MST_CORE_CLKEN_OVR BIT(0) + +#define I2C_CONFIG_LOAD_TIMEOUT 1000000 /* * msg_end_type: The bus control which need to be send at end of transfer. @@ -191,9 +196,11 @@ struct tegra_i2c_dev { u16 clk_divisor_non_hs_mode; bool is_suspended; bool is_multimaster_mode; + spinlock_t xfer_lock; }; -static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, unsigned long reg) +static void dvc_writel(struct tegra_i2c_dev *i2c_dev, u32 val, + unsigned long reg) { writel(val, i2c_dev->base + reg); } @@ -244,15 +251,17 @@ static void i2c_readsl(struct tegra_i2c_dev *i2c_dev, void *data, static void tegra_i2c_mask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask) { - u32 int_mask = i2c_readl(i2c_dev, I2C_INT_MASK); - int_mask &= ~mask; + u32 int_mask; + + int_mask = i2c_readl(i2c_dev, I2C_INT_MASK) & ~mask; i2c_writel(i2c_dev, int_mask, I2C_INT_MASK); } static void tegra_i2c_unmask_irq(struct tegra_i2c_dev *i2c_dev, u32 mask) { - u32 int_mask = i2c_readl(i2c_dev, I2C_INT_MASK); - int_mask |= mask; + u32 int_mask; + + int_mask = i2c_readl(i2c_dev, I2C_INT_MASK) | mask; i2c_writel(i2c_dev, int_mask, I2C_INT_MASK); } @@ -260,6 +269,7 @@ static int tegra_i2c_flush_fifos(struct tegra_i2c_dev *i2c_dev) { unsigned long timeout = jiffies + HZ; u32 val = i2c_readl(i2c_dev, I2C_FIFO_CONTROL); + val |= I2C_FIFO_CONTROL_TX_FLUSH | I2C_FIFO_CONTROL_RX_FLUSH; i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); @@ -385,7 +395,8 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev) */ static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev) { - u32 val = 0; + u32 val; + val = dvc_readl(i2c_dev, DVC_CTRL_REG3); val |= DVC_CTRL_REG3_SW_PROG; val |= DVC_CTRL_REG3_I2C_DONE_INTR_EN; @@ -396,9 +407,15 @@ static void tegra_dvc_init(struct tegra_i2c_dev *i2c_dev) dvc_writel(i2c_dev, val, DVC_CTRL_REG1); } -static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev) +static int tegra_i2c_runtime_resume(struct device *dev) { + struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); int ret; + + ret = pinctrl_pm_select_default_state(i2c_dev->dev); + if (ret) + return ret; + if (!i2c_dev->hw->has_single_clk_source) { ret = clk_enable(i2c_dev->fast_clk); if (ret < 0) { @@ -407,32 +424,66 @@ static inline int tegra_i2c_clock_enable(struct tegra_i2c_dev *i2c_dev) return ret; } } + ret = clk_enable(i2c_dev->div_clk); if (ret < 0) { dev_err(i2c_dev->dev, "Enabling div clk failed, err %d\n", ret); clk_disable(i2c_dev->fast_clk); + return ret; } - return ret; + + return 0; } -static inline void tegra_i2c_clock_disable(struct tegra_i2c_dev *i2c_dev) +static int tegra_i2c_runtime_suspend(struct device *dev) { + struct tegra_i2c_dev *i2c_dev = dev_get_drvdata(dev); + clk_disable(i2c_dev->div_clk); if (!i2c_dev->hw->has_single_clk_source) clk_disable(i2c_dev->fast_clk); + + return pinctrl_pm_select_idle_state(i2c_dev->dev); +} + +static int tegra_i2c_wait_for_config_load(struct tegra_i2c_dev *i2c_dev) +{ + unsigned long reg_offset; + void __iomem *addr; + u32 val; + int err; + + if (i2c_dev->hw->has_config_load_reg) { + reg_offset = tegra_i2c_reg_addr(i2c_dev, I2C_CONFIG_LOAD); + addr = i2c_dev->base + reg_offset; + i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD); + if (in_interrupt()) + err = readl_poll_timeout_atomic(addr, val, val == 0, + 1000, I2C_CONFIG_LOAD_TIMEOUT); + else + err = readl_poll_timeout(addr, val, val == 0, + 1000, I2C_CONFIG_LOAD_TIMEOUT); + + if (err) { + dev_warn(i2c_dev->dev, + "timeout waiting for config load\n"); + return err; + } + } + + return 0; } static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) { u32 val; - int err = 0; + int err; u32 clk_divisor; - unsigned long timeout = jiffies + HZ; - err = tegra_i2c_clock_enable(i2c_dev); + err = pm_runtime_get_sync(i2c_dev->dev); if (err < 0) { - dev_err(i2c_dev->dev, "Clock enable failed %d\n", err); + dev_err(i2c_dev->dev, "runtime resume failed %d\n", err); return err; } @@ -460,54 +511,59 @@ static int tegra_i2c_init(struct tegra_i2c_dev *i2c_dev) if (!i2c_dev->is_dvc) { u32 sl_cfg = i2c_readl(i2c_dev, I2C_SL_CNFG); + sl_cfg |= I2C_SL_CNFG_NACK | I2C_SL_CNFG_NEWSL; i2c_writel(i2c_dev, sl_cfg, I2C_SL_CNFG); i2c_writel(i2c_dev, 0xfc, I2C_SL_ADDR1); i2c_writel(i2c_dev, 0x00, I2C_SL_ADDR2); - } val = 7 << I2C_FIFO_CONTROL_TX_TRIG_SHIFT | 0 << I2C_FIFO_CONTROL_RX_TRIG_SHIFT; i2c_writel(i2c_dev, val, I2C_FIFO_CONTROL); - if (tegra_i2c_flush_fifos(i2c_dev)) - err = -ETIMEDOUT; + err = tegra_i2c_flush_fifos(i2c_dev); + if (err) + goto err; if (i2c_dev->is_multimaster_mode && i2c_dev->hw->has_slcg_override_reg) i2c_writel(i2c_dev, I2C_MST_CORE_CLKEN_OVR, I2C_CLKEN_OVERRIDE); - if (i2c_dev->hw->has_config_load_reg) { - i2c_writel(i2c_dev, I2C_MSTR_CONFIG_LOAD, I2C_CONFIG_LOAD); - while (i2c_readl(i2c_dev, I2C_CONFIG_LOAD) != 0) { - if (time_after(jiffies, timeout)) { - dev_warn(i2c_dev->dev, - "timeout waiting for config load\n"); - err = -ETIMEDOUT; - goto err; - } - msleep(1); - } - } + err = tegra_i2c_wait_for_config_load(i2c_dev); + if (err) + goto err; if (i2c_dev->irq_disabled) { - i2c_dev->irq_disabled = 0; + i2c_dev->irq_disabled = false; enable_irq(i2c_dev->irq); } err: - tegra_i2c_clock_disable(i2c_dev); + pm_runtime_put(i2c_dev->dev); return err; } +static int tegra_i2c_disable_packet_mode(struct tegra_i2c_dev *i2c_dev) +{ + u32 cnfg; + + cnfg = i2c_readl(i2c_dev, I2C_CNFG); + if (cnfg & I2C_CNFG_PACKET_MODE_EN) + i2c_writel(i2c_dev, cnfg & ~I2C_CNFG_PACKET_MODE_EN, I2C_CNFG); + + return tegra_i2c_wait_for_config_load(i2c_dev); +} + static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) { u32 status; const u32 status_err = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST; struct tegra_i2c_dev *i2c_dev = dev_id; + unsigned long flags; status = i2c_readl(i2c_dev, I2C_INT_STATUS); + spin_lock_irqsave(&i2c_dev->xfer_lock, flags); if (status == 0) { dev_warn(i2c_dev->dev, "irq status 0 %08x %08x %08x\n", i2c_readl(i2c_dev, I2C_PACKET_TRANSFER_STATUS), @@ -517,12 +573,13 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) if (!i2c_dev->irq_disabled) { disable_irq_nosync(i2c_dev->irq); - i2c_dev->irq_disabled = 1; + i2c_dev->irq_disabled = true; } goto err; } if (unlikely(status & status_err)) { + tegra_i2c_disable_packet_mode(i2c_dev); if (status & I2C_INT_NO_ACK) i2c_dev->msg_err |= I2C_ERR_NO_ACK; if (status & I2C_INT_ARBITRATION_LOST) @@ -552,7 +609,7 @@ static irqreturn_t tegra_i2c_isr(int irq, void *dev_id) BUG_ON(i2c_dev->msg_buf_remaining); complete(&i2c_dev->msg_complete); } - return IRQ_HANDLED; + goto done; err: /* An error occurred, mask all interrupts */ tegra_i2c_mask_irq(i2c_dev, I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST | @@ -563,6 +620,8 @@ err: dvc_writel(i2c_dev, DVC_STATUS_I2C_DONE_INTR, DVC_STATUS); complete(&i2c_dev->msg_complete); +done: + spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags); return IRQ_HANDLED; } @@ -572,6 +631,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, u32 packet_header; u32 int_mask; unsigned long time_left; + unsigned long flags; tegra_i2c_flush_fifos(i2c_dev); @@ -584,6 +644,11 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, i2c_dev->msg_read = (msg->flags & I2C_M_RD); reinit_completion(&i2c_dev->msg_complete); + spin_lock_irqsave(&i2c_dev->xfer_lock, flags); + + int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST; + tegra_i2c_unmask_irq(i2c_dev, int_mask); + packet_header = (0 << PACKET_HEADER0_HEADER_SIZE_SHIFT) | PACKET_HEADER0_PROTOCOL_I2C | (i2c_dev->cont_id << PACKET_HEADER0_CONT_ID_SHIFT) | @@ -613,14 +678,15 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, if (!(msg->flags & I2C_M_RD)) tegra_i2c_fill_tx_fifo(i2c_dev); - int_mask = I2C_INT_NO_ACK | I2C_INT_ARBITRATION_LOST; if (i2c_dev->hw->has_per_pkt_xfer_complete_irq) int_mask |= I2C_INT_PACKET_XFER_COMPLETE; if (msg->flags & I2C_M_RD) int_mask |= I2C_INT_RX_FIFO_DATA_REQ; else if (i2c_dev->msg_buf_remaining) int_mask |= I2C_INT_TX_FIFO_DATA_REQ; + tegra_i2c_unmask_irq(i2c_dev, int_mask); + spin_unlock_irqrestore(&i2c_dev->xfer_lock, flags); dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n", i2c_readl(i2c_dev, I2C_INT_MASK)); @@ -643,9 +709,10 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev, return 0; /* - * NACK interrupt is generated before the I2C controller generates the - * STOP condition on the bus. So wait for 2 clock periods before resetting - * the controller so that STOP condition has been delivered properly. + * NACK interrupt is generated before the I2C controller generates + * the STOP condition on the bus. So wait for 2 clock periods + * before resetting the controller so that the STOP condition has + * been delivered properly. */ if (i2c_dev->msg_err == I2C_ERR_NO_ACK) udelay(DIV_ROUND_UP(2 * 1000000, i2c_dev->bus_clk_rate)); @@ -670,14 +737,15 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (i2c_dev->is_suspended) return -EBUSY; - ret = tegra_i2c_clock_enable(i2c_dev); + ret = pm_runtime_get_sync(i2c_dev->dev); if (ret < 0) { - dev_err(i2c_dev->dev, "Clock enable failed %d\n", ret); + dev_err(i2c_dev->dev, "runtime resume failed %d\n", ret); return ret; } for (i = 0; i < num; i++) { enum msg_end_type end_type = MSG_END_STOP; + if (i < (num - 1)) { if (msgs[i + 1].flags & I2C_M_NOSTART) end_type = MSG_END_CONTINUE; @@ -688,7 +756,9 @@ static int tegra_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], if (ret) break; } - tegra_i2c_clock_disable(i2c_dev); + + pm_runtime_put(i2c_dev->dev); + return ret ?: i; } @@ -825,7 +895,7 @@ static int tegra_i2c_probe(struct platform_device *pdev) div_clk = devm_clk_get(&pdev->dev, "div-clk"); if (IS_ERR(div_clk)) { - dev_err(&pdev->dev, "missing controller clock"); + dev_err(&pdev->dev, "missing controller clock\n"); return PTR_ERR(div_clk); } @@ -843,27 +913,22 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_dev->rst = devm_reset_control_get(&pdev->dev, "i2c"); if (IS_ERR(i2c_dev->rst)) { - dev_err(&pdev->dev, "missing controller reset"); + dev_err(&pdev->dev, "missing controller reset\n"); return PTR_ERR(i2c_dev->rst); } tegra_i2c_parse_dt(i2c_dev); - i2c_dev->hw = &tegra20_i2c_hw; - - if (pdev->dev.of_node) { - i2c_dev->hw = of_device_get_match_data(&pdev->dev); - i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, - "nvidia,tegra20-i2c-dvc"); - } else if (pdev->id == 3) { - i2c_dev->is_dvc = 1; - } + i2c_dev->hw = of_device_get_match_data(&pdev->dev); + i2c_dev->is_dvc = of_device_is_compatible(pdev->dev.of_node, + "nvidia,tegra20-i2c-dvc"); init_completion(&i2c_dev->msg_complete); + spin_lock_init(&i2c_dev->xfer_lock); if (!i2c_dev->hw->has_single_clk_source) { fast_clk = devm_clk_get(&pdev->dev, "fast-clk"); if (IS_ERR(fast_clk)) { - dev_err(&pdev->dev, "missing fast clock"); + dev_err(&pdev->dev, "missing fast clock\n"); return PTR_ERR(fast_clk); } i2c_dev->fast_clk = fast_clk; @@ -900,18 +965,27 @@ static int tegra_i2c_probe(struct platform_device *pdev) goto unprepare_fast_clk; } + pm_runtime_enable(&pdev->dev); + if (!pm_runtime_enabled(&pdev->dev)) { + ret = tegra_i2c_runtime_resume(&pdev->dev); + if (ret < 0) { + dev_err(&pdev->dev, "runtime resume failed\n"); + goto unprepare_div_clk; + } + } + if (i2c_dev->is_multimaster_mode) { ret = clk_enable(i2c_dev->div_clk); if (ret < 0) { dev_err(i2c_dev->dev, "div_clk enable failed %d\n", ret); - goto unprepare_div_clk; + goto disable_rpm; } } ret = tegra_i2c_init(i2c_dev); if (ret) { - dev_err(&pdev->dev, "Failed to initialize i2c controller"); + dev_err(&pdev->dev, "Failed to initialize i2c controller\n"); goto disable_div_clk; } @@ -925,17 +999,15 @@ static int tegra_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&i2c_dev->adapter, i2c_dev); i2c_dev->adapter.owner = THIS_MODULE; i2c_dev->adapter.class = I2C_CLASS_DEPRECATED; - strlcpy(i2c_dev->adapter.name, "Tegra I2C adapter", + strlcpy(i2c_dev->adapter.name, dev_name(&pdev->dev), sizeof(i2c_dev->adapter.name)); i2c_dev->adapter.dev.parent = &pdev->dev; i2c_dev->adapter.nr = pdev->id; i2c_dev->adapter.dev.of_node = pdev->dev.of_node; ret = i2c_add_numbered_adapter(&i2c_dev->adapter); - if (ret) { - dev_err(&pdev->dev, "Failed to add I2C adapter\n"); + if (ret) goto disable_div_clk; - } return 0; @@ -943,6 +1015,11 @@ disable_div_clk: if (i2c_dev->is_multimaster_mode) clk_disable(i2c_dev->div_clk); +disable_rpm: + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + tegra_i2c_runtime_suspend(&pdev->dev); + unprepare_div_clk: clk_unprepare(i2c_dev->div_clk); @@ -956,11 +1033,16 @@ unprepare_fast_clk: static int tegra_i2c_remove(struct platform_device *pdev) { struct tegra_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + i2c_del_adapter(&i2c_dev->adapter); if (i2c_dev->is_multimaster_mode) clk_disable(i2c_dev->div_clk); + pm_runtime_disable(&pdev->dev); + if (!pm_runtime_status_suspended(&pdev->dev)) + tegra_i2c_runtime_suspend(&pdev->dev); + clk_unprepare(i2c_dev->div_clk); if (!i2c_dev->hw->has_single_clk_source) clk_unprepare(i2c_dev->fast_clk); @@ -988,20 +1070,19 @@ static int tegra_i2c_resume(struct device *dev) i2c_lock_adapter(&i2c_dev->adapter); ret = tegra_i2c_init(i2c_dev); - - if (ret) { - i2c_unlock_adapter(&i2c_dev->adapter); - return ret; - } - - i2c_dev->is_suspended = false; + if (!ret) + i2c_dev->is_suspended = false; i2c_unlock_adapter(&i2c_dev->adapter); - return 0; + return ret; } -static SIMPLE_DEV_PM_OPS(tegra_i2c_pm, tegra_i2c_suspend, tegra_i2c_resume); +static const struct dev_pm_ops tegra_i2c_pm = { + SET_RUNTIME_PM_OPS(tegra_i2c_runtime_suspend, tegra_i2c_runtime_resume, + NULL) + SET_SYSTEM_SLEEP_PM_OPS(tegra_i2c_suspend, tegra_i2c_resume) +}; #define TEGRA_I2C_PM (&tegra_i2c_pm) #else #define TEGRA_I2C_PM NULL diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c new file mode 100644 index 000000000000..bba5b429f69c --- /dev/null +++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c @@ -0,0 +1,259 @@ +/* + * Cavium ThunderX i2c driver. + * + * Copyright (C) 2015,2016 Cavium Inc. + * Authors: Fred Martin + * Jan Glauber + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "i2c-octeon-core.h" + +#define DRV_NAME "i2c-thunderx" + +#define PCI_DEVICE_ID_THUNDER_TWSI 0xa012 + +#define SYS_FREQ_DEFAULT 700000000 + +#define TWSI_INT_ENA_W1C 0x1028 +#define TWSI_INT_ENA_W1S 0x1030 + +/* + * Enable the CORE interrupt. + * The interrupt will be asserted when there is non-STAT_IDLE state in the + * SW_TWSI_EOP_TWSI_STAT register. + */ +static void thunder_i2c_int_enable(struct octeon_i2c *i2c) +{ + octeon_i2c_writeq_flush(TWSI_INT_CORE_INT, + i2c->twsi_base + TWSI_INT_ENA_W1S); +} + +/* + * Disable the CORE interrupt. + */ +static void thunder_i2c_int_disable(struct octeon_i2c *i2c) +{ + octeon_i2c_writeq_flush(TWSI_INT_CORE_INT, + i2c->twsi_base + TWSI_INT_ENA_W1C); +} + +static void thunder_i2c_hlc_int_enable(struct octeon_i2c *i2c) +{ + octeon_i2c_writeq_flush(TWSI_INT_ST_INT | TWSI_INT_TS_INT, + i2c->twsi_base + TWSI_INT_ENA_W1S); +} + +static void thunder_i2c_hlc_int_disable(struct octeon_i2c *i2c) +{ + octeon_i2c_writeq_flush(TWSI_INT_ST_INT | TWSI_INT_TS_INT, + i2c->twsi_base + TWSI_INT_ENA_W1C); +} + +static u32 thunderx_i2c_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | + I2C_FUNC_SMBUS_READ_BLOCK_DATA | I2C_SMBUS_BLOCK_PROC_CALL; +} + +static const struct i2c_algorithm thunderx_i2c_algo = { + .master_xfer = octeon_i2c_xfer, + .functionality = thunderx_i2c_functionality, +}; + +static struct i2c_adapter thunderx_i2c_ops = { + .owner = THIS_MODULE, + .name = "ThunderX adapter", + .algo = &thunderx_i2c_algo, +}; + +static void thunder_i2c_clock_enable(struct device *dev, struct octeon_i2c *i2c) +{ + int ret; + + i2c->clk = clk_get(dev, NULL); + if (IS_ERR(i2c->clk)) { + i2c->clk = NULL; + goto skip; + } + + ret = clk_prepare_enable(i2c->clk); + if (ret) + goto skip; + i2c->sys_freq = clk_get_rate(i2c->clk); + +skip: + if (!i2c->sys_freq) + i2c->sys_freq = SYS_FREQ_DEFAULT; +} + +static void thunder_i2c_clock_disable(struct device *dev, struct clk *clk) +{ + if (!clk) + return; + clk_disable_unprepare(clk); + clk_put(clk); +} + +static int thunder_i2c_smbus_setup_of(struct octeon_i2c *i2c, + struct device_node *node) +{ + u32 type; + + if (!node) + return -EINVAL; + + i2c->alert_data.irq = irq_of_parse_and_map(node, 0); + if (!i2c->alert_data.irq) + return -EINVAL; + + type = irqd_get_trigger_type(irq_get_irq_data(i2c->alert_data.irq)); + i2c->alert_data.alert_edge_triggered = + (type & IRQ_TYPE_LEVEL_MASK) ? 1 : 0; + + i2c->ara = i2c_setup_smbus_alert(&i2c->adap, &i2c->alert_data); + if (!i2c->ara) + return -ENODEV; + return 0; +} + +static int thunder_i2c_smbus_setup(struct octeon_i2c *i2c, + struct device_node *node) +{ + /* TODO: ACPI support */ + if (!acpi_disabled) + return -EOPNOTSUPP; + + return thunder_i2c_smbus_setup_of(i2c, node); +} + +static void thunder_i2c_smbus_remove(struct octeon_i2c *i2c) +{ + if (i2c->ara) + i2c_unregister_device(i2c->ara); +} + +static int thunder_i2c_probe_pci(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct device *dev = &pdev->dev; + struct octeon_i2c *i2c; + int ret; + + i2c = devm_kzalloc(dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + i2c->roff.sw_twsi = 0x1000; + i2c->roff.twsi_int = 0x1010; + i2c->roff.sw_twsi_ext = 0x1018; + + i2c->dev = dev; + pci_set_drvdata(pdev, i2c); + ret = pcim_enable_device(pdev); + if (ret) + return ret; + + ret = pci_request_regions(pdev, DRV_NAME); + if (ret) + return ret; + + i2c->twsi_base = pcim_iomap(pdev, 0, pci_resource_len(pdev, 0)); + if (!i2c->twsi_base) + return -EINVAL; + + thunder_i2c_clock_enable(dev, i2c); + ret = device_property_read_u32(dev, "clock-frequency", &i2c->twsi_freq); + if (ret) + i2c->twsi_freq = 100000; + + init_waitqueue_head(&i2c->queue); + + i2c->int_enable = thunder_i2c_int_enable; + i2c->int_disable = thunder_i2c_int_disable; + i2c->hlc_int_enable = thunder_i2c_hlc_int_enable; + i2c->hlc_int_disable = thunder_i2c_hlc_int_disable; + + ret = pci_enable_msix(pdev, &i2c->i2c_msix, 1); + if (ret) + goto error; + + ret = devm_request_irq(dev, i2c->i2c_msix.vector, octeon_i2c_isr, 0, + DRV_NAME, i2c); + if (ret) + goto error; + + ret = octeon_i2c_init_lowlevel(i2c); + if (ret) + goto error; + + octeon_i2c_set_clock(i2c); + + i2c->adap = thunderx_i2c_ops; + i2c->adap.retries = 5; + i2c->adap.bus_recovery_info = &octeon_i2c_recovery_info; + i2c->adap.dev.parent = dev; + i2c->adap.dev.of_node = pdev->dev.of_node; + snprintf(i2c->adap.name, sizeof(i2c->adap.name), + "Cavium ThunderX i2c adapter at %s", dev_name(dev)); + i2c_set_adapdata(&i2c->adap, i2c); + + ret = i2c_add_adapter(&i2c->adap); + if (ret) + goto error; + + dev_info(i2c->dev, "Probed. Set system clock to %u\n", i2c->sys_freq); + + ret = thunder_i2c_smbus_setup(i2c, pdev->dev.of_node); + if (ret) + dev_info(dev, "SMBUS alert not active on this bus\n"); + + return 0; + +error: + thunder_i2c_clock_disable(dev, i2c->clk); + return ret; +} + +static void thunder_i2c_remove_pci(struct pci_dev *pdev) +{ + struct octeon_i2c *i2c = pci_get_drvdata(pdev); + + thunder_i2c_smbus_remove(i2c); + thunder_i2c_clock_disable(&pdev->dev, i2c->clk); + i2c_del_adapter(&i2c->adap); +} + +static const struct pci_device_id thunder_i2c_pci_id_table[] = { + { PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVICE_ID_THUNDER_TWSI) }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, thunder_i2c_pci_id_table); + +static struct pci_driver thunder_i2c_pci_driver = { + .name = DRV_NAME, + .id_table = thunder_i2c_pci_id_table, + .probe = thunder_i2c_probe_pci, + .remove = thunder_i2c_remove_pci, +}; + +module_pci_driver(thunder_i2c_pci_driver); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Fred Martin "); +MODULE_DESCRIPTION("I2C-Bus adapter for Cavium ThunderX SOC"); diff --git a/drivers/i2c/busses/i2c-uniphier-f.c b/drivers/i2c/busses/i2c-uniphier-f.c index aeead0d27d10..db9105e52c79 100644 --- a/drivers/i2c/busses/i2c-uniphier-f.c +++ b/drivers/i2c/busses/i2c-uniphier-f.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -348,14 +349,19 @@ static int uniphier_fi2c_master_xfer_one(struct i2c_adapter *adap, dev_dbg(&adap->dev, "complete\n"); if (unlikely(priv->flags & UNIPHIER_FI2C_DEFER_STOP_COMP)) { - u32 status = readl(priv->membase + UNIPHIER_FI2C_SR); + u32 status; + int ret; - if (!(status & UNIPHIER_FI2C_SR_STS) || - status & UNIPHIER_FI2C_SR_BB) { + ret = readl_poll_timeout(priv->membase + UNIPHIER_FI2C_SR, + status, + (status & UNIPHIER_FI2C_SR_STS) && + !(status & UNIPHIER_FI2C_SR_BB), + 1, 20); + if (ret) { dev_err(&adap->dev, "stop condition was not completed.\n"); uniphier_fi2c_recover(priv); - return -EBUSY; + return ret; } } @@ -455,54 +461,25 @@ static struct i2c_bus_recovery_info uniphier_fi2c_bus_recovery_info = { .unprepare_recovery = uniphier_fi2c_unprepare_recovery, }; -static int uniphier_fi2c_clk_init(struct device *dev, - struct uniphier_fi2c_priv *priv) +static void uniphier_fi2c_hw_init(struct uniphier_fi2c_priv *priv, + u32 bus_speed, unsigned long clk_rate) { - struct device_node *np = dev->of_node; - unsigned long clk_rate; - u32 bus_speed, clk_count; - int ret; + u32 tmp; - if (of_property_read_u32(np, "clock-frequency", &bus_speed)) - bus_speed = UNIPHIER_FI2C_DEFAULT_SPEED; - - if (!bus_speed) { - dev_err(dev, "clock-frequency should not be zero\n"); - return -EINVAL; - } - - if (bus_speed > UNIPHIER_FI2C_MAX_SPEED) - bus_speed = UNIPHIER_FI2C_MAX_SPEED; - - /* Get input clk rate through clk driver */ - 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); - } - - ret = clk_prepare_enable(priv->clk); - if (ret) - return ret; - - clk_rate = clk_get_rate(priv->clk); - if (!clk_rate) { - dev_err(dev, "input clock rate should not be zero\n"); - return -EINVAL; - } + tmp = readl(priv->membase + UNIPHIER_FI2C_CR); + tmp |= UNIPHIER_FI2C_CR_MST; + writel(tmp, priv->membase + UNIPHIER_FI2C_CR); uniphier_fi2c_reset(priv); - clk_count = clk_rate / bus_speed; + tmp = clk_rate / bus_speed; - writel(clk_count, priv->membase + UNIPHIER_FI2C_CYC); - writel(clk_count / 2, priv->membase + UNIPHIER_FI2C_LCTL); - writel(clk_count / 2, priv->membase + UNIPHIER_FI2C_SSUT); - writel(clk_count / 16, priv->membase + UNIPHIER_FI2C_DSUT); + writel(tmp, priv->membase + UNIPHIER_FI2C_CYC); + writel(tmp / 2, priv->membase + UNIPHIER_FI2C_LCTL); + writel(tmp / 2, priv->membase + UNIPHIER_FI2C_SSUT); + writel(tmp / 16, priv->membase + UNIPHIER_FI2C_DSUT); uniphier_fi2c_prepare_operation(priv); - - return 0; } static int uniphier_fi2c_probe(struct platform_device *pdev) @@ -510,8 +487,9 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct uniphier_fi2c_priv *priv; struct resource *regs; - int irq; - int ret; + u32 bus_speed; + unsigned long clk_rate; + int irq, ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -528,6 +506,31 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) return irq; } + if (of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed)) + bus_speed = UNIPHIER_FI2C_DEFAULT_SPEED; + + if (!bus_speed || bus_speed > UNIPHIER_FI2C_MAX_SPEED) { + 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); + } + + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + clk_rate = clk_get_rate(priv->clk); + if (!clk_rate) { + dev_err(dev, "input clock rate should not be zero\n"); + ret = -EINVAL; + goto err; + } + init_completion(&priv->comp); priv->adap.owner = THIS_MODULE; priv->adap.algo = &uniphier_fi2c_algo; @@ -538,9 +541,7 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) i2c_set_adapdata(&priv->adap, priv); platform_set_drvdata(pdev, priv); - ret = uniphier_fi2c_clk_init(dev, priv); - if (ret) - goto err; + uniphier_fi2c_hw_init(priv, bus_speed, clk_rate); ret = devm_request_irq(dev, irq, uniphier_fi2c_interrupt, 0, pdev->name, priv); @@ -550,11 +551,6 @@ static int uniphier_fi2c_probe(struct platform_device *pdev) } ret = i2c_add_adapter(&priv->adap); - if (ret) { - dev_err(dev, "failed to add I2C adapter\n"); - goto err; - } - err: if (ret) clk_disable_unprepare(priv->clk); diff --git a/drivers/i2c/busses/i2c-uniphier.c b/drivers/i2c/busses/i2c-uniphier.c index 475a5eb514e2..56e92af46ddc 100644 --- a/drivers/i2c/busses/i2c-uniphier.c +++ b/drivers/i2c/busses/i2c-uniphier.c @@ -316,50 +316,15 @@ static struct i2c_bus_recovery_info uniphier_i2c_bus_recovery_info = { .unprepare_recovery = uniphier_i2c_unprepare_recovery, }; -static int uniphier_i2c_clk_init(struct device *dev, - struct uniphier_i2c_priv *priv) +static void uniphier_i2c_hw_init(struct uniphier_i2c_priv *priv, + u32 bus_speed, unsigned long clk_rate) { - struct device_node *np = dev->of_node; - unsigned long clk_rate; - u32 bus_speed; - int ret; - - if (of_property_read_u32(np, "clock-frequency", &bus_speed)) - bus_speed = UNIPHIER_I2C_DEFAULT_SPEED; - - if (!bus_speed) { - dev_err(dev, "clock-frequency should not be zero\n"); - return -EINVAL; - } - - if (bus_speed > UNIPHIER_I2C_MAX_SPEED) - bus_speed = UNIPHIER_I2C_MAX_SPEED; - - /* Get input clk rate through clk driver */ - 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); - } - - ret = clk_prepare_enable(priv->clk); - if (ret) - return ret; - - clk_rate = clk_get_rate(priv->clk); - if (!clk_rate) { - dev_err(dev, "input clock rate should not be zero\n"); - return -EINVAL; - } - uniphier_i2c_reset(priv, true); writel((clk_rate / bus_speed / 2 << 16) | (clk_rate / bus_speed), priv->membase + UNIPHIER_I2C_CLK); uniphier_i2c_reset(priv, false); - - return 0; } static int uniphier_i2c_probe(struct platform_device *pdev) @@ -367,8 +332,9 @@ static int uniphier_i2c_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct uniphier_i2c_priv *priv; struct resource *regs; - int irq; - int ret; + u32 bus_speed; + unsigned long clk_rate; + int irq, ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -385,6 +351,31 @@ static int uniphier_i2c_probe(struct platform_device *pdev) return irq; } + if (of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed)) + bus_speed = UNIPHIER_I2C_DEFAULT_SPEED; + + if (!bus_speed || bus_speed > UNIPHIER_I2C_MAX_SPEED) { + 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); + } + + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + + clk_rate = clk_get_rate(priv->clk); + if (!clk_rate) { + dev_err(dev, "input clock rate should not be zero\n"); + ret = -EINVAL; + goto err; + } + init_completion(&priv->comp); priv->adap.owner = THIS_MODULE; priv->adap.algo = &uniphier_i2c_algo; @@ -395,9 +386,7 @@ static int uniphier_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&priv->adap, priv); platform_set_drvdata(pdev, priv); - ret = uniphier_i2c_clk_init(dev, priv); - if (ret) - goto err; + uniphier_i2c_hw_init(priv, bus_speed, clk_rate); ret = devm_request_irq(dev, irq, uniphier_i2c_interrupt, 0, pdev->name, priv); @@ -407,11 +396,6 @@ static int uniphier_i2c_probe(struct platform_device *pdev) } ret = i2c_add_adapter(&priv->adap); - if (ret) { - dev_err(dev, "failed to add I2C adapter\n"); - goto err; - } - err: if (ret) clk_disable_unprepare(priv->clk); diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c index e1e3a85596c5..fbd0fd59f312 100644 --- a/drivers/i2c/busses/i2c-wmt.c +++ b/drivers/i2c/busses/i2c-wmt.c @@ -432,10 +432,8 @@ static int wmt_i2c_probe(struct platform_device *pdev) } err = i2c_add_adapter(adap); - if (err) { - dev_err(&pdev->dev, "failed to add adapter\n"); + if (err) return err; - } platform_set_drvdata(pdev, i2c_dev); diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c index 4233f5695352..263685c7a512 100644 --- a/drivers/i2c/busses/i2c-xgene-slimpro.c +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -418,7 +418,6 @@ static int xgene_slimpro_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(adapter, ctx); rc = i2c_add_adapter(adapter); if (rc) { - dev_err(&pdev->dev, "Adapter registeration failed\n"); mbox_free_channel(ctx->mbox_chan); return rc; } diff --git a/drivers/i2c/busses/i2c-xiic.c b/drivers/i2c/busses/i2c-xiic.c index 74f54f2f471f..66bce3b311a1 100644 --- a/drivers/i2c/busses/i2c-xiic.c +++ b/drivers/i2c/busses/i2c-xiic.c @@ -804,7 +804,6 @@ static int xiic_i2c_probe(struct platform_device *pdev) /* add i2c adapter to i2c tree */ ret = i2c_add_adapter(&i2c->adap); if (ret) { - dev_err(&pdev->dev, "Failed to add adapter\n"); xiic_deinit(i2c); goto err_clk_dis; } diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index 55a7bef1b2e1..2a972ed7aa0d 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -400,10 +400,8 @@ static int xlp9xx_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&priv->adapter, priv); err = i2c_add_adapter(&priv->adapter); - if (err) { - dev_err(&pdev->dev, "failed to add I2C adapter!\n"); + if (err) return err; - } platform_set_drvdata(pdev, priv); dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr); diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c index 613c3a4f2c51..0968f59b6df5 100644 --- a/drivers/i2c/busses/i2c-xlr.c +++ b/drivers/i2c/busses/i2c-xlr.c @@ -432,10 +432,8 @@ static int xlr_i2c_probe(struct platform_device *pdev) i2c_set_adapdata(&priv->adap, priv); ret = i2c_add_numbered_adapter(&priv->adap); - if (ret < 0) { - dev_err(&priv->adap.dev, "Failed to add i2c bus.\n"); + if (ret < 0) return ret; - } platform_set_drvdata(pdev, priv); dev_info(&priv->adap.dev, "Added I2C Bus.\n"); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index da3a02ef4a31..98fffa3a09f7 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -88,7 +88,7 @@ void i2c_transfer_trace_unreg(void) } #if defined(CONFIG_ACPI) -struct acpi_i2c_handler_data { +struct i2c_acpi_handler_data { struct acpi_connection_info info; struct i2c_adapter *adapter; }; @@ -103,15 +103,18 @@ struct gsb_buffer { }; } __packed; -struct acpi_i2c_lookup { +struct i2c_acpi_lookup { struct i2c_board_info *info; acpi_handle adapter_handle; acpi_handle device_handle; + acpi_handle search_handle; + u32 speed; + u32 min_speed; }; -static int acpi_i2c_fill_info(struct acpi_resource *ares, void *data) +static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data) { - struct acpi_i2c_lookup *lookup = data; + struct i2c_acpi_lookup *lookup = data; struct i2c_board_info *info = lookup->info; struct acpi_resource_i2c_serialbus *sb; acpi_status status; @@ -130,19 +133,18 @@ static int acpi_i2c_fill_info(struct acpi_resource *ares, void *data) return 1; info->addr = sb->slave_address; + lookup->speed = sb->connection_speed; if (sb->access_mode == ACPI_I2C_10BIT_MODE) info->flags |= I2C_CLIENT_TEN; return 1; } -static int acpi_i2c_get_info(struct acpi_device *adev, - struct i2c_board_info *info, - acpi_handle *adapter_handle) +static int i2c_acpi_do_lookup(struct acpi_device *adev, + struct i2c_acpi_lookup *lookup) { + struct i2c_board_info *info = lookup->info; struct list_head resource_list; - struct resource_entry *entry; - struct acpi_i2c_lookup lookup; int ret; if (acpi_bus_get_status(adev) || !adev->status.present || @@ -150,24 +152,58 @@ static int acpi_i2c_get_info(struct acpi_device *adev, return -EINVAL; memset(info, 0, sizeof(*info)); - info->fwnode = acpi_fwnode_handle(adev); - - memset(&lookup, 0, sizeof(lookup)); - lookup.device_handle = acpi_device_handle(adev); - lookup.info = info; + lookup->device_handle = acpi_device_handle(adev); /* Look up for I2cSerialBus resource */ INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, - acpi_i2c_fill_info, &lookup); + i2c_acpi_fill_info, lookup); acpi_dev_free_resource_list(&resource_list); if (ret < 0 || !info->addr) return -EINVAL; - *adapter_handle = lookup.adapter_handle; + return 0; +} + +static int i2c_acpi_get_info(struct acpi_device *adev, + struct i2c_board_info *info, + struct i2c_adapter *adapter, + acpi_handle *adapter_handle) +{ + struct list_head resource_list; + struct resource_entry *entry; + struct i2c_acpi_lookup lookup; + int ret; + + memset(&lookup, 0, sizeof(lookup)); + lookup.info = info; + + ret = i2c_acpi_do_lookup(adev, &lookup); + if (ret) + return ret; + + if (adapter) { + /* The adapter must match the one in I2cSerialBus() connector */ + if (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)) + return -ENODEV; + if (acpi_bus_get_status(adapter_adev) || + !adapter_adev->status.present) + return -ENODEV; + } + + info->fwnode = acpi_fwnode_handle(adev); + if (adapter_handle) + *adapter_handle = lookup.adapter_handle; /* Then fill IRQ number if any */ + INIT_LIST_HEAD(&resource_list); ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); if (ret < 0) return -EINVAL; @@ -186,7 +222,7 @@ static int acpi_i2c_get_info(struct acpi_device *adev, return 0; } -static void acpi_i2c_register_device(struct i2c_adapter *adapter, +static void i2c_acpi_register_device(struct i2c_adapter *adapter, struct acpi_device *adev, struct i2c_board_info *info) { @@ -201,39 +237,35 @@ static void acpi_i2c_register_device(struct i2c_adapter *adapter, } } -static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, +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; - acpi_handle adapter_handle; struct i2c_board_info info; if (acpi_bus_get_device(handle, &adev)) return AE_OK; - if (acpi_i2c_get_info(adev, &info, &adapter_handle)) + if (i2c_acpi_get_info(adev, &info, adapter, NULL)) return AE_OK; - if (adapter_handle != ACPI_HANDLE(&adapter->dev)) - return AE_OK; - - acpi_i2c_register_device(adapter, adev, &info); + i2c_acpi_register_device(adapter, adev, &info); return AE_OK; } -#define ACPI_I2C_MAX_SCAN_DEPTH 32 +#define I2C_ACPI_MAX_SCAN_DEPTH 32 /** - * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter + * i2c_acpi_register_devices - enumerate I2C slave devices behind adapter * @adap: pointer to adapter * * Enumerate all I2C slave devices behind this adapter by walking the ACPI * namespace. When a device is found it will be added to the Linux device * model and bound to the corresponding ACPI handle. */ -static void acpi_i2c_register_devices(struct i2c_adapter *adap) +static void i2c_acpi_register_devices(struct i2c_adapter *adap) { acpi_status status; @@ -241,14 +273,72 @@ static void acpi_i2c_register_devices(struct i2c_adapter *adap) return; status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_I2C_MAX_SCAN_DEPTH, - acpi_i2c_add_device, NULL, + I2C_ACPI_MAX_SCAN_DEPTH, + i2c_acpi_add_device, NULL, adap, NULL); if (ACPI_FAILURE(status)) dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); } -static int acpi_i2c_match_adapter(struct device *dev, void *data) +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; + + if (i2c_acpi_do_lookup(adev, lookup)) + return AE_OK; + + if (lookup->search_handle != lookup->adapter_handle) + return AE_OK; + + if (lookup->speed <= lookup->min_speed) + lookup->min_speed = lookup->speed; + + return AE_OK; +} + +/** + * i2c_acpi_find_bus_speed - find I2C bus speed from ACPI + * @dev: The device owning the bus + * + * Find the I2C bus speed by walking the ACPI namespace for all I2C slaves + * devices connected to this bus and use the speed of slowest device. + * + * Returns the speed in Hz or zero + */ +u32 i2c_acpi_find_bus_speed(struct device *dev) +{ + struct i2c_acpi_lookup lookup; + struct i2c_board_info dummy; + acpi_status status; + + if (!has_acpi_companion(dev)) + return 0; + + memset(&lookup, 0, sizeof(lookup)); + lookup.search_handle = ACPI_HANDLE(dev); + lookup.min_speed = UINT_MAX; + lookup.info = &dummy; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, + I2C_ACPI_MAX_SCAN_DEPTH, + i2c_acpi_lookup_speed, NULL, + &lookup, NULL); + + if (ACPI_FAILURE(status)) { + dev_warn(dev, "unable to find I2C bus speed from ACPI\n"); + return 0; + } + + return lookup.min_speed != UINT_MAX ? lookup.min_speed : 0; +} +EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed); + +static int i2c_acpi_match_adapter(struct device *dev, void *data) { struct i2c_adapter *adapter = i2c_verify_adapter(dev); @@ -258,29 +348,29 @@ static int acpi_i2c_match_adapter(struct device *dev, void *data) return ACPI_HANDLE(dev) == (acpi_handle)data; } -static int acpi_i2c_match_device(struct device *dev, void *data) +static int i2c_acpi_match_device(struct device *dev, void *data) { return ACPI_COMPANION(dev) == data; } -static struct i2c_adapter *acpi_i2c_find_adapter_by_handle(acpi_handle handle) +static struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle) { struct device *dev; dev = bus_find_device(&i2c_bus_type, NULL, handle, - acpi_i2c_match_adapter); + i2c_acpi_match_adapter); return dev ? i2c_verify_adapter(dev) : NULL; } -static struct i2c_client *acpi_i2c_find_client_by_adev(struct acpi_device *adev) +static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev) { struct device *dev; - dev = bus_find_device(&i2c_bus_type, NULL, adev, acpi_i2c_match_device); + dev = bus_find_device(&i2c_bus_type, NULL, adev, i2c_acpi_match_device); return dev ? i2c_verify_client(dev) : NULL; } -static int acpi_i2c_notify(struct notifier_block *nb, unsigned long value, +static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, void *arg) { struct acpi_device *adev = arg; @@ -291,20 +381,20 @@ static int acpi_i2c_notify(struct notifier_block *nb, unsigned long value, switch (value) { case ACPI_RECONFIG_DEVICE_ADD: - if (acpi_i2c_get_info(adev, &info, &adapter_handle)) + if (i2c_acpi_get_info(adev, &info, NULL, &adapter_handle)) break; - adapter = acpi_i2c_find_adapter_by_handle(adapter_handle); + adapter = i2c_acpi_find_adapter_by_handle(adapter_handle); if (!adapter) break; - acpi_i2c_register_device(adapter, adev, &info); + i2c_acpi_register_device(adapter, adev, &info); break; case ACPI_RECONFIG_DEVICE_REMOVE: if (!acpi_device_enumerated(adev)) break; - client = acpi_i2c_find_client_by_adev(adev); + client = i2c_acpi_find_client_by_adev(adev); if (!client) break; @@ -317,10 +407,10 @@ static int acpi_i2c_notify(struct notifier_block *nb, unsigned long value, } static struct notifier_block i2c_acpi_notifier = { - .notifier_call = acpi_i2c_notify, + .notifier_call = i2c_acpi_notify, }; #else /* CONFIG_ACPI */ -static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) { } +static inline void i2c_acpi_register_devices(struct i2c_adapter *adap) { } extern struct notifier_block i2c_acpi_notifier; #endif /* CONFIG_ACPI */ @@ -386,12 +476,12 @@ static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, } static acpi_status -acpi_i2c_space_handler(u32 function, acpi_physical_address command, +i2c_acpi_space_handler(u32 function, acpi_physical_address command, u32 bits, u64 *value64, void *handler_context, void *region_context) { struct gsb_buffer *gsb = (struct gsb_buffer *)value64; - struct acpi_i2c_handler_data *data = handler_context; + struct i2c_acpi_handler_data *data = handler_context; struct acpi_connection_info *info = &data->info; struct acpi_resource_i2c_serialbus *sb; struct i2c_adapter *adapter = data->adapter; @@ -510,10 +600,10 @@ acpi_i2c_space_handler(u32 function, acpi_physical_address command, } -static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) +static int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) { acpi_handle handle; - struct acpi_i2c_handler_data *data; + struct i2c_acpi_handler_data *data; acpi_status status; if (!adapter->dev.parent) @@ -524,7 +614,7 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) if (!handle) return -ENODEV; - data = kzalloc(sizeof(struct acpi_i2c_handler_data), + data = kzalloc(sizeof(struct i2c_acpi_handler_data), GFP_KERNEL); if (!data) return -ENOMEM; @@ -538,7 +628,7 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) status = acpi_install_address_space_handler(handle, ACPI_ADR_SPACE_GSBUS, - &acpi_i2c_space_handler, + &i2c_acpi_space_handler, NULL, data); if (ACPI_FAILURE(status)) { @@ -552,10 +642,10 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) return 0; } -static void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) +static void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) { acpi_handle handle; - struct acpi_i2c_handler_data *data; + struct i2c_acpi_handler_data *data; acpi_status status; if (!adapter->dev.parent) @@ -568,7 +658,7 @@ static void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) acpi_remove_address_space_handler(handle, ACPI_ADR_SPACE_GSBUS, - &acpi_i2c_space_handler); + &i2c_acpi_space_handler); status = acpi_bus_get_private_data(handle, (void **)&data); if (ACPI_SUCCESS(status)) @@ -577,10 +667,10 @@ static void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) acpi_bus_detach_private_data(handle); } #else /* CONFIG_ACPI_I2C_OPREGION */ -static inline void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) +static inline void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) { } -static inline int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) +static inline int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) { return 0; } #endif /* CONFIG_ACPI_I2C_OPREGION */ @@ -853,7 +943,7 @@ static int i2c_device_probe(struct device *dev) status = 0; if (status) - dev_warn(&client->dev, "failed to set up wakeup irq"); + dev_warn(&client->dev, "failed to set up wakeup irq\n"); } dev_dbg(dev, "probe\n"); @@ -1208,8 +1298,9 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) return client; out_err: - dev_err(&adap->dev, "Failed to register i2c client %s at 0x%02x " - "(%d)\n", client->name, client->addr, status); + dev_err(&adap->dev, + "Failed to register i2c client %s at 0x%02x (%d)\n", + client->name, client->addr, status); out_err_silent: kfree(client); return NULL; @@ -1335,21 +1426,19 @@ static void i2c_adapter_dev_release(struct device *dev) complete(&adap->dev_released); } -/* - * This function is only needed for mutex_lock_nested, so it is never - * called unless locking correctness checking is enabled. Thus we - * make it inline to avoid a compiler warning. That's what gcc ends up - * doing anyway. - */ -static inline unsigned int i2c_adapter_depth(struct i2c_adapter *adapter) +unsigned int i2c_adapter_depth(struct i2c_adapter *adapter) { unsigned int depth = 0; while ((adapter = i2c_parent_is_i2c_adapter(adapter))) depth++; + WARN_ONCE(depth >= MAX_LOCKDEP_SUBCLASSES, + "adapter depth exceeds lockdep subclass limit\n"); + return depth; } +EXPORT_SYMBOL_GPL(i2c_adapter_depth); /* * Let users instantiate I2C devices through sysfs. This can be used when @@ -1678,8 +1767,8 @@ static int i2c_do_add_adapter(struct i2c_driver *driver, if (driver->attach_adapter) { dev_warn(&adap->dev, "%s: attach_adapter method is deprecated\n", driver->driver.name); - dev_warn(&adap->dev, "Please use another way to instantiate " - "your i2c_client\n"); + dev_warn(&adap->dev, + "Please use another way to instantiate your i2c_client\n"); /* We ignore the return code; if it fails, too bad */ driver->attach_adapter(adap); } @@ -1691,6 +1780,12 @@ static int __process_new_adapter(struct device_driver *d, void *data) return i2c_do_add_adapter(to_i2c_driver(d), data); } +static const struct i2c_lock_operations i2c_adapter_lock_ops = { + .lock_bus = i2c_adapter_lock_bus, + .trylock_bus = i2c_adapter_trylock_bus, + .unlock_bus = i2c_adapter_unlock_bus, +}; + static int i2c_register_adapter(struct i2c_adapter *adap) { int res = -EINVAL; @@ -1710,11 +1805,8 @@ static int i2c_register_adapter(struct i2c_adapter *adap) goto out_list; } - if (!adap->lock_bus) { - adap->lock_bus = i2c_adapter_lock_bus; - adap->trylock_bus = i2c_adapter_trylock_bus; - adap->unlock_bus = i2c_adapter_unlock_bus; - } + if (!adap->lock_ops) + adap->lock_ops = &i2c_adapter_lock_ops; rt_mutex_init(&adap->bus_lock); rt_mutex_init(&adap->mux_lock); @@ -1752,8 +1844,8 @@ static int i2c_register_adapter(struct i2c_adapter *adap) /* create pre-declared device nodes */ of_i2c_register_devices(adap); - acpi_i2c_register_devices(adap); - acpi_i2c_install_space_handler(adap); + i2c_acpi_register_devices(adap); + i2c_acpi_install_space_handler(adap); if (adap->nr < __i2c_first_dynamic_bus_num) i2c_scan_static_board_info(adap); @@ -1925,7 +2017,7 @@ void i2c_del_adapter(struct i2c_adapter *adap) return; } - acpi_i2c_remove_space_handler(adap); + i2c_acpi_remove_space_handler(adap); /* Tell drivers about this removal */ mutex_lock(&core_lock); bus_for_each_drv(&i2c_bus_type, NULL, adap, @@ -2451,15 +2543,16 @@ int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num) if (adap->algo->master_xfer) { #ifdef DEBUG for (ret = 0; ret < num; ret++) { - dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, " - "len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD) - ? 'R' : 'W', msgs[ret].addr, msgs[ret].len, + dev_dbg(&adap->dev, + "master_xfer[%d] %c, addr=0x%02x, len=%d%s\n", + ret, (msgs[ret].flags & I2C_M_RD) ? 'R' : 'W', + msgs[ret].addr, msgs[ret].len, (msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : ""); } #endif if (in_atomic() || irqs_disabled()) { - ret = adap->trylock_bus(adap, I2C_LOCK_SEGMENT); + ret = i2c_trylock_bus(adap, I2C_LOCK_SEGMENT); if (!ret) /* I2C activity is ongoing. */ return -EAGAIN; @@ -2619,9 +2712,9 @@ static int i2c_detect_address(struct i2c_client *temp_client, /* Consistency check */ if (info.type[0] == '\0') { - dev_err(&adapter->dev, "%s detection function provided " - "no name for 0x%x\n", driver->driver.name, - addr); + dev_err(&adapter->dev, + "%s detection function provided no name for 0x%x\n", + driver->driver.name, addr); } else { struct i2c_client *client; @@ -2659,9 +2752,8 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) /* Warn that the adapter lost class based instantiation */ if (adapter->class == I2C_CLASS_DEPRECATED) { dev_dbg(&adapter->dev, - "This adapter dropped support for I2C classes and " - "won't auto-detect %s devices anymore. If you need it, check " - "'Documentation/i2c/instantiating-devices' for alternatives.\n", + "This adapter dropped support for I2C classes and won't auto-detect %s devices anymore. " + "If you need it, check 'Documentation/i2c/instantiating-devices' for alternatives.\n", driver->driver.name); return 0; } @@ -2677,8 +2769,9 @@ static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver) temp_client->adapter = adapter; for (i = 0; address_list[i] != I2C_CLIENT_END; i += 1) { - dev_dbg(&adapter->dev, "found normal entry for adapter %d, " - "addr 0x%02x\n", adap_id, address_list[i]); + dev_dbg(&adapter->dev, + "found normal entry for adapter %d, addr 0x%02x\n", + adap_id, address_list[i]); temp_client->addr = address_list[i]; err = i2c_detect_address(temp_client, driver); if (unlikely(err)) @@ -2710,15 +2803,16 @@ i2c_new_probed_device(struct i2c_adapter *adap, for (i = 0; addr_list[i] != I2C_CLIENT_END; i++) { /* Check address validity */ if (i2c_check_7bit_addr_validity_strict(addr_list[i]) < 0) { - dev_warn(&adap->dev, "Invalid 7-bit address " - "0x%02x\n", addr_list[i]); + dev_warn(&adap->dev, "Invalid 7-bit address 0x%02x\n", + addr_list[i]); continue; } /* Check address availability (7 bit, no need to encode flags) */ if (i2c_check_addr_busy(adap, addr_list[i])) { - dev_dbg(&adap->dev, "Address 0x%02x already in " - "use, not probing\n", addr_list[i]); + dev_dbg(&adap->dev, + "Address 0x%02x already in use, not probing\n", + addr_list[i]); continue; } diff --git a/drivers/i2c/i2c-mux.c b/drivers/i2c/i2c-mux.c index 8eee98634cda..83768e85a919 100644 --- a/drivers/i2c/i2c-mux.c +++ b/drivers/i2c/i2c-mux.c @@ -159,7 +159,7 @@ static int i2c_mux_trylock_bus(struct i2c_adapter *adapter, unsigned int flags) return 0; /* mux_lock not locked, failure */ if (!(flags & I2C_LOCK_ROOT_ADAPTER)) return 1; /* we only want mux_lock, success */ - if (parent->trylock_bus(parent, flags)) + if (i2c_trylock_bus(parent, flags)) return 1; /* parent locked too, success */ rt_mutex_unlock(&parent->mux_lock); return 0; /* parent not locked, failure */ @@ -193,7 +193,7 @@ static int i2c_parent_trylock_bus(struct i2c_adapter *adapter, if (!rt_mutex_trylock(&parent->mux_lock)) return 0; /* mux_lock not locked, failure */ - if (parent->trylock_bus(parent, flags)) + if (i2c_trylock_bus(parent, flags)) return 1; /* parent locked too, success */ rt_mutex_unlock(&parent->mux_lock); return 0; /* parent not locked, failure */ @@ -255,6 +255,10 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *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->select = select; muxc->deselect = deselect; muxc->max_adapters = max_adapters; @@ -263,6 +267,18 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent, } EXPORT_SYMBOL_GPL(i2c_mux_alloc); +static const struct i2c_lock_operations i2c_mux_lock_ops = { + .lock_bus = i2c_mux_lock_bus, + .trylock_bus = i2c_mux_trylock_bus, + .unlock_bus = i2c_mux_unlock_bus, +}; + +static const struct i2c_lock_operations i2c_parent_lock_ops = { + .lock_bus = i2c_parent_lock_bus, + .trylock_bus = i2c_parent_trylock_bus, + .unlock_bus = i2c_parent_unlock_bus, +}; + int i2c_mux_add_adapter(struct i2c_mux_core *muxc, u32 force_nr, u32 chan_id, unsigned int class) @@ -312,15 +328,10 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, priv->adap.retries = parent->retries; priv->adap.timeout = parent->timeout; priv->adap.quirks = parent->quirks; - if (muxc->mux_locked) { - priv->adap.lock_bus = i2c_mux_lock_bus; - priv->adap.trylock_bus = i2c_mux_trylock_bus; - priv->adap.unlock_bus = i2c_mux_unlock_bus; - } else { - priv->adap.lock_bus = i2c_parent_lock_bus; - priv->adap.trylock_bus = i2c_parent_trylock_bus; - priv->adap.unlock_bus = i2c_parent_unlock_bus; - } + if (muxc->mux_locked) + priv->adap.lock_ops = &i2c_mux_lock_ops; + else + priv->adap.lock_ops = &i2c_parent_lock_ops; /* Sanity check on class */ if (i2c_mux_parent_classes(parent) & class) @@ -335,18 +346,42 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc, * nothing if !CONFIG_OF. */ if (muxc->dev->of_node) { - struct device_node *child; + struct device_node *dev_node = muxc->dev->of_node; + struct device_node *mux_node, *child = NULL; u32 reg; - for_each_child_of_node(muxc->dev->of_node, child) { - ret = of_property_read_u32(child, "reg", ®); - if (ret) - continue; - if (chan_id == reg) { - priv->adap.dev.of_node = child; - break; + if (muxc->arbitrator) + mux_node = of_get_child_by_name(dev_node, "i2c-arb"); + else if (muxc->gate) + mux_node = of_get_child_by_name(dev_node, "i2c-gate"); + else + mux_node = of_get_child_by_name(dev_node, "i2c-mux"); + + if (mux_node) { + /* A "reg" property indicates an old-style DT entry */ + if (!of_property_read_u32(mux_node, "reg", ®)) { + of_node_put(mux_node); + mux_node = NULL; } } + + if (!mux_node) + mux_node = of_node_get(dev_node); + else if (muxc->arbitrator || muxc->gate) + child = of_node_get(mux_node); + + if (!child) { + for_each_child_of_node(mux_node, child) { + ret = of_property_read_u32(child, "reg", ®); + if (ret) + continue; + if (chan_id == reg) + break; + } + } + + priv->adap.dev.of_node = child; + of_node_put(mux_node); } /* diff --git a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c index a90bbc4037dd..86fc2d4c081b 100644 --- a/drivers/i2c/muxes/i2c-arb-gpio-challenge.c +++ b/drivers/i2c/muxes/i2c-arb-gpio-challenge.c @@ -130,7 +130,7 @@ static int i2c_arbitrator_probe(struct platform_device *pdev) return -EINVAL; } - muxc = i2c_mux_alloc(NULL, dev, 1, sizeof(*arb), 0, + muxc = i2c_mux_alloc(NULL, dev, 1, sizeof(*arb), I2C_MUX_ARBITRATOR, i2c_arbitrator_select, i2c_arbitrator_deselect); if (!muxc) return -ENOMEM; diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c index 3cb8af635db5..4ea7e691afc7 100644 --- a/drivers/i2c/muxes/i2c-mux-pca9541.c +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c @@ -85,6 +85,13 @@ static const struct i2c_device_id pca9541_id[] = { MODULE_DEVICE_TABLE(i2c, pca9541_id); +#ifdef CONFIG_OF +static const struct of_device_id pca9541_of_match[] = { + { .compatible = "nxp,pca9541" }, + {} +}; +#endif + /* * Write to chip register. Don't use i2c_transfer()/i2c_smbus_xfer() * as they will try to lock the adapter a second time. @@ -349,7 +356,8 @@ static int pca9541_probe(struct i2c_client *client, force = 0; if (pdata) force = pdata->modes[0].adap_id; - muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), 0, + muxc = i2c_mux_alloc(adap, &client->dev, 1, sizeof(*data), + I2C_MUX_ARBITRATOR, pca9541_select_chan, pca9541_release_chan); if (!muxc) return -ENOMEM; @@ -382,6 +390,7 @@ static int pca9541_remove(struct i2c_client *client) static struct i2c_driver pca9541_driver = { .driver = { .name = "pca9541", + .of_match_table = of_match_ptr(pca9541_of_match), }, .probe = pca9541_probe, .remove = pca9541_remove, diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index 3278ebf1cc5c..1091346f2480 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -58,14 +59,6 @@ enum pca_type { pca_9548, }; -struct pca954x { - enum pca_type type; - - u8 last_chan; /* last register value */ - u8 deselect; - struct i2c_client *client; -}; - struct chip_desc { u8 nchans; u8 enable; /* used for muxes only */ @@ -75,6 +68,14 @@ struct chip_desc { } muxtype; }; +struct pca954x { + const struct chip_desc *chip; + + u8 last_chan; /* last register value */ + u8 deselect; + struct i2c_client *client; +}; + /* Provide specs for the PCA954x types we know about */ static const struct chip_desc chips[] = { [pca_9540] = { @@ -119,6 +120,20 @@ static const struct i2c_device_id pca954x_id[] = { }; MODULE_DEVICE_TABLE(i2c, pca954x_id); +#ifdef CONFIG_OF +static const struct of_device_id pca954x_of_match[] = { + { .compatible = "nxp,pca9540", .data = &chips[pca_9540] }, + { .compatible = "nxp,pca9542", .data = &chips[pca_9542] }, + { .compatible = "nxp,pca9543", .data = &chips[pca_9543] }, + { .compatible = "nxp,pca9544", .data = &chips[pca_9544] }, + { .compatible = "nxp,pca9545", .data = &chips[pca_9545] }, + { .compatible = "nxp,pca9546", .data = &chips[pca_9546] }, + { .compatible = "nxp,pca9547", .data = &chips[pca_9547] }, + { .compatible = "nxp,pca9548", .data = &chips[pca_9548] }, + {} +}; +#endif + /* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer() for this as they will try to lock adapter a second time */ static int pca954x_reg_write(struct i2c_adapter *adap, @@ -151,7 +166,7 @@ static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan) { struct pca954x *data = i2c_mux_priv(muxc); struct i2c_client *client = data->client; - const struct chip_desc *chip = &chips[data->type]; + const struct chip_desc *chip = data->chip; u8 regval; int ret = 0; @@ -197,6 +212,7 @@ static int pca954x_probe(struct i2c_client *client, int num, force, class; struct i2c_mux_core *muxc; struct pca954x *data; + const struct of_device_id *match; int ret; if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE)) @@ -226,14 +242,19 @@ static int pca954x_probe(struct i2c_client *client, return -ENODEV; } - data->type = id->driver_data; + match = of_match_device(of_match_ptr(pca954x_of_match), &client->dev); + if (match) + data->chip = of_device_get_match_data(&client->dev); + else + data->chip = &chips[id->driver_data]; + data->last_chan = 0; /* force the first selection */ idle_disconnect_dt = of_node && of_property_read_bool(of_node, "i2c-mux-idle-disconnect"); /* Now create an adapter for each channel */ - for (num = 0; num < chips[data->type].nchans; num++) { + for (num = 0; num < data->chip->nchans; num++) { bool idle_disconnect_pd = false; force = 0; /* dynamic adap number */ @@ -263,7 +284,7 @@ static int pca954x_probe(struct i2c_client *client, dev_info(&client->dev, "registered %d multiplexed busses for I2C %s %s\n", - num, chips[data->type].muxtype == pca954x_ismux + num, data->chip->muxtype == pca954x_ismux ? "mux" : "switch", client->name); return 0; @@ -299,6 +320,7 @@ static struct i2c_driver pca954x_driver = { .driver = { .name = "pca954x", .pm = &pca954x_pm, + .of_match_table = of_match_ptr(pca954x_of_match), }, .probe = pca954x_probe, .remove = pca954x_remove, diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 3cdf8e1ca0ad..051b14766ef9 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -593,6 +593,7 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) struct at24_data *at24; int err; unsigned i, num_addresses; + u8 test_byte; if (client->dev.platform_data) { chip = *(struct at24_platform_data *)client->dev.platform_data; @@ -743,6 +744,18 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) } } + i2c_set_clientdata(client, at24); + + /* + * Perform a one-byte test read to verify that the + * chip is functional. + */ + err = at24_read(at24, 0, &test_byte, 1); + if (err) { + err = -ENODEV; + goto err_clients; + } + at24->nvmem_config.name = dev_name(&client->dev); at24->nvmem_config.dev = &client->dev; at24->nvmem_config.read_only = !writable; @@ -764,8 +777,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) goto err_clients; } - i2c_set_clientdata(client, at24); - dev_info(&client->dev, "%u byte %s EEPROM, %s, %u bytes/write\n", chip.byte_len, client->name, writable ? "writable" : "read-only", at24->write_max); diff --git a/include/linux/i2c-mux.h b/include/linux/i2c-mux.h index d4c1d12f900d..bd74d5706f3b 100644 --- a/include/linux/i2c-mux.h +++ b/include/linux/i2c-mux.h @@ -32,7 +32,9 @@ struct i2c_mux_core { struct i2c_adapter *parent; struct device *dev; - bool mux_locked; + unsigned int mux_locked:1; + unsigned int arbitrator:1; + unsigned int gate:1; void *priv; @@ -51,7 +53,9 @@ struct i2c_mux_core *i2c_mux_alloc(struct i2c_adapter *parent, int (*deselect)(struct i2c_mux_core *, u32)); /* flags for i2c_mux_alloc */ -#define I2C_MUX_LOCKED BIT(0) +#define I2C_MUX_LOCKED BIT(0) +#define I2C_MUX_ARBITRATOR BIT(1) +#define I2C_MUX_GATE BIT(2) static inline void *i2c_mux_priv(struct i2c_mux_core *muxc) { diff --git a/include/linux/i2c.h b/include/linux/i2c.h index fffdc270ca18..6422eef428c4 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -426,6 +426,20 @@ struct i2c_algorithm { #endif }; +/** + * struct i2c_lock_operations - represent I2C locking operations + * @lock_bus: Get exclusive access to an I2C bus segment + * @trylock_bus: Try to get exclusive access to an I2C bus segment + * @unlock_bus: Release exclusive access to an I2C bus segment + * + * The main operations are wrapped by i2c_lock_bus and i2c_unlock_bus. + */ +struct i2c_lock_operations { + void (*lock_bus)(struct i2c_adapter *, unsigned int flags); + int (*trylock_bus)(struct i2c_adapter *, unsigned int flags); + void (*unlock_bus)(struct i2c_adapter *, unsigned int flags); +}; + /** * struct i2c_timings - I2C timing information * @bus_freq_hz: the bus frequency in Hz @@ -536,6 +550,7 @@ struct i2c_adapter { void *algo_data; /* data fields that are valid for all devices */ + const struct i2c_lock_operations *lock_ops; struct rt_mutex bus_lock; struct rt_mutex mux_lock; @@ -552,10 +567,6 @@ struct i2c_adapter { struct i2c_bus_recovery_info *bus_recovery_info; const struct i2c_adapter_quirks *quirks; - - void (*lock_bus)(struct i2c_adapter *, unsigned int flags); - int (*trylock_bus)(struct i2c_adapter *, unsigned int flags); - void (*unlock_bus)(struct i2c_adapter *, unsigned int flags); }; #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev) @@ -597,7 +608,21 @@ int i2c_for_each_dev(void *data, int (*fn)(struct device *, void *)); static inline void i2c_lock_bus(struct i2c_adapter *adapter, unsigned int flags) { - adapter->lock_bus(adapter, flags); + adapter->lock_ops->lock_bus(adapter, flags); +} + +/** + * i2c_trylock_bus - Try to get exclusive access to an I2C bus segment + * @adapter: Target I2C bus segment + * @flags: I2C_LOCK_ROOT_ADAPTER tries to locks the root i2c adapter, + * I2C_LOCK_SEGMENT tries to lock only this branch in the adapter tree + * + * Return: true if the I2C bus segment is locked, false otherwise + */ +static inline int +i2c_trylock_bus(struct i2c_adapter *adapter, unsigned int flags) +{ + return adapter->lock_ops->trylock_bus(adapter, flags); } /** @@ -609,7 +634,7 @@ i2c_lock_bus(struct i2c_adapter *adapter, unsigned int flags) static inline void i2c_unlock_bus(struct i2c_adapter *adapter, unsigned int flags) { - adapter->unlock_bus(adapter, flags); + adapter->lock_ops->unlock_bus(adapter, flags); } static inline void @@ -673,6 +698,7 @@ extern void i2c_clients_command(struct i2c_adapter *adap, extern struct i2c_adapter *i2c_get_adapter(int nr); extern void i2c_put_adapter(struct i2c_adapter *adap); +extern unsigned int i2c_adapter_depth(struct i2c_adapter *adapter); void i2c_parse_fw_timings(struct device *dev, struct i2c_timings *t, bool use_defaults); @@ -766,4 +792,13 @@ static inline struct i2c_adapter *of_get_i2c_adapter_by_node(struct device_node } #endif /* CONFIG_OF */ +#if IS_ENABLED(CONFIG_ACPI) +u32 i2c_acpi_find_bus_speed(struct device *dev); +#else +static inline u32 i2c_acpi_find_bus_speed(struct device *dev) +{ + return 0; +} +#endif /* CONFIG_ACPI */ + #endif /* _LINUX_I2C_H */ diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index eabe0138eb06..c1458fede1f9 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -16,6 +16,8 @@ struct lockdep_map; extern int prove_locking; extern int lock_stat; +#define MAX_LOCKDEP_SUBCLASSES 8UL + #ifdef CONFIG_LOCKDEP #include @@ -29,8 +31,6 @@ extern int lock_stat; */ #define XXX_LOCK_USAGE_STATES (1+3*4) -#define MAX_LOCKDEP_SUBCLASSES 8UL - /* * NR_LOCKDEP_CACHING_CLASSES ... Number of classes * cached in the instance of lockdep_map