From 1c2d721a7063bc3b8668de07f8d14dfbac4bf515 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 2 Jun 2013 23:05:03 +0000 Subject: i2c: intel-mid: remove obsolete driver Moorestown support is removed from kernel and Medfield is supported by i2c-designware-pci. But i2c-intel-mid is still in upstream and community resources are wasted to maintain it. Signed-off-by: Andy Shevchenko Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 10 - drivers/i2c/busses/Makefile | 1 - drivers/i2c/busses/i2c-intel-mid.c | 1121 ------------------------------------ 3 files changed, 1132 deletions(-) delete mode 100644 drivers/i2c/busses/i2c-intel-mid.c diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 631736e2e7ed..94364d41686f 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -474,16 +474,6 @@ config I2C_IMX This driver can also be built as a module. If so, the module will be called i2c-imx. -config I2C_INTEL_MID - tristate "Intel Moorestown/Medfield Platform I2C controller" - depends on PCI - help - Say Y here if you have an Intel Moorestown/Medfield platform I2C - controller. - - This support is also available as a module. If so, the module - will be called i2c-intel-mid. - config I2C_IOP3XX tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface" depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 8f4fc23b85b1..3e07dc53eeae 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -46,7 +46,6 @@ obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o obj-$(CONFIG_I2C_IMX) += i2c-imx.o -obj-$(CONFIG_I2C_INTEL_MID) += i2c-intel-mid.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o diff --git a/drivers/i2c/busses/i2c-intel-mid.c b/drivers/i2c/busses/i2c-intel-mid.c deleted file mode 100644 index 0fb659726ffc..000000000000 --- a/drivers/i2c/busses/i2c-intel-mid.c +++ /dev/null @@ -1,1121 +0,0 @@ -/* - * Support for Moorestown/Medfield I2C chip - * - * Copyright (c) 2009 Intel Corporation. - * Copyright (c) 2009 Synopsys. Inc. - * - * 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, write to the Free Software Foundation, Inc., 51 - * Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define DRIVER_NAME "i2c-intel-mid" -#define VERSION "Version 0.5ac2" -#define PLATFORM "Moorestown/Medfield" - -/* Tables use: 0 Moorestown, 1 Medfield */ -#define NUM_PLATFORMS 2 -enum platform_enum { - MOORESTOWN = 0, - MEDFIELD = 1, -}; - -enum mid_i2c_status { - STATUS_IDLE = 0, - STATUS_READ_START, - STATUS_READ_IN_PROGRESS, - STATUS_READ_SUCCESS, - STATUS_WRITE_START, - STATUS_WRITE_SUCCESS, - STATUS_XFER_ABORT, - STATUS_STANDBY -}; - -/** - * struct intel_mid_i2c_private - per device I²C context - * @adap: core i2c layer adapter information - * @dev: device reference for power management - * @base: register base - * @speed: speed mode for this port - * @complete: completion object for transaction wait - * @abort: reason for last abort - * @rx_buf: pointer into working receive buffer - * @rx_buf_len: receive buffer length - * @status: adapter state machine - * @msg: the message we are currently processing - * @platform: the MID device type we are part of - * @lock: transaction serialization - * - * We allocate one of these per device we discover, it holds the core - * i2c layer objects and the data we need to track privately. - */ -struct intel_mid_i2c_private { - struct i2c_adapter adap; - struct device *dev; - void __iomem *base; - int speed; - struct completion complete; - int abort; - u8 *rx_buf; - int rx_buf_len; - enum mid_i2c_status status; - struct i2c_msg *msg; - enum platform_enum platform; - struct mutex lock; -}; - -#define NUM_SPEEDS 3 - -#define ACTIVE 0 -#define STANDBY 1 - - -/* Control register */ -#define IC_CON 0x00 -#define SLV_DIS (1 << 6) /* Disable slave mode */ -#define RESTART (1 << 5) /* Send a Restart condition */ -#define ADDR_10BIT (1 << 4) /* 10-bit addressing */ -#define STANDARD_MODE (1 << 1) /* standard mode */ -#define FAST_MODE (2 << 1) /* fast mode */ -#define HIGH_MODE (3 << 1) /* high speed mode */ -#define MASTER_EN (1 << 0) /* Master mode */ - -/* Target address register */ -#define IC_TAR 0x04 -#define IC_TAR_10BIT_ADDR (1 << 12) /* 10-bit addressing */ -#define IC_TAR_SPECIAL (1 << 11) /* Perform special I2C cmd */ -#define IC_TAR_GC_OR_START (1 << 10) /* 0: Gerneral Call Address */ - /* 1: START BYTE */ -/* Slave Address Register */ -#define IC_SAR 0x08 /* Not used in Master mode */ - -/* High Speed Master Mode Code Address Register */ -#define IC_HS_MADDR 0x0c - -/* Rx/Tx Data Buffer and Command Register */ -#define IC_DATA_CMD 0x10 -#define IC_RD (1 << 8) /* 1: Read 0: Write */ - -/* Standard Speed Clock SCL High Count Register */ -#define IC_SS_SCL_HCNT 0x14 - -/* Standard Speed Clock SCL Low Count Register */ -#define IC_SS_SCL_LCNT 0x18 - -/* Fast Speed Clock SCL High Count Register */ -#define IC_FS_SCL_HCNT 0x1c - -/* Fast Spedd Clock SCL Low Count Register */ -#define IC_FS_SCL_LCNT 0x20 - -/* High Speed Clock SCL High Count Register */ -#define IC_HS_SCL_HCNT 0x24 - -/* High Speed Clock SCL Low Count Register */ -#define IC_HS_SCL_LCNT 0x28 - -/* Interrupt Status Register */ -#define IC_INTR_STAT 0x2c /* Read only */ -#define R_GEN_CALL (1 << 11) -#define R_START_DET (1 << 10) -#define R_STOP_DET (1 << 9) -#define R_ACTIVITY (1 << 8) -#define R_RX_DONE (1 << 7) -#define R_TX_ABRT (1 << 6) -#define R_RD_REQ (1 << 5) -#define R_TX_EMPTY (1 << 4) -#define R_TX_OVER (1 << 3) -#define R_RX_FULL (1 << 2) -#define R_RX_OVER (1 << 1) -#define R_RX_UNDER (1 << 0) - -/* Interrupt Mask Register */ -#define IC_INTR_MASK 0x30 /* Read and Write */ -#define M_GEN_CALL (1 << 11) -#define M_START_DET (1 << 10) -#define M_STOP_DET (1 << 9) -#define M_ACTIVITY (1 << 8) -#define M_RX_DONE (1 << 7) -#define M_TX_ABRT (1 << 6) -#define M_RD_REQ (1 << 5) -#define M_TX_EMPTY (1 << 4) -#define M_TX_OVER (1 << 3) -#define M_RX_FULL (1 << 2) -#define M_RX_OVER (1 << 1) -#define M_RX_UNDER (1 << 0) - -/* Raw Interrupt Status Register */ -#define IC_RAW_INTR_STAT 0x34 /* Read Only */ -#define GEN_CALL (1 << 11) /* General call */ -#define START_DET (1 << 10) /* (RE)START occurred */ -#define STOP_DET (1 << 9) /* STOP occurred */ -#define ACTIVITY (1 << 8) /* Bus busy */ -#define RX_DONE (1 << 7) /* Not used in Master mode */ -#define TX_ABRT (1 << 6) /* Transmit Abort */ -#define RD_REQ (1 << 5) /* Not used in Master mode */ -#define TX_EMPTY (1 << 4) /* TX FIFO <= threshold */ -#define TX_OVER (1 << 3) /* TX FIFO overflow */ -#define RX_FULL (1 << 2) /* RX FIFO >= threshold */ -#define RX_OVER (1 << 1) /* RX FIFO overflow */ -#define RX_UNDER (1 << 0) /* RX FIFO empty */ - -/* Receive FIFO Threshold Register */ -#define IC_RX_TL 0x38 - -/* Transmit FIFO Treshold Register */ -#define IC_TX_TL 0x3c - -/* Clear Combined and Individual Interrupt Register */ -#define IC_CLR_INTR 0x40 -#define CLR_INTR (1 << 0) - -/* Clear RX_UNDER Interrupt Register */ -#define IC_CLR_RX_UNDER 0x44 -#define CLR_RX_UNDER (1 << 0) - -/* Clear RX_OVER Interrupt Register */ -#define IC_CLR_RX_OVER 0x48 -#define CLR_RX_OVER (1 << 0) - -/* Clear TX_OVER Interrupt Register */ -#define IC_CLR_TX_OVER 0x4c -#define CLR_TX_OVER (1 << 0) - -#define IC_CLR_RD_REQ 0x50 - -/* Clear TX_ABRT Interrupt Register */ -#define IC_CLR_TX_ABRT 0x54 -#define CLR_TX_ABRT (1 << 0) -#define IC_CLR_RX_DONE 0x58 - -/* Clear ACTIVITY Interrupt Register */ -#define IC_CLR_ACTIVITY 0x5c -#define CLR_ACTIVITY (1 << 0) - -/* Clear STOP_DET Interrupt Register */ -#define IC_CLR_STOP_DET 0x60 -#define CLR_STOP_DET (1 << 0) - -/* Clear START_DET Interrupt Register */ -#define IC_CLR_START_DET 0x64 -#define CLR_START_DET (1 << 0) - -/* Clear GEN_CALL Interrupt Register */ -#define IC_CLR_GEN_CALL 0x68 -#define CLR_GEN_CALL (1 << 0) - -/* Enable Register */ -#define IC_ENABLE 0x6c -#define ENABLE (1 << 0) - -/* Status Register */ -#define IC_STATUS 0x70 /* Read Only */ -#define STAT_SLV_ACTIVITY (1 << 6) /* Slave not in idle */ -#define STAT_MST_ACTIVITY (1 << 5) /* Master not in idle */ -#define STAT_RFF (1 << 4) /* RX FIFO Full */ -#define STAT_RFNE (1 << 3) /* RX FIFO Not Empty */ -#define STAT_TFE (1 << 2) /* TX FIFO Empty */ -#define STAT_TFNF (1 << 1) /* TX FIFO Not Full */ -#define STAT_ACTIVITY (1 << 0) /* Activity Status */ - -/* Transmit FIFO Level Register */ -#define IC_TXFLR 0x74 /* Read Only */ -#define TXFLR (1 << 0) /* TX FIFO level */ - -/* Receive FIFO Level Register */ -#define IC_RXFLR 0x78 /* Read Only */ -#define RXFLR (1 << 0) /* RX FIFO level */ - -/* Transmit Abort Source Register */ -#define IC_TX_ABRT_SOURCE 0x80 -#define ABRT_SLVRD_INTX (1 << 15) -#define ABRT_SLV_ARBLOST (1 << 14) -#define ABRT_SLVFLUSH_TXFIFO (1 << 13) -#define ARB_LOST (1 << 12) -#define ABRT_MASTER_DIS (1 << 11) -#define ABRT_10B_RD_NORSTRT (1 << 10) -#define ABRT_SBYTE_NORSTRT (1 << 9) -#define ABRT_HS_NORSTRT (1 << 8) -#define ABRT_SBYTE_ACKDET (1 << 7) -#define ABRT_HS_ACKDET (1 << 6) -#define ABRT_GCALL_READ (1 << 5) -#define ABRT_GCALL_NOACK (1 << 4) -#define ABRT_TXDATA_NOACK (1 << 3) -#define ABRT_10ADDR2_NOACK (1 << 2) -#define ABRT_10ADDR1_NOACK (1 << 1) -#define ABRT_7B_ADDR_NOACK (1 << 0) - -/* Enable Status Register */ -#define IC_ENABLE_STATUS 0x9c -#define IC_EN (1 << 0) /* I2C in an enabled state */ - -/* Component Parameter Register 1*/ -#define IC_COMP_PARAM_1 0xf4 -#define APB_DATA_WIDTH (0x3 << 0) - -/* added by xiaolin --begin */ -#define SS_MIN_SCL_HIGH 4000 -#define SS_MIN_SCL_LOW 4700 -#define FS_MIN_SCL_HIGH 600 -#define FS_MIN_SCL_LOW 1300 -#define HS_MIN_SCL_HIGH_100PF 60 -#define HS_MIN_SCL_LOW_100PF 120 - -#define STANDARD 0 -#define FAST 1 -#define HIGH 2 - -#define NUM_SPEEDS 3 - -static int speed_mode[6] = { - FAST, - FAST, - FAST, - STANDARD, - FAST, - FAST -}; - -static int ctl_num = 6; -module_param_array(speed_mode, int, &ctl_num, S_IRUGO); -MODULE_PARM_DESC(speed_mode, "Set the speed of the i2c interface (0-2)"); - -/** - * intel_mid_i2c_disable - Disable I2C controller - * @adap: struct pointer to i2c_adapter - * - * Return Value: - * 0 success - * -EBUSY if device is busy - * -ETIMEDOUT if i2c cannot be disabled within the given time - * - * I2C bus state should be checked prior to disabling the hardware. If bus is - * not in idle state, an errno is returned. Write "0" to IC_ENABLE to disable - * I2C controller. - */ -static int intel_mid_i2c_disable(struct i2c_adapter *adap) -{ - struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap); - int err = 0; - int count = 0; - int ret1, ret2; - static const u16 delay[NUM_SPEEDS] = {100, 25, 3}; - - /* Set IC_ENABLE to 0 */ - writel(0, i2c->base + IC_ENABLE); - - /* Check if device is busy */ - dev_dbg(&adap->dev, "mrst i2c disable\n"); - while ((ret1 = readl(i2c->base + IC_ENABLE_STATUS) & 0x1) - || (ret2 = readl(i2c->base + IC_STATUS) & 0x1)) { - udelay(delay[i2c->speed]); - writel(0, i2c->base + IC_ENABLE); - dev_dbg(&adap->dev, "i2c is busy, count is %d speed %d\n", - count, i2c->speed); - if (count++ > 10) { - err = -ETIMEDOUT; - break; - } - } - - /* Clear all interrupts */ - readl(i2c->base + IC_CLR_INTR); - readl(i2c->base + IC_CLR_STOP_DET); - readl(i2c->base + IC_CLR_START_DET); - readl(i2c->base + IC_CLR_ACTIVITY); - readl(i2c->base + IC_CLR_TX_ABRT); - readl(i2c->base + IC_CLR_RX_OVER); - readl(i2c->base + IC_CLR_RX_UNDER); - readl(i2c->base + IC_CLR_TX_OVER); - readl(i2c->base + IC_CLR_RX_DONE); - readl(i2c->base + IC_CLR_GEN_CALL); - - /* Disable all interupts */ - writel(0x0000, i2c->base + IC_INTR_MASK); - - return err; -} - -/** - * intel_mid_i2c_hwinit - Initialize the I2C hardware registers - * @dev: pci device struct pointer - * - * This function will be called in intel_mid_i2c_probe() before device - * registration. - * - * Return Values: - * 0 success - * -EBUSY i2c cannot be disabled - * -ETIMEDOUT i2c cannot be disabled - * -EFAULT If APB data width is not 32-bit wide - * - * I2C should be disabled prior to other register operation. If failed, an - * errno is returned. Mask and Clear all interrpts, this should be done at - * first. Set common registers which will not be modified during normal - * transfers, including: control register, FIFO threshold and clock freq. - * Check APB data width at last. - */ -static int intel_mid_i2c_hwinit(struct intel_mid_i2c_private *i2c) -{ - int err; - - static const u16 hcnt[NUM_PLATFORMS][NUM_SPEEDS] = { - { 0x75, 0x15, 0x07 }, - { 0x04c, 0x10, 0x06 } - }; - static const u16 lcnt[NUM_PLATFORMS][NUM_SPEEDS] = { - { 0x7C, 0x21, 0x0E }, - { 0x053, 0x19, 0x0F } - }; - - /* Disable i2c first */ - err = intel_mid_i2c_disable(&i2c->adap); - if (err) - return err; - - /* - * Setup clock frequency and speed mode - * Enable restart condition, - * enable master FSM, disable slave FSM, - * use target address when initiating transfer - */ - - writel((i2c->speed + 1) << 1 | SLV_DIS | RESTART | MASTER_EN, - i2c->base + IC_CON); - writel(hcnt[i2c->platform][i2c->speed], - i2c->base + (IC_SS_SCL_HCNT + (i2c->speed << 3))); - writel(lcnt[i2c->platform][i2c->speed], - i2c->base + (IC_SS_SCL_LCNT + (i2c->speed << 3))); - - /* Set tranmit & receive FIFO threshold to zero */ - writel(0x0, i2c->base + IC_RX_TL); - writel(0x0, i2c->base + IC_TX_TL); - - return 0; -} - -/** - * intel_mid_i2c_func - Return the supported three I2C operations. - * @adapter: i2c_adapter struct pointer - */ -static u32 intel_mid_i2c_func(struct i2c_adapter *adapter) -{ - return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL; -} - -/** - * intel_mid_i2c_address_neq - To check if the addresses for different i2c messages - * are equal. - * @p1: first i2c_msg - * @p2: second i2c_msg - * - * Return Values: - * 0 if addresses are equal - * 1 if not equal - * - * Within a single transfer, the I2C client may need to send its address more - * than once. So a check if the addresses match is needed. - */ -static inline bool intel_mid_i2c_address_neq(const struct i2c_msg *p1, - const struct i2c_msg *p2) -{ - if (p1->addr != p2->addr) - return 1; - if ((p1->flags ^ p2->flags) & I2C_M_TEN) - return 1; - return 0; -} - -/** - * intel_mid_i2c_abort - To handle transfer abortions and print error messages. - * @adap: i2c_adapter struct pointer - * - * By reading register IC_TX_ABRT_SOURCE, various transfer errors can be - * distingushed. At present, no circumstances have been found out that - * multiple errors would be occurred simutaneously, so we simply use the - * register value directly. - * - * At last the error bits are cleared. (Note clear ABRT_SBYTE_NORSTRT bit need - * a few extra steps) - */ -static void intel_mid_i2c_abort(struct intel_mid_i2c_private *i2c) -{ - /* Read about source register */ - int abort = i2c->abort; - struct i2c_adapter *adap = &i2c->adap; - - /* Single transfer error check: - * According to databook, TX/RX FIFOs would be flushed when - * the abort interrupt occurred. - */ - if (abort & ABRT_MASTER_DIS) - dev_err(&adap->dev, - "initiate master operation with master mode disabled.\n"); - if (abort & ABRT_10B_RD_NORSTRT) - dev_err(&adap->dev, - "RESTART disabled and master sent READ cmd in 10-bit addressing.\n"); - - if (abort & ABRT_SBYTE_NORSTRT) { - dev_err(&adap->dev, - "RESTART disabled and user is trying to send START byte.\n"); - writel(~ABRT_SBYTE_NORSTRT, i2c->base + IC_TX_ABRT_SOURCE); - writel(RESTART, i2c->base + IC_CON); - writel(~IC_TAR_SPECIAL, i2c->base + IC_TAR); - } - - if (abort & ABRT_SBYTE_ACKDET) - dev_err(&adap->dev, - "START byte was not acknowledged.\n"); - if (abort & ABRT_TXDATA_NOACK) - dev_dbg(&adap->dev, - "No acknowledgement received from slave.\n"); - if (abort & ABRT_10ADDR2_NOACK) - dev_dbg(&adap->dev, - "The 2nd address byte of the 10-bit address was not acknowledged.\n"); - if (abort & ABRT_10ADDR1_NOACK) - dev_dbg(&adap->dev, - "The 1st address byte of 10-bit address was not acknowledged.\n"); - if (abort & ABRT_7B_ADDR_NOACK) - dev_dbg(&adap->dev, - "I2C slave device not acknowledged.\n"); - - /* Clear TX_ABRT bit */ - readl(i2c->base + IC_CLR_TX_ABRT); - i2c->status = STATUS_XFER_ABORT; -} - -/** - * xfer_read - Internal function to implement master read transfer. - * @adap: i2c_adapter struct pointer - * @buf: buffer in i2c_msg - * @length: number of bytes to be read - * - * Return Values: - * 0 if the read transfer succeeds - * -ETIMEDOUT if cannot read the "raw" interrupt register - * -EINVAL if a transfer abort occurred - * - * For every byte, a "READ" command will be loaded into IC_DATA_CMD prior to - * data transfer. The actual "read" operation will be performed if an RX_FULL - * interrupt occurred. - * - * Note there may be two interrupt signals captured, one should read - * IC_RAW_INTR_STAT to separate between errors and actual data. - */ -static int xfer_read(struct i2c_adapter *adap, unsigned char *buf, int length) -{ - struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap); - int i = length; - int err; - - if (length >= 256) { - dev_err(&adap->dev, - "I2C FIFO cannot support larger than 256 bytes\n"); - return -EMSGSIZE; - } - - INIT_COMPLETION(i2c->complete); - - readl(i2c->base + IC_CLR_INTR); - writel(0x0044, i2c->base + IC_INTR_MASK); - - i2c->status = STATUS_READ_START; - - while (i--) - writel(IC_RD, i2c->base + IC_DATA_CMD); - - i2c->status = STATUS_READ_START; - err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ); - if (!err) { - dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n"); - intel_mid_i2c_hwinit(i2c); - return -ETIMEDOUT; - } - if (i2c->status == STATUS_READ_SUCCESS) - return 0; - else - return -EIO; -} - -/** - * xfer_write - Internal function to implement master write transfer. - * @adap: i2c_adapter struct pointer - * @buf: buffer in i2c_msg - * @length: number of bytes to be read - * - * Return Values: - * 0 if the read transfer succeeds - * -ETIMEDOUT if we cannot read the "raw" interrupt register - * -EINVAL if a transfer abort occurred - * - * For every byte, a "WRITE" command will be loaded into IC_DATA_CMD prior to - * data transfer. The actual "write" operation will be performed when the - * RX_FULL interrupt signal occurs. - * - * Note there may be two interrupt signals captured, one should read - * IC_RAW_INTR_STAT to separate between errors and actual data. - */ -static int xfer_write(struct i2c_adapter *adap, - unsigned char *buf, int length) -{ - struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap); - int i, err; - - if (length >= 256) { - dev_err(&adap->dev, - "I2C FIFO cannot support larger than 256 bytes\n"); - return -EMSGSIZE; - } - - INIT_COMPLETION(i2c->complete); - - readl(i2c->base + IC_CLR_INTR); - writel(0x0050, i2c->base + IC_INTR_MASK); - - i2c->status = STATUS_WRITE_START; - for (i = 0; i < length; i++) - writel((u16)(*(buf + i)), i2c->base + IC_DATA_CMD); - - i2c->status = STATUS_WRITE_START; - err = wait_for_completion_interruptible_timeout(&i2c->complete, HZ); - if (!err) { - dev_err(&adap->dev, "Timeout for ACK from I2C slave device\n"); - intel_mid_i2c_hwinit(i2c); - return -ETIMEDOUT; - } else { - if (i2c->status == STATUS_WRITE_SUCCESS) - return 0; - else - return -EIO; - } -} - -static int intel_mid_i2c_setup(struct i2c_adapter *adap, struct i2c_msg *pmsg) -{ - struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap); - int err; - u32 reg; - u32 bit_mask; - u32 mode; - - /* Disable device first */ - err = intel_mid_i2c_disable(adap); - if (err) { - dev_err(&adap->dev, - "Cannot disable i2c controller, timeout\n"); - return err; - } - - mode = (1 + i2c->speed) << 1; - /* set the speed mode */ - reg = readl(i2c->base + IC_CON); - if ((reg & 0x06) != mode) { - dev_dbg(&adap->dev, "set mode %d\n", i2c->speed); - writel((reg & ~0x6) | mode, i2c->base + IC_CON); - } - - reg = readl(i2c->base + IC_CON); - /* use 7-bit addressing */ - if (pmsg->flags & I2C_M_TEN) { - if ((reg & ADDR_10BIT) != ADDR_10BIT) { - dev_dbg(&adap->dev, "set i2c 10 bit address mode\n"); - writel(reg | ADDR_10BIT, i2c->base + IC_CON); - } - } else { - if ((reg & ADDR_10BIT) != 0x0) { - dev_dbg(&adap->dev, "set i2c 7 bit address mode\n"); - writel(reg & ~ADDR_10BIT, i2c->base + IC_CON); - } - } - /* enable restart conditions */ - reg = readl(i2c->base + IC_CON); - if ((reg & RESTART) != RESTART) { - dev_dbg(&adap->dev, "enable restart conditions\n"); - writel(reg | RESTART, i2c->base + IC_CON); - } - - /* enable master FSM */ - reg = readl(i2c->base + IC_CON); - dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg); - writel(reg | MASTER_EN, i2c->base + IC_CON); - if ((reg & SLV_DIS) != SLV_DIS) { - dev_dbg(&adap->dev, "enable master FSM\n"); - writel(reg | SLV_DIS, i2c->base + IC_CON); - dev_dbg(&adap->dev, "ic_con reg is 0x%x\n", reg); - } - - /* use target address when initiating transfer */ - reg = readl(i2c->base + IC_TAR); - bit_mask = IC_TAR_SPECIAL | IC_TAR_GC_OR_START; - - if ((reg & bit_mask) != 0x0) { - dev_dbg(&adap->dev, - "WR: use target address when intiating transfer, i2c_tx_target\n"); - writel(reg & ~bit_mask, i2c->base + IC_TAR); - } - - /* set target address to the I2C slave address */ - dev_dbg(&adap->dev, - "set target address to the I2C slave address, addr is %x\n", - pmsg->addr); - writel(pmsg->addr | (pmsg->flags & I2C_M_TEN ? IC_TAR_10BIT_ADDR : 0), - i2c->base + IC_TAR); - - /* Enable I2C controller */ - writel(ENABLE, i2c->base + IC_ENABLE); - - return 0; -} - -/** - * intel_mid_i2c_xfer - Main master transfer routine. - * @adap: i2c_adapter struct pointer - * @pmsg: i2c_msg struct pointer - * @num: number of i2c_msg - * - * Return Values: - * + number of messages transferred - * -ETIMEDOUT If cannot disable I2C controller or read IC_STATUS - * -EINVAL If the address in i2c_msg is invalid - * - * This function will be registered in i2c-core and exposed to external - * I2C clients. - * 1. Disable I2C controller - * 2. Unmask three interrupts: RX_FULL, TX_EMPTY, TX_ABRT - * 3. Check if address in i2c_msg is valid - * 4. Enable I2C controller - * 5. Perform real transfer (call xfer_read or xfer_write) - * 6. Wait until the current transfer is finished (check bus state) - * 7. Mask and clear all interrupts - */ -static int intel_mid_i2c_xfer(struct i2c_adapter *adap, - struct i2c_msg *pmsg, - int num) -{ - struct intel_mid_i2c_private *i2c = i2c_get_adapdata(adap); - int i, err = 0; - - /* if number of messages equal 0*/ - if (num == 0) - return 0; - - pm_runtime_get(i2c->dev); - - mutex_lock(&i2c->lock); - dev_dbg(&adap->dev, "intel_mid_i2c_xfer, process %d msg(s)\n", num); - dev_dbg(&adap->dev, "slave address is %x\n", pmsg->addr); - - - if (i2c->status != STATUS_IDLE) { - dev_err(&adap->dev, "Adapter %d in transfer/standby\n", - adap->nr); - mutex_unlock(&i2c->lock); - pm_runtime_put(i2c->dev); - return -1; - } - - - for (i = 1; i < num; i++) { - /* Message address equal? */ - if (unlikely(intel_mid_i2c_address_neq(&pmsg[0], &pmsg[i]))) { - dev_err(&adap->dev, "Invalid address in msg[%d]\n", i); - mutex_unlock(&i2c->lock); - pm_runtime_put(i2c->dev); - return -EINVAL; - } - } - - if (intel_mid_i2c_setup(adap, pmsg)) { - mutex_unlock(&i2c->lock); - pm_runtime_put(i2c->dev); - return -EINVAL; - } - - for (i = 0; i < num; i++) { - i2c->msg = pmsg; - i2c->status = STATUS_IDLE; - /* Read or Write */ - if (pmsg->flags & I2C_M_RD) { - dev_dbg(&adap->dev, "I2C_M_RD\n"); - err = xfer_read(adap, pmsg->buf, pmsg->len); - } else { - dev_dbg(&adap->dev, "I2C_M_WR\n"); - err = xfer_write(adap, pmsg->buf, pmsg->len); - } - if (err < 0) - break; - dev_dbg(&adap->dev, "msg[%d] transfer complete\n", i); - pmsg++; /* next message */ - } - - /* Mask interrupts */ - writel(0x0000, i2c->base + IC_INTR_MASK); - /* Clear all interrupts */ - readl(i2c->base + IC_CLR_INTR); - - i2c->status = STATUS_IDLE; - mutex_unlock(&i2c->lock); - pm_runtime_put(i2c->dev); - - return err; -} - -static int intel_mid_i2c_runtime_suspend(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev); - struct i2c_adapter *adap = to_i2c_adapter(dev); - int err; - - if (i2c->status != STATUS_IDLE) - return -1; - - intel_mid_i2c_disable(adap); - - err = pci_save_state(pdev); - if (err) { - dev_err(dev, "pci_save_state failed\n"); - return err; - } - - err = pci_set_power_state(pdev, PCI_D3hot); - if (err) { - dev_err(dev, "pci_set_power_state failed\n"); - return err; - } - i2c->status = STATUS_STANDBY; - - return 0; -} - -static int intel_mid_i2c_runtime_resume(struct device *dev) -{ - struct pci_dev *pdev = to_pci_dev(dev); - struct intel_mid_i2c_private *i2c = pci_get_drvdata(pdev); - int err; - - if (i2c->status != STATUS_STANDBY) - return 0; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - err = pci_enable_device(pdev); - if (err) { - dev_err(dev, "pci_enable_device failed\n"); - return err; - } - - i2c->status = STATUS_IDLE; - - intel_mid_i2c_hwinit(i2c); - return err; -} - -static void i2c_isr_read(struct intel_mid_i2c_private *i2c) -{ - struct i2c_msg *msg = i2c->msg; - int rx_num; - u32 len; - u8 *buf; - - if (!(msg->flags & I2C_M_RD)) - return; - - if (i2c->status != STATUS_READ_IN_PROGRESS) { - len = msg->len; - buf = msg->buf; - } else { - len = i2c->rx_buf_len; - buf = i2c->rx_buf; - } - - rx_num = readl(i2c->base + IC_RXFLR); - - for (; len > 0 && rx_num > 0; len--, rx_num--) - *buf++ = readl(i2c->base + IC_DATA_CMD); - - if (len > 0) { - i2c->status = STATUS_READ_IN_PROGRESS; - i2c->rx_buf_len = len; - i2c->rx_buf = buf; - } else - i2c->status = STATUS_READ_SUCCESS; - - return; -} - -static irqreturn_t intel_mid_i2c_isr(int this_irq, void *dev) -{ - struct intel_mid_i2c_private *i2c = dev; - u32 stat = readl(i2c->base + IC_INTR_STAT); - - if (!stat) - return IRQ_NONE; - - dev_dbg(&i2c->adap.dev, "%s, stat = 0x%x\n", __func__, stat); - stat &= 0x54; - - if (i2c->status != STATUS_WRITE_START && - i2c->status != STATUS_READ_START && - i2c->status != STATUS_READ_IN_PROGRESS) - goto err; - - if (stat & TX_ABRT) - i2c->abort = readl(i2c->base + IC_TX_ABRT_SOURCE); - - readl(i2c->base + IC_CLR_INTR); - - if (stat & TX_ABRT) { - intel_mid_i2c_abort(i2c); - goto exit; - } - - if (stat & RX_FULL) { - i2c_isr_read(i2c); - goto exit; - } - - if (stat & TX_EMPTY) { - if (readl(i2c->base + IC_STATUS) & 0x4) - i2c->status = STATUS_WRITE_SUCCESS; - } - -exit: - if (i2c->status == STATUS_READ_SUCCESS || - i2c->status == STATUS_WRITE_SUCCESS || - i2c->status == STATUS_XFER_ABORT) { - /* Clear all interrupts */ - readl(i2c->base + IC_CLR_INTR); - /* Mask interrupts */ - writel(0, i2c->base + IC_INTR_MASK); - complete(&i2c->complete); - } -err: - return IRQ_HANDLED; -} - -static struct i2c_algorithm intel_mid_i2c_algorithm = { - .master_xfer = intel_mid_i2c_xfer, - .functionality = intel_mid_i2c_func, -}; - - -static const struct dev_pm_ops intel_mid_i2c_pm_ops = { - .runtime_suspend = intel_mid_i2c_runtime_suspend, - .runtime_resume = intel_mid_i2c_runtime_resume, -}; - -/** - * intel_mid_i2c_probe - I2C controller initialization routine - * @dev: pci device - * @id: device id - * - * Return Values: - * 0 success - * -ENODEV If cannot allocate pci resource - * -ENOMEM If the register base remapping failed, or - * if kzalloc failed - * - * Initialization steps: - * 1. Request for PCI resource - * 2. Remap the start address of PCI resource to register base - * 3. Request for device memory region - * 4. Fill in the struct members of intel_mid_i2c_private - * 5. Call intel_mid_i2c_hwinit() for hardware initialization - * 6. Register I2C adapter in i2c-core - */ -static int intel_mid_i2c_probe(struct pci_dev *dev, - const struct pci_device_id *id) -{ - struct intel_mid_i2c_private *mrst; - unsigned long start, len; - int err, busnum; - void __iomem *base = NULL; - - dev_dbg(&dev->dev, "Get into probe function for I2C\n"); - err = pci_enable_device(dev); - if (err) { - dev_err(&dev->dev, "Failed to enable I2C PCI device (%d)\n", - err); - goto exit; - } - - /* Determine the address of the I2C area */ - start = pci_resource_start(dev, 0); - len = pci_resource_len(dev, 0); - if (!start || len == 0) { - dev_err(&dev->dev, "base address not set\n"); - err = -ENODEV; - goto exit; - } - dev_dbg(&dev->dev, "%s i2c resource start 0x%lx, len=%ld\n", - PLATFORM, start, len); - - err = pci_request_region(dev, 0, DRIVER_NAME); - if (err) { - dev_err(&dev->dev, "failed to request I2C region " - "0x%lx-0x%lx\n", start, - (unsigned long)pci_resource_end(dev, 0)); - goto exit; - } - - base = ioremap_nocache(start, len); - if (!base) { - dev_err(&dev->dev, "I/O memory remapping failed\n"); - err = -ENOMEM; - goto fail0; - } - - /* Allocate the per-device data structure, intel_mid_i2c_private */ - mrst = kzalloc(sizeof(struct intel_mid_i2c_private), GFP_KERNEL); - if (mrst == NULL) { - dev_err(&dev->dev, "can't allocate interface\n"); - err = -ENOMEM; - goto fail1; - } - - /* Initialize struct members */ - snprintf(mrst->adap.name, sizeof(mrst->adap.name), - "Intel MID I2C at %lx", start); - mrst->adap.owner = THIS_MODULE; - mrst->adap.algo = &intel_mid_i2c_algorithm; - mrst->adap.dev.parent = &dev->dev; - mrst->dev = &dev->dev; - mrst->base = base; - mrst->speed = STANDARD; - mrst->abort = 0; - mrst->rx_buf_len = 0; - mrst->status = STATUS_IDLE; - - pci_set_drvdata(dev, mrst); - i2c_set_adapdata(&mrst->adap, mrst); - - mrst->adap.nr = busnum = id->driver_data; - if (dev->device <= 0x0804) - mrst->platform = MOORESTOWN; - else - mrst->platform = MEDFIELD; - - dev_dbg(&dev->dev, "I2C%d\n", busnum); - - if (ctl_num > busnum) { - if (speed_mode[busnum] < 0 || speed_mode[busnum] >= NUM_SPEEDS) - dev_warn(&dev->dev, "invalid speed %d ignored.\n", - speed_mode[busnum]); - else - mrst->speed = speed_mode[busnum]; - } - - /* Initialize i2c controller */ - err = intel_mid_i2c_hwinit(mrst); - if (err < 0) { - dev_err(&dev->dev, "I2C interface initialization failed\n"); - goto fail2; - } - - mutex_init(&mrst->lock); - init_completion(&mrst->complete); - - /* Clear all interrupts */ - readl(mrst->base + IC_CLR_INTR); - writel(0x0000, mrst->base + IC_INTR_MASK); - - err = request_irq(dev->irq, intel_mid_i2c_isr, IRQF_SHARED, - mrst->adap.name, mrst); - if (err) { - dev_err(&dev->dev, "Failed to request IRQ for I2C controller: " - "%s", mrst->adap.name); - goto fail2; - } - - /* Adapter registration */ - err = i2c_add_numbered_adapter(&mrst->adap); - if (err) { - dev_err(&dev->dev, "Adapter %s registration failed\n", - mrst->adap.name); - goto fail3; - } - - dev_dbg(&dev->dev, "%s I2C bus %d driver bind success.\n", - (mrst->platform == MOORESTOWN) ? "Moorestown" : "Medfield", - busnum); - - pm_runtime_enable(&dev->dev); - return 0; - -fail3: - free_irq(dev->irq, mrst); -fail2: - kfree(mrst); -fail1: - iounmap(base); -fail0: - pci_release_region(dev, 0); -exit: - return err; -} - -static void intel_mid_i2c_remove(struct pci_dev *dev) -{ - struct intel_mid_i2c_private *mrst = pci_get_drvdata(dev); - intel_mid_i2c_disable(&mrst->adap); - i2c_del_adapter(&mrst->adap); - - free_irq(dev->irq, mrst); - iounmap(mrst->base); - kfree(mrst); - pci_release_region(dev, 0); -} - -static DEFINE_PCI_DEVICE_TABLE(intel_mid_i2c_ids) = { - /* Moorestown */ - { PCI_VDEVICE(INTEL, 0x0802), 0 }, - { PCI_VDEVICE(INTEL, 0x0803), 1 }, - { PCI_VDEVICE(INTEL, 0x0804), 2 }, - /* Medfield */ - { PCI_VDEVICE(INTEL, 0x0817), 3,}, - { PCI_VDEVICE(INTEL, 0x0818), 4 }, - { PCI_VDEVICE(INTEL, 0x0819), 5 }, - { PCI_VDEVICE(INTEL, 0x082C), 0 }, - { PCI_VDEVICE(INTEL, 0x082D), 1 }, - { PCI_VDEVICE(INTEL, 0x082E), 2 }, - { 0,} -}; -MODULE_DEVICE_TABLE(pci, intel_mid_i2c_ids); - -static struct pci_driver intel_mid_i2c_driver = { - .name = DRIVER_NAME, - .id_table = intel_mid_i2c_ids, - .probe = intel_mid_i2c_probe, - .remove = intel_mid_i2c_remove, -}; - -module_pci_driver(intel_mid_i2c_driver); - -MODULE_AUTHOR("Ba Zheng "); -MODULE_DESCRIPTION("I2C driver for Moorestown Platform"); -MODULE_LICENSE("GPL"); -MODULE_VERSION(VERSION); -- cgit From d5ac456144413950d2d32ec4f22542e45be13cd7 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 16 May 2013 10:32:08 +0000 Subject: I2C: mv64xxx: use return value from mv64xxx_i2c_map_regs() mv64xxx_i2c_map_regs() already returns an error code, so lets propagate that to mv64xxx_i2c_probe()'s caller. Signed-off-by: Russell King Acked-by: Mark A. Greer Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 1a3abd6a0bfc..940a190b1a53 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -619,10 +619,9 @@ mv64xxx_i2c_probe(struct platform_device *pd) if (!drv_data) return -ENOMEM; - if (mv64xxx_i2c_map_regs(pd, drv_data)) { - rc = -ENODEV; + rc = mv64xxx_i2c_map_regs(pd, drv_data); + if (rc) goto exit_kfree; - } strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter", sizeof(drv_data->adapter.name)); -- cgit From 16874b0709c7c78489de1f502edd33acad2918e8 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 16 May 2013 21:33:09 +0100 Subject: I2C: mv64xxx: use devm_ioremap_resource() Eliminate reg_base_p and reg_size, mv64xxx_i2c_unmap_regs() and an unchecked ioremap() return from this driver by using the devm_* API for requesting and ioremapping resources. Signed-off-by: Russell King Acked-by: Mark A. Greer Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 46 ++++++---------------------------------- 1 file changed, 6 insertions(+), 40 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 940a190b1a53..54b8cf6b6dd0 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -92,8 +92,6 @@ struct mv64xxx_i2c_data { u32 aborting; u32 cntl_bits; void __iomem *reg_base; - u32 reg_base_p; - u32 reg_size; u32 addr1; u32 addr2; u32 bytes_left; @@ -495,40 +493,6 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = { * ***************************************************************************** */ -static int -mv64xxx_i2c_map_regs(struct platform_device *pd, - struct mv64xxx_i2c_data *drv_data) -{ - int size; - struct resource *r = platform_get_resource(pd, IORESOURCE_MEM, 0); - - if (!r) - return -ENODEV; - - size = resource_size(r); - - if (!request_mem_region(r->start, size, drv_data->adapter.name)) - return -EBUSY; - - drv_data->reg_base = ioremap(r->start, size); - drv_data->reg_base_p = r->start; - drv_data->reg_size = size; - - return 0; -} - -static void -mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data) -{ - if (drv_data->reg_base) { - iounmap(drv_data->reg_base); - release_mem_region(drv_data->reg_base_p, drv_data->reg_size); - } - - drv_data->reg_base = NULL; - drv_data->reg_base_p = 0; -} - #ifdef CONFIG_OF static int mv64xxx_calc_freq(const int tclk, const int n, const int m) @@ -610,6 +574,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) { struct mv64xxx_i2c_data *drv_data; struct mv64xxx_i2c_pdata *pdata = pd->dev.platform_data; + struct resource *r; int rc; if ((!pdata && !pd->dev.of_node)) @@ -619,9 +584,12 @@ mv64xxx_i2c_probe(struct platform_device *pd) if (!drv_data) return -ENOMEM; - rc = mv64xxx_i2c_map_regs(pd, drv_data); - if (rc) + r = platform_get_resource(pd, IORESOURCE_MEM, 0); + drv_data->reg_base = devm_ioremap_resource(&pd->dev, r); + if (IS_ERR(drv_data->reg_base)) { + rc = PTR_ERR(drv_data->reg_base); goto exit_kfree; + } strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter", sizeof(drv_data->adapter.name)); @@ -690,7 +658,6 @@ mv64xxx_i2c_probe(struct platform_device *pd) clk_unprepare(drv_data->clk); } #endif - mv64xxx_i2c_unmap_regs(drv_data); exit_kfree: kfree(drv_data); return rc; @@ -703,7 +670,6 @@ mv64xxx_i2c_remove(struct platform_device *dev) i2c_del_adapter(&drv_data->adapter); free_irq(drv_data->irq, drv_data); - mv64xxx_i2c_unmap_regs(drv_data); #if defined(CONFIG_HAVE_CLK) /* Not all platforms have a clk */ if (!IS_ERR(drv_data->clk)) { -- cgit From 4c5c95f53b5cb5666906242a63d4d2c4fd0a0be8 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 16 May 2013 21:34:10 +0100 Subject: I2C: mv64xxx: use devm_clk_get() to avoid missing clk_put() This driver forgets to use clk_put(). Rather than adding clk_put(), lets instead use devm_clk_get() to obtain this clock so that it's automatically handled on cleanup. Signed-off-by: Russell King Acked-by: Mark A. Greer Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 54b8cf6b6dd0..25e64c445e61 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -599,7 +599,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) #if defined(CONFIG_HAVE_CLK) /* Not all platforms have a clk */ - drv_data->clk = clk_get(&pd->dev, NULL); + drv_data->clk = devm_clk_get(&pd->dev, NULL); if (!IS_ERR(drv_data->clk)) { clk_prepare(drv_data->clk); clk_enable(drv_data->clk); -- cgit From 2c911103040faad9d092a72b9f4503f92154c1dc Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 16 May 2013 21:35:10 +0100 Subject: I2C: mv64xxx: use devm_kzalloc() As we're changing to using devm_* APIs to fix various problems in this driver, lets also do devm_kzalloc() while we're here too. Signed-off-by: Russell King Acked-by: Mark A. Greer Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 25e64c445e61..640b49df2ddd 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -580,16 +580,15 @@ mv64xxx_i2c_probe(struct platform_device *pd) if ((!pdata && !pd->dev.of_node)) return -ENODEV; - drv_data = kzalloc(sizeof(struct mv64xxx_i2c_data), GFP_KERNEL); + drv_data = devm_kzalloc(&pd->dev, sizeof(struct mv64xxx_i2c_data), + GFP_KERNEL); if (!drv_data) return -ENOMEM; r = platform_get_resource(pd, IORESOURCE_MEM, 0); drv_data->reg_base = devm_ioremap_resource(&pd->dev, r); - if (IS_ERR(drv_data->reg_base)) { - rc = PTR_ERR(drv_data->reg_base); - goto exit_kfree; - } + if (IS_ERR(drv_data->reg_base)) + return PTR_ERR(drv_data->reg_base); strlcpy(drv_data->adapter.name, MV64XXX_I2C_CTLR_NAME " adapter", sizeof(drv_data->adapter.name)); @@ -613,11 +612,11 @@ mv64xxx_i2c_probe(struct platform_device *pd) } else if (pd->dev.of_node) { rc = mv64xxx_of_config(drv_data, pd->dev.of_node); if (rc) - goto exit_unmap_regs; + goto exit_clk; } if (drv_data->irq < 0) { rc = -ENXIO; - goto exit_unmap_regs; + goto exit_clk; } drv_data->adapter.dev.parent = &pd->dev; @@ -637,7 +636,7 @@ mv64xxx_i2c_probe(struct platform_device *pd) "mv64xxx: Can't register intr handler irq: %d\n", drv_data->irq); rc = -EINVAL; - goto exit_unmap_regs; + goto exit_clk; } else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) { dev_err(&drv_data->adapter.dev, "mv64xxx: Can't add i2c adapter, rc: %d\n", -rc); @@ -648,9 +647,9 @@ mv64xxx_i2c_probe(struct platform_device *pd) return 0; - exit_free_irq: - free_irq(drv_data->irq, drv_data); - exit_unmap_regs: +exit_free_irq: + free_irq(drv_data->irq, drv_data); +exit_clk: #if defined(CONFIG_HAVE_CLK) /* Not all platforms have a clk */ if (!IS_ERR(drv_data->clk)) { @@ -658,8 +657,6 @@ mv64xxx_i2c_probe(struct platform_device *pd) clk_unprepare(drv_data->clk); } #endif - exit_kfree: - kfree(drv_data); return rc; } @@ -677,7 +674,6 @@ mv64xxx_i2c_remove(struct platform_device *dev) clk_unprepare(drv_data->clk); } #endif - kfree(drv_data); return 0; } -- cgit From 0c195afb8741c32974266ba7c964481ba418b4b5 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 16 May 2013 21:36:11 +0100 Subject: I2C: mv64xxx: fix error handling for request_irq() Propagate the error code from request_irq() rather than ignoring it entirely. Signed-off-by: Russell King Acked-by: Mark A. Greer Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 640b49df2ddd..4b45c7363501 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -630,12 +630,12 @@ mv64xxx_i2c_probe(struct platform_device *pd) mv64xxx_i2c_hw_init(drv_data); - if (request_irq(drv_data->irq, mv64xxx_i2c_intr, 0, - MV64XXX_I2C_CTLR_NAME, drv_data)) { + rc = request_irq(drv_data->irq, mv64xxx_i2c_intr, 0, + MV64XXX_I2C_CTLR_NAME, drv_data); + if (rc) { dev_err(&drv_data->adapter.dev, - "mv64xxx: Can't register intr handler irq: %d\n", - drv_data->irq); - rc = -EINVAL; + "mv64xxx: Can't register intr handler irq%d: %d\n", + drv_data->irq, rc); goto exit_clk; } else if ((rc = i2c_add_numbered_adapter(&drv_data->adapter)) != 0) { dev_err(&drv_data->adapter.dev, -- cgit From aa6bce5319a54c050af26e095287472854abccfd Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 16 May 2013 21:37:11 +0100 Subject: I2C: mv64xxx: remove I2C_M_NOSTART code As this driver does not advertise protocol mangling support (I2C_FUNC_PROTOCOL_MANGLING is not set), having code to act on I2C_M_NOSTART is illogical, and in any case isn't supportable on anything but the first message - which makes no sense. Remove the I2C_M_NOSTART code. Signed-off-by: Russell King Acked-by: Mark A. Greer Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 4b45c7363501..f11cb25c3295 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -419,28 +419,12 @@ mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg, spin_lock_irqsave(&drv_data->lock, flags); mv64xxx_i2c_prepare_for_io(drv_data, msg); - if (unlikely(msg->flags & I2C_M_NOSTART)) { /* Skip start/addr phases */ - if (drv_data->msg->flags & I2C_M_RD) { - /* No action to do, wait for slave to send a byte */ - drv_data->action = MV64XXX_I2C_ACTION_CONTINUE; - drv_data->state = - MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_DATA; - } else { - drv_data->action = MV64XXX_I2C_ACTION_SEND_DATA; - drv_data->state = - MV64XXX_I2C_STATE_WAITING_FOR_SLAVE_ACK; - drv_data->bytes_left--; - } + if (is_first) { + drv_data->action = MV64XXX_I2C_ACTION_SEND_START; + drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; } else { - if (is_first) { - drv_data->action = MV64XXX_I2C_ACTION_SEND_START; - drv_data->state = - MV64XXX_I2C_STATE_WAITING_FOR_START_COND; - } else { - drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1; - drv_data->state = - MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK; - } + drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1; + drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK; } drv_data->send_stop = is_last; -- cgit From 3420afbc06058c9c13f7d69cf48b9d5429db6bd9 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 16 May 2013 21:38:11 +0100 Subject: I2C: mv64xxx: move mv64xxx_i2c_prepare_for_io() Move mv64xxx_i2c_prepare_for_io() higher up in the driver to avoid a future forward declaration for this function. Signed-off-by: Russell King Acked-by: Mark A. Greer Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 52 ++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index f11cb25c3295..bb37e14f3fbd 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -110,6 +110,32 @@ struct mv64xxx_i2c_data { struct i2c_adapter adapter; }; +static void +mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data, + struct i2c_msg *msg) +{ + u32 dir = 0; + + drv_data->msg = msg; + drv_data->byte_posn = 0; + drv_data->bytes_left = msg->len; + drv_data->aborting = 0; + drv_data->rc = 0; + drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK | + MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN; + + if (msg->flags & I2C_M_RD) + dir = 1; + + if (msg->flags & I2C_M_TEN) { + drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir; + drv_data->addr2 = (u32)msg->addr & 0xff; + } else { + drv_data->addr1 = ((u32)msg->addr & 0x7f) << 1 | dir; + drv_data->addr2 = 0; + } +} + /* ***************************************************************************** * @@ -346,32 +372,6 @@ mv64xxx_i2c_intr(int irq, void *dev_id) * ***************************************************************************** */ -static void -mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data, - struct i2c_msg *msg) -{ - u32 dir = 0; - - drv_data->msg = msg; - drv_data->byte_posn = 0; - drv_data->bytes_left = msg->len; - drv_data->aborting = 0; - drv_data->rc = 0; - drv_data->cntl_bits = MV64XXX_I2C_REG_CONTROL_ACK | - MV64XXX_I2C_REG_CONTROL_INTEN | MV64XXX_I2C_REG_CONTROL_TWSIEN; - - if (msg->flags & I2C_M_RD) - dir = 1; - - if (msg->flags & I2C_M_TEN) { - drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir; - drv_data->addr2 = (u32)msg->addr & 0xff; - } else { - drv_data->addr1 = ((u32)msg->addr & 0x7f) << 1 | dir; - drv_data->addr2 = 0; - } -} - static void mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data) { -- cgit From 4243fa0bad551b8c8d4ff7104e8fd557ae848845 Mon Sep 17 00:00:00 2001 From: Russell King Date: Thu, 16 May 2013 21:39:12 +0100 Subject: I2C: mv64xxx: fix race between FSM/interrupt and process context Asking for a multi-part message to be handled by this driver is racy; it has been observed that the following sequence is possible with this driver: - send start - send address + write - send data - send (repeated) start - send address + write - send (repeated) start - send address + read - unrecoverable bus hang (except by system reset) The problem is that the interrupt handling sees the next event after the first repeated start is sent - the IFLG bit is set in the register even though INTEN is disabled. Let's fix this by moving all of the message processing into interrupt context, rather than having it partly in IRQ and partly in process context. This allows us to move immediately to the next message in the interrupt handler and get on with the transfer, rather than incuring a couple of scheduling switches to get the next message. Signed-off-by: Russell King Acked-by: Mark A. Greer Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 54 +++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index bb37e14f3fbd..6356439454ee 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -86,6 +86,8 @@ enum { }; struct mv64xxx_i2c_data { + struct i2c_msg *msgs; + int num_msgs; int irq; u32 state; u32 action; @@ -194,7 +196,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) if ((drv_data->bytes_left == 0) || (drv_data->aborting && (drv_data->byte_posn != 0))) { - if (drv_data->send_stop) { + if (drv_data->send_stop || drv_data->aborting) { drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; drv_data->state = MV64XXX_I2C_STATE_IDLE; } else { @@ -271,12 +273,25 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) { switch(drv_data->action) { case MV64XXX_I2C_ACTION_SEND_RESTART: + /* We should only get here if we have further messages */ + BUG_ON(drv_data->num_msgs == 0); + drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START; - drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; writel(drv_data->cntl_bits, drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); - drv_data->block = 0; - wake_up(&drv_data->waitq); + + drv_data->msgs++; + drv_data->num_msgs--; + + /* Setup for the next message */ + mv64xxx_i2c_prepare_for_io(drv_data, drv_data->msgs); + + /* + * We're never at the start of the message here, and by this + * time it's already too late to do any protocol mangling. + * Thankfully, do not advertise support for that feature. + */ + drv_data->send_stop = drv_data->num_msgs == 1; break; case MV64XXX_I2C_ACTION_CONTINUE: @@ -412,20 +427,15 @@ mv64xxx_i2c_wait_for_completion(struct mv64xxx_i2c_data *drv_data) static int mv64xxx_i2c_execute_msg(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg, - int is_first, int is_last) + int is_last) { unsigned long flags; spin_lock_irqsave(&drv_data->lock, flags); mv64xxx_i2c_prepare_for_io(drv_data, msg); - if (is_first) { - drv_data->action = MV64XXX_I2C_ACTION_SEND_START; - drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; - } else { - drv_data->action = MV64XXX_I2C_ACTION_SEND_ADDR_1; - drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_ADDR_1_ACK; - } + drv_data->action = MV64XXX_I2C_ACTION_SEND_START; + drv_data->state = MV64XXX_I2C_STATE_WAITING_FOR_START_COND; drv_data->send_stop = is_last; drv_data->block = 1; @@ -453,16 +463,20 @@ static int mv64xxx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) { struct mv64xxx_i2c_data *drv_data = i2c_get_adapdata(adap); - int i, rc; + int rc, ret = num; - for (i = 0; i < num; i++) { - rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[i], - i == 0, i + 1 == num); - if (rc < 0) - return rc; - } + BUG_ON(drv_data->msgs != NULL); + drv_data->msgs = msgs; + drv_data->num_msgs = num; + + rc = mv64xxx_i2c_execute_msg(drv_data, &msgs[0], num == 1); + if (rc < 0) + ret = rc; + + drv_data->num_msgs = 0; + drv_data->msgs = NULL; - return num; + return ret; } static const struct i2c_algorithm mv64xxx_i2c_algo = { -- cgit From 76b1f723c4f54c2ab05307da3cc5c39e421b029b Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 6 May 2013 15:05:50 -0300 Subject: i2c: imx: Let device core handle pinctrl Since commit ab78029 (drivers/pinctrl: grab default handles from device core), we can rely on device core for handling pinctrl. So remove devm_pinctrl_get_select_default() from the driver. Signed-off-by: Fabio Estevam Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 82f20c60bb7b..8c7526ca912e 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -51,7 +51,6 @@ #include #include #include -#include #include /** Defines ******************************************************************** @@ -493,7 +492,6 @@ static int __init i2c_imx_probe(struct platform_device *pdev) struct imx_i2c_struct *i2c_imx; struct resource *res; struct imxi2c_platform_data *pdata = pdev->dev.platform_data; - struct pinctrl *pinctrl; void __iomem *base; int irq, ret; u32 bitrate; @@ -535,12 +533,6 @@ static int __init i2c_imx_probe(struct platform_device *pdev) i2c_imx->adapter.dev.of_node = pdev->dev.of_node; i2c_imx->base = base; - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) { - dev_err(&pdev->dev, "can't get/select pinctrl\n"); - return PTR_ERR(pinctrl); - } - /* Get I2C clock */ i2c_imx->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(i2c_imx->clk)) { -- cgit From dfda7d8f09323163cad26dd35fe6293b4f7cee85 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 6 May 2013 15:05:51 -0300 Subject: i2c: mxs: Let device core handle pinctrl Since commit ab78029 (drivers/pinctrl: grab default handles from device core), we can rely on device core for handling pinctrl. So remove devm_pinctrl_get_select_default() from the driver. Signed-off-by: Fabio Estevam Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mxs.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c index 2039f230482d..df8ff5aea5b5 100644 --- a/drivers/i2c/busses/i2c-mxs.c +++ b/drivers/i2c/busses/i2c-mxs.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include #include @@ -638,15 +637,10 @@ static int mxs_i2c_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct mxs_i2c_dev *i2c; struct i2c_adapter *adap; - struct pinctrl *pinctrl; struct resource *res; resource_size_t res_size; int err, irq; - pinctrl = devm_pinctrl_get_select_default(dev); - if (IS_ERR(pinctrl)) - return PTR_ERR(pinctrl); - i2c = devm_kzalloc(dev, sizeof(struct mxs_i2c_dev), GFP_KERNEL); if (!i2c) return -ENOMEM; -- cgit From e42dba569fceca5d59a88571370785e9ce9775b8 Mon Sep 17 00:00:00 2001 From: Mika Westerberg Date: Wed, 22 May 2013 13:03:11 +0300 Subject: i2c: designware: prevent signals from aborting I2C transfers If a process receives signal while it is waiting for I2C transfer to complete, an error is returned to the caller and the transfer is aborted. This can cause the driver to fail subsequent transfers. Also according to commit d295a86eab2 (i2c: mv64xxx: work around signals causing I2C transactions to be aborted) I2C drivers aren't supposed to abort transactions on signals. To prevent this switch to use wait_for_completion_timeout() instead of wait_for_completion_interruptible_timeout() in the designware I2C driver. Signed-off-by: Mika Westerberg Reviewed-by: Christian Ruppert Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-core.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index c41ca6354fc5..db20a2841b75 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -580,14 +580,13 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) i2c_dw_xfer_init(dev); /* wait for tx to complete */ - ret = wait_for_completion_interruptible_timeout(&dev->cmd_complete, HZ); + ret = wait_for_completion_timeout(&dev->cmd_complete, HZ); if (ret == 0) { dev_err(dev->dev, "controller timed out\n"); i2c_dw_init(dev); ret = -ETIMEDOUT; goto done; - } else if (ret < 0) - goto done; + } if (dev->msg_err) { ret = dev->msg_err; -- cgit From 3cc2d009bc210516c61536273b304c4f6ccd797c Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Fri, 10 May 2013 10:16:54 +0200 Subject: drivers/i2c/busses: don't check resource with devm_ioremap_resource devm_ioremap_resource does sanity checks on the given resource. No need to duplicate this in the driver. Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-davinci.c | 8 +------- drivers/i2c/busses/i2c-designware-platdrv.c | 8 +------- drivers/i2c/busses/i2c-imx.c | 6 +----- drivers/i2c/busses/i2c-omap.c | 8 +------- drivers/i2c/busses/i2c-rcar.c | 7 +------ 5 files changed, 5 insertions(+), 32 deletions(-) diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c index cf20e06a88e1..fa556057d224 100644 --- a/drivers/i2c/busses/i2c-davinci.c +++ b/drivers/i2c/busses/i2c-davinci.c @@ -646,13 +646,6 @@ static int davinci_i2c_probe(struct platform_device *pdev) struct resource *mem, *irq; int r; - /* NOTE: driver uses the static register mapping */ - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "no mem resource?\n"); - return -ENODEV; - } - irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); if (!irq) { dev_err(&pdev->dev, "no irq resource?\n"); @@ -697,6 +690,7 @@ static int davinci_i2c_probe(struct platform_device *pdev) return -ENODEV; clk_prepare_enable(dev->clk); + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->base = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(dev->base)) { r = PTR_ERR(dev->base); diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index 35b70a1edf57..ee46c92d7e3c 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -87,13 +87,6 @@ static int dw_i2c_probe(struct platform_device *pdev) struct resource *mem; int irq, r; - /* NOTE: driver uses the static register mapping */ - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "no mem resource?\n"); - return -EINVAL; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no irq resource?\n"); @@ -104,6 +97,7 @@ static int dw_i2c_probe(struct platform_device *pdev) if (!dev) return -ENOMEM; + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->base = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(dev->base)) return PTR_ERR(dev->base); diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 8c7526ca912e..6406aa960f2a 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -498,17 +498,13 @@ static int __init i2c_imx_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "<%s>\n", __func__); - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "can't get device resources\n"); - return -ENOENT; - } irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "can't get irq number\n"); return -ENOENT; } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) return PTR_ERR(base); diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index e02f9e36a7b2..352f3c38d1f7 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -1084,13 +1084,6 @@ omap_i2c_probe(struct platform_device *pdev) u32 rev; u16 minor, major, scheme; - /* NOTE: driver uses the static register mapping */ - mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mem) { - dev_err(&pdev->dev, "no mem resource?\n"); - return -ENODEV; - } - irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "no irq resource?\n"); @@ -1103,6 +1096,7 @@ omap_i2c_probe(struct platform_device *pdev) return -ENOMEM; } + mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); dev->base = devm_ioremap_resource(&pdev->dev, mem); if (IS_ERR(dev->base)) return PTR_ERR(dev->base); diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c index 4ba4a95b6b26..0fc585861610 100644 --- a/drivers/i2c/busses/i2c-rcar.c +++ b/drivers/i2c/busses/i2c-rcar.c @@ -623,12 +623,6 @@ static int rcar_i2c_probe(struct platform_device *pdev) u32 bus_speed; int ret; - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(dev, "no mmio resources\n"); - return -ENODEV; - } - priv = devm_kzalloc(dev, sizeof(struct rcar_i2c_priv), GFP_KERNEL); if (!priv) { dev_err(dev, "no mem for private data\n"); @@ -642,6 +636,7 @@ static int rcar_i2c_probe(struct platform_device *pdev) if (ret < 0) return ret; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); priv->io = devm_ioremap_resource(dev, res); if (IS_ERR(priv->io)) return PTR_ERR(priv->io); -- cgit From c2c64954723b9d365f35f36c0cd089e740bb0a0a Mon Sep 17 00:00:00 2001 From: Jingoo Han Date: Thu, 23 May 2013 19:22:40 +0900 Subject: i2c: use platform_{get,set}_drvdata() Use the wrapper functions for getting and setting the driver data using platform_device instead of using dev_{get,set}_drvdata() with &pdev->dev, so we can directly pass a struct platform_device. Signed-off-by: Jingoo Han Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-cpm.c | 4 ++-- drivers/i2c/busses/i2c-ibm_iic.c | 4 ++-- drivers/i2c/busses/i2c-mpc.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c index 3823623baa48..eccf5c2d4a12 100644 --- a/drivers/i2c/busses/i2c-cpm.c +++ b/drivers/i2c/busses/i2c-cpm.c @@ -646,7 +646,7 @@ static int cpm_i2c_probe(struct platform_device *ofdev) cpm->ofdev = ofdev; - dev_set_drvdata(&ofdev->dev, cpm); + platform_set_drvdata(ofdev, cpm); cpm->adap = cpm_ops; i2c_set_adapdata(&cpm->adap, cpm); @@ -689,7 +689,7 @@ out_free: static int cpm_i2c_remove(struct platform_device *ofdev) { - struct cpm_i2c *cpm = dev_get_drvdata(&ofdev->dev); + struct cpm_i2c *cpm = platform_get_drvdata(ofdev); i2c_del_adapter(&cpm->adap); diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c index 405a2e240454..973f51688276 100644 --- a/drivers/i2c/busses/i2c-ibm_iic.c +++ b/drivers/i2c/busses/i2c-ibm_iic.c @@ -705,7 +705,7 @@ static int iic_probe(struct platform_device *ofdev) return -ENOMEM; } - dev_set_drvdata(&ofdev->dev, dev); + platform_set_drvdata(ofdev, dev); dev->vaddr = of_iomap(np, 0); if (dev->vaddr == NULL) { @@ -782,7 +782,7 @@ error_cleanup: */ static int iic_remove(struct platform_device *ofdev) { - struct ibm_iic_private *dev = dev_get_drvdata(&ofdev->dev); + struct ibm_iic_private *dev = platform_get_drvdata(ofdev); i2c_del_adapter(&dev->adap); diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c index 5e705ee02f4a..7607dc061918 100644 --- a/drivers/i2c/busses/i2c-mpc.c +++ b/drivers/i2c/busses/i2c-mpc.c @@ -679,7 +679,7 @@ static int fsl_i2c_probe(struct platform_device *op) } dev_info(i2c->dev, "timeout %u us\n", mpc_ops.timeout * 1000000 / HZ); - dev_set_drvdata(&op->dev, i2c); + platform_set_drvdata(op, i2c); i2c->adap = mpc_ops; i2c_set_adapdata(&i2c->adap, i2c); @@ -707,7 +707,7 @@ static int fsl_i2c_probe(struct platform_device *op) static int fsl_i2c_remove(struct platform_device *op) { - struct mpc_i2c *i2c = dev_get_drvdata(&op->dev); + struct mpc_i2c *i2c = platform_get_drvdata(op); i2c_del_adapter(&i2c->adap); -- cgit From c80f52847c50109ca248c22efbf71ff10553dca4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 13 May 2013 22:18:21 +0200 Subject: i2c: core: make it possible to match a pure device tree driver This tries to address an issue found when writing an MFD driver for the Nomadik STw481x PMICs: as the platform is using device tree exclusively I want to specify the driver matching like this: static const struct of_device_id stw481x_match[] = { { .compatible = "st,stw4810", }, { .compatible = "st,stw4811", }, {}, }; static struct i2c_driver stw481x_driver = { .driver = { .name = "stw481x", .of_match_table = stw481x_match, }, .probe = stw481x_probe, .remove = stw481x_remove, }; However that turns out not to be possible: the I2C probe code is written so that the probe() call is always passed a match from i2c_match_id() using non-devicetree matches. This is probably why most devices using device tree for I2C clients currently will pass no .of_match_table *at all* but instead just use .id_table from struct i2c_driver to match the device. As you realize that means that the whole idea with compatible strings is discarded, and that is why we find strange device tree I2C device compatible strings like "product" instead of "vendor,product" as you could expect. Let's figure out how to fix this before the mess spreads. This patch will allow probeing devices with only an of_match_table as per above, and will pass NULL as the second argument to the probe() function. If the driver wants to deduce secondary info from the struct of_device_id .data field, it has to call of_match_device() on its own match table in the probe function device tree probe path. If drivers define both an .of_match_table *AND* a i2c_driver .id_table, the .of_match_table will take precedence, just as is done in the i2c_device_match() function in i2c-core.c. I2C devices probed from device tree should subsequently be fixed to handle the case where of_match_table() is used (I think none of them do that today), and platforms should fix their device trees to use compatible strings for I2C devices instead of setting the name to Linux device driver names as is done in multiple cases today. Cc: Rob Herring Cc: Grant Likely Signed-off-by: Linus Walleij Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 48e31ed69dbf..93fc5bfdb9b4 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -240,7 +240,7 @@ static int i2c_device_probe(struct device *dev) return 0; driver = to_i2c_driver(dev->driver); - if (!driver->probe || !driver->id_table) + if (!driver->probe || (!driver->id_table && !dev->driver->of_match_table)) return -ENODEV; client->driver = driver; if (!device_can_wakeup(&client->dev)) @@ -248,7 +248,12 @@ static int i2c_device_probe(struct device *dev) client->flags & I2C_CLIENT_WAKE); dev_dbg(dev, "probe\n"); - status = driver->probe(client, i2c_match_id(driver->id_table, client)); + if (of_match_device(dev->driver->of_match_table, dev)) + /* Device tree matching */ + status = driver->probe(client, NULL); + else + /* Fall back to matching the id_table */ + status = driver->probe(client, i2c_match_id(driver->id_table, client)); if (status) { client->driver = NULL; i2c_set_clientdata(client, NULL); -- cgit From 8419c8debdc600b71fb89f0ffad80a6f436d80fe Mon Sep 17 00:00:00 2001 From: Sonic Zhang Date: Tue, 28 May 2013 18:41:09 +0800 Subject: i2c: bfin-twi: Read and write the FIFO in loop TWI transfer interrupts may be lost when system is heavily handling other interrupts, while current transfer handler depends on each accurate interrupt and misses some data in this case. Because there are 2 2-byte FIFOs in blackfin TWI controller, the occurrence of the data loss can be reduced by reading till the RX FIFO is empty and writing till the TX FIFO is full. Reported-by: Bob Maris Signed-off-by: Sonic Zhang Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-bfin-twi.c | 47 ++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/drivers/i2c/busses/i2c-bfin-twi.c b/drivers/i2c/busses/i2c-bfin-twi.c index 05080c449c6b..13ea1c29873d 100644 --- a/drivers/i2c/busses/i2c-bfin-twi.c +++ b/drivers/i2c/busses/i2c-bfin-twi.c @@ -39,33 +39,40 @@ static void bfin_twi_handle_interrupt(struct bfin_twi_iface *iface, unsigned short mast_stat = read_MASTER_STAT(iface); if (twi_int_status & XMTSERV) { + if (iface->writeNum <= 0) { + /* start receive immediately after complete sending in + * combine mode. + */ + if (iface->cur_mode == TWI_I2C_MODE_COMBINED) + write_MASTER_CTL(iface, + read_MASTER_CTL(iface) | MDIR); + else if (iface->manual_stop) + write_MASTER_CTL(iface, + read_MASTER_CTL(iface) | STOP); + else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && + iface->cur_msg + 1 < iface->msg_num) { + if (iface->pmsg[iface->cur_msg + 1].flags & + I2C_M_RD) + write_MASTER_CTL(iface, + read_MASTER_CTL(iface) | + MDIR); + else + write_MASTER_CTL(iface, + read_MASTER_CTL(iface) & + ~MDIR); + } + } /* Transmit next data */ - if (iface->writeNum > 0) { + while (iface->writeNum > 0 && + (read_FIFO_STAT(iface) & XMTSTAT) != XMT_FULL) { SSYNC(); write_XMT_DATA8(iface, *(iface->transPtr++)); iface->writeNum--; } - /* start receive immediately after complete sending in - * combine mode. - */ - else if (iface->cur_mode == TWI_I2C_MODE_COMBINED) - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | MDIR); - else if (iface->manual_stop) - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | STOP); - else if (iface->cur_mode == TWI_I2C_MODE_REPEAT && - iface->cur_msg + 1 < iface->msg_num) { - if (iface->pmsg[iface->cur_msg + 1].flags & I2C_M_RD) - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) | MDIR); - else - write_MASTER_CTL(iface, - read_MASTER_CTL(iface) & ~MDIR); - } } if (twi_int_status & RCVSERV) { - if (iface->readNum > 0) { + while (iface->readNum > 0 && + (read_FIFO_STAT(iface) & RCVSTAT)) { /* Receive next data */ *(iface->transPtr) = read_RCV_DATA8(iface); if (iface->cur_mode == TWI_I2C_MODE_COMBINED) { -- cgit From 38d7fadef4973bb94e36897fcb6bb6a12fdd10c9 Mon Sep 17 00:00:00 2001 From: Christian Ruppert Date: Fri, 7 Jun 2013 10:51:23 +0200 Subject: i2c: designware: fix race between subsequent xfers The designware block is not always properly disabled in the case of transfer errors. Interrupts from aborted transfers might be handled after the data structures for the following transfer are initialised but before the hardware is set up. This can corrupt the data structures to the point that the system is stuck in an infinite interrupt loop (where FIFOs are never emptied because dev->msg_read_idx == dev->msgs_num). This patch cleanly disables the designware-i2c hardware at the end of every transfer, be it successful or not. Signed-off-by: Christian Ruppert [wsa: extended the comment] Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-core.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index db20a2841b75..3de549436992 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -583,11 +583,21 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) ret = wait_for_completion_timeout(&dev->cmd_complete, HZ); if (ret == 0) { dev_err(dev->dev, "controller timed out\n"); + /* i2c_dw_init implicitly disables the adapter */ i2c_dw_init(dev); ret = -ETIMEDOUT; goto done; } + /* + * We must disable the adapter before unlocking the &dev->lock mutex + * below. Otherwise the hardware might continue generating interrupts + * which in turn causes a race condition with the following transfer. + * Needs some more investigation if the additional interrupts are + * a hardware bug or this driver doesn't handle them correctly yet. + */ + __i2c_dw_enable(dev, false); + if (dev->msg_err) { ret = dev->msg_err; goto done; @@ -595,8 +605,6 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num) /* no error */ if (likely(!dev->cmd_err)) { - /* Disable the adapter */ - __i2c_dw_enable(dev, false); ret = num; goto done; } -- cgit From 560746eb79d3124a278452c8dd968682b521cc82 Mon Sep 17 00:00:00 2001 From: Tony Prisk Date: Sat, 15 Jun 2013 09:52:16 +1200 Subject: i2c: vt8500: Add support for I2C bus on Wondermedia SoCs This patch adds support for the I2C bus controllers found on Wondermedia 8xxx-series SoCs. Only master-mode is supported. Signed-off-by: Tony Prisk [wsa: fixed one macro to shift 8 instead of 16] Signed-off-by: Wolfram Sang --- .../devicetree/bindings/i2c/i2c-vt8500.txt | 24 ++ MAINTAINERS | 1 + drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-wmt.c | 479 +++++++++++++++++++++ 5 files changed, 515 insertions(+) create mode 100644 Documentation/devicetree/bindings/i2c/i2c-vt8500.txt create mode 100644 drivers/i2c/busses/i2c-wmt.c diff --git a/Documentation/devicetree/bindings/i2c/i2c-vt8500.txt b/Documentation/devicetree/bindings/i2c/i2c-vt8500.txt new file mode 100644 index 000000000000..94a425eaa6c7 --- /dev/null +++ b/Documentation/devicetree/bindings/i2c/i2c-vt8500.txt @@ -0,0 +1,24 @@ +* Wondermedia I2C Controller + +Required properties : + + - compatible : should be "wm,wm8505-i2c" + - reg : Offset and length of the register set for the device + - interrupts : where IRQ is the interrupt number + - clocks : phandle to the I2C clock source + +Optional properties : + + - clock-frequency : desired I2C bus clock frequency in Hz. + Valid values are 100000 and 400000. + Default to 100000 if not specified, or invalid value. + +Example : + + i2c_0: i2c@d8280000 { + compatible = "wm,wm8505-i2c"; + reg = <0xd8280000 0x1000>; + interrupts = <19>; + clocks = <&clki2c0>; + clock-frequency = <400000>; + }; diff --git a/MAINTAINERS b/MAINTAINERS index f35a259a6564..5fa200fa5b24 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1285,6 +1285,7 @@ S: Maintained F: arch/arm/mach-vt8500/ F: drivers/clocksource/vt8500_timer.c F: drivers/gpio/gpio-vt8500.c +F: drivers/i2c/busses/i2c-wmt.c F: drivers/mmc/host/wmt-sdmmc.c F: drivers/pwm/pwm-vt8500.c F: drivers/rtc/rtc-vt8500.c diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 94364d41686f..6582611bfee6 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -714,6 +714,16 @@ config I2C_VERSATILE This driver can also be built as a module. If so, the module will be called i2c-versatile. +config I2C_WMT + tristate "Wondermedia WM8xxx SoC I2C bus support" + depends on ARCH_VT8500 + help + Say yes if you want to support the I2C bus on Wondermedia 8xxx-series + SoCs. + + This driver can also be built as a module. If so, the module will be + called i2c-wmt. + config I2C_OCTEON tristate "Cavium OCTEON I2C bus support" depends on CPU_CAVIUM_OCTEON diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 3e07dc53eeae..385f99dd1b45 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -70,6 +70,7 @@ obj-$(CONFIG_I2C_SIRF) += i2c-sirf.o obj-$(CONFIG_I2C_STU300) += i2c-stu300.o obj-$(CONFIG_I2C_TEGRA) += i2c-tegra.o obj-$(CONFIG_I2C_VERSATILE) += i2c-versatile.o +obj-$(CONFIG_I2C_WMT) += i2c-wmt.o obj-$(CONFIG_I2C_OCTEON) += i2c-octeon.o obj-$(CONFIG_I2C_XILINX) += i2c-xiic.o obj-$(CONFIG_I2C_XLR) += i2c-xlr.o diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c new file mode 100644 index 000000000000..baaa7d15b73e --- /dev/null +++ b/drivers/i2c/busses/i2c-wmt.c @@ -0,0 +1,479 @@ +/* + * Wondermedia I2C Master Mode Driver + * + * Copyright (C) 2012 Tony Prisk + * + * Derived from GPLv2+ licensed source: + * - Copyright (C) 2008 WonderMedia Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2, or + * (at your option) any later version. as published by the Free Software + * Foundation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REG_CR 0x00 +#define REG_TCR 0x02 +#define REG_CSR 0x04 +#define REG_ISR 0x06 +#define REG_IMR 0x08 +#define REG_CDR 0x0A +#define REG_TR 0x0C +#define REG_MCR 0x0E +#define REG_SLAVE_CR 0x10 +#define REG_SLAVE_SR 0x12 +#define REG_SLAVE_ISR 0x14 +#define REG_SLAVE_IMR 0x16 +#define REG_SLAVE_DR 0x18 +#define REG_SLAVE_TR 0x1A + +/* REG_CR Bit fields */ +#define CR_TX_NEXT_ACK 0x0000 +#define CR_ENABLE 0x0001 +#define CR_TX_NEXT_NO_ACK 0x0002 +#define CR_TX_END 0x0004 +#define CR_CPU_RDY 0x0008 +#define SLAV_MODE_SEL 0x8000 + +/* REG_TCR Bit fields */ +#define TCR_STANDARD_MODE 0x0000 +#define TCR_MASTER_WRITE 0x0000 +#define TCR_HS_MODE 0x2000 +#define TCR_MASTER_READ 0x4000 +#define TCR_FAST_MODE 0x8000 +#define TCR_SLAVE_ADDR_MASK 0x007F + +/* REG_ISR Bit fields */ +#define ISR_NACK_ADDR 0x0001 +#define ISR_BYTE_END 0x0002 +#define ISR_SCL_TIMEOUT 0x0004 +#define ISR_WRITE_ALL 0x0007 + +/* REG_IMR Bit fields */ +#define IMR_ENABLE_ALL 0x0007 + +/* REG_CSR Bit fields */ +#define CSR_RCV_NOT_ACK 0x0001 +#define CSR_RCV_ACK_MASK 0x0001 +#define CSR_READY_MASK 0x0002 + +/* REG_TR */ +#define SCL_TIMEOUT(x) (((x) & 0xFF) << 8) +#define TR_STD 0x0064 +#define TR_HS 0x0019 + +/* REG_MCR */ +#define MCR_APB_96M 7 +#define MCR_APB_166M 12 + +#define I2C_MODE_STANDARD 0 +#define I2C_MODE_FAST 1 + +#define WMT_I2C_TIMEOUT (msecs_to_jiffies(1000)) + +struct wmt_i2c_dev { + struct i2c_adapter adapter; + struct completion complete; + struct device *dev; + void __iomem *base; + struct clk *clk; + int mode; + int irq; + u16 cmd_status; +}; + +static int wmt_i2c_wait_bus_not_busy(struct wmt_i2c_dev *i2c_dev) +{ + unsigned long timeout; + + timeout = jiffies + WMT_I2C_TIMEOUT; + while (!(readw(i2c_dev->base + REG_CSR) & CSR_READY_MASK)) { + if (time_after(jiffies, timeout)) { + dev_warn(i2c_dev->dev, "timeout waiting for bus ready\n"); + return -EBUSY; + } + msleep(20); + } + + return 0; +} + +static int wmt_check_status(struct wmt_i2c_dev *i2c_dev) +{ + int ret = 0; + + if (i2c_dev->cmd_status & ISR_NACK_ADDR) + ret = -EIO; + + if (i2c_dev->cmd_status & ISR_SCL_TIMEOUT) + ret = -ETIMEDOUT; + + return ret; +} + +static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg, + int last) +{ + struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); + u16 val, tcr_val; + int ret, wait_result; + int xfer_len = 0; + + if (!(pmsg->flags & I2C_M_NOSTART)) { + ret = wmt_i2c_wait_bus_not_busy(i2c_dev); + if (ret < 0) + return ret; + } + + if (pmsg->len == 0) { + /* + * We still need to run through the while (..) once, so + * start at -1 and break out early from the loop + */ + xfer_len = -1; + writew(0, i2c_dev->base + REG_CDR); + } else { + writew(pmsg->buf[0] & 0xFF, i2c_dev->base + REG_CDR); + } + + if (!(pmsg->flags & I2C_M_NOSTART)) { + val = readw(i2c_dev->base + REG_CR); + val &= ~CR_TX_END; + writew(val, i2c_dev->base + REG_CR); + + val = readw(i2c_dev->base + REG_CR); + val |= CR_CPU_RDY; + writew(val, i2c_dev->base + REG_CR); + } + + INIT_COMPLETION(i2c_dev->complete); + + if (i2c_dev->mode == I2C_MODE_STANDARD) + tcr_val = TCR_STANDARD_MODE; + else + tcr_val = TCR_FAST_MODE; + + tcr_val |= (TCR_MASTER_WRITE | (pmsg->addr & TCR_SLAVE_ADDR_MASK)); + + writew(tcr_val, i2c_dev->base + REG_TCR); + + if (pmsg->flags & I2C_M_NOSTART) { + val = readw(i2c_dev->base + REG_CR); + val |= CR_CPU_RDY; + writew(val, i2c_dev->base + REG_CR); + } + + while (xfer_len < pmsg->len) { + wait_result = wait_for_completion_timeout(&i2c_dev->complete, + 500 * HZ / 1000); + + if (wait_result == 0) + return -ETIMEDOUT; + + ret = wmt_check_status(i2c_dev); + if (ret) + return ret; + + xfer_len++; + + val = readw(i2c_dev->base + REG_CSR); + if ((val & CSR_RCV_ACK_MASK) == CSR_RCV_NOT_ACK) { + dev_dbg(i2c_dev->dev, "write RCV NACK error\n"); + return -EIO; + } + + if (pmsg->len == 0) { + val = CR_TX_END | CR_CPU_RDY | CR_ENABLE; + writew(val, i2c_dev->base + REG_CR); + break; + } + + if (xfer_len == pmsg->len) { + if (last != 1) + writew(CR_ENABLE, i2c_dev->base + REG_CR); + } else { + writew(pmsg->buf[xfer_len] & 0xFF, i2c_dev->base + + REG_CDR); + writew(CR_CPU_RDY | CR_ENABLE, i2c_dev->base + REG_CR); + } + } + + return 0; +} + +static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg, + int last) +{ + struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap); + u16 val, tcr_val; + int ret, wait_result; + u32 xfer_len = 0; + + if (!(pmsg->flags & I2C_M_NOSTART)) { + ret = wmt_i2c_wait_bus_not_busy(i2c_dev); + if (ret < 0) + return ret; + } + + val = readw(i2c_dev->base + REG_CR); + val &= ~CR_TX_END; + writew(val, i2c_dev->base + REG_CR); + + val = readw(i2c_dev->base + REG_CR); + val &= ~CR_TX_NEXT_NO_ACK; + writew(val, i2c_dev->base + REG_CR); + + if (!(pmsg->flags & I2C_M_NOSTART)) { + val = readw(i2c_dev->base + REG_CR); + val |= CR_CPU_RDY; + writew(val, i2c_dev->base + REG_CR); + } + + if (pmsg->len == 1) { + val = readw(i2c_dev->base + REG_CR); + val |= CR_TX_NEXT_NO_ACK; + writew(val, i2c_dev->base + REG_CR); + } + + INIT_COMPLETION(i2c_dev->complete); + + if (i2c_dev->mode == I2C_MODE_STANDARD) + tcr_val = TCR_STANDARD_MODE; + else + tcr_val = TCR_FAST_MODE; + + tcr_val |= TCR_MASTER_READ | (pmsg->addr & TCR_SLAVE_ADDR_MASK); + + writew(tcr_val, i2c_dev->base + REG_TCR); + + if (pmsg->flags & I2C_M_NOSTART) { + val = readw(i2c_dev->base + REG_CR); + val |= CR_CPU_RDY; + writew(val, i2c_dev->base + REG_CR); + } + + while (xfer_len < pmsg->len) { + wait_result = wait_for_completion_timeout(&i2c_dev->complete, + 500 * HZ / 1000); + + if (!wait_result) + return -ETIMEDOUT; + + ret = wmt_check_status(i2c_dev); + if (ret) + return ret; + + pmsg->buf[xfer_len] = readw(i2c_dev->base + REG_CDR) >> 8; + xfer_len++; + + if (xfer_len == pmsg->len - 1) { + val = readw(i2c_dev->base + REG_CR); + val |= (CR_TX_NEXT_NO_ACK | CR_CPU_RDY); + writew(val, i2c_dev->base + REG_CR); + } else { + val = readw(i2c_dev->base + REG_CR); + val |= CR_CPU_RDY; + writew(val, i2c_dev->base + REG_CR); + } + } + + return 0; +} + +static int wmt_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg msgs[], + int num) +{ + struct i2c_msg *pmsg; + int i, is_last; + int ret = 0; + + for (i = 0; ret >= 0 && i < num; i++) { + is_last = ((i + 1) == num); + + pmsg = &msgs[i]; + if (pmsg->flags & I2C_M_RD) + ret = wmt_i2c_read(adap, pmsg, is_last); + else + ret = wmt_i2c_write(adap, pmsg, is_last); + } + + return (ret < 0) ? ret : i; +} + +static u32 wmt_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART; +} + +static const struct i2c_algorithm wmt_i2c_algo = { + .master_xfer = wmt_i2c_xfer, + .functionality = wmt_i2c_func, +}; + +static irqreturn_t wmt_i2c_isr(int irq, void *data) +{ + struct wmt_i2c_dev *i2c_dev = data; + + /* save the status and write-clear it */ + i2c_dev->cmd_status = readw(i2c_dev->base + REG_ISR); + writew(i2c_dev->cmd_status, i2c_dev->base + REG_ISR); + + complete(&i2c_dev->complete); + + return IRQ_HANDLED; +} + +static int wmt_i2c_reset_hardware(struct wmt_i2c_dev *i2c_dev) +{ + int err; + + err = clk_prepare_enable(i2c_dev->clk); + if (err) { + dev_err(i2c_dev->dev, "failed to enable clock\n"); + return err; + } + + err = clk_set_rate(i2c_dev->clk, 20000000); + if (err) { + dev_err(i2c_dev->dev, "failed to set clock = 20Mhz\n"); + return err; + } + + writew(0, i2c_dev->base + REG_CR); + writew(MCR_APB_166M, i2c_dev->base + REG_MCR); + writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); + writew(IMR_ENABLE_ALL, i2c_dev->base + REG_IMR); + writew(CR_ENABLE, i2c_dev->base + REG_CR); + readw(i2c_dev->base + REG_CSR); /* read clear */ + writew(ISR_WRITE_ALL, i2c_dev->base + REG_ISR); + + if (i2c_dev->mode == I2C_MODE_STANDARD) + writew(SCL_TIMEOUT(128) | TR_STD, i2c_dev->base + REG_TR); + else + writew(SCL_TIMEOUT(128) | TR_HS, i2c_dev->base + REG_TR); + + return 0; +} + +static int wmt_i2c_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct wmt_i2c_dev *i2c_dev; + struct i2c_adapter *adap; + struct resource *res; + int err; + u32 clk_rate; + + i2c_dev = devm_kzalloc(&pdev->dev, sizeof(*i2c_dev), GFP_KERNEL); + if (!i2c_dev) { + dev_err(&pdev->dev, "device memory allocation failed\n"); + 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); + + i2c_dev->irq = irq_of_parse_and_map(np, 0); + if (!i2c_dev->irq) { + dev_err(&pdev->dev, "irq missing or invalid\n"); + return -EINVAL; + } + + i2c_dev->clk = of_clk_get(np, 0); + if (IS_ERR(i2c_dev->clk)) { + dev_err(&pdev->dev, "unable to request clock\n"); + return PTR_ERR(i2c_dev->clk); + } + + i2c_dev->mode = I2C_MODE_STANDARD; + err = of_property_read_u32(np, "clock-frequency", &clk_rate); + if ((!err) && (clk_rate == 400000)) + i2c_dev->mode = I2C_MODE_FAST; + + i2c_dev->dev = &pdev->dev; + + err = devm_request_irq(&pdev->dev, i2c_dev->irq, wmt_i2c_isr, 0, + "i2c", i2c_dev); + if (err) { + dev_err(&pdev->dev, "failed to request irq %i\n", i2c_dev->irq); + return err; + } + + adap = &i2c_dev->adapter; + i2c_set_adapdata(adap, i2c_dev); + strlcpy(adap->name, "WMT I2C adapter", sizeof(adap->name)); + adap->owner = THIS_MODULE; + adap->algo = &wmt_i2c_algo; + adap->dev.parent = &pdev->dev; + adap->dev.of_node = pdev->dev.of_node; + + init_completion(&i2c_dev->complete); + + err = wmt_i2c_reset_hardware(i2c_dev); + if (err) { + dev_err(&pdev->dev, "error initializing hardware\n"); + return err; + } + + err = i2c_add_adapter(adap); + if (err) { + dev_err(&pdev->dev, "failed to add adapter\n"); + return err; + } + + platform_set_drvdata(pdev, i2c_dev); + + of_i2c_register_devices(adap); + + return 0; +} + +static int wmt_i2c_remove(struct platform_device *pdev) +{ + struct wmt_i2c_dev *i2c_dev = platform_get_drvdata(pdev); + + /* Disable interrupts, clock and delete adapter */ + writew(0, i2c_dev->base + REG_IMR); + clk_disable_unprepare(i2c_dev->clk); + i2c_del_adapter(&i2c_dev->adapter); + + return 0; +} + +static struct of_device_id wmt_i2c_dt_ids[] = { + { .compatible = "wm,wm8505-i2c" }, + { /* Sentinel */ }, +}; + +static struct platform_driver wmt_i2c_driver = { + .probe = wmt_i2c_probe, + .remove = wmt_i2c_remove, + .driver = { + .name = "wmt-i2c", + .owner = THIS_MODULE, + .of_match_table = wmt_i2c_dt_ids, + }, +}; + +module_platform_driver(wmt_i2c_driver); + +MODULE_DESCRIPTION("Wondermedia I2C master-mode bus adapter"); +MODULE_AUTHOR("Tony Prisk "); +MODULE_LICENSE("GPL"); +MODULE_DEVICE_TABLE(of, wmt_i2c_dt_ids); -- cgit From 683e69b8bb4744a4088c80d05762c4258afe47e1 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 12 Jun 2013 18:53:30 +0200 Subject: i2c: mv64xxx: Add macros to access parts of registers These macros make it more comprehensive to access to useful masked and shifted area of the various registers used. Signed-off-by: Maxime Ripard Tested-by: Sebastian Hesselbarth Tested-by: Andrew Lunn Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 6356439454ee..d70a2fda4a91 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -33,6 +33,10 @@ #define MV64XXX_I2C_REG_EXT_SLAVE_ADDR 0x10 #define MV64XXX_I2C_REG_SOFT_RESET 0x1c +#define MV64XXX_I2C_ADDR_ADDR(val) ((val & 0x7f) << 1) +#define MV64XXX_I2C_BAUD_DIV_N(val) (val & 0x7) +#define MV64XXX_I2C_BAUD_DIV_M(val) ((val & 0xf) << 3) + #define MV64XXX_I2C_REG_CONTROL_ACK 0x00000004 #define MV64XXX_I2C_REG_CONTROL_IFLG 0x00000008 #define MV64XXX_I2C_REG_CONTROL_STOP 0x00000010 @@ -133,7 +137,7 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data, drv_data->addr1 = 0xf0 | (((u32)msg->addr & 0x300) >> 7) | dir; drv_data->addr2 = (u32)msg->addr & 0xff; } else { - drv_data->addr1 = ((u32)msg->addr & 0x7f) << 1 | dir; + drv_data->addr1 = MV64XXX_I2C_ADDR_ADDR((u32)msg->addr) | dir; drv_data->addr2 = 0; } } @@ -151,7 +155,7 @@ static void mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data) { writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET); - writel((((drv_data->freq_m & 0xf) << 3) | (drv_data->freq_n & 0x7)), + writel(MV64XXX_I2C_BAUD_DIV_M(drv_data->freq_m) | MV64XXX_I2C_BAUD_DIV_N(drv_data->freq_n), drv_data->reg_base + MV64XXX_I2C_REG_BAUD); writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR); writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR); -- cgit From 004e8ed7cc67f4ba07cba95af269210db11a544c Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 12 Jun 2013 18:53:31 +0200 Subject: i2c: mv64xxx: make the registers offset configurable The Allwinner i2c controller uses the same logic as the Marvell one, but with slightly different register offsets. Introduce a structure that will be passed by either the pdata or associated to the compatible strings, and that holds the various registers that might be needed. Signed-off-by: Maxime Ripard Tested-by: Sebastian Hesselbarth Tested-by: Andrew Lunn Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 101 ++++++++++++++++++++++++--------------- 1 file changed, 62 insertions(+), 39 deletions(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index d70a2fda4a91..7ba9bac18478 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -19,20 +19,12 @@ #include #include #include +#include #include #include #include #include -/* Register defines */ -#define MV64XXX_I2C_REG_SLAVE_ADDR 0x00 -#define MV64XXX_I2C_REG_DATA 0x04 -#define MV64XXX_I2C_REG_CONTROL 0x08 -#define MV64XXX_I2C_REG_STATUS 0x0c -#define MV64XXX_I2C_REG_BAUD 0x0c -#define MV64XXX_I2C_REG_EXT_SLAVE_ADDR 0x10 -#define MV64XXX_I2C_REG_SOFT_RESET 0x1c - #define MV64XXX_I2C_ADDR_ADDR(val) ((val & 0x7f) << 1) #define MV64XXX_I2C_BAUD_DIV_N(val) (val & 0x7) #define MV64XXX_I2C_BAUD_DIV_M(val) ((val & 0xf) << 3) @@ -89,6 +81,16 @@ enum { MV64XXX_I2C_ACTION_SEND_STOP, }; +struct mv64xxx_i2c_regs { + u8 addr; + u8 ext_addr; + u8 data; + u8 control; + u8 status; + u8 clock; + u8 soft_reset; +}; + struct mv64xxx_i2c_data { struct i2c_msg *msgs; int num_msgs; @@ -98,6 +100,7 @@ struct mv64xxx_i2c_data { u32 aborting; u32 cntl_bits; void __iomem *reg_base; + struct mv64xxx_i2c_regs reg_offsets; u32 addr1; u32 addr2; u32 bytes_left; @@ -116,6 +119,16 @@ struct mv64xxx_i2c_data { struct i2c_adapter adapter; }; +static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = { + .addr = 0x00, + .ext_addr = 0x10, + .data = 0x04, + .control = 0x08, + .status = 0x0c, + .clock = 0x0c, + .soft_reset = 0x1c, +}; + static void mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg) @@ -154,13 +167,13 @@ mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data, static void mv64xxx_i2c_hw_init(struct mv64xxx_i2c_data *drv_data) { - writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SOFT_RESET); + writel(0, drv_data->reg_base + drv_data->reg_offsets.soft_reset); writel(MV64XXX_I2C_BAUD_DIV_M(drv_data->freq_m) | MV64XXX_I2C_BAUD_DIV_N(drv_data->freq_n), - drv_data->reg_base + MV64XXX_I2C_REG_BAUD); - writel(0, drv_data->reg_base + MV64XXX_I2C_REG_SLAVE_ADDR); - writel(0, drv_data->reg_base + MV64XXX_I2C_REG_EXT_SLAVE_ADDR); + drv_data->reg_base + drv_data->reg_offsets.clock); + writel(0, drv_data->reg_base + drv_data->reg_offsets.addr); + writel(0, drv_data->reg_base + drv_data->reg_offsets.ext_addr); writel(MV64XXX_I2C_REG_CONTROL_TWSIEN | MV64XXX_I2C_REG_CONTROL_STOP, - drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->reg_base + drv_data->reg_offsets.control); drv_data->state = MV64XXX_I2C_STATE_IDLE; } @@ -282,7 +295,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) drv_data->cntl_bits |= MV64XXX_I2C_REG_CONTROL_START; writel(drv_data->cntl_bits, - drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->reg_base + drv_data->reg_offsets.control); drv_data->msgs++; drv_data->num_msgs--; @@ -300,48 +313,48 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) case MV64XXX_I2C_ACTION_CONTINUE: writel(drv_data->cntl_bits, - drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->reg_base + drv_data->reg_offsets.control); break; case MV64XXX_I2C_ACTION_SEND_START: writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_START, - drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->reg_base + drv_data->reg_offsets.control); break; case MV64XXX_I2C_ACTION_SEND_ADDR_1: writel(drv_data->addr1, - drv_data->reg_base + MV64XXX_I2C_REG_DATA); + drv_data->reg_base + drv_data->reg_offsets.data); writel(drv_data->cntl_bits, - drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->reg_base + drv_data->reg_offsets.control); break; case MV64XXX_I2C_ACTION_SEND_ADDR_2: writel(drv_data->addr2, - drv_data->reg_base + MV64XXX_I2C_REG_DATA); + drv_data->reg_base + drv_data->reg_offsets.data); writel(drv_data->cntl_bits, - drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->reg_base + drv_data->reg_offsets.control); break; case MV64XXX_I2C_ACTION_SEND_DATA: writel(drv_data->msg->buf[drv_data->byte_posn++], - drv_data->reg_base + MV64XXX_I2C_REG_DATA); + drv_data->reg_base + drv_data->reg_offsets.data); writel(drv_data->cntl_bits, - drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->reg_base + drv_data->reg_offsets.control); break; case MV64XXX_I2C_ACTION_RCV_DATA: drv_data->msg->buf[drv_data->byte_posn++] = - readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA); + readl(drv_data->reg_base + drv_data->reg_offsets.data); writel(drv_data->cntl_bits, - drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->reg_base + drv_data->reg_offsets.control); break; case MV64XXX_I2C_ACTION_RCV_DATA_STOP: drv_data->msg->buf[drv_data->byte_posn++] = - readl(drv_data->reg_base + MV64XXX_I2C_REG_DATA); + readl(drv_data->reg_base + drv_data->reg_offsets.data); drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, - drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->reg_base + drv_data->reg_offsets.control); drv_data->block = 0; wake_up(&drv_data->waitq); break; @@ -356,7 +369,7 @@ mv64xxx_i2c_do_action(struct mv64xxx_i2c_data *drv_data) case MV64XXX_I2C_ACTION_SEND_STOP: drv_data->cntl_bits &= ~MV64XXX_I2C_REG_CONTROL_INTEN; writel(drv_data->cntl_bits | MV64XXX_I2C_REG_CONTROL_STOP, - drv_data->reg_base + MV64XXX_I2C_REG_CONTROL); + drv_data->reg_base + drv_data->reg_offsets.control); drv_data->block = 0; wake_up(&drv_data->waitq); break; @@ -372,9 +385,9 @@ mv64xxx_i2c_intr(int irq, void *dev_id) irqreturn_t rc = IRQ_NONE; spin_lock_irqsave(&drv_data->lock, flags); - while (readl(drv_data->reg_base + MV64XXX_I2C_REG_CONTROL) & + while (readl(drv_data->reg_base + drv_data->reg_offsets.control) & MV64XXX_I2C_REG_CONTROL_IFLG) { - status = readl(drv_data->reg_base + MV64XXX_I2C_REG_STATUS); + status = readl(drv_data->reg_base + drv_data->reg_offsets.status); mv64xxx_i2c_fsm(drv_data, status); mv64xxx_i2c_do_action(drv_data); rc = IRQ_HANDLED; @@ -495,6 +508,12 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = { * ***************************************************************************** */ +static const struct of_device_id mv64xxx_i2c_of_match_table[] = { + { .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx}, + {} +}; +MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table); + #ifdef CONFIG_OF static int mv64xxx_calc_freq(const int tclk, const int n, const int m) @@ -528,8 +547,10 @@ mv64xxx_find_baud_factors(const u32 req_freq, const u32 tclk, u32 *best_n, static int mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, - struct device_node *np) + struct device *dev) { + const struct of_device_id *device; + struct device_node *np = dev->of_node; u32 bus_freq, tclk; int rc = 0; @@ -558,6 +579,13 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, * So hard code the value to 1 second. */ drv_data->adapter.timeout = HZ; + + device = of_match_device(mv64xxx_i2c_of_match_table, dev); + if (!device) + return -ENODEV; + + memcpy(&drv_data->reg_offsets, device->data, sizeof(drv_data->reg_offsets)); + out: return rc; #endif @@ -565,7 +593,7 @@ out: #else /* CONFIG_OF */ static int mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, - struct device_node *np) + struct device *dev) { return -ENODEV; } @@ -611,8 +639,9 @@ mv64xxx_i2c_probe(struct platform_device *pd) drv_data->freq_n = pdata->freq_n; drv_data->irq = platform_get_irq(pd, 0); drv_data->adapter.timeout = msecs_to_jiffies(pdata->timeout); + memcpy(&drv_data->reg_offsets, &mv64xxx_i2c_regs_mv64xxx, sizeof(drv_data->reg_offsets)); } else if (pd->dev.of_node) { - rc = mv64xxx_of_config(drv_data, pd->dev.of_node); + rc = mv64xxx_of_config(drv_data, &pd->dev); if (rc) goto exit_clk; } @@ -680,12 +709,6 @@ mv64xxx_i2c_remove(struct platform_device *dev) return 0; } -static const struct of_device_id mv64xxx_i2c_of_match_table[] = { - { .compatible = "marvell,mv64xxx-i2c", }, - {} -}; -MODULE_DEVICE_TABLE(of, mv64xxx_i2c_of_match_table); - static struct platform_driver mv64xxx_i2c_driver = { .probe = mv64xxx_i2c_probe, .remove = mv64xxx_i2c_remove, -- cgit From 3d66ac7d81ac70dfaab8a573f7ad2be94f7d6da3 Mon Sep 17 00:00:00 2001 From: Maxime Ripard Date: Wed, 12 Jun 2013 18:53:32 +0200 Subject: i2c: mv64xxx: Add Allwinner sun4i compatible Add the compatible string for the Allwinner A10 i2c controller and the associated register layout. Signed-off-by: Maxime Ripard Tested-by: Sebastian Hesselbarth Tested-by: Andrew Lunn Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 3 ++- drivers/i2c/busses/i2c-mv64xxx.c | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index 6582611bfee6..96c6d82da3ed 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -497,10 +497,11 @@ config I2C_MPC config I2C_MV64XXX tristate "Marvell mv64xxx I2C Controller" - depends on (MV64X60 || PLAT_ORION) + depends on (MV64X60 || PLAT_ORION || ARCH_SUNXI) help If you say yes to this option, support will be included for the built-in I2C interface on the Marvell 64xxx line of host bridges. + This driver is also used for Allwinner SoCs I2C controllers. This driver can also be built as a module. If so, the module will be called i2c-mv64xxx. diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 7ba9bac18478..7a0e39b7f928 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -129,6 +129,16 @@ static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_mv64xxx = { .soft_reset = 0x1c, }; +static struct mv64xxx_i2c_regs mv64xxx_i2c_regs_sun4i = { + .addr = 0x00, + .ext_addr = 0x04, + .data = 0x08, + .control = 0x0c, + .status = 0x10, + .clock = 0x14, + .soft_reset = 0x18, +}; + static void mv64xxx_i2c_prepare_for_io(struct mv64xxx_i2c_data *drv_data, struct i2c_msg *msg) @@ -509,6 +519,7 @@ static const struct i2c_algorithm mv64xxx_i2c_algo = { ***************************************************************************** */ static const struct of_device_id mv64xxx_i2c_of_match_table[] = { + { .compatible = "allwinner,sun4i-i2c", .data = &mv64xxx_i2c_regs_sun4i}, { .compatible = "marvell,mv64xxx-i2c", .data = &mv64xxx_i2c_regs_mv64xxx}, {} }; -- cgit From 3a205be5e8746aac70d4f5083cef4b3becfbab91 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 10 Jun 2013 00:00:58 +0200 Subject: i2c: nomadik: support elder Nomadiks The Nomadik I2C block was introduced with the Nomadik STn8815 SoC (the STn8810 incidentally is identical to the one named i2c-stu300.c). However as developments have only been tested on the DB8500 family, it was not properly working with the STn8815 anymore. Rectify this by adding some vendor variant data in the same manner as other PrimeCells, and switch code path depending on version. Tested on the S8815 Nomadik dongle. Signed-off-by: Linus Walleij Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-nomadik.c | 43 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 650293ff4d62..9f1423ac7b3b 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -106,6 +106,16 @@ /* maximum threshold value */ #define MAX_I2C_FIFO_THRESHOLD 15 +/** + * struct i2c_vendor_data - per-vendor variations + * @has_mtdws: variant has the MTDWS bit + * @fifodepth: variant FIFO depth + */ +struct i2c_vendor_data { + bool has_mtdws; + u32 fifodepth; +}; + enum i2c_status { I2C_NOP, I2C_ON_GOING, @@ -138,6 +148,7 @@ struct i2c_nmk_client { /** * struct nmk_i2c_dev - private data structure of the controller. + * @vendor: vendor data for this variant. * @adev: parent amba device. * @adap: corresponding I2C adapter. * @irq: interrupt line for the controller. @@ -155,6 +166,7 @@ struct i2c_nmk_client { * @busy: Busy doing transfer. */ struct nmk_i2c_dev { + struct i2c_vendor_data *vendor; struct amba_device *adev; struct i2c_adapter adap; int irq; @@ -431,7 +443,7 @@ static int read_i2c(struct nmk_i2c_dev *dev, u16 flags) irq_mask = (I2C_IT_RXFNF | I2C_IT_RXFF | I2C_IT_MAL | I2C_IT_BERR); - if (dev->stop) + if (dev->stop || !dev->vendor->has_mtdws) irq_mask |= I2C_IT_MTD; else irq_mask |= I2C_IT_MTDWS; @@ -511,7 +523,7 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags) * set the MTDWS bit (Master Transaction Done Without Stop) * to start repeated start operation */ - if (dev->stop) + if (dev->stop || !dev->vendor->has_mtdws) irq_mask |= I2C_IT_MTD; else irq_mask |= I2C_IT_MTDWS; @@ -978,6 +990,8 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) struct device_node *np = adev->dev.of_node; struct nmk_i2c_dev *dev; struct i2c_adapter *adap; + struct i2c_vendor_data *vendor = id->data; + u32 max_fifo_threshold = (vendor->fifodepth / 2) - 1; if (!pdata) { if (np) { @@ -994,12 +1008,25 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) pdata = &u8500_i2c; } + if (pdata->tft > max_fifo_threshold) { + dev_warn(&adev->dev, "requested TX FIFO threshold %u, adjusted down to %u\n", + pdata->tft, max_fifo_threshold); + pdata->tft = max_fifo_threshold; + } + + if (pdata->rft > max_fifo_threshold) { + dev_warn(&adev->dev, "requested RX FIFO threshold %u, adjusted down to %u\n", + pdata->rft, max_fifo_threshold); + pdata->rft = max_fifo_threshold; + } + dev = kzalloc(sizeof(struct nmk_i2c_dev), GFP_KERNEL); if (!dev) { dev_err(&adev->dev, "cannot allocate memory\n"); ret = -ENOMEM; goto err_no_mem; } + dev->vendor = vendor; dev->busy = false; dev->adev = adev; amba_set_drvdata(adev, dev); @@ -1134,14 +1161,26 @@ static int nmk_i2c_remove(struct amba_device *adev) return 0; } +static struct i2c_vendor_data vendor_stn8815 = { + .has_mtdws = false, + .fifodepth = 16, /* Guessed from TFTR/RFTR = 7 */ +}; + +static struct i2c_vendor_data vendor_db8500 = { + .has_mtdws = true, + .fifodepth = 32, /* Guessed from TFTR/RFTR = 15 */ +}; + static struct amba_id nmk_i2c_ids[] = { { .id = 0x00180024, .mask = 0x00ffffff, + .data = &vendor_stn8815, }, { .id = 0x00380024, .mask = 0x00ffffff, + .data = &vendor_db8500, }, {}, }; -- cgit From d15b85755b25e1b0201e24bc0c29f31eb4e856c4 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sat, 15 Jun 2013 22:38:14 +0200 Subject: i2c: nomadik: allocate adapter number dynamically The Nomadik I2C was using a local atomic counter to number the I2C adapters. This does not work on configurations where you also add, say a GPIO bit-banged adapter to the system. They will start to conflict about being adapter 0. There is no reason to use the numbered adapter function, and the semantic effect on systems with only Nomadik I2C blocks will be none - instead of increasing the number atomically in the driver itself, it is done in the I2C core. Signed-off-by: Linus Walleij Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-nomadik.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c index 9f1423ac7b3b..063e726dde11 100644 --- a/drivers/i2c/busses/i2c-nomadik.c +++ b/drivers/i2c/busses/i2c-nomadik.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include @@ -981,8 +980,6 @@ static void nmk_i2c_of_probe(struct device_node *np, pdata->sm = I2C_FREQ_MODE_FAST; } -static atomic_t adapter_id = ATOMIC_INIT(0); - static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) { int ret = 0; @@ -1095,10 +1092,8 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) adap->class = I2C_CLASS_HWMON | I2C_CLASS_SPD; adap->algo = &nmk_i2c_algo; adap->timeout = msecs_to_jiffies(pdata->timeout); - adap->nr = atomic_read(&adapter_id); snprintf(adap->name, sizeof(adap->name), - "Nomadik I2C%d at %pR", adap->nr, &adev->res); - atomic_inc(&adapter_id); + "Nomadik I2C at %pR", &adev->res); /* fetch the controller configuration from machine */ dev->cfg.clk_freq = pdata->clk_freq; @@ -1113,7 +1108,7 @@ static int nmk_i2c_probe(struct amba_device *adev, const struct amba_id *id) "initialize %s on virtual base %p\n", adap->name, dev->virtbase); - ret = i2c_add_numbered_adapter(adap); + ret = i2c_add_adapter(adap); if (ret) { dev_err(&adev->dev, "failed to add adapter\n"); goto err_add_adap; -- cgit From 661f6c1cd926c6c973e03c6b5151d161f3a666ed Mon Sep 17 00:00:00 2001 From: Wolfram Sang Date: Tue, 18 Jun 2013 18:02:45 +0200 Subject: Revert "i2c: core: make it possible to match a pure device tree driver" This reverts commit c80f52847c50109ca248c22efbf71ff10553dca4. Regressions have been found and also run time based instantiation would fail. We need more thoughts on this. Signed-off-by: Wolfram Sang --- drivers/i2c/i2c-core.c | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 93fc5bfdb9b4..48e31ed69dbf 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -240,7 +240,7 @@ static int i2c_device_probe(struct device *dev) return 0; driver = to_i2c_driver(dev->driver); - if (!driver->probe || (!driver->id_table && !dev->driver->of_match_table)) + if (!driver->probe || !driver->id_table) return -ENODEV; client->driver = driver; if (!device_can_wakeup(&client->dev)) @@ -248,12 +248,7 @@ static int i2c_device_probe(struct device *dev) client->flags & I2C_CLIENT_WAKE); dev_dbg(dev, "probe\n"); - if (of_match_device(dev->driver->of_match_table, dev)) - /* Device tree matching */ - status = driver->probe(client, NULL); - else - /* Fall back to matching the id_table */ - status = driver->probe(client, i2c_match_id(driver->id_table, client)); + status = driver->probe(client, i2c_match_id(driver->id_table, client)); if (status) { client->driver = NULL; i2c_set_clientdata(client, NULL); -- cgit From 7a10f4732972b48f75a547a42f9cdfef340124a6 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Mon, 17 Jun 2013 11:30:36 -0400 Subject: i2c-pxa: prepare clock before use On OLPC XO-1.75 (MMP2), a WARN_ON() was occurring during boot since the clock being enabled by i2c-pxa had not been prepared. Use clk_prepare_enable() to ensure that the prepare operation has taken place, and use clk_disable_unprepare() in the matching shutdown paths. Signed-off-by: Daniel Drake Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-pxa.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index ea6d45d1dcd6..fbafed29fb81 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c @@ -1160,7 +1160,7 @@ static int i2c_pxa_probe(struct platform_device *dev) i2c->adap.class = plat->class; } - clk_enable(i2c->clk); + clk_prepare_enable(i2c->clk); if (i2c->use_pio) { i2c->adap.algo = &i2c_pxa_pio_algorithm; @@ -1202,7 +1202,7 @@ eadapt: if (!i2c->use_pio) free_irq(irq, i2c); ereqirq: - clk_disable(i2c->clk); + clk_disable_unprepare(i2c->clk); iounmap(i2c->reg_base); eremap: clk_put(i2c->clk); @@ -1221,7 +1221,7 @@ static int i2c_pxa_remove(struct platform_device *dev) if (!i2c->use_pio) free_irq(i2c->irq, i2c); - clk_disable(i2c->clk); + clk_disable_unprepare(i2c->clk); clk_put(i2c->clk); iounmap(i2c->reg_base); -- cgit From 4368de19ed3f67168d714ab34b5b27c6a0ebad4e Mon Sep 17 00:00:00 2001 From: Oleksandr Dmytryshyn Date: Mon, 3 Jun 2013 10:37:20 +0300 Subject: i2c: omap: correct usage of the interrupt enable register We've been lucky not to have any interrupts fire during the suspend path, otherwise we would have unpredictable behaviour in the kernel. Based on the logic of the kernel code interrupts from i2c should be prohibited during suspend. Kernel writes 0 to the I2C_IE register in the omap_i2c_runtime_suspend() function. In the other side kernel writes saved interrupt flags to the I2C_IE register in omap_i2c_runtime_resume() function. I.e. interrupts should be disabled during suspend. This works for chips with version1 registers scheme. Interrupts are disabled during suspend. For chips with version2 scheme registers writting 0 to the I2C_IE register does nothing (because now the I2C_IRQENABLE_SET register is located at this address). This register is used to enable interrupts. For disabling interrupts I2C_IRQENABLE_CLR register should be used. Because the registers I2C_IRQENABLE_SET and I2C_IE have the same addresses, the interrupt enabling procedure is unchanged. I've checked that interrupts in the i2c controller are still enabled after writting 0 to the I2C_IRQENABLE_SET register. With this patch interrupts are disabled in the omap_i2c_runtime_suspend() function. Patch is based on: git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git tag: v3.10-rc2 Verified on OMAP4430. Signed-off-by: Oleksandr Dmytryshyn Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-omap.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c index 352f3c38d1f7..142b694d1c60 100644 --- a/drivers/i2c/busses/i2c-omap.c +++ b/drivers/i2c/busses/i2c-omap.c @@ -180,6 +180,8 @@ enum { #define I2C_OMAP_ERRATA_I207 (1 << 0) #define I2C_OMAP_ERRATA_I462 (1 << 1) +#define OMAP_I2C_IP_V2_INTERRUPTS_MASK 0x6FFF + struct omap_i2c_dev { spinlock_t lock; /* IRQ synchronization */ struct device *dev; @@ -193,6 +195,7 @@ struct omap_i2c_dev { long latency); u32 speed; /* Speed of bus in kHz */ u32 flags; + u16 scheme; u16 cmd_err; u8 *buf; u8 *regs; @@ -1082,7 +1085,7 @@ omap_i2c_probe(struct platform_device *pdev) int irq; int r; u32 rev; - u16 minor, major, scheme; + u16 minor, major; irq = platform_get_irq(pdev, 0); if (irq < 0) { @@ -1153,8 +1156,8 @@ omap_i2c_probe(struct platform_device *pdev) */ rev = __raw_readw(dev->base + 0x04); - scheme = OMAP_I2C_SCHEME(rev); - switch (scheme) { + dev->scheme = OMAP_I2C_SCHEME(rev); + switch (dev->scheme) { case OMAP_I2C_SCHEME_0: dev->regs = (u8 *)reg_map_ip_v1; dev->rev = omap_i2c_read_reg(dev, OMAP_I2C_REV_REG); @@ -1283,7 +1286,11 @@ static int omap_i2c_runtime_suspend(struct device *dev) _dev->iestate = omap_i2c_read_reg(_dev, OMAP_I2C_IE_REG); - omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0); + if (_dev->scheme == OMAP_I2C_SCHEME_0) + omap_i2c_write_reg(_dev, OMAP_I2C_IE_REG, 0); + else + omap_i2c_write_reg(_dev, OMAP_I2C_IP_V2_IRQENABLE_CLR, + OMAP_I2C_IP_V2_INTERRUPTS_MASK); if (_dev->rev < OMAP_I2C_OMAP1_REV_2) { omap_i2c_read_reg(_dev, OMAP_I2C_IV_REG); /* Read clears */ -- cgit From f39901c1befa556bc91902516a3e2e460000b4a8 Mon Sep 17 00:00:00 2001 From: Seth Heasley Date: Wed, 19 Jun 2013 16:59:57 -0700 Subject: i2c: i801: SMBus patch for Intel Coleto Creek DeviceIDs This patch adds the i801 SMBus Controller DeviceIDs for the Intel Coleto Creek PCH. Signed-off-by: Seth Heasley 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 d55b8ab2d10f..d29dea0f3232 100644 --- a/Documentation/i2c/busses/i2c-i801 +++ b/Documentation/i2c/busses/i2c-i801 @@ -24,6 +24,7 @@ Supported adapters: * Intel Lynx Point-LP (PCH) * Intel Avoton (SOC) * Intel Wellsburg (PCH) + * Intel Coleto Creek (PCH) 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 96c6d82da3ed..b865c8979aec 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -108,6 +108,7 @@ config I2C_I801 Lynx Point-LP (PCH) Avoton (SOC) Wellsburg (PCH) + Coleto Creek (PCH) 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 3a6903f63913..4ebceed6bc66 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -58,6 +58,7 @@ Wellsburg (PCH) MS 0x8d7d 32 hard yes yes yes Wellsburg (PCH) MS 0x8d7e 32 hard yes yes yes Wellsburg (PCH) MS 0x8d7f 32 hard yes yes yes + Coleto Creek (PCH) 0x23b0 32 hard yes yes yes Features supported by this driver: Software PEC no @@ -169,6 +170,7 @@ #define PCI_DEVICE_ID_INTEL_PANTHERPOINT_SMBUS 0x1e22 #define PCI_DEVICE_ID_INTEL_AVOTON_SMBUS 0x1f3c #define PCI_DEVICE_ID_INTEL_DH89XXCC_SMBUS 0x2330 +#define PCI_DEVICE_ID_INTEL_COLETOCREEK_SMBUS 0x23b0 #define PCI_DEVICE_ID_INTEL_5_3400_SERIES_SMBUS 0x3b30 #define PCI_DEVICE_ID_INTEL_LYNXPOINT_SMBUS 0x8c22 #define PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS 0x8d22 @@ -817,6 +819,7 @@ static DEFINE_PCI_DEVICE_TABLE(i801_ids) = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_WELLSBURG_SMBUS_MS0) }, { 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) }, { 0, } }; -- cgit From 6faa3535599a6f9ef367e3fd5c5126207a356a53 Mon Sep 17 00:00:00 2001 From: Guenter Roeck Date: Wed, 19 Jun 2013 14:53:52 -0700 Subject: i2c: mv64xxx: Fix transfer error code The driver returns -ENODEV as error code if it did not get an ACK from the device. Per Documentation/i2c/fault-codes, it should return -ENXIO. Signed-off-by: Guenter Roeck Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-mv64xxx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index 7a0e39b7f928..ed854573b427 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -280,7 +280,7 @@ mv64xxx_i2c_fsm(struct mv64xxx_i2c_data *drv_data, u32 status) /* Doesn't seem to be a device at other end */ drv_data->action = MV64XXX_I2C_ACTION_SEND_STOP; drv_data->state = MV64XXX_I2C_STATE_IDLE; - drv_data->rc = -ENODEV; + drv_data->rc = -ENXIO; break; default: -- cgit From 2f641a8bdb1b808b9bf1d0ca7d169d199aaf6ff4 Mon Sep 17 00:00:00 2001 From: "Arnaud Patard \\(Rtp\\)" Date: Thu, 20 Jun 2013 23:07:06 +0200 Subject: i2c: imx: allow autoloading on dt ids Allow udev to autoload the module when booting with device-tree Signed-off-by: Arnaud Patard Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-imx.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c index 6406aa960f2a..e24279725d36 100644 --- a/drivers/i2c/busses/i2c-imx.c +++ b/drivers/i2c/busses/i2c-imx.c @@ -147,6 +147,7 @@ static const struct of_device_id i2c_imx_dt_ids[] = { { .compatible = "fsl,imx21-i2c", .data = &imx_i2c_devtype[IMX21_I2C], }, { /* sentinel */ } }; +MODULE_DEVICE_TABLE(of, i2c_imx_dt_ids); static inline int is_imx1_i2c(struct imx_i2c_struct *i2c_imx) { -- cgit From 4c730a06c19bb83d2fa4308ee4cbb23abc84c9ca Mon Sep 17 00:00:00 2001 From: Gregory CLEMENT Date: Fri, 21 Jun 2013 15:32:06 +0200 Subject: i2c: mv64xxx: Set bus frequency to 100kHz if clock-frequency is not provided This commit adds checking whether clock-frequency property acquisition has succeeded. If not, the frequency is set to 100kHz by default. The Device Tree binding documentation is updated accordingly. Based on the intials patches from Zbigniew Bodek Signed-off-by: Gregory CLEMENT Signed-off-by: Zbigniew Bodek Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt | 6 +++++- drivers/i2c/busses/i2c-mv64xxx.c | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt index f46d928aa73d..a1ee681942cc 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-mv64xxx.txt @@ -6,7 +6,11 @@ Required properties : - reg : Offset and length of the register set for the device - compatible : Should be "marvell,mv64xxx-i2c" - interrupts : The interrupt number - - clock-frequency : Desired I2C bus clock frequency in Hz. + +Optional properties : + + - clock-frequency : Desired I2C bus clock frequency in Hz. If not set the +default frequency is 100kHz Examples: diff --git a/drivers/i2c/busses/i2c-mv64xxx.c b/drivers/i2c/busses/i2c-mv64xxx.c index ed854573b427..b1f42bf40963 100644 --- a/drivers/i2c/busses/i2c-mv64xxx.c +++ b/drivers/i2c/busses/i2c-mv64xxx.c @@ -578,7 +578,11 @@ mv64xxx_of_config(struct mv64xxx_i2c_data *drv_data, goto out; } tclk = clk_get_rate(drv_data->clk); - of_property_read_u32(np, "clock-frequency", &bus_freq); + + rc = of_property_read_u32(np, "clock-frequency", &bus_freq); + if (rc) + bus_freq = 100000; /* 100kHz by default */ + if (!mv64xxx_find_baud_factors(bus_freq, tclk, &drv_data->freq_n, &drv_data->freq_m)) { rc = -EINVAL; -- cgit From 9803f868944e879c4623c0d910e81f1ae89ccfb4 Mon Sep 17 00:00:00 2001 From: Christian Ruppert Date: Wed, 26 Jun 2013 10:55:06 +0200 Subject: i2c-designware: make SDA hold time configurable This patch makes the SDA hold time configurable through device tree. Signed-off-by: Christian Ruppert Signed-off-by: Pierrick Hascoet Acked-by: Vineet Gupta for arch/arc bits Signed-off-by: Wolfram Sang --- Documentation/devicetree/bindings/i2c/i2c-designware.txt | 15 +++++++++++++++ arch/arc/boot/dts/abilis_tb100_dvk.dts | 10 +++++----- arch/arc/boot/dts/abilis_tb101_dvk.dts | 10 +++++----- drivers/i2c/busses/i2c-designware-core.c | 13 +++++++++++++ drivers/i2c/busses/i2c-designware-core.h | 1 + drivers/i2c/busses/i2c-designware-platdrv.c | 10 ++++++++++ 6 files changed, 49 insertions(+), 10 deletions(-) diff --git a/Documentation/devicetree/bindings/i2c/i2c-designware.txt b/Documentation/devicetree/bindings/i2c/i2c-designware.txt index e42a2ee233e6..7fd7fa25e9b0 100644 --- a/Documentation/devicetree/bindings/i2c/i2c-designware.txt +++ b/Documentation/devicetree/bindings/i2c/i2c-designware.txt @@ -10,6 +10,10 @@ Recommended properties : - clock-frequency : desired I2C bus clock frequency in Hz. +Optional properties : + - i2c-sda-hold-time-ns : should contain the SDA hold time in nanoseconds. + This option is only supported in hardware blocks version 1.11a or newer. + Example : i2c@f0000 { @@ -20,3 +24,14 @@ Example : interrupts = <11>; clock-frequency = <400000>; }; + + i2c@1120000 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "snps,designware-i2c"; + reg = <0x1120000 0x1000>; + interrupt-parent = <&ictl>; + interrupts = <12 1>; + clock-frequency = <400000>; + i2c-sda-hold-time-ns = <300>; + }; diff --git a/arch/arc/boot/dts/abilis_tb100_dvk.dts b/arch/arc/boot/dts/abilis_tb100_dvk.dts index 0fa0d4abe795..ebc313a9f5b2 100644 --- a/arch/arc/boot/dts/abilis_tb100_dvk.dts +++ b/arch/arc/boot/dts/abilis_tb100_dvk.dts @@ -45,19 +45,19 @@ }; i2c0: i2c@FF120000 { - sda-hold-time = <432>; + i2c-sda-hold-time-ns = <432>; }; i2c1: i2c@FF121000 { - sda-hold-time = <432>; + i2c-sda-hold-time-ns = <432>; }; i2c2: i2c@FF122000 { - sda-hold-time = <432>; + i2c-sda-hold-time-ns = <432>; }; i2c3: i2c@FF123000 { - sda-hold-time = <432>; + i2c-sda-hold-time-ns = <432>; }; i2c4: i2c@FF124000 { - sda-hold-time = <432>; + i2c-sda-hold-time-ns = <432>; }; leds { diff --git a/arch/arc/boot/dts/abilis_tb101_dvk.dts b/arch/arc/boot/dts/abilis_tb101_dvk.dts index a4d80ce283ae..b204657993aa 100644 --- a/arch/arc/boot/dts/abilis_tb101_dvk.dts +++ b/arch/arc/boot/dts/abilis_tb101_dvk.dts @@ -45,19 +45,19 @@ }; i2c0: i2c@FF120000 { - sda-hold-time = <432>; + i2c-sda-hold-time-ns = <432>; }; i2c1: i2c@FF121000 { - sda-hold-time = <432>; + i2c-sda-hold-time-ns = <432>; }; i2c2: i2c@FF122000 { - sda-hold-time = <432>; + i2c-sda-hold-time-ns = <432>; }; i2c3: i2c@FF123000 { - sda-hold-time = <432>; + i2c-sda-hold-time-ns = <432>; }; i2c4: i2c@FF124000 { - sda-hold-time = <432>; + i2c-sda-hold-time-ns = <432>; }; leds { diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c index 3de549436992..ad46616de29e 100644 --- a/drivers/i2c/busses/i2c-designware-core.c +++ b/drivers/i2c/busses/i2c-designware-core.c @@ -67,9 +67,12 @@ #define DW_IC_STATUS 0x70 #define DW_IC_TXFLR 0x74 #define DW_IC_RXFLR 0x78 +#define DW_IC_SDA_HOLD 0x7c #define DW_IC_TX_ABRT_SOURCE 0x80 #define DW_IC_ENABLE_STATUS 0x9c #define DW_IC_COMP_PARAM_1 0xf4 +#define DW_IC_COMP_VERSION 0xf8 +#define DW_IC_SDA_HOLD_MIN_VERS 0x3131312A #define DW_IC_COMP_TYPE 0xfc #define DW_IC_COMP_TYPE_VALUE 0x44570140 @@ -332,6 +335,16 @@ int i2c_dw_init(struct dw_i2c_dev *dev) dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT); dev_dbg(dev->dev, "Fast-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt); + /* Configure SDA Hold Time if required */ + if (dev->sda_hold_time) { + reg = dw_readl(dev, DW_IC_COMP_VERSION); + if (reg >= DW_IC_SDA_HOLD_MIN_VERS) + dw_writel(dev, dev->sda_hold_time, DW_IC_SDA_HOLD); + else + dev_warn(dev->dev, + "Hardware too old to adjust SDA hold time."); + } + /* Configure Tx/Rx FIFO threshold levels */ dw_writel(dev, dev->tx_fifo_depth - 1, DW_IC_TX_TL); dw_writel(dev, 0, DW_IC_RX_TL); diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h index e761ad18dd61..912aa2262866 100644 --- a/drivers/i2c/busses/i2c-designware-core.h +++ b/drivers/i2c/busses/i2c-designware-core.h @@ -90,6 +90,7 @@ struct dw_i2c_dev { unsigned int tx_fifo_depth; unsigned int rx_fifo_depth; int rx_outstanding; + u32 sda_hold_time; }; #define ACCESS_SWAP 0x00000001 diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index ee46c92d7e3c..def79b5fd4c8 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -115,6 +116,15 @@ static int dw_i2c_probe(struct platform_device *pdev) return PTR_ERR(dev->clk); clk_prepare_enable(dev->clk); + if (pdev->dev.of_node) { + u32 ht = 0; + u32 ic_clk = dev->get_clk_rate_khz(dev); + + of_property_read_u32(pdev->dev.of_node, + "i2c-sda-hold-time-ns", &ht); + dev->sda_hold_time = ((u64)ic_clk * ht + 500000) / 1000000; + } + dev->functionality = I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | -- cgit From 88a8e4aa08f428da3a2a34890732a446ec9f2f5d Mon Sep 17 00:00:00 2001 From: Kevin Hilman Date: Fri, 28 Jun 2013 14:35:52 -0700 Subject: i2c: iop3xxx: fix build failure after waitqueue changes There has long been a syntax problem in iop3xx_i2c_wait_event() which has been somehow hidden by the macros in . After some recent cleanup/rework of the wait_event_* helpers, the bug has come out from hiding and now results in build failure: /work/kernel/next/drivers/i2c/busses/i2c-iop3xx.c: In function 'iop3xx_i2c_wait_event': /work/kernel/next/drivers/i2c/busses/i2c-iop3xx.c:176:143: error: expected ')' before ';' token /work/kernel/next/drivers/i2c/busses/i2c-iop3xx.c:176:157: error: expected ')' before ';' token /work/kernel/next/drivers/i2c/busses/i2c-iop3xx.c:176:213: error: expected ')' before ';' token /work/kernel/next/drivers/i2c/busses/i2c-iop3xx.c:176:291: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement] /work/kernel/next/drivers/i2c/busses/i2c-iop3xx.c:176:551: error: expected ')' before ';' token /work/kernel/next/drivers/i2c/busses/i2c-iop3xx.c:176:565: error: expected ')' before ';' token /work/kernel/next/drivers/i2c/busses/i2c-iop3xx.c:176:764: error: expected ')' before ';' token /work/kernel/next/drivers/i2c/busses/i2c-iop3xx.c:176:778: error: expected ')' b Fix by removing stray ';' Signed-off-by: Kevin Hilman Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-iop3xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-iop3xx.c b/drivers/i2c/busses/i2c-iop3xx.c index bc993331c695..dd24aa0424a9 100644 --- a/drivers/i2c/busses/i2c-iop3xx.c +++ b/drivers/i2c/busses/i2c-iop3xx.c @@ -176,7 +176,7 @@ iop3xx_i2c_wait_event(struct i2c_algo_iop3xx_data *iop3xx_adap, interrupted = wait_event_interruptible_timeout ( iop3xx_adap->waitq, (done = compare( sr = iop3xx_i2c_get_srstat(iop3xx_adap) ,flags )), - 1 * HZ; + 1 * HZ ); if ((rc = iop3xx_i2c_error(sr)) < 0) { *status = sr; -- cgit From e0b9b7b06704eab2b95372a7c8daf9c0cce46bd0 Mon Sep 17 00:00:00 2001 From: Kevin Strasser Date: Sun, 23 Jun 2013 21:00:04 -0700 Subject: i2c: Kontron PLD i2c bus driver Add i2c support for the on-board PLD found on some Kontron embedded modules. Originally-From: Michael Brunner Signed-off-by: Kevin Strasser Acked-by: Guenter Roeck Acked-by: Darren Hart Signed-off-by: Wolfram Sang --- drivers/i2c/busses/Kconfig | 10 + drivers/i2c/busses/Makefile | 1 + drivers/i2c/busses/i2c-kempld.c | 410 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 421 insertions(+) create mode 100644 drivers/i2c/busses/i2c-kempld.c diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig index b865c8979aec..3c046097be71 100644 --- a/drivers/i2c/busses/Kconfig +++ b/drivers/i2c/busses/Kconfig @@ -485,6 +485,16 @@ config I2C_IOP3XX This driver can also be built as a module. If so, the module will be called i2c-iop3xx. +config I2C_KEMPLD + tristate "Kontron COM I2C Controller" + depends on MFD_KEMPLD + help + This enables support for the I2C bus interface on some Kontron ETX + and COMexpress (ETXexpress) modules. + + This driver can also be built as a module. If so, the module + will be called i2c-kempld. + config I2C_MPC tristate "MPC107/824x/85xx/512x/52xx/83xx/86xx" depends on PPC diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile index 385f99dd1b45..d00997f3eb3b 100644 --- a/drivers/i2c/busses/Makefile +++ b/drivers/i2c/busses/Makefile @@ -47,6 +47,7 @@ obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o obj-$(CONFIG_I2C_IMX) += i2c-imx.o obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o +obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o obj-$(CONFIG_I2C_MPC) += i2c-mpc.o obj-$(CONFIG_I2C_MV64XXX) += i2c-mv64xxx.o obj-$(CONFIG_I2C_MXS) += i2c-mxs.o diff --git a/drivers/i2c/busses/i2c-kempld.c b/drivers/i2c/busses/i2c-kempld.c new file mode 100644 index 000000000000..ccec916bc3eb --- /dev/null +++ b/drivers/i2c/busses/i2c-kempld.c @@ -0,0 +1,410 @@ +/* + * I2C bus driver for Kontron COM modules + * + * Copyright (c) 2010-2013 Kontron Europe GmbH + * Author: Michael Brunner + * + * The driver is based on the i2c-ocores driver by Peter Korsgaard. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License 2 as published + * by the Free Software Foundation. + * + * This program is distributed in the hope that 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. + */ + +#include +#include +#include +#include +#include + +#define KEMPLD_I2C_PRELOW 0x0b +#define KEMPLD_I2C_PREHIGH 0x0c +#define KEMPLD_I2C_DATA 0x0e + +#define KEMPLD_I2C_CTRL 0x0d +#define I2C_CTRL_IEN 0x40 +#define I2C_CTRL_EN 0x80 + +#define KEMPLD_I2C_STAT 0x0f +#define I2C_STAT_IF 0x01 +#define I2C_STAT_TIP 0x02 +#define I2C_STAT_ARBLOST 0x20 +#define I2C_STAT_BUSY 0x40 +#define I2C_STAT_NACK 0x80 + +#define KEMPLD_I2C_CMD 0x0f +#define I2C_CMD_START 0x91 +#define I2C_CMD_STOP 0x41 +#define I2C_CMD_READ 0x21 +#define I2C_CMD_WRITE 0x11 +#define I2C_CMD_READ_ACK 0x21 +#define I2C_CMD_READ_NACK 0x29 +#define I2C_CMD_IACK 0x01 + +#define KEMPLD_I2C_FREQ_MAX 2700 /* 2.7 mHz */ +#define KEMPLD_I2C_FREQ_STD 100 /* 100 kHz */ + +enum { + STATE_DONE = 0, + STATE_INIT, + STATE_ADDR, + STATE_ADDR10, + STATE_START, + STATE_WRITE, + STATE_READ, + STATE_ERROR, +}; + +struct kempld_i2c_data { + struct device *dev; + struct kempld_device_data *pld; + struct i2c_adapter adap; + struct i2c_msg *msg; + int pos; + int nmsgs; + int state; + bool was_active; +}; + +static unsigned int bus_frequency = KEMPLD_I2C_FREQ_STD; +module_param(bus_frequency, uint, 0); +MODULE_PARM_DESC(bus_frequency, "Set I2C bus frequency in kHz (default=" + __MODULE_STRING(KEMPLD_I2C_FREQ_STD)")"); + +static int i2c_bus = -1; +module_param(i2c_bus, int, 0); +MODULE_PARM_DESC(i2c_bus, "Set I2C bus number (default=-1 for dynamic assignment)"); + +static bool i2c_gpio_mux; +module_param(i2c_gpio_mux, bool, 0); +MODULE_PARM_DESC(i2c_gpio_mux, "Enable I2C port on GPIO out (default=false)"); + +/* + * kempld_get_mutex must be called prior to calling this function. + */ +static int kempld_i2c_process(struct kempld_i2c_data *i2c) +{ + struct kempld_device_data *pld = i2c->pld; + u8 stat = kempld_read8(pld, KEMPLD_I2C_STAT); + struct i2c_msg *msg = i2c->msg; + u8 addr; + + /* Ready? */ + if (stat & I2C_STAT_TIP) + return -EBUSY; + + if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) { + /* Stop has been sent */ + kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_IACK); + if (i2c->state == STATE_ERROR) + return -EIO; + return 0; + } + + /* Error? */ + if (stat & I2C_STAT_ARBLOST) { + i2c->state = STATE_ERROR; + kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP); + return -EAGAIN; + } + + if (i2c->state == STATE_INIT) { + if (stat & I2C_STAT_BUSY) + return -EBUSY; + + i2c->state = STATE_ADDR; + } + + if (i2c->state == STATE_ADDR) { + /* 10 bit address? */ + if (i2c->msg->flags & I2C_M_TEN) { + addr = 0xf0 | ((i2c->msg->addr >> 7) & 0x6); + i2c->state = STATE_ADDR10; + } else { + addr = (i2c->msg->addr << 1); + i2c->state = STATE_START; + } + + /* Set read bit if necessary */ + addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0; + + kempld_write8(pld, KEMPLD_I2C_DATA, addr); + kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_START); + + return 0; + } + + /* Second part of 10 bit addressing */ + if (i2c->state == STATE_ADDR10) { + kempld_write8(pld, KEMPLD_I2C_DATA, i2c->msg->addr & 0xff); + kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE); + + i2c->state = STATE_START; + return 0; + } + + if (i2c->state == STATE_START || i2c->state == STATE_WRITE) { + i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE; + + if (stat & I2C_STAT_NACK) { + i2c->state = STATE_ERROR; + kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP); + return -ENXIO; + } + } else { + msg->buf[i2c->pos++] = kempld_read8(pld, KEMPLD_I2C_DATA); + } + + if (i2c->pos >= msg->len) { + i2c->nmsgs--; + i2c->msg++; + i2c->pos = 0; + msg = i2c->msg; + + if (i2c->nmsgs) { + if (!(msg->flags & I2C_M_NOSTART)) { + i2c->state = STATE_ADDR; + return 0; + } else { + i2c->state = (msg->flags & I2C_M_RD) + ? STATE_READ : STATE_WRITE; + } + } else { + i2c->state = STATE_DONE; + kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP); + return 0; + } + } + + if (i2c->state == STATE_READ) { + kempld_write8(pld, KEMPLD_I2C_CMD, i2c->pos == (msg->len - 1) ? + I2C_CMD_READ_NACK : I2C_CMD_READ_ACK); + } else { + kempld_write8(pld, KEMPLD_I2C_DATA, msg->buf[i2c->pos++]); + kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_WRITE); + } + + return 0; +} + +static int kempld_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, + int num) +{ + struct kempld_i2c_data *i2c = i2c_get_adapdata(adap); + struct kempld_device_data *pld = i2c->pld; + unsigned long timeout = jiffies + HZ; + int ret; + + i2c->msg = msgs; + i2c->pos = 0; + i2c->nmsgs = num; + i2c->state = STATE_INIT; + + /* Handle the transfer */ + while (time_before(jiffies, timeout)) { + kempld_get_mutex(pld); + ret = kempld_i2c_process(i2c); + kempld_release_mutex(pld); + + if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) + return (i2c->state == STATE_DONE) ? num : ret; + + if (ret == 0) + timeout = jiffies + HZ; + + usleep_range(5, 15); + } + + i2c->state = STATE_ERROR; + + return -ETIMEDOUT; +} + +/* + * kempld_get_mutex must be called prior to calling this function. + */ +static void kempld_i2c_device_init(struct kempld_i2c_data *i2c) +{ + struct kempld_device_data *pld = i2c->pld; + u16 prescale_corr; + long prescale; + u8 ctrl; + u8 stat; + u8 cfg; + + /* Make sure the device is disabled */ + ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL); + ctrl &= ~(I2C_CTRL_EN | I2C_CTRL_IEN); + kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl); + + if (bus_frequency > KEMPLD_I2C_FREQ_MAX) + bus_frequency = KEMPLD_I2C_FREQ_MAX; + + if (pld->info.spec_major == 1) + prescale = pld->pld_clock / bus_frequency * 5 - 1000; + else + prescale = pld->pld_clock / bus_frequency * 4 - 3000; + + if (prescale < 0) + prescale = 0; + + /* Round to the best matching value */ + prescale_corr = prescale / 1000; + if (prescale % 1000 >= 500) + prescale_corr++; + + kempld_write8(pld, KEMPLD_I2C_PRELOW, prescale_corr & 0xff); + kempld_write8(pld, KEMPLD_I2C_PREHIGH, prescale_corr >> 8); + + /* Activate I2C bus output on GPIO pins */ + cfg = kempld_read8(pld, KEMPLD_CFG); + if (i2c_gpio_mux) + cfg |= KEMPLD_CFG_GPIO_I2C_MUX; + else + cfg &= ~KEMPLD_CFG_GPIO_I2C_MUX; + kempld_write8(pld, KEMPLD_CFG, cfg); + + /* Enable the device */ + kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_IACK); + ctrl |= I2C_CTRL_EN; + kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl); + + stat = kempld_read8(pld, KEMPLD_I2C_STAT); + if (stat & I2C_STAT_BUSY) + kempld_write8(pld, KEMPLD_I2C_CMD, I2C_CMD_STOP); +} + +static u32 kempld_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_10BIT_ADDR | I2C_FUNC_SMBUS_EMUL; +} + +static const struct i2c_algorithm kempld_i2c_algorithm = { + .master_xfer = kempld_i2c_xfer, + .functionality = kempld_i2c_func, +}; + +static struct i2c_adapter kempld_i2c_adapter = { + .owner = THIS_MODULE, + .name = "i2c-kempld", + .class = I2C_CLASS_HWMON | I2C_CLASS_SPD, + .algo = &kempld_i2c_algorithm, +}; + +static int kempld_i2c_probe(struct platform_device *pdev) +{ + struct kempld_device_data *pld = dev_get_drvdata(pdev->dev.parent); + struct kempld_i2c_data *i2c; + int ret; + u8 ctrl; + + i2c = devm_kzalloc(&pdev->dev, sizeof(*i2c), GFP_KERNEL); + if (!i2c) + return -ENOMEM; + + i2c->pld = pld; + i2c->dev = &pdev->dev; + i2c->adap = kempld_i2c_adapter; + i2c->adap.dev.parent = i2c->dev; + i2c_set_adapdata(&i2c->adap, i2c); + platform_set_drvdata(pdev, i2c); + + kempld_get_mutex(pld); + ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL); + + if (ctrl & I2C_CTRL_EN) + i2c->was_active = true; + + kempld_i2c_device_init(i2c); + kempld_release_mutex(pld); + + /* Add I2C adapter to I2C tree */ + if (i2c_bus >= -1) + i2c->adap.nr = i2c_bus; + ret = i2c_add_numbered_adapter(&i2c->adap); + if (ret) + return ret; + + dev_info(i2c->dev, "I2C bus initialized at %dkHz\n", + bus_frequency); + + return 0; +} + +static int kempld_i2c_remove(struct platform_device *pdev) +{ + struct kempld_i2c_data *i2c = platform_get_drvdata(pdev); + struct kempld_device_data *pld = i2c->pld; + u8 ctrl; + + kempld_get_mutex(pld); + /* + * Disable I2C logic if it was not activated before the + * driver loaded + */ + if (!i2c->was_active) { + ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL); + ctrl &= ~I2C_CTRL_EN; + kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl); + } + kempld_release_mutex(pld); + + i2c_del_adapter(&i2c->adap); + + return 0; +} + +#ifdef CONFIG_PM +static int kempld_i2c_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct kempld_i2c_data *i2c = platform_get_drvdata(pdev); + struct kempld_device_data *pld = i2c->pld; + u8 ctrl; + + kempld_get_mutex(pld); + ctrl = kempld_read8(pld, KEMPLD_I2C_CTRL); + ctrl &= ~I2C_CTRL_EN; + kempld_write8(pld, KEMPLD_I2C_CTRL, ctrl); + kempld_release_mutex(pld); + + return 0; +} + +static int kempld_i2c_resume(struct platform_device *pdev) +{ + struct kempld_i2c_data *i2c = platform_get_drvdata(pdev); + struct kempld_device_data *pld = i2c->pld; + + kempld_get_mutex(pld); + kempld_i2c_device_init(i2c); + kempld_release_mutex(pld); + + return 0; +} +#else +#define kempld_i2c_suspend NULL +#define kempld_i2c_resume NULL +#endif + +static struct platform_driver kempld_i2c_driver = { + .driver = { + .name = "kempld-i2c", + .owner = THIS_MODULE, + }, + .probe = kempld_i2c_probe, + .remove = kempld_i2c_remove, + .suspend = kempld_i2c_suspend, + .resume = kempld_i2c_resume, +}; + +module_platform_driver(kempld_i2c_driver); + +MODULE_DESCRIPTION("KEM PLD I2C Driver"); +MODULE_AUTHOR("Michael Brunner "); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:kempld_i2c"); -- cgit From 97191d734f6ac028e5e6dcd574378c1544a16c0b Mon Sep 17 00:00:00 2001 From: Vincent Stehlé Date: Tue, 2 Jul 2013 11:46:54 +0200 Subject: i2c-designware: use div_u64 to fix link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the following link error: drivers/built-in.o: In function `dw_i2c_probe': of_iommu.c:(.text+0x18c8f0): undefined reference to `__aeabi_uldivmod' make: *** [vmlinux] Error 1 Signed-off-by: Vincent Stehlé Tested-by: Kevin Hilman Reviewed-by: Christian Ruppert Acked-by: Arnd Bergmann Signed-off-by: Wolfram Sang --- drivers/i2c/busses/i2c-designware-platdrv.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c index def79b5fd4c8..4c5fadabe49d 100644 --- a/drivers/i2c/busses/i2c-designware-platdrv.c +++ b/drivers/i2c/busses/i2c-designware-platdrv.c @@ -122,7 +122,8 @@ static int dw_i2c_probe(struct platform_device *pdev) of_property_read_u32(pdev->dev.of_node, "i2c-sda-hold-time-ns", &ht); - dev->sda_hold_time = ((u64)ic_clk * ht + 500000) / 1000000; + dev->sda_hold_time = div_u64((u64)ic_clk * ht + 500000, + 1000000); } dev->functionality = -- cgit