From 33eb46e1dca1cdeeb4b5a7e794f7b8c3eb98fba4 Mon Sep 17 00:00:00 2001 From: M'boumba Cedric Madianga Date: Thu, 19 Jan 2017 14:25:12 +0100 Subject: dt-bindings: Document the STM32 I2C bindings This patch adds documentation of device tree bindings for the STM32 I2C controller. Signed-off-by: M'boumba Cedric Madianga Acked-by: Rob Herring Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-stm32.txt | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-stm32.txt diff --git a/Documentation/devicetree/bindings/i2c/i2c-stm32.txt b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt new file mode 100644 index 000000000000..78eaf7b718ed --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-stm32.txt @@ -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"; + }; -- cgit v1.2.3-70-g09d2 From 62817fc8d282996b67dcfeae28e0beeb7fd028dd Mon Sep 17 00:00:00 2001 From: M'boumba Cedric Madianga Date: Thu, 19 Jan 2017 14:25:13 +0100 Subject: i2c: stm32f4: add driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for the STM32F4 I2C controller. Signed-off-by: M'boumba Cedric Madianga Acked-by: Uwe Kleine-König Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-stm32f4.c | 897 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 908 insertions(+) create mode 100644 drivers/i2c/busses/i2c-stm32f4.c diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 0cdc8443deab..271920847bca 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -886,6 +886,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 diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 1c1bac87a9db..a2c6ff558578 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -85,6 +85,7 @@ 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 diff --git a/drivers/i2c/busses/i2c-stm32f4.c b/drivers/i2c/busses/i2c-stm32f4.c new file mode 100644 index 000000000000..f9dd7e86b861 --- /dev/null +++ b/drivers/i2c/busses/i2c-stm32f4.c @@ -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 + * + * This driver is based on i2c-st.c + * + * License terms: GNU General Public License (GPL), version 2 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 "); +MODULE_DESCRIPTION("STMicroelectronics STM32F4 I2C driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-70-g09d2 From a4f64ae2b5434fe1f3e8dc157dc5260628b0f582 Mon Sep 17 00:00:00 2001 From: Grzegorz Jaszczyk Date: Thu, 22 Dec 2016 16:54:02 +0100 Subject: i2c: mv64xxx: add suspend/resume support This commit implements suspend/resume support in the mv64xxx I2C controller driver. There is no need to implement a ->suspend() hook, as calling mv64xxx_i2c_hw_init() at ->resume() time is enough. Signed-off-by: Grzegorz Jaszczyk Reviewed-by: Nadav Haklai Reviewed-by: Lior Amsalem Tested-by: Lior Amsalem [Thomas: switch to dev_pm_ops, fix build warning when !PM.] Signed-off-by: Thomas Petazzoni Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index b4dec0841bc2..a50bd6891e27 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -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, }, }; -- cgit v1.2.3-70-g09d2 From 50b918c5a6ffad1d9fae29c4fdcb52383b123665 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Sun, 15 Jan 2017 15:29:41 +0530 Subject: i2c: omap: constify dev_pm_ops structures Declare dev_pm_ops structures as const as they are only stored in the pm field of a device_driver structure. This field is of type const, so dev_pm_ops structures having similar properties can be declared const too. Signed-off-by: Bhumika Goyal Acked-by: Tony Lindgren Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index c7da0c42baee..1ebb5e947e0b 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -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) }; -- cgit v1.2.3-70-g09d2 From cefae80249f6bf3fdbc7c3a00bc43deb4c1bccf0 Mon Sep 17 00:00:00 2001 From: Luis Oliveira Date: Thu, 26 Jan 2017 17:45:32 +0000 Subject: i2c: core: helper function to detect slave mode This function has the purpose of mode detection by checking the device nodes for a reg matching with the I2C_OWN_SLAVE_ADDREESS flag. Currently only checks using OF functions (ACPI slave not supported yet). Signed-off-by: Luis Oliveira Suggested-by: Andy Shevchenko Reviewed-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 33 +++++++++++++++++++++++++++++++++ include/linux/i2c.h | 1 + 2 files changed, 34 insertions(+) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 583e95042a21..408de741fec5 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -3690,6 +3690,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 "); diff --git a/include/linux/i2c.h b/include/linux/i2c.h index 4b45ec46161f..f0ba4bac7452 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -282,6 +282,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) -- cgit v1.2.3-70-g09d2 From 22ae11245e17a74c1b0864b55b63c0ed21f10ceb Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Tue, 26 Jul 2016 15:34:01 -0700 Subject: i2c: i2c-cros-ec-tunnel: Reduce logging noise If an i2c access through i2c-cros-ec-tunnel returns an error, the following log message is seen on the console. cros-ec-i2c-tunnel ff200000.spi:ec@0:i2c-tunnel: Error parsing EC i2c message -121 This can happen a lot if, for example, the i2c-detect command is executed. Since it is perfectly normal for an i2c controller to report an error, drop the message. Also, report -ENXIO instead of -EREMOTEIO if the access error is due to NAK from the device, and return -EIO instead of -EREMOTEIO for other errors, as suggested in Documentation/i2c/fault-codes. Signed-off-by: Guenter Roeck Reviewed-by: Douglas Anderson Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-cros-ec-tunnel.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c index 9b36a7b3befd..eb76b76f4754 100644 --- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c +++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c @@ -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; -- cgit v1.2.3-70-g09d2 From 45345e9a85f94f2f7f563cd9b881a19e5d99c72c Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 26 Jan 2017 09:47:31 +0100 Subject: i2c: sh_mobile: document support for r8a7796 (R-Car M3-W) Explicitly list per-SoC binding for r8a7796. No driver change is required as the initialisation sequence is currently the same as for the R-Car Gen3 fallback binding. Signed-off-by: Simon Horman Acked-by: Geert Uytterhoeven Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt b/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt index 7716acc55dec..ae9c2a735f39 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-sh_mobile.txt @@ -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) -- cgit v1.2.3-70-g09d2 From 6b66a6f27e799d9441ef2c0b1e00913a6a070fa5 Mon Sep 17 00:00:00 2001 From: Peter Rosin Date: Tue, 7 Feb 2017 22:41:55 +0100 Subject: i2c: i2c-mux-gpio: rename i2c-gpio-mux to i2c-mux-gpio The rename did the wrong thing for this documentation file all those years ago. Fix that as well as the neglected rename of the platform data structure. Fixes: e7065e20d9a6 ("i2c: Rename last mux driver to standard pattern") Signed-off-by: Peter Rosin Signed-off-by: Wolfram Sang --- Documentation/i2c/muxes/i2c-mux-gpio | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Documentation/i2c/muxes/i2c-mux-gpio b/Documentation/i2c/muxes/i2c-mux-gpio index d4d91a53fc39..7a8d7d261632 100644 --- a/Documentation/i2c/muxes/i2c-mux-gpio +++ b/Documentation/i2c/muxes/i2c-mux-gpio @@ -1,11 +1,11 @@ -Kernel driver i2c-gpio-mux +Kernel driver i2c-mux-gpio Author: Peter Korsgaard 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 +#include #include 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. -- cgit v1.2.3-70-g09d2 From 92d9d0dfb0fd2f1a6f0c411530df65fba274a79d Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Fri, 27 Jan 2017 23:36:17 +0530 Subject: i2c: busses: constify i2c_algorithm structures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Declare i2c_algorithm structures as const as they are only stored in the algo field of an i2c_adapter structure. This field is of type const, so i2c_algorithm structures having this property can be made const too. Signed-off-by: Bhumika Goyal Acked-by: Uwe Kleine-König for Acked-by: Patrice Chotard Acked-by: Jarkko Nikula Reviewed-by: Jean Delvare Acked-by: Ludovic Desroches Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 2 +- drivers/i2c/busses/i2c-bfin-twi.c | 2 +- drivers/i2c/busses/i2c-designware-core.c | 2 +- drivers/i2c/busses/i2c-eg20t.c | 2 +- drivers/i2c/busses/i2c-emev2.c | 2 +- drivers/i2c/busses/i2c-imx-lpi2c.c | 2 +- drivers/i2c/busses/i2c-imx.c | 2 +- drivers/i2c/busses/i2c-nforce2.c | 2 +- drivers/i2c/busses/i2c-robotfuzz-osif.c | 2 +- drivers/i2c/busses/i2c-sh_mobile.c | 2 +- drivers/i2c/busses/i2c-st.c | 2 +- drivers/i2c/busses/i2c-xgene-slimpro.c | 2 +- drivers/i2c/busses/i2c-xlp9xx.c | 2 +- drivers/i2c/busses/i2c-xlr.c | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index 0b86c6173e07..e4fcb0c2bc97 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -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, }; diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 29d00c4f7824..9fe942b8c610 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -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, diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 6d81c56184d3..a62c14c3b2b7 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -822,7 +822,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, }; diff --git a/drivers/i2c/busses/i2c-eg20t.c b/drivers/i2c/busses/i2c-eg20t.c index 5ce71ce7b6c4..bdeab0174fec 100644 --- a/drivers/i2c/busses/i2c-eg20t.c +++ b/drivers/i2c/busses/i2c-eg20t.c @@ -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 }; diff --git a/drivers/i2c/busses/i2c-emev2.c b/drivers/i2c/busses/i2c-emev2.c index 96bb4e749012..312912708854 100644 --- a/drivers/i2c/busses/i2c-emev2.c +++ b/drivers/i2c/busses/i2c-emev2.c @@ -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, diff --git a/drivers/i2c/busses/i2c-imx-lpi2c.c b/drivers/i2c/busses/i2c-imx-lpi2c.c index c62b7cd475f8..934f5485f3c5 100644 --- a/drivers/i2c/busses/i2c-imx-lpi2c.c +++ b/drivers/i2c/busses/i2c-imx-lpi2c.c @@ -537,7 +537,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, }; diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 47fc1f1acff7..95ed17183e73 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -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, }; diff --git a/drivers/i2c/busses/i2c-nforce2.c b/drivers/i2c/busses/i2c-nforce2.c index 374b35e7e450..3241bb9d6c18 100644 --- a/drivers/i2c/busses/i2c-nforce2.c +++ b/drivers/i2c/busses/i2c-nforce2.c @@ -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, }; diff --git a/drivers/i2c/busses/i2c-robotfuzz-osif.c b/drivers/i2c/busses/i2c-robotfuzz-osif.c index 89d8b41b6668..9c0f52b7ff7e 100644 --- a/drivers/i2c/busses/i2c-robotfuzz-osif.c +++ b/drivers/i2c/busses/i2c-robotfuzz-osif.c @@ -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, }; diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c index 3d9ebe6e5716..3d7559348745 100644 --- a/drivers/i2c/busses/i2c-sh_mobile.c +++ b/drivers/i2c/busses/i2c-sh_mobile.c @@ -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, }; diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c index 1371547ce1a3..1eb9fa82dcfd 100644 --- a/drivers/i2c/busses/i2c-st.c +++ b/drivers/i2c/busses/i2c-st.c @@ -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, }; diff --git a/drivers/i2c/busses/i2c-xgene-slimpro.c b/drivers/i2c/busses/i2c-xgene-slimpro.c index 0ab1e55558bc..dbe7e44c9321 100644 --- a/drivers/i2c/busses/i2c-xgene-slimpro.c +++ b/drivers/i2c/busses/i2c-xgene-slimpro.c @@ -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, }; diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c index 84a8b2eccffb..66b464d52c9c 100644 --- a/drivers/i2c/busses/i2c-xlp9xx.c +++ b/drivers/i2c/busses/i2c-xlp9xx.c @@ -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, }; diff --git a/drivers/i2c/busses/i2c-xlr.c b/drivers/i2c/busses/i2c-xlr.c index ad17d88d8573..484bfa15d58e 100644 --- a/drivers/i2c/busses/i2c-xlr.c +++ b/drivers/i2c/busses/i2c-xlr.c @@ -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, }; -- cgit v1.2.3-70-g09d2 From 1da87267006246137a96682404bc0716a10c85a7 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 12 Jan 2017 14:29:04 +0000 Subject: i2c: mux: mlxcpld: remove unused including Remove including that don't need it. Signed-off-by: Wei Yongjun Acked-by: Vadim Pasternak Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-mlxcpld.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/i2c/muxes/i2c-mux-mlxcpld.c b/drivers/i2c/muxes/i2c-mux-mlxcpld.c index b7ca249ec9c3..e53f2abd1350 100644 --- a/drivers/i2c/muxes/i2c-mux-mlxcpld.c +++ b/drivers/i2c/muxes/i2c-mux-mlxcpld.c @@ -40,7 +40,6 @@ #include #include #include -#include #include #define CPLD_MUX_MAX_NCHANS 8 -- cgit v1.2.3-70-g09d2 From acf6ef1d6c963532242b40731b0734e4acd3310f Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 16 Jan 2017 10:54:54 -0300 Subject: i2c: mux: pca954x: Export OF device ID table as module aliases The I2C core always reports a MODALIAS of the form i2c: even if the device was registered via OF, this means that exporting the OF device ID table device aliases in the module is not needed. But in order to change how the core reports modaliases to user-space, it's better to export it. Signed-off-by: Javier Martinez Canillas Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-pca954x.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index dd18b9ccb1f4..a0232e079545 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -148,6 +148,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() -- cgit v1.2.3-70-g09d2 From e278d64190c2dafc49f63857dd1e0e7689a15bfa Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Mon, 16 Jan 2017 10:54:55 -0300 Subject: i2c: mux: pca9541: Export OF device ID table as module aliases The I2C core always reports a MODALIAS of the form i2c: even if the device was registered via OF, this means that exporting the OF device ID table device aliases in the module is not needed. But in order to change how the core reports modaliases to user-space, it's better to export it. Signed-off-by: Javier Martinez Canillas Acked-by: Peter Rosin Signed-off-by: Wolfram Sang --- drivers/i2c/muxes/i2c-mux-pca9541.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/muxes/i2c-mux-pca9541.c b/drivers/i2c/muxes/i2c-mux-pca9541.c index 4ea7e691afc7..77840f7845a1 100644 --- a/drivers/i2c/muxes/i2c-mux-pca9541.c +++ b/drivers/i2c/muxes/i2c-mux-pca9541.c @@ -90,6 +90,7 @@ static const struct of_device_id pca9541_of_match[] = { { .compatible = "nxp,pca9541" }, {} }; +MODULE_DEVICE_TABLE(of, pca9541_of_match); #endif /* -- cgit v1.2.3-70-g09d2 From 9827f9eb79c56424eac6409197a290601cf78eee Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 1 Feb 2017 19:20:59 +0300 Subject: i2c: i801: Add support for Intel Gemini Lake Intel Gemini Lake has the same SMBus host controller than Intel Broxton. Signed-off-by: Mika Westerberg Signed-off-by: Jean Delvare Signed-off-by: Wolfram Sang --- Documentation/i2c/busses/i2c-i801 | 1 + drivers/i2c/busses/Kconfig | 1 + drivers/i2c/busses/i2c-i801.c | 3 +++ 3 files changed, 5 insertions(+) diff --git a/Documentation/i2c/busses/i2c-i801 b/Documentation/i2c/busses/i2c-i801 index 1bba38dd2637..820d9040de16 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -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 diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 271920847bca..c64221d143ff 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -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. diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index e242db43774b..6484fa6dbb84 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -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) }, -- cgit v1.2.3-70-g09d2 From 71ccea095ea1d4efd004dab971be6d599e06fc3f Mon Sep 17 00:00:00 2001 From: Chris Brandt Date: Tue, 7 Feb 2017 21:41:22 -0500 Subject: i2c: riic: correctly finish transfers This fixes the condition where the controller has not fully completed its final transfer and leaves the bus and controller in a undesirable state. At the end of the last transmitted byte, the existing driver would just signal for a STOP condition to be transmitted then immediately signal completion. However, the full STOP procedure might not have fully taken place by the time the runtime PM shuts off the peripheral clock, leaving the bus in a suspended state. Alternatively, the STOP condition on the bus may have completed, but when the next transaction is requested by the upper layer, not all the necessary register cleanup was finished from the last transfer which made the driver return BUS BUSY when it really wasn't. This patch now makes all transmit and receive transactions wait for the STOP condition to fully complete before signaling a completed transaction. With this new method, runtime PM no longer seems to be an issue. Fixes: 310c18a41450 ("i2c: riic: add driver") Signed-off-by: Chris Brandt Reviewed-by: Wolfram Sang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-riic.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-riic.c b/drivers/i2c/busses/i2c-riic.c index 6263ea82d6ac..8f11d347b3ec 100644 --- a/drivers/i2c/busses/i2c-riic.c +++ b/drivers/i2c/busses/i2c-riic.c @@ -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" }, }; -- cgit v1.2.3-70-g09d2 From f8251f1dfda9e1200545bf19270d9df2273bdfa1 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Wed, 25 Jan 2017 09:31:06 +0800 Subject: i2c: mux: pca954x: Add missing pca9542 definition to chip_desc The spec for the pca954x was missing. This chip is the same as the pca9540 except that it has interrupt lines. While the i2c_device_id table mapped the pca9542 to the pca9540 definition the compatible table did not. In preparation for irq support add the pca9542 definition. Signed-off-by: Phil Reid Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-mux-pca954x.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index dd18b9ccb1f4..bbf088e08d73 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -84,6 +84,11 @@ static const struct chip_desc chips[] = { .enable = 0x4, .muxtype = pca954x_ismux, }, + [pca_9542] = { + .nchans = 2, + .enable = 0x4, + .muxtype = pca954x_ismux, + }, [pca_9543] = { .nchans = 2, .muxtype = pca954x_isswi, @@ -110,7 +115,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 +129,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 }, -- cgit v1.2.3-70-g09d2 From 9aedcc61ed101b4dbb7fa7013deca4a7ed7ff418 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Wed, 25 Jan 2017 09:31:07 +0800 Subject: dt: bindings: i2c-mux-pca954x: Add documentation for interrupt controller Various muxes can aggregate multiple irq lines and provide a control register to determine the active line. Add bindings for interrupt controller support. Acked-by: Rob Herring Signed-off-by: Phil Reid Signed-off-by: Peter Rosin --- Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt b/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt index cf53d5fba20a..aa097045a10e 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mux-pca954x.txt @@ -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>; -- cgit v1.2.3-70-g09d2 From f2114795f721bd5028284ddf84b150798a9b7a73 Mon Sep 17 00:00:00 2001 From: Phil Reid Date: Wed, 25 Jan 2017 09:31:08 +0800 Subject: i2c: mux: pca954x: Add interrupt controller support Various muxes can aggregate multiple interrupts from each i2c bus. All of the muxes with interrupt support combine the active low irq lines using an internal 'and' function and generate a combined active low output. The muxes do provide the ability to read a control register to determine which irq is active. By making the mux an irq controller isr latency can potentially be reduced by reading the status register and then only calling the registered isr on that bus segment. As there is no irq masking on the mux irq are disabled until irq_unmask is called at least once. Signed-off-by: Phil Reid Signed-off-by: Peter Rosin --- drivers/i2c/muxes/i2c-mux-pca954x.c | 141 +++++++++++++++++++++++++++++++++++- 1 file changed, 139 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c index bbf088e08d73..06fd9cc85b23 100644 --- a/drivers/i2c/muxes/i2c-mux-pca954x.c +++ b/drivers/i2c/muxes/i2c-mux-pca954x.c @@ -41,14 +41,20 @@ #include #include #include +#include +#include #include #include #include +#include #include #include +#include #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 */ @@ -87,19 +98,23 @@ static const struct chip_desc chips[] = { [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] = { @@ -222,6 +237,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 */ @@ -286,6 +409,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; @@ -311,7 +438,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; } } @@ -322,7 +449,7 @@ static int pca954x_probe(struct i2c_client *client, return 0; -virt_reg_failed: +fail_del_adapters: i2c_mux_del_adapters(muxc); return ret; } @@ -330,6 +457,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; -- cgit v1.2.3-70-g09d2 From dd905a61e95e057277115888e1b8d5d9070795e1 Mon Sep 17 00:00:00 2001 From: Ben Gardner Date: Thu, 9 Feb 2017 11:36:08 -0600 Subject: misc: eeprom: at24: use device_property_*() functions instead of of_get_property() Allow the at24 driver to get configuration information from both OF and ACPI by using the more generic device_property functions. This change was inspired by the at25.c driver. I have a custom board with a ST M24C02 EEPROM attached to an I2C bus. With the following ACPI construct, this patch instantiates a working instance of the driver. Device (EEP0) { Name (_HID, "PRP0001") Name (_DSD, Package () { ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), Package () { Package () {"compatible", Package () {"st,24c02"}}, Package () {"pagesize", 16}, }, }) Name (_CRS, ResourceTemplate () { I2cSerialBus ( 0x0057, ControllerInitiated, 400000, AddressingMode7Bit, "\\_SB.PCI0.I2C3", 0x00, ResourceConsumer,,) }) } Signed-off-by: Ben Gardner Reviewed-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/misc/eeprom/at24.c | 45 +++++++++++++++++++-------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c index 051b14766ef9..764ff5df0dbc 100644 --- a/drivers/misc/eeprom/at24.c +++ b/drivers/misc/eeprom/at24.c @@ -19,7 +19,7 @@ #include #include #include -#include +#include #include #include #include @@ -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; - - 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); + int err; + u32 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; -- cgit v1.2.3-70-g09d2 From 6a405f7c5d0e9d67163f25fad7fde9e70a9837bb Mon Sep 17 00:00:00 2001 From: Stephen Warren Date: Mon, 20 Feb 2017 17:52:33 +0100 Subject: dt-bindings: Add Tegra186 BPMP I2C binding 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. Signed-off-by: Stephen Warren Reviewed-by: Simon Glass Signed-off-by: Tom Warren Acked-by: Rob Herring Acked-by: Jon Hunter Signed-off-by: Thierry Reding Signed-off-by: Wolfram Sang --- .../bindings/i2c/nvidia,tegra186-bpmp-i2c.txt | 42 ++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/nvidia,tegra186-bpmp-i2c.txt diff --git a/Documentation/devicetree/bindings/i2c/nvidia,tegra186-bpmp-i2c.txt b/Documentation/devicetree/bindings/i2c/nvidia,tegra186-bpmp-i2c.txt new file mode 100644 index 000000000000..ab240e10debc --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/nvidia,tegra186-bpmp-i2c.txt @@ -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>; + }; +}; -- cgit v1.2.3-70-g09d2 From 0297ffa69cab614f508ef5d9abdb4c0ffd709795 Mon Sep 17 00:00:00 2001 From: Shardar Shariff Md Date: Mon, 20 Feb 2017 17:52:34 +0100 Subject: i2c: Add Tegra BPMP I2C proxy driver Add Tegra BPMP I2C driver. The BPMP is the boot and power management processor embedded in Tegra SoCs. In newer SoC versions, access to one of the I2C busses goes via the BPMP, requiring a different "proxy" I2C driver that accesses the bus via the real I2C driver embedded in the BPMP firmware. Signed-off-by: Shardar Shariff Md Signed-off-by: Thierry Reding Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 11 ++ drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-tegra-bpmp.c | 346 ++++++++++++++++++++++++++++++++++++ 3 files changed, 358 insertions(+) create mode 100644 drivers/i2c/busses/i2c-tegra-bpmp.c diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index c64221d143ff..8adc0f1d7ad0 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -930,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 diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index a2c6ff558578..30b60855fbcd 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -89,6 +89,7 @@ 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 diff --git a/drivers/i2c/busses/i2c-tegra-bpmp.c b/drivers/i2c/busses/i2c-tegra-bpmp.c new file mode 100644 index 000000000000..9eed69d5e17e --- /dev/null +++ b/drivers/i2c/busses/i2c-tegra-bpmp.c @@ -0,0 +1,346 @@ +/* + * drivers/i2c/busses/i2c-tegra-bpmp.c + * + * Copyright (c) 2016 NVIDIA Corporation. All rights reserved. + * + * Author: Shardar Shariff Md + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * 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 "); +MODULE_AUTHOR("Juha-Matti Tilli"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3-70-g09d2 From ababb08938df7ac245d30a58b95b94ecf8dc04fc Mon Sep 17 00:00:00 2001 From: Stefan Wahren Date: Thu, 16 Feb 2017 21:20:45 +0000 Subject: i2c: bcm2835: Avoid possible NULL ptr dereference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit e2474541032d ("bcm2835: Fix hang for writing messages larger than 16 bytes") the interrupt handler is prone to a possible NULL pointer dereference. This could happen if an interrupt fires before curr_msg is set by bcm2835_i2c_xfer_msg() and randomly occurs on the RPi 3. Even this is an unexpected behavior the driver must handle that with an error instead of a crash. Reported-by: Peter Robinson Fixes: e2474541032d ("bcm2835: Fix hang for writing messages larger than 16 bytes") Signed-off-by: Stefan Wahren Acked-by: Noralf Trønnes Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bcm2835.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c index c3436f627028..cd07a69e2e93 100644 --- a/drivers/i2c/busses/i2c-bcm2835.c +++ b/drivers/i2c/busses/i2c-bcm2835.c @@ -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); } -- cgit v1.2.3-70-g09d2 From e3ccc921b7d8fd1fcd10a00720e09823d8078666 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Thu, 16 Feb 2017 18:27:59 +0100 Subject: i2c: at91: ensure state is restored after suspending When going to suspend, the I2C registers may be lost because the power to VDDcore is cut. Restore them when resuming. Signed-off-by: Alexandre Belloni Acked-by: Ludovic Desroches Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-at91.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c index e4fcb0c2bc97..fabbb9e49161 100644 --- a/drivers/i2c/busses/i2c-at91.c +++ b/drivers/i2c/busses/i2c-at91.c @@ -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; } -- cgit v1.2.3-70-g09d2 From fd1c9c8568439198a66f42108a9b01854e25346e Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Wed, 22 Feb 2017 11:11:20 +0100 Subject: i2c: exynos5: disable fifo-almost-empty irq signal when necessary Fifo-almost-empty irq signal should be disabled as soon as possible, to avoid unnecessary interrupt storm. The best moment is when there is no more data to feed fifo. This patch fixes system stalls caused by IRQ storm. Signed-off-by: Andrzej Hajda Tested-by: Marek Szyprowski Tested-by: Andi Shyti Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-exynos5.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index bea607149972..00e81e3564ff 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -502,8 +502,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++]; -- cgit v1.2.3-70-g09d2 From 7999eecb7e5675c3c7c2981a3ba9be6fc8e2ee27 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Wed, 22 Feb 2017 12:04:34 +0100 Subject: i2c: exynos5: fix arbitration lost handling In case of arbitration lost adequate interrupt sometimes is not signaled. As a result transfer timeouts and is not retried, as it should. To avoid such cases code is added to check transaction status in case of every interrupt. Signed-off-by: Andrzej Hajda Tested-by: Andi Shyti Reviewed-by: Andi Shyti Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-exynos5.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-exynos5.c b/drivers/i2c/busses/i2c-exynos5.c index 00e81e3564ff..cbd93ce0661f 100644 --- a/drivers/i2c/busses/i2c-exynos5.c +++ b/drivers/i2c/busses/i2c-exynos5.c @@ -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; -- cgit v1.2.3-70-g09d2 From 4c21541d8da17fbe94ecadbfc913d6dff3be7ca2 Mon Sep 17 00:00:00 2001 From: Jan Glauber Date: Tue, 21 Feb 2017 14:07:50 +0100 Subject: i2c: thunderx: Replace pci_enable_msix() Using pci_alloc_irq_vectors() instead of the deprecated pci_enable_msix() allows to remove the msix_entry from struct octeon_i2c and thus to get rid of the config symbol check. Signed-off-by: Jan Glauber Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-octeon-core.h | 4 ---- drivers/i2c/busses/i2c-thunderx-pcidrv.c | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-octeon-core.h b/drivers/i2c/busses/i2c-octeon-core.h index e160f838c254..aa3c8f4771c1 100644 --- a/drivers/i2c/busses/i2c-octeon-core.h +++ b/drivers/i2c/busses/i2c-octeon-core.h @@ -6,7 +6,6 @@ #include #include #include -#include /* 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; }; diff --git a/drivers/i2c/busses/i2c-thunderx-pcidrv.c b/drivers/i2c/busses/i2c-thunderx-pcidrv.c index bba5b429f69c..1d4c2beacf2e 100644 --- a/drivers/i2c/busses/i2c-thunderx-pcidrv.c +++ b/drivers/i2c/busses/i2c-thunderx-pcidrv.c @@ -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; -- cgit v1.2.3-70-g09d2