Commit 7067739d authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'i2c/for-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux

Pull i2c updates from Wolfram Sang:
 "I2C has for you two new drivers (Tegra BPMP and STM32F4), interrupt
  support for pca954x muxes, and a bunch of driver bugfixes and
  improvements. Nothing really special this cycle.

  A few commits have been added to my tree just recently. Those are the
  Tegra BPMP driver and a few straightforward bugfixes or cleanups which
  I prefer to have upstream rather soonish. The rest had proper
  linux-next exposure"

* 'i2c/for-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/wsa/linux: (25 commits)
  i2c: thunderx: Replace pci_enable_msix()
  i2c: exynos5: fix arbitration lost handling
  i2c: exynos5: disable fifo-almost-empty irq signal when necessary
  i2c: at91: ensure state is restored after suspending
  i2c: bcm2835: Avoid possible NULL ptr dereference
  i2c: Add Tegra BPMP I2C proxy driver
  dt-bindings: Add Tegra186 BPMP I2C binding
  misc: eeprom: at24: use device_property_*() functions instead of of_get_property()
  i2c: mux: pca954x: Add interrupt controller support
  dt: bindings: i2c-mux-pca954x: Add documentation for interrupt controller
  i2c: mux: pca954x: Add missing pca9542 definition to chip_desc
  i2c: riic: correctly finish transfers
  i2c: i801: Add support for Intel Gemini Lake
  i2c: mux: pca9541: Export OF device ID table as module aliases
  i2c: mux: pca954x: Export OF device ID table as module aliases
  i2c: mux: mlxcpld: remove unused including <linux/version.h>
  i2c: busses: constify i2c_algorithm structures
  i2c: i2c-mux-gpio: rename i2c-gpio-mux to i2c-mux-gpio
  i2c: sh_mobile: document support for r8a7796 (R-Car M3-W)
  i2c: i2c-cros-ec-tunnel: Reduce logging noise
  ...
