mirror of
https://github.com/torvalds/linux.git
synced 2024-11-30 16:11:38 +00:00
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:
commit
7067739df2
@ -19,7 +19,14 @@ Optional Properties:
|
||||
- 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
|
||||
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:
|
||||
|
||||
@ -29,6 +36,11 @@ Example:
|
||||
#size-cells = <0>;
|
||||
reg = <0x74>;
|
||||
|
||||
interrupt-parent = <&ipic>;
|
||||
interrupts = <17 IRQ_TYPE_LEVEL_LOW>;
|
||||
interrupt-controller;
|
||||
#interrupt-cells = <2>;
|
||||
|
||||
i2c@2 {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
@ -10,6 +10,7 @@ Required properties:
|
||||
- "renesas,iic-r8a7793" (R-Car M2-N)
|
||||
- "renesas,iic-r8a7794" (R-Car E2)
|
||||
- "renesas,iic-r8a7795" (R-Car H3)
|
||||
- "renesas,iic-r8a7796" (R-Car M3-W)
|
||||
- "renesas,iic-sh73a0" (SH-Mobile AG5)
|
||||
- "renesas,rcar-gen2-iic" (generic R-Car Gen2 compatible device)
|
||||
- "renesas,rcar-gen3-iic" (generic R-Car Gen3 compatible device)
|
||||
|
33
Documentation/devicetree/bindings/i2c/i2c-stm32.txt
Normal file
33
Documentation/devicetree/bindings/i2c/i2c-stm32.txt
Normal file
@ -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 Broxton (SOC)
|
||||
* Intel Lewisburg (PCH)
|
||||
* Intel Gemini Lake (SOC)
|
||||
Datasheets: Publicly available at the Intel website
|
||||
|
||||
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>
|
||||
|
||||
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.
|
||||
|
||||
E.G.:
|
||||
@ -26,16 +26,16 @@ according to the settings of the GPIO pins 1..N.
|
||||
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
|
||||
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
|
||||
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
|
||||
controlled through 3 GPIO pins:
|
||||
|
||||
#include <linux/i2c-gpio-mux.h>
|
||||
#include <linux/i2c-mux-gpio.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static const unsigned myboard_gpiomux_gpios[] = {
|
||||
@ -46,7 +46,7 @@ static const unsigned myboard_gpiomux_values[] = {
|
||||
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,
|
||||
.base_nr = 2, /* optional */
|
||||
.values = myboard_gpiomux_values,
|
||||
@ -57,7 +57,7 @@ static struct gpio_i2cmux_platform_data myboard_i2cmux_data = {
|
||||
};
|
||||
|
||||
static struct platform_device myboard_i2cmux = {
|
||||
.name = "i2c-gpio-mux",
|
||||
.name = "i2c-mux-gpio",
|
||||
.id = 0,
|
||||
.dev = {
|
||||
.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,
|
||||
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
|
||||
available.
|
||||
|
||||
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
|
||||
instance has a different ID.
|
||||
|
||||
|
@ -128,6 +128,7 @@ config I2C_I801
|
||||
DNV (SOC)
|
||||
Broxton (SOC)
|
||||
Lewisburg (PCH)
|
||||
Gemini Lake (SOC)
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called i2c-i801.
|
||||
@ -886,6 +887,16 @@ config I2C_ST
|
||||
This driver can also be built as module. If so, the module
|
||||
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
|
||||
tristate "ST Microelectronics DDC I2C interface"
|
||||
depends on MACH_U300
|
||||
@ -919,6 +930,17 @@ config I2C_TEGRA
|
||||
If you say yes to this option, support will be included for the
|
||||
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
|
||||
tristate "UniPhier FIFO-less I2C controller"
|
||||
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_SIRF) += i2c-sirf.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_SUN6I_P2WI) += i2c-sun6i-p2wi.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_F) += i2c-uniphier-f.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;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm at91_twi_algorithm = {
|
||||
static const struct i2c_algorithm at91_twi_algorithm = {
|
||||
.master_xfer = at91_twi_xfer,
|
||||
.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)
|
||||
{
|
||||
struct at91_twi_dev *twi_dev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
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_request_autosuspend(dev);
|
||||
|
||||
at91_init_twi_bus(twi_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,9 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data)
|
||||
}
|
||||
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm bfin_twi_algorithm = {
|
||||
static const struct i2c_algorithm bfin_twi_algorithm = {
|
||||
.master_xfer = bfin_twi_master_xfer,
|
||||
.smbus_xfer = bfin_twi_smbus_xfer,
|
||||
.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;
|
||||
if (resp->i2c_status & EC_I2C_STATUS_TIMEOUT)
|
||||
return -ETIMEDOUT;
|
||||
else if (resp->i2c_status & EC_I2C_STATUS_NAK)
|
||||
return -ENXIO;
|
||||
else if (resp->i2c_status & EC_I2C_STATUS_ERROR)
|
||||
return -EREMOTEIO;
|
||||
return -EIO;
|
||||
|
||||
/* Other side could send us back fewer messages, but not more */
|
||||
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);
|
||||
if (result < 0) {
|
||||
dev_err(dev, "Error parsing EC i2c message %d\n", result);
|
||||
if (result < 0)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* Indicate success by saying how many messages were sent */
|
||||
result = num;
|
||||
|
@ -820,7 +820,7 @@ static u32 i2c_dw_func(struct i2c_adapter *adap)
|
||||
return dev->functionality;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm i2c_dw_algo = {
|
||||
static const struct i2c_algorithm i2c_dw_algo = {
|
||||
.master_xfer = i2c_dw_xfer,
|
||||
.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;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm pch_algorithm = {
|
||||
static const struct i2c_algorithm pch_algorithm = {
|
||||
.master_xfer = pch_i2c_xfer,
|
||||
.functionality = pch_i2c_func
|
||||
};
|
||||
|
@ -347,7 +347,7 @@ static int em_i2c_unreg_slave(struct i2c_client *slave)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm em_i2c_algo = {
|
||||
static const struct i2c_algorithm em_i2c_algo = {
|
||||
.master_xfer = em_i2c_xfer,
|
||||
.functionality = em_i2c_func,
|
||||
.reg_slave = em_i2c_reg_slave,
|
||||
|
@ -130,12 +130,32 @@
|
||||
/* I2C_TRANS_STATUS register bits */
|
||||
#define HSI2C_MASTER_BUSY (1u << 17)
|
||||
#define HSI2C_SLAVE_BUSY (1u << 16)
|
||||
|
||||
/* I2C_TRANS_STATUS register bits for Exynos5 variant */
|
||||
#define HSI2C_TIMEOUT_AUTO (1u << 4)
|
||||
#define HSI2C_NO_DEV (1u << 3)
|
||||
#define HSI2C_NO_DEV_ACK (1u << 2)
|
||||
#define HSI2C_TRANS_ABORT (1u << 1)
|
||||
#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 */
|
||||
#define HSI2C_SLV_ADDR_SLV(x) ((x & 0x3ff) << 0)
|
||||
#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);
|
||||
writel(int_status, i2c->regs + HSI2C_INT_STATUS);
|
||||
trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS);
|
||||
|
||||
/* handle interrupt related to the transfer status */
|
||||
if (i2c->variant->hw == HSI2C_EXYNOS7) {
|
||||
@ -460,8 +481,12 @@ static irqreturn_t exynos5_i2c_irq(int irqno, void *dev_id)
|
||||
i2c->state = -ETIMEDOUT;
|
||||
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) {
|
||||
trans_status = readl(i2c->regs + HSI2C_TRANS_STATUS);
|
||||
if (trans_status & HSI2C_NO_DEV_ACK) {
|
||||
dev_dbg(i2c->dev, "No ACK from device\n");
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
while (len > 0) {
|
||||
byte = i2c->msg->buf[i2c->msg_ptr++];
|
||||
|
@ -65,6 +65,7 @@
|
||||
* Lewisburg (PCH) 0xa1a3 32 hard yes yes yes
|
||||
* Lewisburg Supersku (PCH) 0xa223 32 hard yes yes yes
|
||||
* Kaby Lake PCH-H (PCH) 0xa2a3 32 hard yes yes yes
|
||||
* Gemini Lake (SOC) 0x31d4 32 hard yes yes yes
|
||||
*
|
||||
* Features supported by this driver:
|
||||
* Software PEC no
|
||||
@ -213,6 +214,7 @@
|
||||
#define PCI_DEVICE_ID_INTEL_BRASWELL_SMBUS 0x2292
|
||||
#define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330
|
||||
#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_BROXTON_SMBUS 0x5ad4
|
||||
#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_MS2) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_GEMINILAKE_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WILDCATPOINT_LP_SMBUS) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BAYTRAIL_SMBUS) },
|
||||
|
@ -538,7 +538,7 @@ static u32 lpi2c_imx_func(struct i2c_adapter *adapter)
|
||||
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,
|
||||
.functionality = lpi2c_imx_func,
|
||||
};
|
||||
|
@ -1037,7 +1037,7 @@ static u32 i2c_imx_func(struct i2c_adapter *adapter)
|
||||
| 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,
|
||||
.functionality = i2c_imx_func,
|
||||
};
|
||||
|
@ -977,11 +977,32 @@ mv64xxx_i2c_remove(struct platform_device *dev)
|
||||
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 = {
|
||||
.probe = mv64xxx_i2c_probe,
|
||||
.remove = mv64xxx_i2c_remove,
|
||||
.driver = {
|
||||
.name = MV64XXX_I2C_CTLR_NAME,
|
||||
.pm = mv64xxx_i2c_pm_ops,
|
||||
.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);
|
||||
}
|
||||
|
||||
static struct i2c_algorithm smbus_algorithm = {
|
||||
static const struct i2c_algorithm smbus_algorithm = {
|
||||
.smbus_xfer = nforce2_access,
|
||||
.functionality = nforce2_func,
|
||||
};
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include <linux/i2c-smbus.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
/* Controller command patterns */
|
||||
#define SW_TWSI_V BIT_ULL(63) /* Valid bit */
|
||||
@ -118,9 +117,6 @@ struct octeon_i2c {
|
||||
void (*hlc_int_disable)(struct octeon_i2c *);
|
||||
atomic_t int_enable_cnt;
|
||||
atomic_t hlc_int_enable_cnt;
|
||||
#if IS_ENABLED(CONFIG_I2C_THUNDERX)
|
||||
struct msix_entry i2c_msix;
|
||||
#endif
|
||||
struct i2c_smbus_alert_setup alert_data;
|
||||
struct i2c_client *ara;
|
||||
};
|
||||
|
@ -1504,7 +1504,7 @@ static int omap_i2c_runtime_resume(struct device *dev)
|
||||
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,
|
||||
omap_i2c_runtime_resume, NULL)
|
||||
};
|
||||
|
@ -80,6 +80,7 @@
|
||||
#define ICIER_TEIE 0x40
|
||||
#define ICIER_RIE 0x20
|
||||
#define ICIER_NAKIE 0x10
|
||||
#define ICIER_SPIE 0x08
|
||||
|
||||
#define ICSR2_NACKF 0x10
|
||||
|
||||
@ -216,11 +217,10 @@ static irqreturn_t riic_tend_isr(int irq, void *data)
|
||||
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(0, riic->base + RIIC_ICIER);
|
||||
complete(&riic->msg_done);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@ -240,13 +240,13 @@ static irqreturn_t riic_rdrf_isr(int irq, void *data)
|
||||
|
||||
if (riic->bytes_left == 1) {
|
||||
/* 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);
|
||||
}
|
||||
|
||||
riic_clear_set_bit(riic, 0, ICMR3_ACKBT, RIIC_ICMR3);
|
||||
|
||||
writeb(0, riic->base + RIIC_ICIER);
|
||||
complete(&riic->msg_done);
|
||||
} else {
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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 = 1, .isr = riic_rdrf_isr, .name = "riic-rdrf" },
|
||||
{ .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" },
|
||||
};
|
||||
|
||||
|
@ -117,7 +117,7 @@ static u32 osif_func(struct i2c_adapter *adapter)
|
||||
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,
|
||||
.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;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm sh_mobile_i2c_algorithm = {
|
||||
static const struct i2c_algorithm sh_mobile_i2c_algorithm = {
|
||||
.functionality = sh_mobile_i2c_func,
|
||||
.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;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm st_i2c_algo = {
|
||||
static const struct i2c_algorithm st_i2c_algo = {
|
||||
.master_xfer = st_i2c_xfer,
|
||||
.functionality = st_i2c_func,
|
||||
};
|
||||
|
897
drivers/i2c/busses/i2c-stm32f4.c
Normal file
897
drivers/i2c/busses/i2c-stm32f4.c
Normal file
@ -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");
|
346
drivers/i2c/busses/i2c-tegra-bpmp.c
Normal file
346
drivers/i2c/busses/i2c-tegra-bpmp.c
Normal file
@ -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_disable = thunder_i2c_hlc_int_disable;
|
||||
|
||||
ret = pci_enable_msix(pdev, &i2c->i2c_msix, 1);
|
||||
if (ret)
|
||||
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
|
||||
if (ret < 0)
|
||||
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);
|
||||
if (ret)
|
||||
goto error;
|
||||
|
@ -372,7 +372,7 @@ static u32 xgene_slimpro_i2c_func(struct i2c_adapter *adapter)
|
||||
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,
|
||||
.functionality = xgene_slimpro_i2c_func,
|
||||
};
|
||||
|
@ -334,7 +334,7 @@ static u32 xlp9xx_i2c_functionality(struct i2c_adapter *adapter)
|
||||
I2C_FUNC_10BIT_ADDR;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm xlp9xx_i2c_algo = {
|
||||
static const struct i2c_algorithm xlp9xx_i2c_algo = {
|
||||
.master_xfer = xlp9xx_i2c_xfer,
|
||||
.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;
|
||||
}
|
||||
|
||||
static struct i2c_algorithm xlr_i2c_algo = {
|
||||
static const struct i2c_algorithm xlr_i2c_algo = {
|
||||
.master_xfer = xlr_i2c_xfer,
|
||||
.functionality = xlr_func,
|
||||
};
|
||||
|
@ -3705,6 +3705,39 @@ int i2c_slave_unregister(struct i2c_client *client)
|
||||
return ret;
|
||||
}
|
||||
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", ®);
|
||||
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
|
||||
|
||||
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
|
||||
|
@ -40,7 +40,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/i2c/mlxcpld.h>
|
||||
|
||||
#define CPLD_MUX_MAX_NCHANS 8
|
||||
|
@ -90,6 +90,7 @@ static const struct of_device_id pca9541_of_match[] = {
|
||||
{ .compatible = "nxp,pca9541" },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pca9541_of_match);
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
@ -41,14 +41,20 @@
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/i2c-mux.h>
|
||||
#include <linux/i2c/pca954x.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_irq.h>
|
||||
#include <linux/pm.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
|
||||
#define PCA954X_MAX_NCHANS 8
|
||||
|
||||
#define PCA954X_IRQ_OFFSET 4
|
||||
|
||||
enum pca_type {
|
||||
pca_9540,
|
||||
pca_9542,
|
||||
@ -63,6 +69,7 @@ enum pca_type {
|
||||
struct chip_desc {
|
||||
u8 nchans;
|
||||
u8 enable; /* used for muxes only */
|
||||
u8 has_irq;
|
||||
enum muxtype {
|
||||
pca954x_ismux = 0,
|
||||
pca954x_isswi
|
||||
@ -75,6 +82,10 @@ struct pca954x {
|
||||
u8 last_chan; /* last register value */
|
||||
u8 deselect;
|
||||
struct i2c_client *client;
|
||||
|
||||
struct irq_domain *irq;
|
||||
unsigned int irq_mask;
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
/* Provide specs for the PCA954x types we know about */
|
||||
@ -84,17 +95,26 @@ static const struct chip_desc chips[] = {
|
||||
.enable = 0x4,
|
||||
.muxtype = pca954x_ismux,
|
||||
},
|
||||
[pca_9542] = {
|
||||
.nchans = 2,
|
||||
.enable = 0x4,
|
||||
.has_irq = 1,
|
||||
.muxtype = pca954x_ismux,
|
||||
},
|
||||
[pca_9543] = {
|
||||
.nchans = 2,
|
||||
.has_irq = 1,
|
||||
.muxtype = pca954x_isswi,
|
||||
},
|
||||
[pca_9544] = {
|
||||
.nchans = 4,
|
||||
.enable = 0x4,
|
||||
.has_irq = 1,
|
||||
.muxtype = pca954x_ismux,
|
||||
},
|
||||
[pca_9545] = {
|
||||
.nchans = 4,
|
||||
.has_irq = 1,
|
||||
.muxtype = pca954x_isswi,
|
||||
},
|
||||
[pca_9547] = {
|
||||
@ -110,7 +130,7 @@ static const struct chip_desc chips[] = {
|
||||
|
||||
static const struct i2c_device_id pca954x_id[] = {
|
||||
{ "pca9540", pca_9540 },
|
||||
{ "pca9542", pca_9540 },
|
||||
{ "pca9542", pca_9542 },
|
||||
{ "pca9543", pca_9543 },
|
||||
{ "pca9544", pca_9544 },
|
||||
{ "pca9545", pca_9545 },
|
||||
@ -124,7 +144,7 @@ MODULE_DEVICE_TABLE(i2c, pca954x_id);
|
||||
#ifdef CONFIG_ACPI
|
||||
static const struct acpi_device_id pca954x_acpi_ids[] = {
|
||||
{ .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 = "PCA9544", .driver_data = pca_9544 },
|
||||
{ .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] },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, pca954x_of_match);
|
||||
#endif
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
@ -281,6 +410,10 @@ static int pca954x_probe(struct i2c_client *client,
|
||||
idle_disconnect_dt = of_node &&
|
||||
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 */
|
||||
for (num = 0; num < data->chip->nchans; num++) {
|
||||
bool idle_disconnect_pd = false;
|
||||
@ -306,7 +439,7 @@ static int pca954x_probe(struct i2c_client *client,
|
||||
dev_err(&client->dev,
|
||||
"failed to register multiplexed adapter"
|
||||
" %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;
|
||||
|
||||
virt_reg_failed:
|
||||
fail_del_adapters:
|
||||
i2c_mux_del_adapters(muxc);
|
||||
return ret;
|
||||
}
|
||||
@ -325,6 +458,16 @@ virt_reg_failed:
|
||||
static int pca954x_remove(struct i2c_client *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);
|
||||
return 0;
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include <linux/log2.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/property.h>
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/i2c.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;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static void at24_get_ofdata(struct i2c_client *client,
|
||||
struct at24_platform_data *chip)
|
||||
static void at24_get_pdata(struct device *dev, struct at24_platform_data *chip)
|
||||
{
|
||||
const __be32 *val;
|
||||
struct device_node *node = client->dev.of_node;
|
||||
int err;
|
||||
u32 val;
|
||||
|
||||
if (node) {
|
||||
if (of_get_property(node, "read-only", NULL))
|
||||
chip->flags |= AT24_FLAG_READONLY;
|
||||
val = of_get_property(node, "pagesize", NULL);
|
||||
if (val)
|
||||
chip->page_size = be32_to_cpup(val);
|
||||
if (device_property_present(dev, "read-only"))
|
||||
chip->flags |= AT24_FLAG_READONLY;
|
||||
|
||||
err = device_property_read_u32(dev, "pagesize", &val);
|
||||
if (!err) {
|
||||
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)
|
||||
{
|
||||
@ -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));
|
||||
magic >>= AT24_SIZE_BYTELEN;
|
||||
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_ofdata(client, &chip);
|
||||
at24_get_pdata(&client->dev, &chip);
|
||||
|
||||
chip.setup = 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_unregister(struct i2c_client *client);
|
||||
extern bool i2c_detect_slave_mode(struct device *dev);
|
||||
|
||||
static inline int i2c_slave_event(struct i2c_client *client,
|
||||
enum i2c_slave_event event, u8 *val)
|
||||
|
Loading…
Reference in New Issue
Block a user