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
  ...
This commit is contained in:
Linus Torvalds 2017-02-25 14:21:18 -08:00
Родитель ac1820fb28 4c21541d8d
Коммит 7067739df2
39 изменённых файлов: 1674 добавлений и 77 удалений

Просмотреть файл

@ -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:
#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:
- "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)

Просмотреть файл

@ -0,0 +1,33 @@
* 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";
};

Просмотреть файл

@ -0,0 +1,42 @@
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:
* 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

Просмотреть файл

@ -1,11 +1,11 @@
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.
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[] = {
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 = {
}; };
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 = {
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
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
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
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
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)
| 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)
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)
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)
} }
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)
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[],
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[],
} }
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)
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)
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)
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 @@
/* 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)
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)
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)
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 @@
* 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 @@
#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[] = {
{ 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)
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)
| 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)
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)
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 @@
#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 {
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)
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 @@
#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)
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)
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)
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[] = {
{ .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)
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)
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)
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,
}; };

Просмотреть файл

@ -0,0 +1,897 @@
/*
* Driver for STMicroelectronics STM32 I2C controller
*
* This I2C controller is described in the STM32F429/439 Soc reference manual.
* Please see below a link to the documentation:
* http://www.st.com/resource/en/reference_manual/DM00031020.pdf
*
* Copyright (C) M'boumba Cedric Madianga 2016
* Author: M'boumba Cedric Madianga <cedric.madianga@gmail.com>
*
* This driver is based on i2c-st.c
*
* License terms: GNU General Public License (GPL), version 2
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
/* STM32F4 I2C offset registers */
#define STM32F4_I2C_CR1 0x00
#define STM32F4_I2C_CR2 0x04
#define STM32F4_I2C_DR 0x10
#define STM32F4_I2C_SR1 0x14
#define STM32F4_I2C_SR2 0x18
#define STM32F4_I2C_CCR 0x1C
#define STM32F4_I2C_TRISE 0x20
#define STM32F4_I2C_FLTR 0x24
/* STM32F4 I2C control 1*/
#define STM32F4_I2C_CR1_POS BIT(11)
#define STM32F4_I2C_CR1_ACK BIT(10)
#define STM32F4_I2C_CR1_STOP BIT(9)
#define STM32F4_I2C_CR1_START BIT(8)
#define STM32F4_I2C_CR1_PE BIT(0)
/* STM32F4 I2C control 2 */
#define STM32F4_I2C_CR2_FREQ_MASK GENMASK(5, 0)
#define STM32F4_I2C_CR2_FREQ(n) ((n) & STM32F4_I2C_CR2_FREQ_MASK)
#define STM32F4_I2C_CR2_ITBUFEN BIT(10)
#define STM32F4_I2C_CR2_ITEVTEN BIT(9)
#define STM32F4_I2C_CR2_ITERREN BIT(8)
#define STM32F4_I2C_CR2_IRQ_MASK (STM32F4_I2C_CR2_ITBUFEN | \
STM32F4_I2C_CR2_ITEVTEN | \
STM32F4_I2C_CR2_ITERREN)
/* STM32F4 I2C Status 1 */
#define STM32F4_I2C_SR1_AF BIT(10)
#define STM32F4_I2C_SR1_ARLO BIT(9)
#define STM32F4_I2C_SR1_BERR BIT(8)
#define STM32F4_I2C_SR1_TXE BIT(7)
#define STM32F4_I2C_SR1_RXNE BIT(6)
#define STM32F4_I2C_SR1_BTF BIT(2)
#define STM32F4_I2C_SR1_ADDR BIT(1)
#define STM32F4_I2C_SR1_SB BIT(0)
#define STM32F4_I2C_SR1_ITEVTEN_MASK (STM32F4_I2C_SR1_BTF | \
STM32F4_I2C_SR1_ADDR | \
STM32F4_I2C_SR1_SB)
#define STM32F4_I2C_SR1_ITBUFEN_MASK (STM32F4_I2C_SR1_TXE | \
STM32F4_I2C_SR1_RXNE)
#define STM32F4_I2C_SR1_ITERREN_MASK (STM32F4_I2C_SR1_AF | \
STM32F4_I2C_SR1_ARLO | \
STM32F4_I2C_SR1_BERR)
/* STM32F4 I2C Status 2 */
#define STM32F4_I2C_SR2_BUSY BIT(1)
/* STM32F4 I2C Control Clock */
#define STM32F4_I2C_CCR_CCR_MASK GENMASK(11, 0)
#define STM32F4_I2C_CCR_CCR(n) ((n) & STM32F4_I2C_CCR_CCR_MASK)
#define STM32F4_I2C_CCR_FS BIT(15)
#define STM32F4_I2C_CCR_DUTY BIT(14)
/* STM32F4 I2C Trise */
#define STM32F4_I2C_TRISE_VALUE_MASK GENMASK(5, 0)
#define STM32F4_I2C_TRISE_VALUE(n) ((n) & STM32F4_I2C_TRISE_VALUE_MASK)
#define STM32F4_I2C_MIN_STANDARD_FREQ 2U
#define STM32F4_I2C_MIN_FAST_FREQ 6U
#define STM32F4_I2C_MAX_FREQ 46U
#define HZ_TO_MHZ 1000000
enum stm32f4_i2c_speed {
STM32F4_I2C_SPEED_STANDARD, /* 100 kHz */
STM32F4_I2C_SPEED_FAST, /* 400 kHz */
STM32F4_I2C_SPEED_END,
};
/**
* struct stm32f4_i2c_msg - client specific data
* @addr: 8-bit slave addr, including r/w bit
* @count: number of bytes to be transferred
* @buf: data buffer
* @result: result of the transfer
* @stop: last I2C msg to be sent, i.e. STOP to be generated
*/
struct stm32f4_i2c_msg {
u8 addr;
u32 count;
u8 *buf;
int result;
bool stop;
};
/**
* struct stm32f4_i2c_dev - private data of the controller
* @adap: I2C adapter for this controller
* @dev: device for this controller
* @base: virtual memory area
* @complete: completion of I2C message
* @clk: hw i2c clock
* @speed: I2C clock frequency of the controller. Standard or Fast are supported
* @parent_rate: I2C clock parent rate in MHz
* @msg: I2C transfer information
*/
struct stm32f4_i2c_dev {
struct i2c_adapter adap;
struct device *dev;
void __iomem *base;
struct completion complete;
struct clk *clk;
int speed;
int parent_rate;
struct stm32f4_i2c_msg msg;
};
static inline void stm32f4_i2c_set_bits(void __iomem *reg, u32 mask)
{
writel_relaxed(readl_relaxed(reg) | mask, reg);
}
static inline void stm32f4_i2c_clr_bits(void __iomem *reg, u32 mask)
{
writel_relaxed(readl_relaxed(reg) & ~mask, reg);
}
static void stm32f4_i2c_disable_irq(struct stm32f4_i2c_dev *i2c_dev)
{
void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_IRQ_MASK);
}
static int stm32f4_i2c_set_periph_clk_freq(struct stm32f4_i2c_dev *i2c_dev)
{
u32 freq;
u32 cr2 = 0;
i2c_dev->parent_rate = clk_get_rate(i2c_dev->clk);
freq = DIV_ROUND_UP(i2c_dev->parent_rate, HZ_TO_MHZ);
if (i2c_dev->speed == STM32F4_I2C_SPEED_STANDARD) {
/*
* To reach 100 kHz, the parent clk frequency should be between
* a minimum value of 2 MHz and a maximum value of 46 MHz due
* to hardware limitation
*/
if (freq < STM32F4_I2C_MIN_STANDARD_FREQ ||
freq > STM32F4_I2C_MAX_FREQ) {
dev_err(i2c_dev->dev,
"bad parent clk freq for standard mode\n");
return -EINVAL;
}
} else {
/*
* To be as close as possible to 400 kHz, the parent clk
* frequency should be between a minimum value of 6 MHz and a
* maximum value of 46 MHz due to hardware limitation
*/
if (freq < STM32F4_I2C_MIN_FAST_FREQ ||
freq > STM32F4_I2C_MAX_FREQ) {
dev_err(i2c_dev->dev,
"bad parent clk freq for fast mode\n");
return -EINVAL;
}
}
cr2 |= STM32F4_I2C_CR2_FREQ(freq);
writel_relaxed(cr2, i2c_dev->base + STM32F4_I2C_CR2);
return 0;
}
static void stm32f4_i2c_set_rise_time(struct stm32f4_i2c_dev *i2c_dev)
{
u32 freq = DIV_ROUND_UP(i2c_dev->parent_rate, HZ_TO_MHZ);
u32 trise;
/*
* These bits must be programmed with the maximum SCL rise time given in
* the I2C bus specification, incremented by 1.
*
* In standard mode, the maximum allowed SCL rise time is 1000 ns.
* If, in the I2C_CR2 register, the value of FREQ[5:0] bits is equal to
* 0x08 so period = 125 ns therefore the TRISE[5:0] bits must be
* programmed with 0x9. (1000 ns / 125 ns + 1)
* So, for I2C standard mode TRISE = FREQ[5:0] + 1
*
* In fast mode, the maximum allowed SCL rise time is 300 ns.
* If, in the I2C_CR2 register, the value of FREQ[5:0] bits is equal to
* 0x08 so period = 125 ns therefore the TRISE[5:0] bits must be
* programmed with 0x3. (300 ns / 125 ns + 1)
* So, for I2C fast mode TRISE = FREQ[5:0] * 300 / 1000 + 1
*
* Function stm32f4_i2c_set_periph_clk_freq made sure that parent rate
* is not higher than 46 MHz . As a result trise is at most 4 bits wide
* and so fits into the TRISE bits [5:0].
*/
if (i2c_dev->speed == STM32F4_I2C_SPEED_STANDARD)
trise = freq + 1;
else
trise = freq * 3 / 10 + 1;
writel_relaxed(STM32F4_I2C_TRISE_VALUE(trise),
i2c_dev->base + STM32F4_I2C_TRISE);
}
static void stm32f4_i2c_set_speed_mode(struct stm32f4_i2c_dev *i2c_dev)
{
u32 val;
u32 ccr = 0;
if (i2c_dev->speed == STM32F4_I2C_SPEED_STANDARD) {
/*
* In standard mode:
* t_scl_high = t_scl_low = CCR * I2C parent clk period
* So to reach 100 kHz, we have:
* CCR = I2C parent rate / 100 kHz >> 1
*
* For example with parent rate = 2 MHz:
* CCR = 2000000 / (100000 << 1) = 10
* t_scl_high = t_scl_low = 10 * (1 / 2000000) = 5000 ns
* t_scl_high + t_scl_low = 10000 ns so 100 kHz is reached
*
* Function stm32f4_i2c_set_periph_clk_freq made sure that
* parent rate is not higher than 46 MHz . As a result val
* is at most 8 bits wide and so fits into the CCR bits [11:0].
*/
val = i2c_dev->parent_rate / (100000 << 1);
} else {
/*
* In fast mode, we compute CCR with duty = 0 as with low
* frequencies we are not able to reach 400 kHz.
* In that case:
* t_scl_high = CCR * I2C parent clk period
* t_scl_low = 2 * CCR * I2C parent clk period
* So, CCR = I2C parent rate / (400 kHz * 3)
*
* For example with parent rate = 6 MHz:
* CCR = 6000000 / (400000 * 3) = 5
* t_scl_high = 5 * (1 / 6000000) = 833 ns > 600 ns
* t_scl_low = 2 * 5 * (1 / 6000000) = 1667 ns > 1300 ns
* t_scl_high + t_scl_low = 2500 ns so 400 kHz is reached
*
* Function stm32f4_i2c_set_periph_clk_freq made sure that
* parent rate is not higher than 46 MHz . As a result val
* is at most 6 bits wide and so fits into the CCR bits [11:0].
*/
val = DIV_ROUND_UP(i2c_dev->parent_rate, 400000 * 3);
/* Select Fast mode */
ccr |= STM32F4_I2C_CCR_FS;
}
ccr |= STM32F4_I2C_CCR_CCR(val);
writel_relaxed(ccr, i2c_dev->base + STM32F4_I2C_CCR);
}
/**
* stm32f4_i2c_hw_config() - Prepare I2C block
* @i2c_dev: Controller's private data
*/
static int stm32f4_i2c_hw_config(struct stm32f4_i2c_dev *i2c_dev)
{
int ret;
ret = stm32f4_i2c_set_periph_clk_freq(i2c_dev);
if (ret)
return ret;
stm32f4_i2c_set_rise_time(i2c_dev);
stm32f4_i2c_set_speed_mode(i2c_dev);
/* Enable I2C */
writel_relaxed(STM32F4_I2C_CR1_PE, i2c_dev->base + STM32F4_I2C_CR1);
return 0;
}
static int stm32f4_i2c_wait_free_bus(struct stm32f4_i2c_dev *i2c_dev)
{
u32 status;
int ret;
ret = readl_relaxed_poll_timeout(i2c_dev->base + STM32F4_I2C_SR2,
status,
!(status & STM32F4_I2C_SR2_BUSY),
10, 1000);
if (ret) {
dev_dbg(i2c_dev->dev, "bus not free\n");
ret = -EBUSY;
}
return ret;
}
/**
* stm32f4_i2c_write_ byte() - Write a byte in the data register
* @i2c_dev: Controller's private data
* @byte: Data to write in the register
*/
static void stm32f4_i2c_write_byte(struct stm32f4_i2c_dev *i2c_dev, u8 byte)
{
writel_relaxed(byte, i2c_dev->base + STM32F4_I2C_DR);
}
/**
* stm32f4_i2c_write_msg() - Fill the data register in write mode
* @i2c_dev: Controller's private data
*
* This function fills the data register with I2C transfer buffer
*/
static void stm32f4_i2c_write_msg(struct stm32f4_i2c_dev *i2c_dev)
{
struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
stm32f4_i2c_write_byte(i2c_dev, *msg->buf++);
msg->count--;
}
static void stm32f4_i2c_read_msg(struct stm32f4_i2c_dev *i2c_dev)
{
struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
u32 rbuf;
rbuf = readl_relaxed(i2c_dev->base + STM32F4_I2C_DR);
*msg->buf++ = rbuf;
msg->count--;
}
static void stm32f4_i2c_terminate_xfer(struct stm32f4_i2c_dev *i2c_dev)
{
struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
stm32f4_i2c_disable_irq(i2c_dev);
reg = i2c_dev->base + STM32F4_I2C_CR1;
if (msg->stop)
stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
else
stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
complete(&i2c_dev->complete);
}
/**
* stm32f4_i2c_handle_write() - Handle FIFO empty interrupt in case of write
* @i2c_dev: Controller's private data
*/
static void stm32f4_i2c_handle_write(struct stm32f4_i2c_dev *i2c_dev)
{
struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
if (msg->count) {
stm32f4_i2c_write_msg(i2c_dev);
if (!msg->count) {
/*
* Disable buffer interrupts for RX not empty and TX
* empty events
*/
stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_ITBUFEN);
}
} else {
stm32f4_i2c_terminate_xfer(i2c_dev);
}
}
/**
* stm32f4_i2c_handle_read() - Handle FIFO empty interrupt in case of read
* @i2c_dev: Controller's private data
*
* This function is called when a new data is received in data register
*/
static void stm32f4_i2c_handle_read(struct stm32f4_i2c_dev *i2c_dev)
{
struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR2;
switch (msg->count) {
case 1:
stm32f4_i2c_disable_irq(i2c_dev);
stm32f4_i2c_read_msg(i2c_dev);
complete(&i2c_dev->complete);
break;
/*
* For 2-byte reception, 3-byte reception and for Data N-2, N-1 and N
* for N-byte reception with N > 3, we do not have to read the data
* register when RX not empty event occurs as we have to wait for byte
* transferred finished event before reading data.
* So, here we just disable buffer interrupt in order to avoid another
* system preemption due to RX not empty event.
*/
case 2:
case 3:
stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR2_ITBUFEN);
break;
/*
* For N byte reception with N > 3 we directly read data register
* until N-2 data.
*/
default:
stm32f4_i2c_read_msg(i2c_dev);
}
}
/**
* stm32f4_i2c_handle_rx_done() - Handle byte transfer finished interrupt
* in case of read
* @i2c_dev: Controller's private data
*
* This function is called when a new data is received in the shift register
* but data register has not been read yet.
*/
static void stm32f4_i2c_handle_rx_done(struct stm32f4_i2c_dev *i2c_dev)
{
struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
void __iomem *reg;
u32 mask;
int i;
switch (msg->count) {
case 2:
/*
* In order to correctly send the Stop or Repeated Start
* condition on the I2C bus, the STOP/START bit has to be set
* before reading the last two bytes (data N-1 and N).
* After that, we could read the last two bytes, disable
* remaining interrupts and notify the end of xfer to the
* client
*/
reg = i2c_dev->base + STM32F4_I2C_CR1;
if (msg->stop)
stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
else
stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
for (i = 2; i > 0; i--)
stm32f4_i2c_read_msg(i2c_dev);
reg = i2c_dev->base + STM32F4_I2C_CR2;
mask = STM32F4_I2C_CR2_ITEVTEN | STM32F4_I2C_CR2_ITERREN;
stm32f4_i2c_clr_bits(reg, mask);
complete(&i2c_dev->complete);
break;
case 3:
/*
* In order to correctly generate the NACK pulse after the last
* received data byte, we have to enable NACK before reading N-2
* data
*/
reg = i2c_dev->base + STM32F4_I2C_CR1;
stm32f4_i2c_clr_bits(reg, STM32F4_I2C_CR1_ACK);
stm32f4_i2c_read_msg(i2c_dev);
break;
default:
stm32f4_i2c_read_msg(i2c_dev);
}
}
/**
* stm32f4_i2c_handle_rx_addr() - Handle address matched interrupt in case of
* master receiver
* @i2c_dev: Controller's private data
*/
static void stm32f4_i2c_handle_rx_addr(struct stm32f4_i2c_dev *i2c_dev)
{
struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
u32 cr1;
switch (msg->count) {
case 0:
stm32f4_i2c_terminate_xfer(i2c_dev);
/* Clear ADDR flag */
readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
break;
case 1:
/*
* Single byte reception:
* Enable NACK and reset POS (Acknowledge position).
* Then, clear ADDR flag and set STOP or RepSTART.
* In that way, the NACK and STOP or RepStart pulses will be
* sent as soon as the byte will be received in shift register
*/
cr1 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR1);
cr1 &= ~(STM32F4_I2C_CR1_ACK | STM32F4_I2C_CR1_POS);
writel_relaxed(cr1, i2c_dev->base + STM32F4_I2C_CR1);
readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
if (msg->stop)
cr1 |= STM32F4_I2C_CR1_STOP;
else
cr1 |= STM32F4_I2C_CR1_START;
writel_relaxed(cr1, i2c_dev->base + STM32F4_I2C_CR1);
break;
case 2:
/*
* 2-byte reception:
* Enable NACK, set POS (NACK position) and clear ADDR flag.
* In that way, NACK will be sent for the next byte which will
* be received in the shift register instead of the current
* one.
*/
cr1 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR1);
cr1 &= ~STM32F4_I2C_CR1_ACK;
cr1 |= STM32F4_I2C_CR1_POS;
writel_relaxed(cr1, i2c_dev->base + STM32F4_I2C_CR1);
readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
break;
default:
/*
* N-byte reception:
* Enable ACK, reset POS (ACK postion) and clear ADDR flag.
* In that way, ACK will be sent as soon as the current byte
* will be received in the shift register
*/
cr1 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR1);
cr1 |= STM32F4_I2C_CR1_ACK;
cr1 &= ~STM32F4_I2C_CR1_POS;
writel_relaxed(cr1, i2c_dev->base + STM32F4_I2C_CR1);
readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
break;
}
}
/**
* stm32f4_i2c_isr_event() - Interrupt routine for I2C bus event
* @irq: interrupt number
* @data: Controller's private data
*/
static irqreturn_t stm32f4_i2c_isr_event(int irq, void *data)
{
struct stm32f4_i2c_dev *i2c_dev = data;
struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
u32 possible_status = STM32F4_I2C_SR1_ITEVTEN_MASK;
u32 status, ien, event, cr2;
cr2 = readl_relaxed(i2c_dev->base + STM32F4_I2C_CR2);
ien = cr2 & STM32F4_I2C_CR2_IRQ_MASK;
/* Update possible_status if buffer interrupt is enabled */
if (ien & STM32F4_I2C_CR2_ITBUFEN)
possible_status |= STM32F4_I2C_SR1_ITBUFEN_MASK;
status = readl_relaxed(i2c_dev->base + STM32F4_I2C_SR1);
event = status & possible_status;
if (!event) {
dev_dbg(i2c_dev->dev,
"spurious evt irq (status=0x%08x, ien=0x%08x)\n",
status, ien);
return IRQ_NONE;
}
/* Start condition generated */
if (event & STM32F4_I2C_SR1_SB)
stm32f4_i2c_write_byte(i2c_dev, msg->addr);
/* I2C Address sent */
if (event & STM32F4_I2C_SR1_ADDR) {
if (msg->addr & I2C_M_RD)
stm32f4_i2c_handle_rx_addr(i2c_dev);
else
readl_relaxed(i2c_dev->base + STM32F4_I2C_SR2);
/*
* Enable buffer interrupts for RX not empty and TX empty
* events
*/
cr2 |= STM32F4_I2C_CR2_ITBUFEN;
writel_relaxed(cr2, i2c_dev->base + STM32F4_I2C_CR2);
}
/* TX empty */
if ((event & STM32F4_I2C_SR1_TXE) && !(msg->addr & I2C_M_RD))
stm32f4_i2c_handle_write(i2c_dev);
/* RX not empty */
if ((event & STM32F4_I2C_SR1_RXNE) && (msg->addr & I2C_M_RD))
stm32f4_i2c_handle_read(i2c_dev);
/*
* The BTF (Byte Transfer finished) event occurs when:
* - in reception : a new byte is received in the shift register
* but the previous byte has not been read yet from data register
* - in transmission: a new byte should be sent but the data register
* has not been written yet
*/
if (event & STM32F4_I2C_SR1_BTF) {
if (msg->addr & I2C_M_RD)
stm32f4_i2c_handle_rx_done(i2c_dev);
else
stm32f4_i2c_handle_write(i2c_dev);
}
return IRQ_HANDLED;
}
/**
* stm32f4_i2c_isr_error() - Interrupt routine for I2C bus error
* @irq: interrupt number
* @data: Controller's private data
*/
static irqreturn_t stm32f4_i2c_isr_error(int irq, void *data)
{
struct stm32f4_i2c_dev *i2c_dev = data;
struct stm32f4_i2c_msg *msg = &i2c_dev->msg;
void __iomem *reg;
u32 status;
status = readl_relaxed(i2c_dev->base + STM32F4_I2C_SR1);
/* Arbitration lost */
if (status & STM32F4_I2C_SR1_ARLO) {
status &= ~STM32F4_I2C_SR1_ARLO;
writel_relaxed(status, i2c_dev->base + STM32F4_I2C_SR1);
msg->result = -EAGAIN;
}
/*
* Acknowledge failure:
* In master transmitter mode a Stop must be generated by software
*/
if (status & STM32F4_I2C_SR1_AF) {
if (!(msg->addr & I2C_M_RD)) {
reg = i2c_dev->base + STM32F4_I2C_CR1;
stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_STOP);
}
status &= ~STM32F4_I2C_SR1_AF;
writel_relaxed(status, i2c_dev->base + STM32F4_I2C_SR1);
msg->result = -EIO;
}
/* Bus error */
if (status & STM32F4_I2C_SR1_BERR) {
status &= ~STM32F4_I2C_SR1_BERR;
writel_relaxed(status, i2c_dev->base + STM32F4_I2C_SR1);
msg->result = -EIO;
}
stm32f4_i2c_disable_irq(i2c_dev);
complete(&i2c_dev->complete);
return IRQ_HANDLED;
}
/**
* stm32f4_i2c_xfer_msg() - Transfer a single I2C message
* @i2c_dev: Controller's private data
* @msg: I2C message to transfer
* @is_first: first message of the sequence
* @is_last: last message of the sequence
*/
static int stm32f4_i2c_xfer_msg(struct stm32f4_i2c_dev *i2c_dev,
struct i2c_msg *msg, bool is_first,
bool is_last)
{
struct stm32f4_i2c_msg *f4_msg = &i2c_dev->msg;
void __iomem *reg = i2c_dev->base + STM32F4_I2C_CR1;
unsigned long timeout;
u32 mask;
int ret;
f4_msg->addr = i2c_8bit_addr_from_msg(msg);
f4_msg->buf = msg->buf;
f4_msg->count = msg->len;
f4_msg->result = 0;
f4_msg->stop = is_last;
reinit_completion(&i2c_dev->complete);
/* Enable events and errors interrupts */
mask = STM32F4_I2C_CR2_ITEVTEN | STM32F4_I2C_CR2_ITERREN;
stm32f4_i2c_set_bits(i2c_dev->base + STM32F4_I2C_CR2, mask);
if (is_first) {
ret = stm32f4_i2c_wait_free_bus(i2c_dev);
if (ret)
return ret;
/* START generation */
stm32f4_i2c_set_bits(reg, STM32F4_I2C_CR1_START);
}
timeout = wait_for_completion_timeout(&i2c_dev->complete,
i2c_dev->adap.timeout);
ret = f4_msg->result;
if (!timeout)
ret = -ETIMEDOUT;
return ret;
}
/**
* stm32f4_i2c_xfer() - Transfer combined I2C message
* @i2c_adap: Adapter pointer to the controller
* @msgs: Pointer to data to be written.
* @num: Number of messages to be executed
*/
static int stm32f4_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[],
int num)
{
struct stm32f4_i2c_dev *i2c_dev = i2c_get_adapdata(i2c_adap);
int ret, i;
ret = clk_enable(i2c_dev->clk);
if (ret) {
dev_err(i2c_dev->dev, "Failed to enable clock\n");
return ret;
}
for (i = 0; i < num && !ret; i++)
ret = stm32f4_i2c_xfer_msg(i2c_dev, &msgs[i], i == 0,
i == num - 1);
clk_disable(i2c_dev->clk);
return (ret < 0) ? ret : num;
}
static u32 stm32f4_i2c_func(struct i2c_adapter *adap)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
}
static struct i2c_algorithm stm32f4_i2c_algo = {
.master_xfer = stm32f4_i2c_xfer,
.functionality = stm32f4_i2c_func,
};
static int stm32f4_i2c_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct stm32f4_i2c_dev *i2c_dev;
struct resource *res;
u32 irq_event, irq_error, clk_rate;
struct i2c_adapter *adap;
struct reset_control *rst;
int ret;
i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL);
if (!i2c_dev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
i2c_dev->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(i2c_dev->base))
return PTR_ERR(i2c_dev->base);
irq_event = irq_of_parse_and_map(np, 0);
if (!irq_event) {
dev_err(&pdev->dev, "IRQ event missing or invalid\n");
return -EINVAL;
}
irq_error = irq_of_parse_and_map(np, 1);
if (!irq_error) {
dev_err(&pdev->dev, "IRQ error missing or invalid\n");
return -EINVAL;
}
i2c_dev->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(i2c_dev->clk)) {
dev_err(&pdev->dev, "Error: Missing controller clock\n");
return PTR_ERR(i2c_dev->clk);
}
ret = clk_prepare_enable(i2c_dev->clk);
if (ret) {
dev_err(i2c_dev->dev, "Failed to prepare_enable clock\n");
return ret;
}
rst = devm_reset_control_get(&pdev->dev, NULL);
if (IS_ERR(rst)) {
dev_err(&pdev->dev, "Error: Missing controller reset\n");
ret = PTR_ERR(rst);
goto clk_free;
}
reset_control_assert(rst);
udelay(2);
reset_control_deassert(rst);
i2c_dev->speed = STM32F4_I2C_SPEED_STANDARD;
ret = of_property_read_u32(np, "clock-frequency", &clk_rate);
if (!ret && clk_rate >= 400000)
i2c_dev->speed = STM32F4_I2C_SPEED_FAST;
i2c_dev->dev = &pdev->dev;
ret = devm_request_irq(&pdev->dev, irq_event, stm32f4_i2c_isr_event, 0,
pdev->name, i2c_dev);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq event %i\n",
irq_event);
goto clk_free;
}
ret = devm_request_irq(&pdev->dev, irq_error, stm32f4_i2c_isr_error, 0,
pdev->name, i2c_dev);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq error %i\n",
irq_error);
goto clk_free;
}
ret = stm32f4_i2c_hw_config(i2c_dev);
if (ret)
goto clk_free;
adap = &i2c_dev->adap;
i2c_set_adapdata(adap, i2c_dev);
snprintf(adap->name, sizeof(adap->name), "STM32 I2C(%pa)", &res->start);
adap->owner = THIS_MODULE;
adap->timeout = 2 * HZ;
adap->retries = 0;
adap->algo = &stm32f4_i2c_algo;
adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node;
init_completion(&i2c_dev->complete);
ret = i2c_add_adapter(adap);
if (ret)
goto clk_free;
platform_set_drvdata(pdev, i2c_dev);
clk_disable(i2c_dev->clk);
dev_info(i2c_dev->dev, "STM32F4 I2C driver registered\n");
return 0;
clk_free:
clk_disable_unprepare(i2c_dev->clk);
return ret;
}
static int stm32f4_i2c_remove(struct platform_device *pdev)
{
struct stm32f4_i2c_dev *i2c_dev = platform_get_drvdata(pdev);
i2c_del_adapter(&i2c_dev->adap);
clk_unprepare(i2c_dev->clk);
return 0;
}
static const struct of_device_id stm32f4_i2c_match[] = {
{ .compatible = "st,stm32f4-i2c", },
{},
};
MODULE_DEVICE_TABLE(of, stm32f4_i2c_match);
static struct platform_driver stm32f4_i2c_driver = {
.driver = {
.name = "stm32f4-i2c",
.of_match_table = stm32f4_i2c_match,
},
.probe = stm32f4_i2c_probe,
.remove = stm32f4_i2c_remove,
};
module_platform_driver(stm32f4_i2c_driver);
MODULE_AUTHOR("M'boumba Cedric Madianga <cedric.madianga@gmail.com>");
MODULE_DESCRIPTION("STMicroelectronics STM32F4 I2C driver");
MODULE_LICENSE("GPL v2");

Просмотреть файл

@ -0,0 +1,346 @@
/*
* 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,
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)
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)
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)
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)
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 @@
#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[] = {
{ .compatible = "nxp,pca9541" }, { .compatible = "nxp,pca9541" },
{} {}
}; };
MODULE_DEVICE_TABLE(of, pca9541_of_match);
#endif #endif
/* /*

Просмотреть файл

@ -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 {
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 {
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[] = {
.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[] = {
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);
#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[] = {
{ .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)
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,
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,
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,
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 @@ virt_reg_failed:
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 @@
#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)
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)
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 {
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)