parents ac1820fb 4c21541d
...@@ -19,7 +19,14 @@ Optional Properties: ...@@ -19,7 +19,14 @@ Optional Properties:
- i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all - i2c-mux-idle-disconnect: Boolean; if defined, forces mux to disconnect all
children in idle state. This is necessary for example, if there are several children in idle state. This is necessary for example, if there are several
multiplexers on the bus and the devices behind them use same I2C addresses. multiplexers on the bus and the devices behind them use same I2C addresses.
- interrupt-parent: Phandle for the interrupt controller that services
interrupts for this device.
- interrupts: Interrupt mapping for IRQ.
- interrupt-controller: Marks the device node as an interrupt controller.
- #interrupt-cells : Should be two.
- first cell is the pin number
- second cell is used to specify flags.
See also Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
Example: Example:
...@@ -29,6 +36,11 @@ Example: ...@@ -29,6 +36,11 @@ Example:
#size-cells = <0>; #size-cells = <0>;
reg = <0x74>; reg = <0x74>;
interrupt-parent = <&ipic>;
interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
interrupt-controller;
#interrupt-cells = <2>;
i2c@2 { i2c@2 {
#address-cells = <1>; #address-cells = <1>;
#size-cells = <0>; #size-cells = <0>;
......
...@@ -10,6 +10,7 @@ Required properties: ...@@ -10,6 +10,7 @@ Required properties:
- "renesas,iic-r8a7793" (R-Car M2-N) - "renesas,iic-r8a7793" (R-Car M2-N)
- "renesas,iic-r8a7794" (R-Car E2) - "renesas,iic-r8a7794" (R-Car E2)
- "renesas,iic-r8a7795" (R-Car H3) - "renesas,iic-r8a7795" (R-Car H3)
- "renesas,iic-r8a7796" (R-Car M3-W)
- "renesas,iic-sh73a0" (SH-Mobile AG5) - "renesas,iic-sh73a0" (SH-Mobile AG5)
- "renesas,rcar-gen2-iic" (generic R-Car Gen2 compatible device) - "renesas,rcar-gen2-iic" (generic R-Car Gen2 compatible device)
- "renesas,rcar-gen3-iic" (generic R-Car Gen3 compatible device) - "renesas,rcar-gen3-iic" (generic R-Car Gen3 compatible device)
......
* I2C controller embedded in STMicroelectronics STM32 I2C platform
Required properties :
- compatible : Must be "st,stm32f4-i2c"
- reg : Offset and length of the register set for the device
- interrupts : Must contain the interrupt id for I2C event and then the
interrupt id for I2C error.
- resets: Must contain the phandle to the reset controller.
- clocks: Must contain the input clock of the I2C instance.
- A pinctrl state named "default" must be defined to set pins in mode of
operation for I2C transfer
- #address-cells = <1>;
- #size-cells = <0>;
Optional properties :
- clock-frequency : Desired I2C bus clock frequency in Hz. If not specified,
the default 100 kHz frequency will be used. As only Normal and Fast modes
are supported, possible values are 100000 and 400000.
Example :
i2c@40005400 {
compatible = "st,stm32f4-i2c";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x40005400 0x400>;
interrupts = <31>,
<32>;
resets = <&rcc 277>;
clocks = <&rcc 0 149>;
pinctrl-0 = <&i2c1_sda_pin>, <&i2c1_scl_pin>;
pinctrl-names = "default";
};
NVIDIA Tegra186 BPMP I2C controller
In Tegra186, the BPMP (Boot and Power Management Processor) owns certain HW
devices, such as the I2C controller for the power management I2C bus. Software
running on other CPUs must perform IPC to the BPMP in order to execute
transactions on that I2C bus. This binding describes an I2C bus that is
accessed in such a fashion.
The BPMP I2C node must be located directly inside the main BPMP node. See
../firmware/nvidia,tegra186-bpmp.txt for details of the BPMP binding.
This node represents an I2C controller. See ../i2c/i2c.txt for details of the
core I2C binding.
Required properties:
- compatible:
Array of strings.
One of:
- "nvidia,tegra186-bpmp-i2c".
- #address-cells: Address cells for I2C device address.
Single-cell integer.
Must be <1>.
- #size-cells:
Single-cell integer.
Must be <0>.
- nvidia,bpmp-bus-id:
Single-cell integer.
Indicates the I2C bus number this DT node represent, as defined by the
BPMP firmware.
Example:
bpmp {
...
i2c {
compatible = "nvidia,tegra186-bpmp-i2c";
#address-cells = <1>;
#size-cells = <0>;
nvidia,bpmp-bus-id = <5>;
};
};
...@@ -33,6 +33,7 @@ Supported adapters: ...@@ -33,6 +33,7 @@ Supported adapters:
* Intel DNV (SOC) * Intel DNV (SOC)
* Intel Broxton (SOC) * Intel Broxton (SOC)
* Intel Lewisburg (PCH) * Intel Lewisburg (PCH)
* Intel Gemini Lake (SOC)
Datasheets: Publicly available at the Intel website Datasheets: Publicly available at the Intel website
On Intel Patsburg and later chipsets, both the normal host SMBus controller On Intel Patsburg and later chipsets, both the normal host SMBus controller
......
Kernel driver i2c-gpio-mux Kernel driver i2c-mux-gpio
Author: Peter Korsgaard <peter.korsgaard@barco.com> Author: Peter Korsgaard <peter.korsgaard@barco.com>
Description Description
----------- -----------
i2c-gpio-mux is an i2c mux driver providing access to I2C bus segments i2c-mux-gpio is an i2c mux driver providing access to I2C bus segments
from a master I2C bus and a hardware MUX controlled through GPIO pins. from a master I2C bus and a hardware MUX controlled through GPIO pins.
E.G.: E.G.:
...@@ -26,16 +26,16 @@ according to the settings of the GPIO pins 1..N. ...@@ -26,16 +26,16 @@ according to the settings of the GPIO pins 1..N.
Usage Usage
----- -----
i2c-gpio-mux uses the platform bus, so you need to provide a struct i2c-mux-gpio uses the platform bus, so you need to provide a struct
platform_device with the platform_data pointing to a struct platform_device with the platform_data pointing to a struct
gpio_i2cmux_platform_data with the I2C adapter number of the master i2c_mux_gpio_platform_data with the I2C adapter number of the master
bus, the number of bus segments to create and the GPIO pins used bus, the number of bus segments to create and the GPIO pins used
to control it. See include/linux/i2c-gpio-mux.h for details. to control it. See include/linux/i2c-mux-gpio.h for details.
E.G. something like this for a MUX providing 4 bus segments E.G. something like this for a MUX providing 4 bus segments
controlled through 3 GPIO pins: controlled through 3 GPIO pins:
#include <linux/i2c-gpio-mux.h> #include <linux/i2c-mux-gpio.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
static const unsigned myboard_gpiomux_gpios[] = { static const unsigned myboard_gpiomux_gpios[] = {
...@@ -46,7 +46,7 @@ static const unsigned myboard_gpiomux_values[] = { ...@@ -46,7 +46,7 @@ static const unsigned myboard_gpiomux_values[] = {
0, 1, 2, 3 0, 1, 2, 3
}; };
static struct gpio_i2cmux_platform_data myboard_i2cmux_data = { static struct i2c_mux_gpio_platform_data myboard_i2cmux_data = {
.parent = 1, .parent = 1,
.base_nr = 2, /* optional */ .base_nr = 2, /* optional */
.values = myboard_gpiomux_values, .values = myboard_gpiomux_values,
...@@ -57,7 +57,7 @@ static struct gpio_i2cmux_platform_data myboard_i2cmux_data = { ...@@ -57,7 +57,7 @@ static struct gpio_i2cmux_platform_data myboard_i2cmux_data = {
}; };
static struct platform_device myboard_i2cmux = { static struct platform_device myboard_i2cmux = {
.name = "i2c-gpio-mux", .name = "i2c-mux-gpio",
.id = 0, .id = 0,
.dev = { .dev = {
.platform_data = &myboard_i2cmux_data, .platform_data = &myboard_i2cmux_data,
...@@ -66,14 +66,14 @@ static struct platform_device myboard_i2cmux = { ...@@ -66,14 +66,14 @@ static struct platform_device myboard_i2cmux = {
If you don't know the absolute GPIO pin numbers at registration time, If you don't know the absolute GPIO pin numbers at registration time,
you can instead provide a chip name (.chip_name) and relative GPIO pin you can instead provide a chip name (.chip_name) and relative GPIO pin
numbers, and the i2c-gpio-mux driver will do the work for you, numbers, and the i2c-mux-gpio driver will do the work for you,
including deferred probing if the GPIO chip isn't immediately including deferred probing if the GPIO chip isn't immediately
available. available.
Device Registration Device Registration
------------------- -------------------
When registering your i2c-gpio-mux device, you should pass the number When registering your i2c-mux-gpio device, you should pass the number
of any GPIO pin it uses as the device ID. This guarantees that every of any GPIO pin it uses as the device ID. This guarantees that every
instance has a different ID. instance has a different ID.
......
...@@ -128,6 +128,7 @@ config I2C_I801 ...@@ -128,6 +128,7 @@ config I2C_I801
DNV (SOC) DNV (SOC)
Broxton (SOC) Broxton (SOC)
Lewisburg (PCH) Lewisburg (PCH)
Gemini Lake (SOC)
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called i2c-i801. will be called i2c-i801.
...@@ -886,6 +887,16 @@ config I2C_ST ...@@ -886,6 +887,16 @@ config I2C_ST
This driver can also be built as module. If so, the module This driver can also be built as module. If so, the module
will be called i2c-st. will be called i2c-st.
config I2C_STM32F4
tristate "STMicroelectronics STM32F4 I2C support"
depends on ARCH_STM32 || COMPILE_TEST
help
Enable this option to add support for STM32 I2C controller embedded
in STM32F4 SoCs.
This driver can also be built as module. If so, the module
will be called i2c-stm32f4.
config I2C_STU300 config I2C_STU300
tristate "ST Microelectronics DDC I2C interface" tristate "ST Microelectronics DDC I2C interface"
depends on MACH_U300 depends on MACH_U300
...@@ -919,6 +930,17 @@ config I2C_TEGRA ...@@ -919,6 +930,17 @@ config I2C_TEGRA
If you say yes to this option, support will be included for the If you say yes to this option, support will be included for the
I2C controller embedded in NVIDIA Tegra SOCs I2C controller embedded in NVIDIA Tegra SOCs
config I2C_TEGRA_BPMP
tristate "NVIDIA Tegra BPMP I2C controller"
depends on TEGRA_BPMP
help
If you say yes to this option, support will be included for the I2C
controller embedded in NVIDIA Tegra SoCs accessed via the BPMP.
This I2C driver is a 'virtual' I2C driver. The real driver is part
of the BPMP firmware, and this driver merely communicates with that
real driver.
config I2C_UNIPHIER config I2C_UNIPHIER
tristate "UniPhier FIFO-less I2C controller" tristate "UniPhier FIFO-less I2C controller"
depends on ARCH_UNIPHIER || COMPILE_TEST depends on ARCH_UNIPHIER || COMPILE_TEST
......
...@@ -85,9 +85,11 @@ obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o ...@@ -85,9 +85,11 @@ obj-$(CONFIG_I2C_SH_MOBILE) += i2c-sh_mobile.o
obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o obj-$(CONFIG_I2C_SIMTEC) += i2c-simtec.o
obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o
obj-$(CONFIG_I2C_ST) += i2c-st.o obj-$(CONFIG_I2C_ST) += i2c-st.o
obj-$(CONFIG_I2C_STM32F4) += i2c-stm32f4.o
obj-$(CONFIG_I2C_STU300) += i2c-stu300.o obj-$(CONFIG_I2C_STU300) += i2c-stu300.o
obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o obj-$(CONFIG_I2C_SUN6I_P2WI) += i2c-sun6i-p2wi.o
obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o
obj-$(CONFIG_I2C_TEGRA_BPMP) += i2c-tegra-bpmp.o
obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o obj-$(CONFIG_I2C_UNIPHIER) += i2c-uniphier.o
obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o obj-$(CONFIG_I2C_UNIPHIER_F) += i2c-uniphier-f.o
obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o
......
...@@ -820,7 +820,7 @@ static u32 at91_twi_func(struct i2c_adapter *adapter) ...@@ -820,7 +820,7 @@ static u32 at91_twi_func(struct i2c_adapter *adapter)
| I2C_FUNC_SMBUS_READ_BLOCK_DATA; | I2C_FUNC_SMBUS_READ_BLOCK_DATA;
} }
static struct i2c_algorithm at91_twi_algorithm = { static const struct i2c_algorithm at91_twi_algorithm = {
.master_xfer = at91_twi_xfer, .master_xfer = at91_twi_xfer,
.functionality = at91_twi_func, .functionality = at91_twi_func,
}; };
...@@ -1180,6 +1180,7 @@ static int at91_twi_suspend_noirq(struct device *dev) ...@@ -1180,6 +1180,7 @@ static int at91_twi_suspend_noirq(struct device *dev)
static int at91_twi_resume_noirq(struct device *dev) static int at91_twi_resume_noirq(struct device *dev)
{ {
struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
int ret; int ret;
if (!pm_runtime_status_suspended(dev)) { if (!pm_runtime_status_suspended(dev)) {
...@@ -1191,6 +1192,8 @@ static int at91_twi_resume_noirq(struct device *dev) ...@@ -1191,6 +1192,8 @@ static int at91_twi_resume_noirq(struct device *dev)
pm_runtime_mark_last_busy(dev); pm_runtime_mark_last_busy(dev);
pm_request_autosuspend(dev); pm_request_autosuspend(dev);
at91_init_twi_bus(twi_dev);
return 0; return 0;
} }
......
...@@ -195,7 +195,9 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) ...@@ -195,7 +195,9 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
} }
if (val & BCM2835_I2C_S_DONE) { if (val & BCM2835_I2C_S_DONE) {
if (i2c_dev->curr_msg->flags & I2C_M_RD) { if (!i2c_dev->curr_msg) {
dev_err(i2c_dev->dev, "Got unexpected interrupt (from firmware?)\n");
} else if (i2c_dev->curr_msg->flags & I2C_M_RD) {
bcm2835_drain_rxfifo(i2c_dev); bcm2835_drain_rxfifo(i2c_dev);
val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S);
} }
......
...@@ -563,7 +563,7 @@ static u32 bfin_twi_functionality(struct i2c_adapter *adap) ...@@ -563,7 +563,7 @@ static u32 bfin_twi_functionality(struct i2c_adapter *adap)
I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK; I2C_FUNC_I2C | I2C_FUNC_SMBUS_I2C_BLOCK;
} }
static struct i2c_algorithm bfin_twi_algorithm = { static const struct i2c_algorithm bfin_twi_algorithm = {
.master_xfer = bfin_twi_master_xfer, .master_xfer = bfin_twi_master_xfer,
.smbus_xfer = bfin_twi_smbus_xfer, .smbus_xfer = bfin_twi_smbus_xfer,
.functionality = bfin_twi_functionality, .functionality = bfin_twi_functionality,
......
...@@ -154,8 +154,10 @@ static int ec_i2c_parse_response(const u8 *buf, struct i2c_msg i2c_msgs[], ...@@ -154,8 +154,10 @@ static int ec_i2c_parse_response(const u8 *buf, struct i2c_msg i2c_msgs[],
resp = (const struct ec_response_i2c_passthru *)buf; resp = (const struct ec_response_i2c_passthru *)buf;
if (resp->i2c_status & EC_I2C_STATUS_TIMEOUT) if (resp->i2c_status & EC_I2C_STATUS_TIMEOUT)
return -ETIMEDOUT; return -ETIMEDOUT;
else if (resp->i2c_status & EC_I2C_STATUS_NAK)
return -ENXIO;
else if (resp->i2c_status & EC_I2C_STATUS_ERROR) else if (resp->i2c_status & EC_I2C_STATUS_ERROR)
return -EREMOTEIO; return -EIO;
/* Other side could send us back fewer messages, but not more */ /* Other side could send us back fewer messages, but not more */
if (resp->num_msgs > *num) if (resp->num_msgs > *num)
...@@ -222,10 +224,8 @@ static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[], ...@@ -222,10 +224,8 @@ static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[],
} }
result = ec_i2c_parse_response(msg->data, i2c_msgs, &num); result = ec_i2c_parse_response(msg->data, i2c_msgs, &num);
if (result < 0) { if (result < 0)
dev_err(dev, "Error parsing EC i2c message %d\n", result);
goto exit; goto exit;
}
/* Indicate success by saying how many messages were sent */ /* Indicate success by saying how many messages were sent */
result = num; result = num;
......
...@@ -820,7 +820,7 @@ static u32 i2c_dw_func(struct i2c_adapter *adap) ...@@ -820,7 +820,7 @@ static u32 i2c_dw_func(struct i2c_adapter *adap)
return dev->functionality; return dev->functionality;
} }
static struct i2c_algorithm i2c_dw_algo = { static const struct i2c_algorithm i2c_dw_algo = {
.master_xfer = i2c_dw_xfer, .master_xfer = i2c_dw_xfer,
.functionality = i2c_dw_func, .functionality = i2c_dw_func,
}; };
......
...@@ -715,7 +715,7 @@ static u32 pch_i2c_func(struct i2c_adapter *adap) ...@@ -715,7 +715,7 @@ static u32 pch_i2c_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR; return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR;
} }
static struct i2c_algorithm pch_algorithm = { static const struct i2c_algorithm pch_algorithm = {
.master_xfer = pch_i2c_xfer, .master_xfer = pch_i2c_xfer,
.functionality = pch_i2c_func .functionality = pch_i2c_func
}; };
......
...@@ -347,7 +347,7 @@ static int em_i2c_unreg_slave(struct i2c_client *slave) ...@@ -347,7 +347,7 @@ static int em_i2c_unreg_slave(struct i2c_client *slave)
return 0; return 0;
} }
static struct i2c_algorithm em_i2c_algo = { static const struct i2c_algorithm em_i2c_algo = {
.master_xfer = em_i2c_xfer, .master_xfer = em_i2c_xfer,
.functionality = em_i2c_func, .functionality = em_i2c_func,
.reg_slave = em_i2c_reg_slave, .reg_slave = em_i2c_reg_slave,
......
...@@ -130,12 +130,32 @@ ...@@ -130,12 +130,32 @@
/* I2C_TRANS_STATUS register bits */ /* I2C_TRANS_STATUS register bits */
#define HSI2C_MASTER_BUSY (1u << 17) #define HSI2C_MASTER_BUSY (1u << 17)
#define HSI2C_SLAVE_BUSY (1u << 16) #define HSI2C_SLAVE_BUSY (1u << 16)
/* I2C_TRANS_STATUS register bits for Exynos5 variant */
#define HSI2C_TIMEOUT_AUTO (1u << 4) #define HSI2C_TIMEOUT_AUTO (1u << 4)
#define HSI2C_NO_DEV (1u << 3) #define HSI2C_NO_DEV (1u << 3)
#define HSI2C_NO_DEV_ACK (1u << 2) #define HSI2C_NO_DEV_ACK (1u << 2)
#define HSI2C_TRANS_ABORT (1u << 1) #define HSI2C_TRANS_ABORT (1u << 1)
#define HSI2C_TRANS_DONE (1u << 0) #define HSI2C_TRANS_DONE (1u << 0)
/* I2C_TRANS_STATUS register bits for Exynos7 variant */
#define HSI2C_MASTER_ST_MASK 0xf
#define HSI2C_MASTER_ST_IDLE 0x0
#define HSI2C_MASTER_ST_START 0x1
#define HSI2C_MASTER_ST_RESTART 0x2
#define HSI2C_MASTER_ST_STOP 0x3
#define HSI2C_MASTER_ST_MASTER_ID 0x4
#define HSI2C_MASTER_ST_ADDR0 0x5
#define HSI2C_MASTER_ST_ADDR1 0x6
#define HSI2C_MASTER_ST_ADDR2 0x7
#define HSI2C_MASTER_ST_ADDR_SR 0x8
#define HSI2C_MASTER_ST_READ 0x9
#define HSI2C_MASTER_ST_WRITE 0xa
#define HSI2C_MASTER_ST_NO_ACK 0xb
#define HSI2C_MASTER_ST_LOSE 0xc
#define HSI2C_MASTER_ST_WAIT 0xd
#define HSI2C_MASTER_ST_WAIT_CMD 0xe
/* I2C_ADDR register bits */ /* I2C_ADDR register bits */
#define HSI2C_SLV_ADDR_SLV(x) ((x & 0x3ff) << 0) #define HSI2C_SLV_ADDR_SLV(x) ((x & 0x3ff) << 0)
#define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10) #define HSI2C_SLV_ADDR_MAS(x) ((x & 0x3ff) << 10)
...@@ -437,6 +457,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) ...@@ -437,6 +457,7 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
int_status = readl(i2c->regs + HSI2C_INT_STATUS); int_status = readl(i2c->regs + HSI2C_INT_STATUS);
writel(int_status, i2c->regs + HSI2C_INT_STATUS); writel(int_status, i2c->regs + HSI2C_INT_STATUS);
trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS);
/* handle interrupt related to the transfer status */ /* handle interrupt related to the transfer status */
if (i2c->variant->hw == HSI2C_EXYNOS7) { if (i2c->variant->hw == HSI2C_EXYNOS7) {
...@@ -460,8 +481,12 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) ...@@ -460,8 +481,12 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
i2c->state = -ETIMEDOUT; i2c->state = -ETIMEDOUT;
goto stop; goto stop;
} }
if ((trans_status & HSI2C_MASTER_ST_MASK) == HSI2C_MASTER_ST_LOSE) {
i2c->state = -EAGAIN;
goto stop;
}
} else if (int_status & HSI2C_INT_I2C) { } else if (int_status & HSI2C_INT_I2C) {
trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS);
if (trans_status & HSI2C_NO_DEV_ACK) { if (trans_status & HSI2C_NO_DEV_ACK) {
dev_dbg(i2c->dev, "No ACK from device\n"); dev_dbg(i2c->dev, "No ACK from device\n");
i2c->state = -ENXIO; i2c->state = -ENXIO;
...@@ -502,8 +527,13 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id) ...@@ -502,8 +527,13 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
fifo_level = HSI2C_TX_FIFO_LVL(fifo_status); fifo_level = HSI2C_TX_FIFO_LVL(fifo_status);
len = i2c->variant->fifo_depth - fifo_level; len = i2c->variant->fifo_depth - fifo_level;
if (len > (i2c->msg->len - i2c->msg_ptr)) if (len > (i2c->msg->len - i2c->msg_ptr)) {
u32 int_en = readl(i2c->regs + HSI2C_INT_ENABLE);
int_en &= ~HSI2C_INT_TX_ALMOSTEMPTY_EN;
writel(int_en, i2c->regs + HSI2C_INT_ENABLE);
len = i2c->msg->len - i2c->msg_ptr; len = i2c->msg->len - i2c->msg_ptr;
}
while (len > 0) { while (len > 0) {
byte = i2c->msg->buf[i2c->msg_ptr++]; byte = i2c->msg->buf[i2c->msg_ptr++];
......
...@@ -65,6 +65,7 @@ ...@@ -65,6 +65,7 @@
* Lewisburg (PCH) 0xa1a3 32 hard yes yes yes * Lewisburg (PCH) 0xa1a3 32 hard yes yes yes
* Lewisburg Supersku (PCH) 0xa223 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 * Kaby Lake PCH-H (PCH) 0xa2a3 32 hard yes yes yes
* Gemini Lake (SOC) 0x31d4 32 hard yes yes yes
* *
* Features supported by this driver: * Features supported by this driver:
* Software PEC no * Software PEC no
...@@ -213,6 +214,7 @@ ...@@ -213,6 +214,7 @@
#define PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS 0x2292 #define PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS 0x2292
#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
#define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0 #define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0
#define PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS 0x31d4
#define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30
#define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4 #define PCI_DEVICE_ID_INTEL_BROXTON_SMBUS 0x5ad4
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22
...@@ -1012,6 +1014,7 @@ static const struct pci_device_id i801_ids[] = { ...@@ -1012,6 +1014,7 @@ static const struct pci_device_id i801_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS1) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS2) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) },
......
...@@ -538,7 +538,7 @@ static u32 lpi2c_imx_func(struct i2c_adapter *adapter) ...@@ -538,7 +538,7 @@ static u32 lpi2c_imx_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_READ_BLOCK_DATA; I2C_FUNC_SMBUS_READ_BLOCK_DATA;
} }
static struct i2c_algorithm lpi2c_imx_algo = { static const struct i2c_algorithm lpi2c_imx_algo = {
.master_xfer = lpi2c_imx_xfer, .master_xfer = lpi2c_imx_xfer,
.functionality = lpi2c_imx_func, .functionality = lpi2c_imx_func,
}; };
......
...@@ -1037,7 +1037,7 @@ static u32 i2c_imx_func(struct i2c_adapter *adapter) ...@@ -1037,7 +1037,7 @@ static u32 i2c_imx_func(struct i2c_adapter *adapter)
| I2C_FUNC_SMBUS_READ_BLOCK_DATA; | I2C_FUNC_SMBUS_READ_BLOCK_DATA;
} }
static struct i2c_algorithm i2c_imx_algo = { static const struct i2c_algorithm i2c_imx_algo = {
.master_xfer = i2c_imx_xfer, .master_xfer = i2c_imx_xfer,
.functionality = i2c_imx_func, .functionality = i2c_imx_func,
}; };
......
...@@ -977,11 +977,32 @@ mv64xxx_i2c_remove(struct platform_device *dev) ...@@ -977,11 +977,32 @@ mv64xxx_i2c_remove(struct platform_device *dev)
return 0; return 0;
} }
#ifdef CONFIG_PM
static int mv64xxx_i2c_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct mv64xxx_i2c_data *drv_data = platform_get_drvdata(pdev);
mv64xxx_i2c_hw_init(drv_data);
return 0;
}
static const struct dev_pm_ops mv64xxx_i2c_pm = {
.resume = mv64xxx_i2c_resume,
};
#define mv64xxx_i2c_pm_ops (&mv64xxx_i2c_pm)
#else
#define mv64xxx_i2c_pm_ops NULL
#endif
static struct platform_driver mv64xxx_i2c_driver = { static struct platform_driver mv64xxx_i2c_driver = {
.probe = mv64xxx_i2c_probe, .probe = mv64xxx_i2c_probe,
.remove = mv64xxx_i2c_remove, .remove = mv64xxx_i2c_remove,
.driver = { .driver = {
.name = MV64XXX_I2C_CTLR_NAME, .name = MV64XXX_I2C_CTLR_NAME,
.pm = mv64xxx_i2c_pm_ops,
.of_match_table = mv64xxx_i2c_of_match_table, .of_match_table = mv64xxx_i2c_of_match_table,
}, },
}; };
......
...@@ -296,7 +296,7 @@ static u32 nforce2_func(struct i2c_adapter *adapter) ...@@ -296,7 +296,7 @@ static u32 nforce2_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_BLOCK_DATA : 0); I2C_FUNC_SMBUS_BLOCK_DATA : 0);
} }
static struct i2c_algorithm smbus_algorithm = { static const struct i2c_algorithm smbus_algorithm = {
.smbus_xfer = nforce2_access, .smbus_xfer = nforce2_access,
.functionality = nforce2_func, .functionality = nforce2_func,
}; };
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
#include <linux/i2c-smbus.h> #include <linux/i2c-smbus.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/pci.h>
/* Controller command patterns */ /* Controller command patterns */
#define SW_TWSI_V BIT_ULL(63) /* Valid bit */ #define SW_TWSI_V BIT_ULL(63) /* Valid bit */
...@@ -118,9 +117,6 @@ struct octeon_i2c { ...@@ -118,9 +117,6 @@ struct octeon_i2c {
void (*hlc_int_disable)(struct octeon_i2c *); void (*hlc_int_disable)(struct octeon_i2c *);
atomic_t int_enable_cnt; atomic_t int_enable_cnt;
atomic_t hlc_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_smbus_alert_setup alert_data;
struct i2c_client *ara; struct i2c_client *ara;
}; };
......
...@@ -1504,7 +1504,7 @@ static int omap_i2c_runtime_resume(struct device *dev) ...@@ -1504,7 +1504,7 @@ static int omap_i2c_runtime_resume(struct device *dev)
return 0; return 0;
} }
static struct dev_pm_ops omap_i2c_pm_ops = { static const struct dev_pm_ops omap_i2c_pm_ops = {
SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend, SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend,
omap_i2c_runtime_resume, NULL) omap_i2c_runtime_resume, NULL)
}; };
......
...@@ -80,6 +80,7 @@ ...@@ -80,6 +80,7 @@
#define ICIER_TEIE 0x40 #define ICIER_TEIE 0x40
#define ICIER_RIE 0x20 #define ICIER_RIE 0x20
#define ICIER_NAKIE 0x10 #define ICIER_NAKIE 0x10
#define ICIER_SPIE 0x08
#define ICSR2_NACKF 0x10 #define ICSR2_NACKF 0x10
...@@ -216,11 +217,10 @@ static irqreturn_t riic_tend_isr(int irq, void *data) ...@@ -216,11 +217,10 @@ static irqreturn_t riic_tend_isr(int irq, void *data)
return IRQ_NONE; return IRQ_NONE;
} }
if (riic->is_last || riic->err) if (riic->is_last || riic->err) {
riic_clear_set_bit(riic, 0, ICIER_SPIE, RIIC_ICIER);
writeb(ICCR2_SP, riic->base + RIIC_ICCR2); writeb(ICCR2_SP, riic->base + RIIC_ICCR2);
}
writeb(0, riic->base + RIIC_ICIER);
complete(&riic->msg_done);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -240,13 +240,13 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data) ...@@ -240,13 +240,13 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data)
if (riic->bytes_left == 1) { if (riic->bytes_left == 1) {
/* STOP must come before we set ACKBT! */ /* STOP must come before we set ACKBT! */
if (riic->is_last) if (riic->is_last) {
riic_clear_set_bit(riic, 0, ICIER_SPIE, RIIC_ICIER);
writeb(ICCR2_SP, riic->base + RIIC_ICCR2); writeb(ICCR2_SP, riic->base + RIIC_ICCR2);
}
riic_clear_set_bit(riic, 0, ICMR3_ACKBT, RIIC_ICMR3); riic_clear_set_bit(riic, 0, ICMR3_ACKBT, RIIC_ICMR3);
writeb(0, riic->base + RIIC_ICIER);
complete(&riic->msg_done);
} else { } else {
riic_clear_set_bit(riic, ICMR3_ACKBT, 0, RIIC_ICMR3); riic_clear_set_bit(riic, ICMR3_ACKBT, 0, RIIC_ICMR3);
} }
...@@ -259,6 +259,21 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data) ...@@ -259,6 +259,21 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static irqreturn_t riic_stop_isr(int irq, void *data)
{
struct riic_dev *riic = data;
/* read back registers to confirm writes have fully propagated */
writeb(0, riic->base + RIIC_ICSR2);
readb(riic->base + RIIC_ICSR2);
writeb(0, riic->base + RIIC_ICIER);
readb(riic->base + RIIC_ICIER);
complete(&riic->msg_done);
return IRQ_HANDLED;
}
static u32 riic_func(struct i2c_adapter *adap) static u32 riic_func(struct i2c_adapter *adap)
{ {
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
...@@ -326,6 +341,7 @@ static struct riic_irq_desc riic_irqs[] = { ...@@ -326,6 +341,7 @@ static struct riic_irq_desc riic_irqs[] = {
{ .res_num = 0, .isr = riic_tend_isr, .name = "riic-tend" }, { .res_num = 0, .isr = riic_tend_isr, .name = "riic-tend" },
{ .res_num = 1, .isr = riic_rdrf_isr, .name = "riic-rdrf" }, { .res_num = 1, .isr = riic_rdrf_isr, .name = "riic-rdrf" },
{ .res_num = 2, .isr = riic_tdre_isr, .name = "riic-tdre" }, { .res_num = 2, .isr = riic_tdre_isr, .name = "riic-tdre" },
{ .res_num = 3, .isr = riic_stop_isr, .name = "riic-stop" },
{ .res_num = 5, .isr = riic_tend_isr, .name = "riic-nack" }, { .res_num = 5, .isr = riic_tend_isr, .name = "riic-nack" },
}; };
......
...@@ -117,7 +117,7 @@ static u32 osif_func(struct i2c_adapter *adapter) ...@@ -117,7 +117,7 @@ static u32 osif_func(struct i2c_adapter *adapter)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
} }
static struct i2c_algorithm osif_algorithm = { static const struct i2c_algorithm osif_algorithm = {
.master_xfer = osif_xfer, .master_xfer = osif_xfer,
.functionality = osif_func, .functionality = osif_func,
}; };
......
...@@ -781,7 +781,7 @@ static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter) ...@@ -781,7 +781,7 @@ static u32 sh_mobile_i2c_func(struct i2c_adapter *adapter)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING; return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_PROTOCOL_MANGLING;
} }
static struct i2c_algorithm sh_mobile_i2c_algorithm = { static const struct i2c_algorithm sh_mobile_i2c_algorithm = {
.functionality = sh_mobile_i2c_func, .functionality = sh_mobile_i2c_func,
.master_xfer = sh_mobile_i2c_xfer, .master_xfer = sh_mobile_i2c_xfer,
}; };
......
...@@ -776,7 +776,7 @@ static u32 st_i2c_func(struct i2c_adapter *adap) ...@@ -776,7 +776,7 @@ static u32 st_i2c_func(struct i2c_adapter *adap)
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
} }
static struct i2c_algorithm st_i2c_algo = { static const struct i2c_algorithm st_i2c_algo = {
.master_xfer = st_i2c_xfer, .master_xfer = st_i2c_xfer,
.functionality = st_i2c_func, .functionality = st_i2c_func,
}; };
......
This diff is collapsed.
/*
* drivers/i2c/busses/i2c-tegra-bpmp.c
*
* Copyright (c) 2016 NVIDIA Corporation. All rights reserved.
*
* Author: Shardar Shariff Md <smohammed@nvidia.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <soc/tegra/bpmp-abi.h>
#include <soc/tegra/bpmp.h>
/*
* Serialized I2C message header size is 6 bytes and includes address, flags
* and length
*/
#define SERIALI2C_HDR_SIZE 6
struct tegra_bpmp_i2c {
struct i2c_adapter adapter;
struct device *dev;
struct tegra_bpmp *bpmp;
unsigned int bus;
};
/*
* Linux flags are translated to BPMP defined I2C flags that are used in BPMP
* firmware I2C driver to avoid any issues in future if Linux I2C flags are
* changed.
*/
static int tegra_bpmp_xlate_flags(u16 flags, u16 *out)
{
if (flags & I2C_M_TEN) {
*out |= SERIALI2C_TEN;
flags &= ~I2C_M_TEN;
}
if (flags & I2C_M_RD) {
*out |= SERIALI2C_RD;
flags &= ~I2C_M_RD;
}
if (flags & I2C_M_STOP) {
*out |= SERIALI2C_STOP;
flags &= ~I2C_M_STOP;
}
if (flags & I2C_M_NOSTART) {
*out |= SERIALI2C_NOSTART;
flags &= ~I2C_M_NOSTART;
}
if (flags & I2C_M_REV_DIR_ADDR) {
*out |= SERIALI2C_REV_DIR_ADDR;
flags &= ~I2C_M_REV_DIR_ADDR;
}
if (flags & I2C_M_IGNORE_NAK) {
*out |= SERIALI2C_IGNORE_NAK;
flags &= ~I2C_M_IGNORE_NAK;
}
if (flags & I2C_M_NO_RD_ACK) {
*out |= SERIALI2C_NO_RD_ACK;
flags &= ~I2C_M_NO_RD_ACK;
}
if (flags & I2C_M_RECV_LEN) {
*out |= SERIALI2C_RECV_LEN;
flags &= ~I2C_M_RECV_LEN;
}
return (flags != 0) ? -EINVAL : 0;
}
/**
* The serialized I2C format is simply the following:
* [addr little-endian][flags little-endian][len little-endian][data if write]
* [addr little-endian][flags little-endian][len little-endian][data if write]
* ...
*
* The flags are translated from Linux kernel representation to seriali2c
* representation. Any undefined flag being set causes an error.
*
* The data is there only for writes. Reads have the data transferred in the
* other direction, and thus data is not present.
*
* See deserialize_i2c documentation for the data format in the other direction.
*/
static int tegra_bpmp_serialize_i2c_msg(struct tegra_bpmp_i2c *i2c,
struct mrq_i2c_request *request,
struct i2c_msg *msgs,
unsigned int num)
{
char *buf = request->xfer.data_buf;
unsigned int i, j, pos = 0;
int err;
for (i = 0; i < num; i++) {
struct i2c_msg *msg = &msgs[i];
u16 flags = 0;
err = tegra_bpmp_xlate_flags(msg->flags, &flags);
if (err < 0)
return err;
buf[pos++] = msg->addr & 0xff;
buf[pos++] = (msg->addr & 0xff00) >> 8;
buf[pos++] = flags & 0xff;
buf[pos++] = (flags & 0xff00) >> 8;
buf[pos++] = msg->len & 0xff;
buf[pos++] = (msg->len & 0xff00) >> 8;
if ((flags & SERIALI2C_RD) == 0) {
for (j = 0; j < msg->len; j++)
buf[pos++] = msg->buf[j];
}
}
request->xfer.data_size = pos;
return 0;
}
/**
* The data in the BPMP -> CPU direction is composed of sequential blocks for
* those messages that have I2C_M_RD. So, for example, if you have:
*
* - !I2C_M_RD, len == 5, data == a0 01 02 03 04
* - !I2C_M_RD, len == 1, data == a0
* - I2C_M_RD, len == 2, data == [uninitialized buffer 1]
* - !I2C_M_RD, len == 1, data == a2
* - I2C_M_RD, len == 2, data == [uninitialized buffer 2]
*
* ...then the data in the BPMP -> CPU direction would be 4 bytes total, and
* would contain 2 bytes that will go to uninitialized buffer 1, and 2 bytes
* that will go to uninitialized buffer 2.
*/
static int tegra_bpmp_i2c_deserialize(struct tegra_bpmp_i2c *i2c,
struct mrq_i2c_response *response,
struct i2c_msg *msgs,
unsigned int num)
{
size_t size = response->xfer.data_size, len = 0, pos = 0;
char *buf = response->xfer.data_buf;
unsigned int i;
for (i = 0; i < num; i++)
if (msgs[i].flags & I2C_M_RD)
len += msgs[i].len;
if (len != size)
return -EINVAL;
for (i = 0; i < num; i++) {
if (msgs[i].flags & I2C_M_RD) {
memcpy(msgs[i].buf, buf + pos, msgs[i].len);
pos += msgs[i].len;
}
}
return 0;
}
static int tegra_bpmp_i2c_msg_len_check(struct i2c_msg *msgs, unsigned int num)
{
size_t tx_len = 0, rx_len = 0;
unsigned int i;
for (i = 0; i < num; i++)
if (!(msgs[i].flags & I2C_M_RD))
tx_len += SERIALI2C_HDR_SIZE + msgs[i].len;
if (tx_len > TEGRA_I2C_IPC_MAX_IN_BUF_SIZE)
return -EINVAL;
for (i = 0; i < num; i++)
if ((msgs[i].flags & I2C_M_RD))
rx_len += msgs[i].len;
if (rx_len > TEGRA_I2C_IPC_MAX_OUT_BUF_SIZE)
return -EINVAL;
return 0;
}
static int tegra_bpmp_i2c_msg_xfer(struct tegra_bpmp_i2c *i2c,
struct mrq_i2c_request *request,
struct mrq_i2c_response *response)
{
struct tegra_bpmp_message msg;
int err;
request->cmd = CMD_I2C_XFER;
request->xfer.bus_id = i2c->bus;
memset(&msg, 0, sizeof(msg));
msg.mrq = MRQ_I2C;
msg.tx.data = request;
msg.tx.size = sizeof(*request);
msg.rx.data = response;
msg.rx.size = sizeof(*response);
if (irqs_disabled())
err = tegra_bpmp_transfer_atomic(i2c->bpmp, &msg);
else
err = tegra_bpmp_transfer(i2c->bpmp, &msg);
return err;
}
static int tegra_bpmp_i2c_xfer(struct i2c_adapter *adapter,
struct i2c_msg *msgs, int num)
{
struct tegra_bpmp_i2c *i2c = i2c_get_adapdata(adapter);
struct mrq_i2c_response response;
struct mrq_i2c_request request;
int err;
err = tegra_bpmp_i2c_msg_len_check(msgs, num);
if (err < 0) {
dev_err(i2c->dev, "unsupported message length\n");
return err;
}
memset(&request, 0, sizeof(request));
memset(&response, 0, sizeof(response));
err = tegra_bpmp_serialize_i2c_msg(i2c, &request, msgs, num);
if (err < 0) {
dev_err(i2c->dev, "failed to serialize message: %d\n", err);
return err;
}
err = tegra_bpmp_i2c_msg_xfer(i2c, &request, &response);
if (err < 0) {
dev_err(i2c->dev, "failed to transfer message: %d\n", err);
return err;
}
err = tegra_bpmp_i2c_deserialize(i2c, &response, msgs, num);
if (err < 0) {
dev_err(i2c->dev, "failed to deserialize message: %d\n", err);
return err;
}
return num;
}
static u32 tegra_bpmp_i2c_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_10BIT_ADDR |
I2C_FUNC_PROTOCOL_MANGLING | I2C_FUNC_NOSTART;
}
static const struct i2c_algorithm tegra_bpmp_i2c_algo = {
.master_xfer = tegra_bpmp_i2c_xfer,
.functionality = tegra_bpmp_i2c_func,
};
static int tegra_bpmp_i2c_probe(struct platform_device *pdev)
{
struct tegra_bpmp_i2c *i2c;
u32 value;
int err;
i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL);
if (!i2c)
return -ENOMEM;
i2c->dev = &pdev->dev;
i2c->bpmp = dev_get_drvdata(pdev->dev.parent);
if (!i2c->bpmp)
return -ENODEV;
err = of_property_read_u32(pdev->dev.of_node, "nvidia,bpmp-bus-id",
&value);
if (err < 0)
return err;
i2c->bus = value;
i2c_set_adapdata(&i2c->adapter, i2c);
i2c->adapter.owner = THIS_MODULE;
strlcpy(i2c->adapter.name, "Tegra BPMP I2C adapter",
sizeof(i2c->adapter.name));
i2c->adapter.algo = &tegra_bpmp_i2c_algo;
i2c->adapter.dev.parent = &pdev->dev;
i2c->adapter.dev.of_node = pdev->dev.of_node;
platform_set_drvdata(pdev, i2c);
return i2c_add_adapter(&i2c->adapter);
}
static int tegra_bpmp_i2c_remove(struct platform_device *pdev)
{
struct tegra_bpmp_i2c *i2c = platform_get_drvdata(pdev);
i2c_del_adapter(&i2c->adapter);
return 0;
}
static const struct of_device_id tegra_bpmp_i2c_of_match[] = {
{ .compatible = "nvidia,tegra186-bpmp-i2c", },
{ }
};
MODULE_DEVICE_TABLE(of, tegra_bpmp_i2c_of_match);
static struct platform_driver tegra_bpmp_i2c_driver = {
.driver = {
.name = "tegra-bpmp-i2c",
.of_match_table = tegra_bpmp_i2c_of_match,
},
.probe = tegra_bpmp_i2c_probe,
.remove = tegra_bpmp_i2c_remove,
};
module_platform_driver(tegra_bpmp_i2c_driver);
MODULE_DESCRIPTION("NVIDIA Tegra BPMP I2C bus contoller driver");
MODULE_AUTHOR("Shardar Shariff Md <smohammed@nvidia.com>");
MODULE_AUTHOR("Juha-Matti Tilli");
MODULE_LICENSE("GPL v2");
...@@ -188,11 +188,11 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev, ...@@ -188,11 +188,11 @@ static int thunder_i2c_probe_pci(struct pci_dev *pdev,
i2c->hlc_int_enable = thunder_i2c_hlc_int_enable; i2c->hlc_int_enable = thunder_i2c_hlc_int_enable;
i2c->hlc_int_disable = thunder_i2c_hlc_int_disable; i2c->hlc_int_disable = thunder_i2c_hlc_int_disable;
ret = pci_enable_msix(pdev, &i2c->i2c_msix, 1); ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
if (ret) if (ret < 0)
goto error; goto error;
ret = devm_request_irq(dev, i2c->i2c_msix.vector, octeon_i2c_isr, 0, ret = devm_request_irq(dev, pci_irq_vector(pdev, 0), octeon_i2c_isr, 0,
DRV_NAME, i2c); DRV_NAME, i2c);
if (ret) if (ret)
goto error; goto error;
......
...@@ -372,7 +372,7 @@ static u32 xgene_slimpro_i2c_func(struct i2c_adapter *adapter) ...@@ -372,7 +372,7 @@ static u32 xgene_slimpro_i2c_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_I2C_BLOCK; I2C_FUNC_SMBUS_I2C_BLOCK;
} }
static struct i2c_algorithm xgene_slimpro_i2c_algorithm = { static const struct i2c_algorithm xgene_slimpro_i2c_algorithm = {
.smbus_xfer = xgene_slimpro_i2c_xfer, .smbus_xfer = xgene_slimpro_i2c_xfer,
.functionality = xgene_slimpro_i2c_func, .functionality = xgene_slimpro_i2c_func,
}; };
......
...@@ -334,7 +334,7 @@ static u32 xlp9xx_i2c_functionality(struct i2c_adapter *adapter) ...@@ -334,7 +334,7 @@ static u32 xlp9xx_i2c_functionality(struct i2c_adapter *adapter)
I2C_FUNC_10BIT_ADDR; I2C_FUNC_10BIT_ADDR;
} }
static struct i2c_algorithm xlp9xx_i2c_algo = { static const struct i2c_algorithm xlp9xx_i2c_algo = {
.master_xfer = xlp9xx_i2c_xfer, .master_xfer = xlp9xx_i2c_xfer,
.functionality = xlp9xx_i2c_functionality, .functionality = xlp9xx_i2c_functionality,
}; };
......
...@@ -335,7 +335,7 @@ static u32 xlr_func(struct i2c_adapter *adap) ...@@ -335,7 +335,7 @@ static u32 xlr_func(struct i2c_adapter *adap)
return (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | I2C_FUNC_I2C; return (I2C_FUNC_SMBUS_EMUL & ~I2C_FUNC_SMBUS_QUICK) | I2C_FUNC_I2C;
} }
static struct i2c_algorithm xlr_i2c_algo = { static const struct i2c_algorithm xlr_i2c_algo = {
.master_xfer = xlr_i2c_xfer, .master_xfer = xlr_i2c_xfer,
.functionality = xlr_func, .functionality = xlr_func,
}; };
......
...@@ -3705,6 +3705,39 @@ int i2c_slave_unregister(struct i2c_client *client) ...@@ -3705,6 +3705,39 @@ int i2c_slave_unregister(struct i2c_client *client)
return ret; return ret;
} }
EXPORT_SYMBOL_GPL(i2c_slave_unregister); EXPORT_SYMBOL_GPL(i2c_slave_unregister);
/**
* i2c_detect_slave_mode - detect operation mode
* @dev: The device owning the bus
*
* This checks the device nodes for an I2C slave by checking the address
* used in the reg property. If the address match the I2C_OWN_SLAVE_ADDRESS
* flag this means the device is configured to act as a I2C slave and it will
* be listening at that address.
*
* Returns true if an I2C own slave address is detected, otherwise returns
* false.
*/
bool i2c_detect_slave_mode(struct device *dev)
{
if (IS_BUILTIN(CONFIG_OF) && dev->of_node) {
struct device_node *child;
u32 reg;
for_each_child_of_node(dev->of_node, child) {
of_property_read_u32(child, "reg", &reg);
if (reg & I2C_OWN_SLAVE_ADDRESS) {
of_node_put(child);
return true;
}
}
} else if (IS_BUILTIN(CONFIG_ACPI) && ACPI_HANDLE(dev)) {
dev_dbg(dev, "ACPI slave is not supported yet\n");
}
return false;
}
EXPORT_SYMBOL_GPL(i2c_detect_slave_mode);
#endif #endif
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>"); MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
......
...@@ -40,7 +40,6 @@ ...@@ -40,7 +40,6 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/version.h>
#include <linux/i2c/mlxcpld.h> #include <linux/i2c/mlxcpld.h>
#define CPLD_MUX_MAX_NCHANS 8 #define CPLD_MUX_MAX_NCHANS 8
......
...@@ -90,6 +90,7 @@ static const struct of_device_id pca9541_of_match[] = { ...@@ -90,6 +90,7 @@ static const struct of_device_id pca9541_of_match[] = {
{ .compatible = "nxp,pca9541" }, { .compatible = "nxp,pca9541" },
{} {}
}; };
MODULE_DEVICE_TABLE(of, pca9541_of_match);
#endif #endif
/* /*
......
...@@ -41,14 +41,20 @@ ...@@ -41,14 +41,20 @@
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/i2c-mux.h> #include <linux/i2c-mux.h>
#include <linux/i2c/pca954x.h> #include <linux/i2c/pca954x.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/of_irq.h>
#include <linux/pm.h> #include <linux/pm.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h>
#define PCA954X_MAX_NCHANS 8 #define PCA954X_MAX_NCHANS 8
#define PCA954X_IRQ_OFFSET 4
enum pca_type { enum pca_type {
pca_9540, pca_9540,
pca_9542, pca_9542,
...@@ -63,6 +69,7 @@ enum pca_type { ...@@ -63,6 +69,7 @@ enum pca_type {
struct chip_desc { struct chip_desc {
u8 nchans; u8 nchans;
u8 enable; /* used for muxes only */ u8 enable; /* used for muxes only */
u8 has_irq;
enum muxtype { enum muxtype {
pca954x_ismux = 0, pca954x_ismux = 0,
pca954x_isswi pca954x_isswi
...@@ -75,6 +82,10 @@ struct pca954x { ...@@ -75,6 +82,10 @@ struct pca954x {
u8 last_chan; /* last register value */ u8 last_chan; /* last register value */
u8 deselect; u8 deselect;
struct i2c_client *client; struct i2c_client *client;
struct irq_domain *irq;
unsigned int irq_mask;
spinlock_t lock;
}; };
/* Provide specs for the PCA954x types we know about */ /* Provide specs for the PCA954x types we know about */
...@@ -84,17 +95,26 @@ static const struct chip_desc chips[] = { ...@@ -84,17 +95,26 @@ static const struct chip_desc chips[] = {
.enable = 0x4, .enable = 0x4,
.muxtype = pca954x_ismux, .muxtype = pca954x_ismux,
}, },
[pca_9542] = {
.nchans = 2,
.enable = 0x4,
.has_irq = 1,
.muxtype = pca954x_ismux,
},
[pca_9543] = { [pca_9543] = {
.nchans = 2, .nchans = 2,
.has_irq = 1,
.muxtype = pca954x_isswi, .muxtype = pca954x_isswi,
}, },
[pca_9544] = { [pca_9544] = {
.nchans = 4, .nchans = 4,
.enable = 0x4, .enable = 0x4,
.has_irq = 1,
.muxtype = pca954x_ismux, .muxtype = pca954x_ismux,
}, },
[pca_9545] = { [pca_9545] = {
.nchans = 4, .nchans = 4,
.has_irq = 1,
.muxtype = pca954x_isswi, .muxtype = pca954x_isswi,
}, },
[pca_9547] = { [pca_9547] = {
...@@ -110,7 +130,7 @@ static const struct chip_desc chips[] = { ...@@ -110,7 +130,7 @@ static const struct chip_desc chips[] = {
static const struct i2c_device_id pca954x_id[] = { static const struct i2c_device_id pca954x_id[] = {
{ "pca9540", pca_9540 }, { "pca9540", pca_9540 },
{ "pca9542", pca_9540 }, { "pca9542", pca_9542 },
{ "pca9543", pca_9543 }, { "pca9543", pca_9543 },
{ "pca9544", pca_9544 }, { "pca9544", pca_9544 },
{ "pca9545", pca_9545 }, { "pca9545", pca_9545 },
...@@ -124,7 +144,7 @@ MODULE_DEVICE_TABLE(i2c, pca954x_id); ...@@ -124,7 +144,7 @@ MODULE_DEVICE_TABLE(i2c, pca954x_id);
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
static const struct acpi_device_id pca954x_acpi_ids[] = { static const struct acpi_device_id pca954x_acpi_ids[] = {
{ .id = "PCA9540", .driver_data = pca_9540 }, { .id = "PCA9540", .driver_data = pca_9540 },
{ .id = "PCA9542", .driver_data = pca_9540 }, { .id = "PCA9542", .driver_data = pca_9542 },
{ .id = "PCA9543", .driver_data = pca_9543 }, { .id = "PCA9543", .driver_data = pca_9543 },
{ .id = "PCA9544", .driver_data = pca_9544 }, { .id = "PCA9544", .driver_data = pca_9544 },
{ .id = "PCA9545", .driver_data = pca_9545 }, { .id = "PCA9545", .driver_data = pca_9545 },
...@@ -148,6 +168,7 @@ static const struct of_device_id pca954x_of_match[] = { ...@@ -148,6 +168,7 @@ static const struct of_device_id pca954x_of_match[] = {
{ .compatible = "nxp,pca9548", .data = &chips[pca_9548] }, { .compatible = "nxp,pca9548", .data = &chips[pca_9548] },
{} {}
}; };
MODULE_DEVICE_TABLE(of, pca954x_of_match);
#endif #endif
/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer() /* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
...@@ -217,6 +238,114 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan) ...@@ -217,6 +238,114 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
return pca954x_reg_write(muxc->parent, client, data->last_chan); return pca954x_reg_write(muxc->parent, client, data->last_chan);
} }
static irqreturn_t pca954x_irq_handler(int irq, void *dev_id)
{
struct pca954x *data = dev_id;
unsigned int child_irq;
int ret, i, handled = 0;
ret = i2c_smbus_read_byte(data->client);
if (ret < 0)
return IRQ_NONE;
for (i = 0; i < data->chip->nchans; i++) {
if (ret & BIT(PCA954X_IRQ_OFFSET + i)) {
child_irq = irq_linear_revmap(data->irq, i);
handle_nested_irq(child_irq);
handled++;
}
}
return handled ? IRQ_HANDLED : IRQ_NONE;
}
static void pca954x_irq_mask(struct irq_data *idata)
{
struct pca954x *data = irq_data_get_irq_chip_data(idata);
unsigned int pos = idata->hwirq;
unsigned long flags;
spin_lock_irqsave(&data->lock, flags);
data->irq_mask &= ~BIT(pos);
if (!data->irq_mask)
disable_irq(data->client->irq);
spin_unlock_irqrestore(&data->lock, flags);
}
static void pca954x_irq_unmask(struct irq_data *idata)
{
struct pca954x *data = irq_data_get_irq_chip_data(idata);
unsigned int pos = idata->hwirq;
unsigned long flags;
spin_lock_irqsave(&data->lock, flags);
if (!data->irq_mask)
enable_irq(data->client->irq);
data->irq_mask |= BIT(pos);
spin_unlock_irqrestore(&data->lock, flags);
}
static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type)
{
if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_LOW)
return -EINVAL;
return 0;
}
static struct irq_chip pca954x_irq_chip = {
.name = "i2c-mux-pca954x",
.irq_mask = pca954x_irq_mask,
.irq_unmask = pca954x_irq_unmask,
.irq_set_type = pca954x_irq_set_type,
};
static int pca954x_irq_setup(struct i2c_mux_core *muxc)
{
struct pca954x *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
int c, err, irq;
if (!data->chip->has_irq || client->irq <= 0)
return 0;
spin_lock_init(&data->lock);
data->irq = irq_domain_add_linear(client->dev.of_node,
data->chip->nchans,
&irq_domain_simple_ops, data);
if (!data->irq)
return -ENODEV;
for (c = 0; c < data->chip->nchans; c++) {
irq = irq_create_mapping(data->irq, c);
irq_set_chip_data(irq, data);
irq_set_chip_and_handler(irq, &pca954x_irq_chip,
handle_simple_irq);
}
err = devm_request_threaded_irq(&client->dev, data->client->irq, NULL,
pca954x_irq_handler,
IRQF_ONESHOT | IRQF_SHARED,
"pca954x", data);
if (err)
goto err_req_irq;
disable_irq(data->client->irq);
return 0;
err_req_irq:
for (c = 0; c < data->chip->nchans; c++) {
irq = irq_find_mapping(data->irq, c);
irq_dispose_mapping(irq);
}
irq_domain_remove(data->irq);
return err;
}
/* /*
* I2C init/probing/exit functions * I2C init/probing/exit functions
*/ */
...@@ -281,6 +410,10 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -281,6 +410,10 @@ static int pca954x_probe(struct i2c_client *client,
idle_disconnect_dt = of_node && idle_disconnect_dt = of_node &&
of_property_read_bool(of_node, "i2c-mux-idle-disconnect"); of_property_read_bool(of_node, "i2c-mux-idle-disconnect");
ret = pca954x_irq_setup(muxc);
if (ret)
goto fail_del_adapters;
/* Now create an adapter for each channel */ /* Now create an adapter for each channel */
for (num = 0; num < data->chip->nchans; num++) { for (num = 0; num < data->chip->nchans; num++) {
bool idle_disconnect_pd = false; bool idle_disconnect_pd = false;
...@@ -306,7 +439,7 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -306,7 +439,7 @@ static int pca954x_probe(struct i2c_client *client,
dev_err(&client->dev, dev_err(&client->dev,
"failed to register multiplexed adapter" "failed to register multiplexed adapter"
" %d as bus %d\n", num, force); " %d as bus %d\n", num, force);
goto virt_reg_failed; goto fail_del_adapters;
} }
} }
...@@ -317,7 +450,7 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -317,7 +450,7 @@ static int pca954x_probe(struct i2c_client *client,
return 0; return 0;
virt_reg_failed: fail_del_adapters:
i2c_mux_del_adapters(muxc); i2c_mux_del_adapters(muxc);
return ret; return ret;
} }
...@@ -325,6 +458,16 @@ static int pca954x_probe(struct i2c_client *client, ...@@ -325,6 +458,16 @@ static int pca954x_probe(struct i2c_client *client,
static int pca954x_remove(struct i2c_client *client) static int pca954x_remove(struct i2c_client *client)
{ {
struct i2c_mux_core *muxc = i2c_get_clientdata(client); struct i2c_mux_core *muxc = i2c_get_clientdata(client);
struct pca954x *data = i2c_mux_priv(muxc);
int c, irq;
if (data->irq) {
for (c = 0; c < data->chip->nchans; c++) {
irq = irq_find_mapping(data->irq, c);
irq_dispose_mapping(irq);
}
irq_domain_remove(data->irq);
}
i2c_mux_del_adapters(muxc); i2c_mux_del_adapters(muxc);
return 0; return 0;
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
#include <linux/log2.h> #include <linux/log2.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/of.h> #include <linux/property.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/nvmem-provider.h> #include <linux/nvmem-provider.h>
...@@ -562,26 +562,26 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count) ...@@ -562,26 +562,26 @@ static int at24_write(void *priv, unsigned int off, void *val, size_t count)
return 0; return 0;
} }
#ifdef CONFIG_OF static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip)
static void at24_get_ofdata(struct i2c_client *client,
struct at24_platform_data *chip)
{ {
const __be32 *val; int err;
struct device_node *node = client->dev.of_node; u32 val;
if (node) { if (device_property_present(dev, "read-only"))
if (of_get_property(node, "read-only", NULL)) chip->flags |= AT24_FLAG_READONLY;
chip->flags |= AT24_FLAG_READONLY;
val = of_get_property(node, "pagesize", NULL); err = device_property_read_u32(dev, "pagesize", &val);
if (val) if (!err) {
chip->page_size = be32_to_cpup(val); chip->page_size = val;
} else {
/*
* This is slow, but we can't know all eeproms, so we better
* play safe. Specifying custom eeprom-types via platform_data
* is recommended anyhow.
*/
chip->page_size = 1;
} }
} }
#else
static void at24_get_ofdata(struct i2c_client *client,
struct at24_platform_data *chip)
{ }
#endif /* CONFIG_OF */
static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
{ {
...@@ -613,15 +613,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id) ...@@ -613,15 +613,8 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN)); chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));
magic >>= AT24_SIZE_BYTELEN; magic >>= AT24_SIZE_BYTELEN;
chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS); chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);
/*
* This is slow, but we can't know all eeproms, so we better
* play safe. Specifying custom eeprom-types via platform_data
* is recommended anyhow.
*/
chip.page_size = 1;
/* update chipdata if OF is present */ at24_get_pdata(&client->dev, &chip);
at24_get_ofdata(client, &chip);
chip.setup = NULL; chip.setup = NULL;
chip.context = NULL; chip.context = NULL;
......
...@@ -283,6 +283,7 @@ enum i2c_slave_event { ...@@ -283,6 +283,7 @@ enum i2c_slave_event {
extern int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb); extern int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb);
extern int i2c_slave_unregister(struct i2c_client *client); extern int i2c_slave_unregister(struct i2c_client *client);
extern bool i2c_detect_slave_mode(struct device *dev);
static inline int i2c_slave_event(struct i2c_client *client, static inline int i2c_slave_event(struct i2c_client *client,
enum i2c_slave_event event, u8 *val) enum i2c_slave_event event, u8 *val)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment