mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 04:02:20 +00:00
Merge branch 'i2c/for-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux
Pull i2c updates from Wolfram Sang: "Here is the 4.9 pull request from I2C including: - centralized error messages when registering to the core - improved lockdep annotations to prevent false positives - DT support for muxes, gates, and arbitrators - bus speeds can now be obtained from ACPI - i2c-octeon got refactored and now supports ThunderX SoCs, too - i2c-tegra and i2c-designware got a bigger bunch of updates - a couple of standard driver fixes and improvements" * 'i2c/for-4.9' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (71 commits) i2c: axxia: disable clks in case of failure in probe i2c: octeon: thunderx: Limit register access retries i2c: uniphier-f: fix misdetection of incomplete STOP condition gpio: pca953x: variable 'id' was used twice i2c: i801: Add support for Kaby Lake PCH-H gpio: pca953x: fix an incorrect lockdep warning i2c: add a warning to i2c_adapter_depth() lockdep: make MAX_LOCKDEP_SUBCLASSES unconditionally visible i2c: export i2c_adapter_depth() i2c: rk3x: Fix variable 'min_total_ns' unused warning i2c: rk3x: Fix sparse warning i2c / ACPI: Do not touch an I2C device if it belongs to another adapter i2c: octeon: Fix high-level controller status check i2c: octeon: Avoid sending STOP during recovery i2c: octeon: Fix set SCL recovery function i2c: rcar: add support for r8a7796 (R-Car M3-W) i2c: imx: make bus recovery through pinctrl optional i2c: meson: add gxbb compatible string i2c: uniphier-f: set the adapter to master mode when probing i2c: uniphier-f: avoid WARN_ON() of clk_disable() in failure path ...
This commit is contained in:
commit
87840a2b7e
@ -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>;
|
||||
|
||||
|
35
Documentation/devicetree/bindings/i2c/i2c-arb.txt
Normal file
35
Documentation/devicetree/bindings/i2c/i2c-arb.txt
Normal file
@ -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;
|
||||
};
|
||||
};
|
||||
};
|
41
Documentation/devicetree/bindings/i2c/i2c-gate.txt
Normal file
41
Documentation/devicetree/bindings/i2c/i2c-gate.txt
Normal file
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
29
Documentation/devicetree/bindings/i2c/nxp,pca9541.txt
Normal file
29
Documentation/devicetree/bindings/i2c/nxp,pca9541.txt
Normal file
@ -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>;
|
||||
};
|
||||
};
|
||||
};
|
10
MAINTAINERS
10
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 <jglauber@cavium.com>
|
||||
M: David Daney <david.daney@cavium.com>
|
||||
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 <derek.chickles@caviumnetworks.com>
|
||||
M: Satanand Burla <satananda.burla@caviumnetworks.com>
|
||||
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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)) {
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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)");
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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) {
|
||||
|
File diff suppressed because it is too large
Load Diff
216
drivers/i2c/busses/i2c-octeon-core.h
Normal file
216
drivers/i2c/busses/i2c-octeon-core.h
Normal file
@ -0,0 +1,216 @@
|
||||
#include <linux/atomic.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-smbus.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
/* 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;
|
286
drivers/i2c/busses/i2c-octeon-platdrv.c
Normal file
286
drivers/i2c/busses/i2c-octeon-platdrv.c
Normal file
@ -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 <linux/atomic.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include <asm/octeon/octeon.h>
|
||||
#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 <michael.lawnick.ext@nsn.com>");
|
||||
MODULE_DESCRIPTION("I2C-Bus adapter for Cavium OCTEON processors");
|
||||
MODULE_LICENSE("GPL");
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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",
|
||||
|
@ -28,6 +28,9 @@
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
@ -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
|
||||
|
259
drivers/i2c/busses/i2c-thunderx-pcidrv.c
Normal file
259
drivers/i2c/busses/i2c-thunderx-pcidrv.c
Normal file
@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Cavium ThunderX i2c driver.
|
||||
*
|
||||
* Copyright (C) 2015,2016 Cavium Inc.
|
||||
* Authors: Fred Martin <fmartin@caviumnetworks.com>
|
||||
* Jan Glauber <jglauber@cavium.com>
|
||||
*
|
||||
* This file is licensed under the terms of the GNU General Public
|
||||
* License version 2. This program is licensed "as is" without any
|
||||
* warranty of any kind, whether express or implied.
|
||||
*/
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-smbus.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#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 <fmartin@caviumnetworks.com>");
|
||||
MODULE_DESCRIPTION("I2C-Bus adapter for Cavium ThunderX SOC");
|
@ -14,6 +14,7 @@
|
||||
|
||||
#include <linux/clk.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include <linux/i2c/pca954x.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -16,6 +16,8 @@ struct lockdep_map;
|
||||
extern int prove_locking;
|
||||
extern int lock_stat;
|
||||
|
||||
#define MAX_LOCKDEP_SUBCLASSES 8UL
|
||||
|
||||
#ifdef CONFIG_LOCKDEP
|
||||
|
||||
#include <linux/linkage.h>
|
||||
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user