summaryrefslogtreecommitdiff
path: root/drivers/i2c/busses
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c/busses')
-rw-r--r--drivers/i2c/busses/Kconfig28
-rw-r--r--drivers/i2c/busses/Makefile3
-rw-r--r--drivers/i2c/busses/i2c-at91.c39
-rw-r--r--drivers/i2c/busses/i2c-axxia.c27
-rw-r--r--drivers/i2c/busses/i2c-bcm-iproc.c15
-rw-r--r--drivers/i2c/busses/i2c-bcm2835.c2
-rw-r--r--drivers/i2c/busses/i2c-cadence.c6
-rw-r--r--drivers/i2c/busses/i2c-cpm.c20
-rw-r--r--drivers/i2c/busses/i2c-cros-ec-tunnel.c51
-rw-r--r--drivers/i2c/busses/i2c-davinci.c194
-rw-r--r--drivers/i2c/busses/i2c-designware-baytrail.c40
-rw-r--r--drivers/i2c/busses/i2c-designware-core.c3
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c10
-rw-r--r--drivers/i2c/busses/i2c-digicolor.c384
-rw-r--r--drivers/i2c/busses/i2c-dln2.c13
-rw-r--r--drivers/i2c/busses/i2c-i801.c51
-rw-r--r--drivers/i2c/busses/i2c-img-scb.c14
-rw-r--r--drivers/i2c/busses/i2c-imx.c10
-rw-r--r--drivers/i2c/busses/i2c-ismt.c5
-rw-r--r--drivers/i2c/busses/i2c-jz4780.c833
-rw-r--r--drivers/i2c/busses/i2c-mpc.c33
-rw-r--r--drivers/i2c/busses/i2c-mxs.c7
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c6
-rw-r--r--drivers/i2c/busses/i2c-opal.c24
-rw-r--r--drivers/i2c/busses/i2c-pca-platform.c2
-rw-r--r--drivers/i2c/busses/i2c-pmcmsp.c42
-rw-r--r--drivers/i2c/busses/i2c-powermac.c10
-rw-r--r--drivers/i2c/busses/i2c-qup.c21
-rw-r--r--drivers/i2c/busses/i2c-rcar.c10
-rw-r--r--drivers/i2c/busses/i2c-rk3x.c2
-rw-r--r--drivers/i2c/busses/i2c-st.c13
-rw-r--r--drivers/i2c/busses/i2c-tegra.c12
-rw-r--r--drivers/i2c/busses/i2c-viperboard.c10
-rw-r--r--drivers/i2c/busses/i2c-wmt.c10
-rw-r--r--drivers/i2c/busses/i2c-xlp9xx.c445
35 files changed, 2076 insertions, 319 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 22da9c2ffa22..2255af23b9c7 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -485,6 +485,15 @@ config I2C_DESIGNWARE_BAYTRAIL
the platform firmware controlling it. You should say Y if running on
a BayTrail system using the AXP288.
+config I2C_DIGICOLOR
+ tristate "Conexant Digicolor I2C driver"
+ depends on ARCH_DIGICOLOR
+ help
+ Support for Conexant Digicolor SoCs (CX92755) I2C controller driver.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-digicolor.
+
config I2C_EFM32
tristate "EFM32 I2C controller"
depends on ARCH_EFM32 || COMPILE_TEST
@@ -574,6 +583,15 @@ config I2C_IOP3XX
This driver can also be built as a module. If so, the module
will be called i2c-iop3xx.
+config I2C_JZ4780
+ tristate "JZ4780 I2C controller interface support"
+ depends on MACH_JZ4780 || COMPILE_TEST
+ help
+ If you say yes to this option, support will be included for the
+ Ingenic JZ4780 I2C controller.
+
+ If you don't know what to do here, say N.
+
config I2C_KEMPLD
tristate "Kontron COM I2C Controller"
depends on MFD_KEMPLD
@@ -898,6 +916,16 @@ config I2C_XLR
This driver can also be built as a module. If so, the module
will be called i2c-xlr.
+config I2C_XLP9XX
+ tristate "XLP9XX I2C support"
+ depends on CPU_XLP || COMPILE_TEST
+ help
+ This driver enables support for the on-chip I2C interface of
+ the Broadcom XLP9xx/XLP5xx MIPS processors.
+
+ This driver can also be built as a module. If so, the module will
+ be called i2c-xlp9xx.
+
config I2C_RCAR
tristate "Renesas R-Car I2C Controller"
depends on ARCH_SHMOBILE || COMPILE_TEST
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 3638feb6677e..cdf941da91c6 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -45,6 +45,7 @@ i2c-designware-platform-objs := i2c-designware-platdrv.o
i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
i2c-designware-pci-objs := i2c-designware-pcidrv.o
+obj-$(CONFIG_I2C_DIGICOLOR) += i2c-digicolor.o
obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o
obj-$(CONFIG_I2C_EG20T) += i2c-eg20t.o
obj-$(CONFIG_I2C_EXYNOS5) += i2c-exynos5.o
@@ -55,6 +56,7 @@ obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
obj-$(CONFIG_I2C_IMG) += i2c-img-scb.o
obj-$(CONFIG_I2C_IMX) += i2c-imx.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
+obj-$(CONFIG_I2C_JZ4780) += i2c-jz4780.o
obj-$(CONFIG_I2C_KEMPLD) += i2c-kempld.o
obj-$(CONFIG_I2C_MESON) += i2c-meson.o
obj-$(CONFIG_I2C_MPC) += i2c-mpc.o
@@ -87,6 +89,7 @@ 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
+obj-$(CONFIG_I2C_XLP9XX) += i2c-xlp9xx.o
obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
# External I2C/SMBus adapter drivers
diff --git a/drivers/i2c/busses/i2c-at91.c b/drivers/i2c/busses/i2c-at91.c
index 636fd2efad88..ff23d1bdd230 100644
--- a/drivers/i2c/busses/i2c-at91.c
+++ b/drivers/i2c/busses/i2c-at91.c
@@ -381,6 +381,7 @@ static irqreturn_t atmel_twi_interrupt(int irq, void *dev_id)
static int at91_do_twi_transfer(struct at91_twi_dev *dev)
{
int ret;
+ unsigned long time_left;
bool has_unre_flag = dev->pdata->has_unre_flag;
dev_dbg(dev->dev, "transfer: %s %d bytes.\n",
@@ -436,9 +437,9 @@ static int at91_do_twi_transfer(struct at91_twi_dev *dev)
}
}
- ret = wait_for_completion_timeout(&dev->cmd_complete,
- dev->adapter.timeout);
- if (ret == 0) {
+ time_left = wait_for_completion_timeout(&dev->cmd_complete,
+ dev->adapter.timeout);
+ if (time_left == 0) {
dev_err(dev->dev, "controller timed out\n");
at91_init_twi_bus(dev);
ret = -ETIMEDOUT;
@@ -487,30 +488,10 @@ static int at91_twi_xfer(struct i2c_adapter *adap, struct i2c_msg *msg, int num)
if (ret < 0)
goto out;
- /*
- * The hardware can handle at most two messages concatenated by a
- * repeated start via it's internal address feature.
- */
- if (num > 2) {
- dev_err(dev->dev,
- "cannot handle more than two concatenated messages.\n");
- ret = 0;
- goto out;
- } else if (num == 2) {
+ if (num == 2) {
int internal_address = 0;
int i;
- if (msg->flags & I2C_M_RD) {
- dev_err(dev->dev, "first transfer must be write.\n");
- ret = -EINVAL;
- goto out;
- }
- if (msg->len > 3) {
- dev_err(dev->dev, "first message size must be <= 3.\n");
- ret = -EINVAL;
- goto out;
- }
-
/* 1st msg is put into the internal address, start with 2nd */
m_start = &msg[1];
for (i = 0; i < msg->len; ++i) {
@@ -540,6 +521,15 @@ out:
return ret;
}
+/*
+ * The hardware can handle at most two messages concatenated by a
+ * repeated start via it's internal address feature.
+ */
+static struct i2c_adapter_quirks at91_twi_quirks = {
+ .flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | I2C_AQ_COMB_SAME_ADDR,
+ .max_comb_1st_msg_len = 3,
+};
+
static u32 at91_twi_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL
@@ -777,6 +767,7 @@ static int at91_twi_probe(struct platform_device *pdev)
dev->adapter.owner = THIS_MODULE;
dev->adapter.class = I2C_CLASS_DEPRECATED;
dev->adapter.algo = &at91_twi_algorithm;
+ dev->adapter.quirks = &at91_twi_quirks;
dev->adapter.dev.parent = dev->dev;
dev->adapter.nr = pdev->id;
dev->adapter.timeout = AT91_I2C_TIMEOUT;
diff --git a/drivers/i2c/busses/i2c-axxia.c b/drivers/i2c/busses/i2c-axxia.c
index 768a598d8d03..32d883490863 100644
--- a/drivers/i2c/busses/i2c-axxia.c
+++ b/drivers/i2c/busses/i2c-axxia.c
@@ -334,12 +334,7 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
u32 int_mask = MST_STATUS_ERR | MST_STATUS_SNS;
u32 rx_xfer, tx_xfer;
u32 addr_1, addr_2;
- int ret;
-
- if (msg->len > 255) {
- dev_warn(idev->dev, "unsupported length %u\n", msg->len);
- return -EINVAL;
- }
+ unsigned long time_left;
idev->msg = msg;
idev->msg_xfrd = 0;
@@ -388,15 +383,15 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
i2c_int_enable(idev, int_mask);
- ret = wait_for_completion_timeout(&idev->msg_complete,
- I2C_XFER_TIMEOUT);
+ time_left = wait_for_completion_timeout(&idev->msg_complete,
+ I2C_XFER_TIMEOUT);
i2c_int_disable(idev, int_mask);
if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
dev_warn(idev->dev, "busy after xfer\n");
- if (ret == 0)
+ if (time_left == 0)
idev->msg_err = -ETIMEDOUT;
if (unlikely(idev->msg_err) && idev->msg_err != -ENXIO)
@@ -408,17 +403,17 @@ static int axxia_i2c_xfer_msg(struct axxia_i2c_dev *idev, struct i2c_msg *msg)
static int axxia_i2c_stop(struct axxia_i2c_dev *idev)
{
u32 int_mask = MST_STATUS_ERR | MST_STATUS_SCC;
- int ret;
+ unsigned long time_left;
reinit_completion(&idev->msg_complete);
/* Issue stop */
writel(0xb, idev->base + MST_COMMAND);
i2c_int_enable(idev, int_mask);
- ret = wait_for_completion_timeout(&idev->msg_complete,
- I2C_STOP_TIMEOUT);
+ time_left = wait_for_completion_timeout(&idev->msg_complete,
+ I2C_STOP_TIMEOUT);
i2c_int_disable(idev, int_mask);
- if (ret == 0)
+ if (time_left == 0)
return -ETIMEDOUT;
if (readl(idev->base + MST_COMMAND) & CMD_BUSY)
@@ -454,6 +449,11 @@ static const struct i2c_algorithm axxia_i2c_algo = {
.functionality = axxia_i2c_func,
};
+static struct i2c_adapter_quirks axxia_i2c_quirks = {
+ .max_read_len = 255,
+ .max_write_len = 255,
+};
+
static int axxia_i2c_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -511,6 +511,7 @@ static int axxia_i2c_probe(struct platform_device *pdev)
strlcpy(idev->adapter.name, pdev->name, sizeof(idev->adapter.name));
idev->adapter.owner = THIS_MODULE;
idev->adapter.algo = &axxia_i2c_algo;
+ idev->adapter.quirks = &axxia_i2c_quirks;
idev->adapter.dev.parent = &pdev->dev;
idev->adapter.dev.of_node = pdev->dev.of_node;
diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
index d3c89157b337..f9f2c2082151 100644
--- a/drivers/i2c/busses/i2c-bcm-iproc.c
+++ b/drivers/i2c/busses/i2c-bcm-iproc.c
@@ -160,14 +160,6 @@ static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
u32 val;
unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MESC);
- /* need to reserve one byte in the FIFO for the slave address */
- if (msg->len > M_TX_RX_FIFO_SIZE - 1) {
- dev_err(iproc_i2c->device,
- "only support data length up to %u bytes\n",
- M_TX_RX_FIFO_SIZE - 1);
- return -EOPNOTSUPP;
- }
-
/* check if bus is busy */
if (!!(readl(iproc_i2c->base + M_CMD_OFFSET) &
BIT(M_CMD_START_BUSY_SHIFT))) {
@@ -287,6 +279,12 @@ static const struct i2c_algorithm bcm_iproc_algo = {
.functionality = bcm_iproc_i2c_functionality,
};
+static struct i2c_adapter_quirks bcm_iproc_i2c_quirks = {
+ /* need to reserve one byte in the FIFO for the slave address */
+ .max_read_len = M_TX_RX_FIFO_SIZE - 1,
+ .max_write_len = M_TX_RX_FIFO_SIZE - 1,
+};
+
static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)
{
unsigned int bus_speed;
@@ -413,6 +411,7 @@ static int bcm_iproc_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(adap, iproc_i2c);
strlcpy(adap->name, "Broadcom iProc I2C adapter", sizeof(adap->name));
adap->algo = &bcm_iproc_algo;
+ adap->quirks = &bcm_iproc_i2c_quirks;
adap->dev.parent = &pdev->dev;
adap->dev.of_node = pdev->dev.of_node;
diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c
index 5d6feb937b9d..c9336a3202d5 100644
--- a/drivers/i2c/busses/i2c-bcm2835.c
+++ b/drivers/i2c/busses/i2c-bcm2835.c
@@ -147,7 +147,7 @@ static int bcm2835_i2c_xfer_msg(struct bcm2835_i2c_dev *i2c_dev,
struct i2c_msg *msg)
{
u32 c;
- int time_left;
+ unsigned long time_left;
i2c_dev->msg_buf = msg->buf;
i2c_dev->msg_buf_remaining = msg->len;
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 7d7a14cdadfb..2ee78e099d30 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -475,7 +475,7 @@ static void cdns_i2c_master_reset(struct i2c_adapter *adap)
static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
struct i2c_adapter *adap)
{
- int ret;
+ unsigned long time_left;
u32 reg;
id->p_msg = msg;
@@ -501,8 +501,8 @@ static int cdns_i2c_process_msg(struct cdns_i2c *id, struct i2c_msg *msg,
cdns_i2c_msend(id);
/* Wait for the signal of completion */
- ret = wait_for_completion_timeout(&id->xfer_done, adap->timeout);
- if (!ret) {
+ time_left = wait_for_completion_timeout(&id->xfer_done, adap->timeout);
+ if (time_left == 0) {
cdns_i2c_master_reset(adap);
dev_err(id->adap.dev.parent,
"timeout waiting on completion\n");
diff --git a/drivers/i2c/busses/i2c-cpm.c b/drivers/i2c/busses/i2c-cpm.c
index 2d466538b2e2..714bdc837769 100644
--- a/drivers/i2c/busses/i2c-cpm.c
+++ b/drivers/i2c/busses/i2c-cpm.c
@@ -308,22 +308,12 @@ static int cpm_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
struct i2c_reg __iomem *i2c_reg = cpm->i2c_reg;
struct i2c_ram __iomem *i2c_ram = cpm->i2c_ram;
struct i2c_msg *pmsg;
- int ret, i;
+ int ret;
int tptr;
int rptr;
cbd_t __iomem *tbdf;
cbd_t __iomem *rbdf;
- if (num > CPM_MAXBD)
- return -EINVAL;
-
- /* Check if we have any oversized READ requests */
- for (i = 0; i < num; i++) {
- pmsg = &msgs[i];
- if (pmsg->len >= CPM_MAX_READ)
- return -EINVAL;
- }
-
/* Reset to use first buffer */
out_be16(&i2c_ram->rbptr, in_be16(&i2c_ram->rbase));
out_be16(&i2c_ram->tbptr, in_be16(&i2c_ram->tbase));
@@ -424,10 +414,18 @@ static const struct i2c_algorithm cpm_i2c_algo = {
.functionality = cpm_i2c_func,
};
+/* CPM_MAX_READ is also limiting writes according to the code! */
+static struct i2c_adapter_quirks cpm_i2c_quirks = {
+ .max_num_msgs = CPM_MAXBD,
+ .max_read_len = CPM_MAX_READ,
+ .max_write_len = CPM_MAX_READ,
+};
+
static const struct i2c_adapter cpm_ops = {
.owner = THIS_MODULE,
.name = "i2c-cpm",
.algo = &cpm_i2c_algo,
+ .quirks = &cpm_i2c_quirks,
};
static int cpm_i2c_setup(struct cpm_i2c *cpm)
diff --git a/drivers/i2c/busses/i2c-cros-ec-tunnel.c b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
index 875c22ae5400..fa8dedd8c3a2 100644
--- a/drivers/i2c/busses/i2c-cros-ec-tunnel.c
+++ b/drivers/i2c/busses/i2c-cros-ec-tunnel.c
@@ -182,72 +182,41 @@ static int ec_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg i2c_msgs[],
const u16 bus_num = bus->remote_bus;
int request_len;
int response_len;
- u8 *request = NULL;
- u8 *response = NULL;
int result;
- struct cros_ec_command msg;
+ struct cros_ec_command msg = { };
request_len = ec_i2c_count_message(i2c_msgs, num);
if (request_len < 0) {
dev_warn(dev, "Error constructing message %d\n", request_len);
- result = request_len;
- goto exit;
+ return request_len;
}
+
response_len = ec_i2c_count_response(i2c_msgs, num);
if (response_len < 0) {
/* Unexpected; no errors should come when NULL response */
dev_warn(dev, "Error preparing response %d\n", response_len);
- result = response_len;
- goto exit;
- }
-
- if (request_len <= ARRAY_SIZE(bus->request_buf)) {
- request = bus->request_buf;
- } else {
- request = kzalloc(request_len, GFP_KERNEL);
- if (request == NULL) {
- result = -ENOMEM;
- goto exit;
- }
- }
- if (response_len <= ARRAY_SIZE(bus->response_buf)) {
- response = bus->response_buf;
- } else {
- response = kzalloc(response_len, GFP_KERNEL);
- if (response == NULL) {
- result = -ENOMEM;
- goto exit;
- }
+ return response_len;
}
- result = ec_i2c_construct_message(request, i2c_msgs, num, bus_num);
+ result = ec_i2c_construct_message(msg.outdata, i2c_msgs, num, bus_num);
if (result)
- goto exit;
+ return result;
msg.version = 0;
msg.command = EC_CMD_I2C_PASSTHRU;
- msg.outdata = request;
msg.outsize = request_len;
- msg.indata = response;
msg.insize = response_len;
result = cros_ec_cmd_xfer(bus->ec, &msg);
if (result < 0)
- goto exit;
+ return result;
- result = ec_i2c_parse_response(response, i2c_msgs, &num);
+ result = ec_i2c_parse_response(msg.indata, i2c_msgs, &num);
if (result < 0)
- goto exit;
+ return result;
/* Indicate success by saying how many messages were sent */
- result = num;
-exit:
- if (request != bus->request_buf)
- kfree(request);
- if (response != bus->response_buf)
- kfree(response);
-
- return result;
+ return num;
}
static u32 ec_i2c_functionality(struct i2c_adapter *adap)
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index 6dc7ff5d3d9a..4788a32afb86 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -60,6 +60,12 @@
#define DAVINCI_I2C_IVR_REG 0x28
#define DAVINCI_I2C_EMDR_REG 0x2c
#define DAVINCI_I2C_PSC_REG 0x30
+#define DAVINCI_I2C_FUNC_REG 0x48
+#define DAVINCI_I2C_DIR_REG 0x4c
+#define DAVINCI_I2C_DIN_REG 0x50
+#define DAVINCI_I2C_DOUT_REG 0x54
+#define DAVINCI_I2C_DSET_REG 0x58
+#define DAVINCI_I2C_DCLR_REG 0x5c
#define DAVINCI_I2C_IVR_AAS 0x07
#define DAVINCI_I2C_IVR_SCD 0x06
@@ -93,6 +99,29 @@
#define DAVINCI_I2C_IMR_NACK BIT(1)
#define DAVINCI_I2C_IMR_AL BIT(0)
+/* set SDA and SCL as GPIO */
+#define DAVINCI_I2C_FUNC_PFUNC0 BIT(0)
+
+/* set SCL as output when used as GPIO*/
+#define DAVINCI_I2C_DIR_PDIR0 BIT(0)
+/* set SDA as output when used as GPIO*/
+#define DAVINCI_I2C_DIR_PDIR1 BIT(1)
+
+/* read SCL GPIO level */
+#define DAVINCI_I2C_DIN_PDIN0 BIT(0)
+/* read SDA GPIO level */
+#define DAVINCI_I2C_DIN_PDIN1 BIT(1)
+
+/*set the SCL GPIO high */
+#define DAVINCI_I2C_DSET_PDSET0 BIT(0)
+/*set the SDA GPIO high */
+#define DAVINCI_I2C_DSET_PDSET1 BIT(1)
+
+/* set the SCL GPIO low */
+#define DAVINCI_I2C_DCLR_PDCLR0 BIT(0)
+/* set the SDA GPIO low */
+#define DAVINCI_I2C_DCLR_PDCLR1 BIT(1)
+
struct davinci_i2c_dev {
struct device *dev;
void __iomem *base;
@@ -129,43 +158,6 @@ static inline u16 davinci_i2c_read_reg(struct davinci_i2c_dev *i2c_dev, int reg)
return readw_relaxed(i2c_dev->base + reg);
}
-/* Generate a pulse on the i2c clock pin. */
-static void davinci_i2c_clock_pulse(unsigned int scl_pin)
-{
- u16 i;
-
- if (scl_pin) {
- /* Send high and low on the SCL line */
- for (i = 0; i < 9; i++) {
- gpio_set_value(scl_pin, 0);
- udelay(20);
- gpio_set_value(scl_pin, 1);
- udelay(20);
- }
- }
-}
-
-/* This routine does i2c bus recovery as specified in the
- * i2c protocol Rev. 03 section 3.16 titled "Bus clear"
- */
-static void davinci_i2c_recover_bus(struct davinci_i2c_dev *dev)
-{
- u32 flag = 0;
- struct davinci_i2c_platform_data *pdata = dev->pdata;
-
- dev_err(dev->dev, "initiating i2c bus recovery\n");
- /* Send NACK to the slave */
- flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
- flag |= DAVINCI_I2C_MDR_NACK;
- /* write the data into mode register */
- davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
- davinci_i2c_clock_pulse(pdata->scl_pin);
- /* Send STOP */
- flag = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
- flag |= DAVINCI_I2C_MDR_STP;
- davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
-}
-
static inline void davinci_i2c_reset_ctrl(struct davinci_i2c_dev *i2c_dev,
int val)
{
@@ -263,6 +255,99 @@ static int i2c_davinci_init(struct davinci_i2c_dev *dev)
}
/*
+ * This routine does i2c bus recovery by using i2c_generic_gpio_recovery
+ * which is provided by I2C Bus recovery infrastructure.
+ */
+static void davinci_i2c_prepare_recovery(struct i2c_adapter *adap)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ /* Disable interrupts */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_IMR_REG, 0);
+
+ /* put I2C into reset */
+ davinci_i2c_reset_ctrl(dev, 0);
+}
+
+static void davinci_i2c_unprepare_recovery(struct i2c_adapter *adap)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ i2c_davinci_init(dev);
+}
+
+static struct i2c_bus_recovery_info davinci_i2c_gpio_recovery_info = {
+ .recover_bus = i2c_generic_gpio_recovery,
+ .prepare_recovery = davinci_i2c_prepare_recovery,
+ .unprepare_recovery = davinci_i2c_unprepare_recovery,
+};
+
+static void davinci_i2c_set_scl(struct i2c_adapter *adap, int val)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ if (val)
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_DSET_REG,
+ DAVINCI_I2C_DSET_PDSET0);
+ else
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_DCLR_REG,
+ DAVINCI_I2C_DCLR_PDCLR0);
+}
+
+static int davinci_i2c_get_scl(struct i2c_adapter *adap)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+ int val;
+
+ /* read the state of SCL */
+ val = davinci_i2c_read_reg(dev, DAVINCI_I2C_DIN_REG);
+ return val & DAVINCI_I2C_DIN_PDIN0;
+}
+
+static int davinci_i2c_get_sda(struct i2c_adapter *adap)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+ int val;
+
+ /* read the state of SDA */
+ val = davinci_i2c_read_reg(dev, DAVINCI_I2C_DIN_REG);
+ return val & DAVINCI_I2C_DIN_PDIN1;
+}
+
+static void davinci_i2c_scl_prepare_recovery(struct i2c_adapter *adap)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ davinci_i2c_prepare_recovery(adap);
+
+ /* SCL output, SDA input */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_DIR_REG, DAVINCI_I2C_DIR_PDIR0);
+
+ /* change to GPIO mode */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_FUNC_REG,
+ DAVINCI_I2C_FUNC_PFUNC0);
+}
+
+static void davinci_i2c_scl_unprepare_recovery(struct i2c_adapter *adap)
+{
+ struct davinci_i2c_dev *dev = i2c_get_adapdata(adap);
+
+ /* change back to I2C mode */
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_FUNC_REG, 0);
+
+ davinci_i2c_unprepare_recovery(adap);
+}
+
+static struct i2c_bus_recovery_info davinci_i2c_scl_recovery_info = {
+ .recover_bus = i2c_generic_scl_recovery,
+ .set_scl = davinci_i2c_set_scl,
+ .get_scl = davinci_i2c_get_scl,
+ .get_sda = davinci_i2c_get_sda,
+ .prepare_recovery = davinci_i2c_scl_prepare_recovery,
+ .unprepare_recovery = davinci_i2c_scl_unprepare_recovery,
+};
+
+/*
* Waiting for bus not busy
*/
static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev,
@@ -282,8 +367,7 @@ static int i2c_davinci_wait_bus_not_busy(struct davinci_i2c_dev *dev,
return -ETIMEDOUT;
} else {
to_cnt = 0;
- davinci_i2c_recover_bus(dev);
- i2c_davinci_init(dev);
+ i2c_recover_bus(&dev->adapter);
}
}
if (allow_sleep)
@@ -304,7 +388,7 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
struct davinci_i2c_platform_data *pdata = dev->pdata;
u32 flag;
u16 w;
- int r;
+ unsigned long time_left;
/* Introduce a delay, required for some boards (e.g Davinci EVM) */
if (pdata->bus_delay)
@@ -368,11 +452,11 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
flag |= DAVINCI_I2C_MDR_STP;
davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, flag);
- r = wait_for_completion_timeout(&dev->cmd_complete, dev->adapter.timeout);
- if (r == 0) {
+ time_left = wait_for_completion_timeout(&dev->cmd_complete,
+ dev->adapter.timeout);
+ if (!time_left) {
dev_err(dev->dev, "controller timed out\n");
- davinci_i2c_recover_bus(dev);
- i2c_davinci_init(dev);
+ i2c_recover_bus(adap);
dev->buf_len = 0;
return -ETIMEDOUT;
}
@@ -380,17 +464,13 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
/* This should be 0 if all bytes were transferred
* or dev->cmd_err denotes an error.
*/
- if (r >= 0) {
- dev_err(dev->dev, "abnormal termination buf_len=%i\n",
- dev->buf_len);
- r = -EREMOTEIO;
- }
+ dev_err(dev->dev, "abnormal termination buf_len=%i\n",
+ dev->buf_len);
dev->terminate = 1;
wmb();
dev->buf_len = 0;
+ return -EREMOTEIO;
}
- if (r < 0)
- return r;
/* no error */
if (likely(!dev->cmd_err))
@@ -674,6 +754,10 @@ static int davinci_i2c_probe(struct platform_device *pdev)
if (!of_property_read_u32(pdev->dev.of_node, "clock-frequency",
&prop))
dev->pdata->bus_freq = prop / 1000;
+
+ dev->pdata->has_pfunc =
+ of_property_read_bool(pdev->dev.of_node,
+ "ti,has-pfunc");
} else if (!dev->pdata) {
dev->pdata = &davinci_i2c_platform_data_default;
}
@@ -715,6 +799,14 @@ static int davinci_i2c_probe(struct platform_device *pdev)
adap->timeout = DAVINCI_I2C_TIMEOUT;
adap->dev.of_node = pdev->dev.of_node;
+ if (dev->pdata->has_pfunc)
+ adap->bus_recovery_info = &davinci_i2c_scl_recovery_info;
+ else if (dev->pdata->scl_pin) {
+ adap->bus_recovery_info = &davinci_i2c_gpio_recovery_info;
+ adap->bus_recovery_info->scl_gpio = dev->pdata->scl_pin;
+ adap->bus_recovery_info->sda_gpio = dev->pdata->sda_pin;
+ }
+
adap->nr = pdev->id;
r = i2c_add_numbered_adapter(adap);
if (r) {
diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c
index 5f1ff4cc5c34..7d7ae97476e2 100644
--- a/drivers/i2c/busses/i2c-designware-baytrail.c
+++ b/drivers/i2c/busses/i2c-designware-baytrail.c
@@ -17,27 +17,31 @@
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
+
#include <asm/iosf_mbi.h>
+
#include "i2c-designware-core.h"
#define SEMAPHORE_TIMEOUT 100
#define PUNIT_SEMAPHORE 0x7
+#define PUNIT_SEMAPHORE_BIT BIT(0)
+#define PUNIT_SEMAPHORE_ACQUIRE BIT(1)
static unsigned long acquired;
static int get_sem(struct device *dev, u32 *sem)
{
- u32 reg_val;
+ u32 data;
int ret;
ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, PUNIT_SEMAPHORE,
- &reg_val);
+ &data);
if (ret) {
dev_err(dev, "iosf failed to read punit semaphore\n");
return ret;
}
- *sem = reg_val & 0x1;
+ *sem = data & PUNIT_SEMAPHORE_BIT;
return 0;
}
@@ -52,27 +56,29 @@ static void reset_semaphore(struct device *dev)
return;
}
- data = data & 0xfffffffe;
+ data &= ~PUNIT_SEMAPHORE_BIT;
if (iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
- PUNIT_SEMAPHORE, data))
+ PUNIT_SEMAPHORE, data))
dev_err(dev, "iosf failed to reset punit semaphore during write\n");
}
-int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
+static int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
{
- u32 sem = 0;
+ u32 sem;
int ret;
unsigned long start, end;
+ might_sleep();
+
if (!dev || !dev->dev)
return -ENODEV;
- if (!dev->acquire_lock)
+ if (!dev->release_lock)
return 0;
- /* host driver writes 0x2 to side band semaphore register */
+ /* host driver writes to side band semaphore register */
ret = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
- PUNIT_SEMAPHORE, 0x2);
+ PUNIT_SEMAPHORE, PUNIT_SEMAPHORE_ACQUIRE);
if (ret) {
dev_err(dev->dev, "iosf punit semaphore request failed\n");
return ret;
@@ -81,7 +87,7 @@ int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
/* host driver waits for bit 0 to be set in semaphore register */
start = jiffies;
end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
- while (!time_after(jiffies, end)) {
+ do {
ret = get_sem(dev->dev, &sem);
if (!ret && sem) {
acquired = jiffies;
@@ -91,14 +97,14 @@ int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
}
usleep_range(1000, 2000);
- }
+ } while (time_before(jiffies, end));
dev_err(dev->dev, "punit semaphore timed out, resetting\n");
reset_semaphore(dev->dev);
ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ,
- PUNIT_SEMAPHORE, &sem);
- if (!ret)
+ PUNIT_SEMAPHORE, &sem);
+ if (ret)
dev_err(dev->dev, "iosf failed to read punit semaphore\n");
else
dev_err(dev->dev, "PUNIT SEM: %d\n", sem);
@@ -107,9 +113,8 @@ int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
return -ETIMEDOUT;
}
-EXPORT_SYMBOL(baytrail_i2c_acquire);
-void baytrail_i2c_release(struct dw_i2c_dev *dev)
+static void baytrail_i2c_release(struct dw_i2c_dev *dev)
{
if (!dev || !dev->dev)
return;
@@ -121,7 +126,6 @@ void baytrail_i2c_release(struct dw_i2c_dev *dev)
dev_dbg(dev->dev, "punit semaphore held for %ums\n",
jiffies_to_msecs(jiffies - acquired));
}
-EXPORT_SYMBOL(baytrail_i2c_release);
int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
{
@@ -137,7 +141,6 @@ int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
return 0;
status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host);
-
if (ACPI_FAILURE(status))
return 0;
@@ -153,7 +156,6 @@ int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
return 0;
}
-EXPORT_SYMBOL(i2c_dw_eval_lock_support);
MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
MODULE_DESCRIPTION("Baytrail I2C Semaphore driver");
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 6e25c010e690..6f19a33773fe 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -656,8 +656,7 @@ 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_timeout(&dev->cmd_complete, HZ);
- if (ret == 0) {
+ if (!wait_for_completion_timeout(&dev->cmd_complete, HZ)) {
dev_err(dev->dev, "controller timed out\n");
/* i2c_dw_init implicitly disables the adapter */
i2c_dw_init(dev);
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index c270f5f9a8f9..0a80e4aabaed 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -143,10 +143,8 @@ static int dw_i2c_probe(struct platform_device *pdev)
u32 clk_freq, ht = 0;
irq = platform_get_irq(pdev, 0);
- if (irq < 0) {
- dev_err(&pdev->dev, "no irq resource?\n");
- return irq; /* -ENXIO */
- }
+ if (irq < 0)
+ return irq;
dev = devm_kzalloc(&pdev->dev, sizeof(struct dw_i2c_dev), GFP_KERNEL);
if (!dev)
@@ -166,7 +164,7 @@ static int dw_i2c_probe(struct platform_device *pdev)
/* fast mode by default because of legacy reasons */
clk_freq = 400000;
- if (ACPI_COMPANION(&pdev->dev)) {
+ if (has_acpi_companion(&pdev->dev)) {
dw_i2c_acpi_configure(pdev);
} else if (pdev->dev.of_node) {
of_property_read_u32(pdev->dev.of_node,
@@ -286,7 +284,7 @@ static int dw_i2c_remove(struct platform_device *pdev)
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- if (ACPI_COMPANION(&pdev->dev))
+ if (has_acpi_companion(&pdev->dev))
dw_i2c_acpi_unconfigure(pdev);
return 0;
diff --git a/drivers/i2c/busses/i2c-digicolor.c b/drivers/i2c/busses/i2c-digicolor.c
new file mode 100644
index 000000000000..9604024e0eb0
--- /dev/null
+++ b/drivers/i2c/busses/i2c-digicolor.c
@@ -0,0 +1,384 @@
+/*
+ * I2C bus driver for Conexant Digicolor SoCs
+ *
+ * Author: Baruch Siach <baruch@tkos.co.il>
+ *
+ * Copyright (C) 2015 Paradox Innovation Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#define DEFAULT_FREQ 100000
+#define TIMEOUT_MS 100
+
+#define II_CONTROL 0x0
+#define II_CONTROL_LOCAL_RESET BIT(0)
+
+#define II_CLOCKTIME 0x1
+
+#define II_COMMAND 0x2
+#define II_CMD_START 1
+#define II_CMD_RESTART 2
+#define II_CMD_SEND_ACK 3
+#define II_CMD_GET_ACK 6
+#define II_CMD_GET_NOACK 7
+#define II_CMD_STOP 10
+#define II_COMMAND_GO BIT(7)
+#define II_COMMAND_COMPLETION_STATUS(r) (((r) >> 5) & 3)
+#define II_CMD_STATUS_NORMAL 0
+#define II_CMD_STATUS_ACK_GOOD 1
+#define II_CMD_STATUS_ACK_BAD 2
+#define II_CMD_STATUS_ABORT 3
+
+#define II_DATA 0x3
+#define II_INTFLAG_CLEAR 0x8
+#define II_INTENABLE 0xa
+
+struct dc_i2c {
+ struct i2c_adapter adap;
+ struct device *dev;
+ void __iomem *regs;
+ struct clk *clk;
+ unsigned int frequency;
+
+ struct i2c_msg *msg;
+ unsigned int msgbuf_ptr;
+ int last;
+ spinlock_t lock;
+ struct completion done;
+ int state;
+ int error;
+};
+
+enum {
+ STATE_IDLE,
+ STATE_START,
+ STATE_ADDR,
+ STATE_WRITE,
+ STATE_READ,
+ STATE_STOP,
+};
+
+static void dc_i2c_cmd(struct dc_i2c *i2c, u8 cmd)
+{
+ writeb_relaxed(cmd | II_COMMAND_GO, i2c->regs + II_COMMAND);
+}
+
+static u8 dc_i2c_addr_cmd(struct i2c_msg *msg)
+{
+ u8 addr = (msg->addr & 0x7f) << 1;
+
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+
+ return addr;
+}
+
+static void dc_i2c_data(struct dc_i2c *i2c, u8 data)
+{
+ writeb_relaxed(data, i2c->regs + II_DATA);
+}
+
+static void dc_i2c_write_byte(struct dc_i2c *i2c, u8 byte)
+{
+ dc_i2c_data(i2c, byte);
+ dc_i2c_cmd(i2c, II_CMD_SEND_ACK);
+}
+
+static void dc_i2c_write_buf(struct dc_i2c *i2c)
+{
+ dc_i2c_write_byte(i2c, i2c->msg->buf[i2c->msgbuf_ptr++]);
+}
+
+static void dc_i2c_next_read(struct dc_i2c *i2c)
+{
+ bool last = (i2c->msgbuf_ptr + 1 == i2c->msg->len);
+
+ dc_i2c_cmd(i2c, last ? II_CMD_GET_NOACK : II_CMD_GET_ACK);
+}
+
+static void dc_i2c_stop(struct dc_i2c *i2c)
+{
+ i2c->state = STATE_STOP;
+ if (i2c->last)
+ dc_i2c_cmd(i2c, II_CMD_STOP);
+ else
+ complete(&i2c->done);
+}
+
+static u8 dc_i2c_read_byte(struct dc_i2c *i2c)
+{
+ return readb_relaxed(i2c->regs + II_DATA);
+}
+
+static void dc_i2c_read_buf(struct dc_i2c *i2c)
+{
+ i2c->msg->buf[i2c->msgbuf_ptr++] = dc_i2c_read_byte(i2c);
+ dc_i2c_next_read(i2c);
+}
+
+static void dc_i2c_set_irq(struct dc_i2c *i2c, int enable)
+{
+ if (enable)
+ writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR);
+ writeb_relaxed(!!enable, i2c->regs + II_INTENABLE);
+}
+
+static int dc_i2c_cmd_status(struct dc_i2c *i2c)
+{
+ u8 cmd = readb_relaxed(i2c->regs + II_COMMAND);
+
+ return II_COMMAND_COMPLETION_STATUS(cmd);
+}
+
+static void dc_i2c_start_msg(struct dc_i2c *i2c, int first)
+{
+ struct i2c_msg *msg = i2c->msg;
+
+ if (!(msg->flags & I2C_M_NOSTART)) {
+ i2c->state = STATE_START;
+ dc_i2c_cmd(i2c, first ? II_CMD_START : II_CMD_RESTART);
+ } else if (msg->flags & I2C_M_RD) {
+ i2c->state = STATE_READ;
+ dc_i2c_next_read(i2c);
+ } else {
+ i2c->state = STATE_WRITE;
+ dc_i2c_write_buf(i2c);
+ }
+}
+
+static irqreturn_t dc_i2c_irq(int irq, void *dev_id)
+{
+ struct dc_i2c *i2c = dev_id;
+ int cmd_status = dc_i2c_cmd_status(i2c);
+ unsigned long flags;
+ u8 addr_cmd;
+
+ writeb_relaxed(1, i2c->regs + II_INTFLAG_CLEAR);
+
+ spin_lock_irqsave(&i2c->lock, flags);
+
+ if (cmd_status == II_CMD_STATUS_ACK_BAD
+ || cmd_status == II_CMD_STATUS_ABORT) {
+ i2c->error = -EIO;
+ complete(&i2c->done);
+ goto out;
+ }
+
+ switch (i2c->state) {
+ case STATE_START:
+ addr_cmd = dc_i2c_addr_cmd(i2c->msg);
+ dc_i2c_write_byte(i2c, addr_cmd);
+ i2c->state = STATE_ADDR;
+ break;
+ case STATE_ADDR:
+ if (i2c->msg->flags & I2C_M_RD) {
+ dc_i2c_next_read(i2c);
+ i2c->state = STATE_READ;
+ break;
+ }
+ i2c->state = STATE_WRITE;
+ /* fall through */
+ case STATE_WRITE:
+ if (i2c->msgbuf_ptr < i2c->msg->len)
+ dc_i2c_write_buf(i2c);
+ else
+ dc_i2c_stop(i2c);
+ break;
+ case STATE_READ:
+ if (i2c->msgbuf_ptr < i2c->msg->len)
+ dc_i2c_read_buf(i2c);
+ else
+ dc_i2c_stop(i2c);
+ break;
+ case STATE_STOP:
+ i2c->state = STATE_IDLE;
+ complete(&i2c->done);
+ break;
+ }
+
+out:
+ spin_unlock_irqrestore(&i2c->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static int dc_i2c_xfer_msg(struct dc_i2c *i2c, struct i2c_msg *msg, int first,
+ int last)
+{
+ unsigned long timeout = msecs_to_jiffies(TIMEOUT_MS);
+ unsigned long flags;
+
+ spin_lock_irqsave(&i2c->lock, flags);
+ i2c->msg = msg;
+ i2c->msgbuf_ptr = 0;
+ i2c->last = last;
+ i2c->error = 0;
+
+ reinit_completion(&i2c->done);
+ dc_i2c_set_irq(i2c, 1);
+ dc_i2c_start_msg(i2c, first);
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ timeout = wait_for_completion_timeout(&i2c->done, timeout);
+ dc_i2c_set_irq(i2c, 0);
+ if (timeout == 0) {
+ i2c->state = STATE_IDLE;
+ return -ETIMEDOUT;
+ }
+
+ if (i2c->error)
+ return i2c->error;
+
+ return 0;
+}
+
+static int dc_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct dc_i2c *i2c = adap->algo_data;
+ int i, ret;
+
+ for (i = 0; i < num; i++) {
+ ret = dc_i2c_xfer_msg(i2c, &msgs[i], i == 0, i == num - 1);
+ if (ret)
+ return ret;
+ }
+
+ return num;
+}
+
+static int dc_i2c_init_hw(struct dc_i2c *i2c)
+{
+ unsigned long clk_rate = clk_get_rate(i2c->clk);
+ unsigned int clocktime;
+
+ writeb_relaxed(II_CONTROL_LOCAL_RESET, i2c->regs + II_CONTROL);
+ udelay(100);
+ writeb_relaxed(0, i2c->regs + II_CONTROL);
+ udelay(100);
+
+ clocktime = DIV_ROUND_UP(clk_rate, 64 * i2c->frequency);
+ if (clocktime < 1 || clocktime > 0xff) {
+ dev_err(i2c->dev, "can't set bus speed of %u Hz\n",
+ i2c->frequency);
+ return -EINVAL;
+ }
+ writeb_relaxed(clocktime - 1, i2c->regs + II_CLOCKTIME);
+
+ return 0;
+}
+
+static u32 dc_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL | I2C_FUNC_NOSTART;
+}
+
+static const struct i2c_algorithm dc_i2c_algorithm = {
+ .master_xfer = dc_i2c_xfer,
+ .functionality = dc_i2c_func,
+};
+
+static int dc_i2c_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct dc_i2c *i2c;
+ struct resource *r;
+ int ret = 0, irq;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct dc_i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &i2c->frequency))
+ i2c->frequency = DEFAULT_FREQ;
+
+ i2c->dev = &pdev->dev;
+ platform_set_drvdata(pdev, i2c);
+
+ spin_lock_init(&i2c->lock);
+ init_completion(&i2c->done);
+
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c->clk))
+ return PTR_ERR(i2c->clk);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->regs = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(i2c->regs))
+ return PTR_ERR(i2c->regs);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(&pdev->dev, irq, dc_i2c_irq, 0,
+ dev_name(&pdev->dev), i2c);
+ if (ret < 0)
+ return ret;
+
+ strlcpy(i2c->adap.name, "Conexant Digicolor I2C adapter",
+ sizeof(i2c->adap.name));
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.algo = &dc_i2c_algorithm;
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.dev.of_node = np;
+ i2c->adap.algo_data = i2c;
+
+ ret = dc_i2c_init_hw(i2c);
+ if (ret)
+ return ret;
+
+ ret = clk_prepare_enable(i2c->clk);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret < 0) {
+ clk_unprepare(i2c->clk);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int dc_i2c_remove(struct platform_device *pdev)
+{
+ struct dc_i2c *i2c = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&i2c->adap);
+ clk_disable_unprepare(i2c->clk);
+
+ return 0;
+}
+
+static const struct of_device_id dc_i2c_match[] = {
+ { .compatible = "cnxt,cx92755-i2c" },
+ { },
+};
+
+static struct platform_driver dc_i2c_driver = {
+ .probe = dc_i2c_probe,
+ .remove = dc_i2c_remove,
+ .driver = {
+ .name = "digicolor-i2c",
+ .of_match_table = dc_i2c_match,
+ },
+};
+module_platform_driver(dc_i2c_driver);
+
+MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
+MODULE_DESCRIPTION("Conexant Digicolor I2C master driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c
index b3fb86af4cbb..1600edd57ce9 100644
--- a/drivers/i2c/busses/i2c-dln2.c
+++ b/drivers/i2c/busses/i2c-dln2.c
@@ -144,7 +144,6 @@ static int dln2_i2c_xfer(struct i2c_adapter *adapter,
{
struct dln2_i2c *dln2 = i2c_get_adapdata(adapter);
struct i2c_msg *pmsg;
- struct device *dev = &dln2->adapter.dev;
int i;
for (i = 0; i < num; i++) {
@@ -152,11 +151,6 @@ static int dln2_i2c_xfer(struct i2c_adapter *adapter,
pmsg = &msgs[i];
- if (pmsg->len > DLN2_I2C_MAX_XFER_SIZE) {
- dev_warn(dev, "maximum transfer size exceeded\n");
- return -EOPNOTSUPP;
- }
-
if (pmsg->flags & I2C_M_RD) {
ret = dln2_i2c_read(dln2, pmsg->addr, pmsg->buf,
pmsg->len);
@@ -187,6 +181,11 @@ static const struct i2c_algorithm dln2_i2c_usb_algorithm = {
.functionality = dln2_i2c_func,
};
+static struct i2c_adapter_quirks dln2_i2c_quirks = {
+ .max_read_len = DLN2_I2C_MAX_XFER_SIZE,
+ .max_write_len = DLN2_I2C_MAX_XFER_SIZE,
+};
+
static int dln2_i2c_probe(struct platform_device *pdev)
{
int ret;
@@ -209,7 +208,9 @@ static int dln2_i2c_probe(struct platform_device *pdev)
dln2->adapter.owner = THIS_MODULE;
dln2->adapter.class = I2C_CLASS_HWMON;
dln2->adapter.algo = &dln2_i2c_usb_algorithm;
+ dln2->adapter.quirks = &dln2_i2c_quirks;
dln2->adapter.dev.parent = dev;
+ dln2->adapter.dev.of_node = dev->of_node;
i2c_set_adapdata(&dln2->adapter, dln2);
snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d",
"dln2-i2c", dev_name(pdev->dev.parent), dln2->port);
diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
index 8fafb254e42a..5ecbb3fdc27e 100644
--- a/drivers/i2c/busses/i2c-i801.c
+++ b/drivers/i2c/busses/i2c-i801.c
@@ -223,8 +223,6 @@ struct i801_priv {
#endif
};
-static struct pci_driver i801_driver;
-
#define FEATURE_SMBUS_PEC (1 << 0)
#define FEATURE_BLOCK_BUFFER (1 << 1)
#define FEATURE_BLOCK_PROC (1 << 2)
@@ -1140,7 +1138,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
int err, i;
struct i801_priv *priv;
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
@@ -1182,34 +1180,35 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
}
priv->features &= ~disable_features;
- err = pci_enable_device(dev);
+ err = pcim_enable_device(dev);
if (err) {
dev_err(&dev->dev, "Failed to enable SMBus PCI device (%d)\n",
err);
- goto exit;
+ return err;
}
+ pcim_pin_device(dev);
/* Determine the address of the SMBus area */
priv->smba = pci_resource_start(dev, SMBBAR);
if (!priv->smba) {
- dev_err(&dev->dev, "SMBus base address uninitialized, "
- "upgrade BIOS\n");
- err = -ENODEV;
- goto exit;
+ dev_err(&dev->dev,
+ "SMBus base address uninitialized, upgrade BIOS\n");
+ return -ENODEV;
}
err = acpi_check_resource_conflict(&dev->resource[SMBBAR]);
if (err) {
- err = -ENODEV;
- goto exit;
+ return -ENODEV;
}
- err = pci_request_region(dev, SMBBAR, i801_driver.name);
+ err = pcim_iomap_regions(dev, 1 << SMBBAR,
+ dev_driver_string(&dev->dev));
if (err) {
- dev_err(&dev->dev, "Failed to request SMBus region "
- "0x%lx-0x%Lx\n", priv->smba,
+ dev_err(&dev->dev,
+ "Failed to request SMBus region 0x%lx-0x%Lx\n",
+ priv->smba,
(unsigned long long)pci_resource_end(dev, SMBBAR));
- goto exit;
+ return err;
}
pci_read_config_byte(priv->pci_dev, SMBHSTCFG, &temp);
@@ -1254,8 +1253,9 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (priv->features & FEATURE_IRQ) {
init_waitqueue_head(&priv->waitq);
- err = request_irq(dev->irq, i801_isr, IRQF_SHARED,
- i801_driver.name, priv);
+ err = devm_request_irq(&dev->dev, dev->irq, i801_isr,
+ IRQF_SHARED,
+ dev_driver_string(&dev->dev), priv);
if (err) {
dev_err(&dev->dev, "Failed to allocate irq %d: %d\n",
dev->irq, err);
@@ -1276,7 +1276,7 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
err = i2c_add_adapter(&priv->adapter);
if (err) {
dev_err(&dev->dev, "Failed to add SMBus adapter\n");
- goto exit_free_irq;
+ return err;
}
i801_probe_optional_slaves(priv);
@@ -1286,14 +1286,6 @@ static int i801_probe(struct pci_dev *dev, const struct pci_device_id *id)
pci_set_drvdata(dev, priv);
return 0;
-
-exit_free_irq:
- if (priv->features & FEATURE_IRQ)
- free_irq(dev->irq, priv);
- pci_release_region(dev, SMBBAR);
-exit:
- kfree(priv);
- return err;
}
static void i801_remove(struct pci_dev *dev)
@@ -1304,11 +1296,6 @@ static void i801_remove(struct pci_dev *dev)
i2c_del_adapter(&priv->adapter);
pci_write_config_byte(dev, SMBHSTCFG, priv->original_hstcfg);
- if (priv->features & FEATURE_IRQ)
- free_irq(dev->irq, priv);
- pci_release_region(dev, SMBBAR);
-
- kfree(priv);
/*
* do not call pci_disable_device(dev) since it can cause hard hangs on
* some systems during power-off (eg. Fujitsu-Siemens Lifebook E8010)
@@ -1330,7 +1317,7 @@ static int i801_resume(struct pci_dev *dev)
{
pci_set_power_state(dev, PCI_D0);
pci_restore_state(dev);
- return pci_enable_device(dev);
+ return 0;
}
#else
#define i801_suspend NULL
diff --git a/drivers/i2c/busses/i2c-img-scb.c b/drivers/i2c/busses/i2c-img-scb.c
index 0fcc1694c607..00ffd6613680 100644
--- a/drivers/i2c/busses/i2c-img-scb.c
+++ b/drivers/i2c/busses/i2c-img-scb.c
@@ -988,15 +988,16 @@ out:
static int img_i2c_reset_bus(struct img_i2c *i2c)
{
unsigned long flags;
- int ret;
+ unsigned long time_left;
spin_lock_irqsave(&i2c->lock, flags);
reinit_completion(&i2c->msg_complete);
img_i2c_reset_start(i2c);
spin_unlock_irqrestore(&i2c->lock, flags);
- ret = wait_for_completion_timeout(&i2c->msg_complete, IMG_I2C_TIMEOUT);
- if (ret == 0)
+ time_left = wait_for_completion_timeout(&i2c->msg_complete,
+ IMG_I2C_TIMEOUT);
+ if (time_left == 0)
return -ETIMEDOUT;
return 0;
}
@@ -1007,6 +1008,7 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
struct img_i2c *i2c = i2c_get_adapdata(adap);
bool atomic = false;
int i, ret;
+ unsigned long time_left;
if (i2c->mode == MODE_SUSPEND) {
WARN(1, "refusing to service transaction in suspended state\n");
@@ -1068,11 +1070,11 @@ static int img_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
img_i2c_write(i2c);
spin_unlock_irqrestore(&i2c->lock, flags);
- ret = wait_for_completion_timeout(&i2c->msg_complete,
- IMG_I2C_TIMEOUT);
+ time_left = wait_for_completion_timeout(&i2c->msg_complete,
+ IMG_I2C_TIMEOUT);
del_timer_sync(&i2c->check_timer);
- if (ret == 0) {
+ if (time_left == 0) {
dev_err(adap->dev.parent, "i2c transfer timed out\n");
i2c->msg_status = -ETIMEDOUT;
break;
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index d7b26fc6f432..a53a7dd66945 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -601,6 +601,7 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
struct i2c_msg *msgs)
{
int result;
+ unsigned long time_left;
unsigned int temp = 0;
unsigned long orig_jiffies = jiffies;
struct imx_i2c_dma *dma = i2c_imx->dma;
@@ -624,10 +625,10 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
*/
imx_i2c_write_reg(msgs->addr << 1, i2c_imx, IMX_I2C_I2DR);
reinit_completion(&i2c_imx->dma->cmd_complete);
- result = wait_for_completion_timeout(
+ time_left = wait_for_completion_timeout(
&i2c_imx->dma->cmd_complete,
msecs_to_jiffies(DMA_TIMEOUT));
- if (result == 0) {
+ if (time_left == 0) {
dmaengine_terminate_all(dma->chan_using);
return -ETIMEDOUT;
}
@@ -663,6 +664,7 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
struct i2c_msg *msgs, bool is_lastmsg)
{
int result;
+ unsigned long time_left;
unsigned int temp;
unsigned long orig_jiffies = jiffies;
struct imx_i2c_dma *dma = i2c_imx->dma;
@@ -682,10 +684,10 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
return result;
reinit_completion(&i2c_imx->dma->cmd_complete);
- result = wait_for_completion_timeout(
+ time_left = wait_for_completion_timeout(
&i2c_imx->dma->cmd_complete,
msecs_to_jiffies(DMA_TIMEOUT));
- if (result == 0) {
+ if (time_left == 0) {
dmaengine_terminate_all(dma->chan_using);
return -ETIMEDOUT;
}
diff --git a/drivers/i2c/busses/i2c-ismt.c b/drivers/i2c/busses/i2c-ismt.c
index f2b0ff011631..f994712d0904 100644
--- a/drivers/i2c/busses/i2c-ismt.c
+++ b/drivers/i2c/busses/i2c-ismt.c
@@ -380,6 +380,7 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
int size, union i2c_smbus_data *data)
{
int ret;
+ unsigned long time_left;
dma_addr_t dma_addr = 0; /* address of the data buffer */
u8 dma_size = 0;
enum dma_data_direction dma_direction = 0;
@@ -578,13 +579,13 @@ static int ismt_access(struct i2c_adapter *adap, u16 addr,
ismt_submit_desc(priv);
/* Now we wait for interrupt completion, 1s */
- ret = wait_for_completion_timeout(&priv->cmp, HZ*1);
+ time_left = wait_for_completion_timeout(&priv->cmp, HZ*1);
/* unmap the data buffer */
if (dma_size != 0)
dma_unmap_single(&adap->dev, dma_addr, dma_size, dma_direction);
- if (unlikely(!ret)) {
+ if (unlikely(!time_left)) {
dev_err(dev, "completion wait timed out\n");
ret = -ETIMEDOUT;
goto out;
diff --git a/drivers/i2c/busses/i2c-jz4780.c b/drivers/i2c/busses/i2c-jz4780.c
new file mode 100644
index 000000000000..19b2d689a5ef
--- /dev/null
+++ b/drivers/i2c/busses/i2c-jz4780.c
@@ -0,0 +1,833 @@
+/*
+ * Ingenic JZ4780 I2C bus driver
+ *
+ * Copyright (C) 2006 - 2009 Ingenic Semiconductor Inc.
+ * Copyright (C) 2015 Imagination Technologies
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/time.h>
+
+#define JZ4780_I2C_CTRL 0x00
+#define JZ4780_I2C_TAR 0x04
+#define JZ4780_I2C_SAR 0x08
+#define JZ4780_I2C_DC 0x10
+#define JZ4780_I2C_SHCNT 0x14
+#define JZ4780_I2C_SLCNT 0x18
+#define JZ4780_I2C_FHCNT 0x1C
+#define JZ4780_I2C_FLCNT 0x20
+#define JZ4780_I2C_INTST 0x2C
+#define JZ4780_I2C_INTM 0x30
+#define JZ4780_I2C_RXTL 0x38
+#define JZ4780_I2C_TXTL 0x3C
+#define JZ4780_I2C_CINTR 0x40
+#define JZ4780_I2C_CRXUF 0x44
+#define JZ4780_I2C_CRXOF 0x48
+#define JZ4780_I2C_CTXOF 0x4C
+#define JZ4780_I2C_CRXREQ 0x50
+#define JZ4780_I2C_CTXABRT 0x54
+#define JZ4780_I2C_CRXDONE 0x58
+#define JZ4780_I2C_CACT 0x5C
+#define JZ4780_I2C_CSTP 0x60
+#define JZ4780_I2C_CSTT 0x64
+#define JZ4780_I2C_CGC 0x68
+#define JZ4780_I2C_ENB 0x6C
+#define JZ4780_I2C_STA 0x70
+#define JZ4780_I2C_TXABRT 0x80
+#define JZ4780_I2C_DMACR 0x88
+#define JZ4780_I2C_DMATDLR 0x8C
+#define JZ4780_I2C_DMARDLR 0x90
+#define JZ4780_I2C_SDASU 0x94
+#define JZ4780_I2C_ACKGC 0x98
+#define JZ4780_I2C_ENSTA 0x9C
+#define JZ4780_I2C_SDAHD 0xD0
+
+#define JZ4780_I2C_CTRL_STPHLD BIT(7)
+#define JZ4780_I2C_CTRL_SLVDIS BIT(6)
+#define JZ4780_I2C_CTRL_REST BIT(5)
+#define JZ4780_I2C_CTRL_MATP BIT(4)
+#define JZ4780_I2C_CTRL_SATP BIT(3)
+#define JZ4780_I2C_CTRL_SPDF BIT(2)
+#define JZ4780_I2C_CTRL_SPDS BIT(1)
+#define JZ4780_I2C_CTRL_MD BIT(0)
+
+#define JZ4780_I2C_STA_SLVACT BIT(6)
+#define JZ4780_I2C_STA_MSTACT BIT(5)
+#define JZ4780_I2C_STA_RFF BIT(4)
+#define JZ4780_I2C_STA_RFNE BIT(3)
+#define JZ4780_I2C_STA_TFE BIT(2)
+#define JZ4780_I2C_STA_TFNF BIT(1)
+#define JZ4780_I2C_STA_ACT BIT(0)
+
+static const char * const jz4780_i2c_abrt_src[] = {
+ "ABRT_7B_ADDR_NOACK",
+ "ABRT_10ADDR1_NOACK",
+ "ABRT_10ADDR2_NOACK",
+ "ABRT_XDATA_NOACK",
+ "ABRT_GCALL_NOACK",
+ "ABRT_GCALL_READ",
+ "ABRT_HS_ACKD",
+ "SBYTE_ACKDET",
+ "ABRT_HS_NORSTRT",
+ "SBYTE_NORSTRT",
+ "ABRT_10B_RD_NORSTRT",
+ "ABRT_MASTER_DIS",
+ "ARB_LOST",
+ "SLVFLUSH_TXFIFO",
+ "SLV_ARBLOST",
+ "SLVRD_INTX",
+};
+
+#define JZ4780_I2C_INTST_IGC BIT(11)
+#define JZ4780_I2C_INTST_ISTT BIT(10)
+#define JZ4780_I2C_INTST_ISTP BIT(9)
+#define JZ4780_I2C_INTST_IACT BIT(8)
+#define JZ4780_I2C_INTST_RXDN BIT(7)
+#define JZ4780_I2C_INTST_TXABT BIT(6)
+#define JZ4780_I2C_INTST_RDREQ BIT(5)
+#define JZ4780_I2C_INTST_TXEMP BIT(4)
+#define JZ4780_I2C_INTST_TXOF BIT(3)
+#define JZ4780_I2C_INTST_RXFL BIT(2)
+#define JZ4780_I2C_INTST_RXOF BIT(1)
+#define JZ4780_I2C_INTST_RXUF BIT(0)
+
+#define JZ4780_I2C_INTM_MIGC BIT(11)
+#define JZ4780_I2C_INTM_MISTT BIT(10)
+#define JZ4780_I2C_INTM_MISTP BIT(9)
+#define JZ4780_I2C_INTM_MIACT BIT(8)
+#define JZ4780_I2C_INTM_MRXDN BIT(7)
+#define JZ4780_I2C_INTM_MTXABT BIT(6)
+#define JZ4780_I2C_INTM_MRDREQ BIT(5)
+#define JZ4780_I2C_INTM_MTXEMP BIT(4)
+#define JZ4780_I2C_INTM_MTXOF BIT(3)
+#define JZ4780_I2C_INTM_MRXFL BIT(2)
+#define JZ4780_I2C_INTM_MRXOF BIT(1)
+#define JZ4780_I2C_INTM_MRXUF BIT(0)
+
+#define JZ4780_I2C_DC_READ BIT(8)
+
+#define JZ4780_I2C_SDAHD_HDENB BIT(8)
+
+#define JZ4780_I2C_ENB_I2C BIT(0)
+
+#define JZ4780_I2CSHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8))
+#define JZ4780_I2CSLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1))
+#define JZ4780_I2CFHCNT_ADJUST(n) (((n) - 8) < 6 ? 6 : ((n) - 8))
+#define JZ4780_I2CFLCNT_ADJUST(n) (((n) - 1) < 8 ? 8 : ((n) - 1))
+
+#define JZ4780_I2C_FIFO_LEN 16
+#define TX_LEVEL 3
+#define RX_LEVEL (JZ4780_I2C_FIFO_LEN - TX_LEVEL - 1)
+
+#define JZ4780_I2C_TIMEOUT 300
+
+#define BUFSIZE 200
+
+struct jz4780_i2c {
+ void __iomem *iomem;
+ int irq;
+ struct clk *clk;
+ struct i2c_adapter adap;
+
+ /* lock to protect rbuf and wbuf between xfer_rd/wr and irq handler */
+ spinlock_t lock;
+
+ /* beginning of lock scope */
+ unsigned char *rbuf;
+ int rd_total_len;
+ int rd_data_xfered;
+ int rd_cmd_xfered;
+
+ unsigned char *wbuf;
+ int wt_len;
+
+ int is_write;
+ int stop_hold;
+ int speed;
+
+ int data_buf[BUFSIZE];
+ int cmd_buf[BUFSIZE];
+ int cmd;
+
+ /* end of lock scope */
+ struct completion trans_waitq;
+};
+
+static inline unsigned short jz4780_i2c_readw(struct jz4780_i2c *i2c,
+ unsigned long offset)
+{
+ return readw(i2c->iomem + offset);
+}
+
+static inline void jz4780_i2c_writew(struct jz4780_i2c *i2c,
+ unsigned long offset, unsigned short val)
+{
+ writew(val, i2c->iomem + offset);
+}
+
+static int jz4780_i2c_disable(struct jz4780_i2c *i2c)
+{
+ unsigned short regval;
+ unsigned long loops = 5;
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_ENB, 0);
+
+ do {
+ regval = jz4780_i2c_readw(i2c, JZ4780_I2C_ENSTA);
+ if (!(regval & JZ4780_I2C_ENB_I2C))
+ return 0;
+
+ usleep_range(5000, 15000);
+ } while (--loops);
+
+ dev_err(&i2c->adap.dev, "disable failed: ENSTA=0x%04x\n", regval);
+ return -ETIMEDOUT;
+}
+
+static int jz4780_i2c_enable(struct jz4780_i2c *i2c)
+{
+ unsigned short regval;
+ unsigned long loops = 5;
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_ENB, 1);
+
+ do {
+ regval = jz4780_i2c_readw(i2c, JZ4780_I2C_ENSTA);
+ if (regval & JZ4780_I2C_ENB_I2C)
+ return 0;
+
+ usleep_range(5000, 15000);
+ } while (--loops);
+
+ dev_err(&i2c->adap.dev, "enable failed: ENSTA=0x%04x\n", regval);
+ return -ETIMEDOUT;
+}
+
+static int jz4780_i2c_set_target(struct jz4780_i2c *i2c, unsigned char address)
+{
+ unsigned short regval;
+ unsigned long loops = 5;
+
+ do {
+ regval = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
+ if ((regval & JZ4780_I2C_STA_TFE) &&
+ !(regval & JZ4780_I2C_STA_MSTACT))
+ break;
+
+ usleep_range(5000, 15000);
+ } while (--loops);
+
+ if (loops) {
+ jz4780_i2c_writew(i2c, JZ4780_I2C_TAR, address);
+ return 0;
+ }
+
+ dev_err(&i2c->adap.dev,
+ "set device to address 0x%02x failed, STA=0x%04x\n",
+ address, regval);
+
+ return -ENXIO;
+}
+
+static int jz4780_i2c_set_speed(struct jz4780_i2c *i2c)
+{
+ int dev_clk_khz = clk_get_rate(i2c->clk) / 1000;
+ int cnt_high = 0; /* HIGH period count of the SCL clock */
+ int cnt_low = 0; /* LOW period count of the SCL clock */
+ int cnt_period = 0; /* period count of the SCL clock */
+ int setup_time = 0;
+ int hold_time = 0;
+ unsigned short tmp = 0;
+ int i2c_clk = i2c->speed;
+
+ if (jz4780_i2c_disable(i2c))
+ dev_dbg(&i2c->adap.dev, "i2c not disabled\n");
+
+ /*
+ * 1 JZ4780_I2C cycle equals to cnt_period PCLK(i2c_clk)
+ * standard mode, min LOW and HIGH period are 4700 ns and 4000 ns
+ * fast mode, min LOW and HIGH period are 1300 ns and 600 ns
+ */
+ cnt_period = dev_clk_khz / i2c_clk;
+
+ if (i2c_clk <= 100)
+ cnt_high = (cnt_period * 4000) / (4700 + 4000);
+ else
+ cnt_high = (cnt_period * 600) / (1300 + 600);
+
+ cnt_low = cnt_period - cnt_high;
+
+ /*
+ * NOTE: JZ4780_I2C_CTRL_REST can't set when i2c enabled, because
+ * normal read are 2 messages, we cannot disable i2c controller
+ * between these two messages, this means that we must always set
+ * JZ4780_I2C_CTRL_REST when init JZ4780_I2C_CTRL
+ *
+ */
+ if (i2c_clk <= 100) {
+ tmp = JZ4780_I2C_CTRL_SPDS | JZ4780_I2C_CTRL_REST
+ | JZ4780_I2C_CTRL_SLVDIS | JZ4780_I2C_CTRL_MD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_SHCNT,
+ JZ4780_I2CSHCNT_ADJUST(cnt_high));
+ jz4780_i2c_writew(i2c, JZ4780_I2C_SLCNT,
+ JZ4780_I2CSLCNT_ADJUST(cnt_low));
+ } else {
+ tmp = JZ4780_I2C_CTRL_SPDF | JZ4780_I2C_CTRL_REST
+ | JZ4780_I2C_CTRL_SLVDIS | JZ4780_I2C_CTRL_MD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_FHCNT,
+ JZ4780_I2CFHCNT_ADJUST(cnt_high));
+ jz4780_i2c_writew(i2c, JZ4780_I2C_FLCNT,
+ JZ4780_I2CFLCNT_ADJUST(cnt_low));
+ }
+
+ /*
+ * a i2c device must internally provide a hold time at least 300ns
+ * tHD:DAT
+ * Standard Mode: min=300ns, max=3450ns
+ * Fast Mode: min=0ns, max=900ns
+ * tSU:DAT
+ * Standard Mode: min=250ns, max=infinite
+ * Fast Mode: min=100(250ns is recommended), max=infinite
+ *
+ * 1i2c_clk = 10^6 / dev_clk_khz
+ * on FPGA, dev_clk_khz = 12000, so 1i2c_clk = 1000/12 = 83ns
+ * on Pisces(1008M), dev_clk_khz=126000, so 1i2c_clk = 1000 / 126 = 8ns
+ *
+ * The actual hold time is (SDAHD + 1) * (i2c_clk period).
+ *
+ * Length of setup time calculated using (SDASU - 1) * (ic_clk_period)
+ *
+ */
+ if (i2c_clk <= 100) { /* standard mode */
+ setup_time = 300;
+ hold_time = 400;
+ } else {
+ setup_time = 450;
+ hold_time = 450;
+ }
+
+ hold_time = ((hold_time * dev_clk_khz) / 1000000) - 1;
+ setup_time = ((setup_time * dev_clk_khz) / 1000000) + 1;
+
+ if (setup_time > 255)
+ setup_time = 255;
+
+ if (setup_time <= 0)
+ setup_time = 1;
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_SDASU, setup_time);
+
+ if (hold_time > 255)
+ hold_time = 255;
+
+ if (hold_time >= 0) {
+ /*i2c hold time enable */
+ hold_time |= JZ4780_I2C_SDAHD_HDENB;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, hold_time);
+ } else {
+ /* disable hold time */
+ jz4780_i2c_writew(i2c, JZ4780_I2C_SDAHD, 0);
+ }
+
+ return 0;
+}
+
+static int jz4780_i2c_cleanup(struct jz4780_i2c *i2c)
+{
+ int ret;
+ unsigned long flags;
+ unsigned short tmp;
+
+ spin_lock_irqsave(&i2c->lock, flags);
+
+ /* can send stop now if need */
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+ tmp &= ~JZ4780_I2C_CTRL_STPHLD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+ /* disable all interrupts first */
+ jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0);
+
+ /* then clear all interrupts */
+ jz4780_i2c_readw(i2c, JZ4780_I2C_CTXABRT);
+ jz4780_i2c_readw(i2c, JZ4780_I2C_CINTR);
+
+ /* then disable the controller */
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+ tmp &= ~JZ4780_I2C_ENB_I2C;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+ udelay(10);
+ tmp |= JZ4780_I2C_ENB_I2C;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ ret = jz4780_i2c_disable(i2c);
+ if (ret)
+ dev_err(&i2c->adap.dev,
+ "unable to disable device during cleanup!\n");
+
+ if (unlikely(jz4780_i2c_readw(i2c, JZ4780_I2C_INTM)
+ & jz4780_i2c_readw(i2c, JZ4780_I2C_INTST)))
+ dev_err(&i2c->adap.dev,
+ "device has interrupts after a complete cleanup!\n");
+
+ return ret;
+}
+
+static int jz4780_i2c_prepare(struct jz4780_i2c *i2c)
+{
+ jz4780_i2c_set_speed(i2c);
+ return jz4780_i2c_enable(i2c);
+}
+
+static void jz4780_i2c_send_rcmd(struct jz4780_i2c *i2c, int cmd_count)
+{
+ int i;
+
+ for (i = 0; i < cmd_count; i++)
+ jz4780_i2c_writew(i2c, JZ4780_I2C_DC, JZ4780_I2C_DC_READ);
+}
+
+static void jz4780_i2c_trans_done(struct jz4780_i2c *i2c)
+{
+ jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0);
+ complete(&i2c->trans_waitq);
+}
+
+static irqreturn_t jz4780_i2c_irq(int irqno, void *dev_id)
+{
+ unsigned short tmp;
+ unsigned short intst;
+ unsigned short intmsk;
+ struct jz4780_i2c *i2c = dev_id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&i2c->lock, flags);
+ intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM);
+ intst = jz4780_i2c_readw(i2c, JZ4780_I2C_INTST);
+
+ intst &= intmsk;
+
+ if (intst & JZ4780_I2C_INTST_TXABT) {
+ jz4780_i2c_trans_done(i2c);
+ goto done;
+ }
+
+ if (intst & JZ4780_I2C_INTST_RXOF) {
+ dev_dbg(&i2c->adap.dev, "received fifo overflow!\n");
+ jz4780_i2c_trans_done(i2c);
+ goto done;
+ }
+
+ /*
+ * When reading, always drain RX FIFO before we send more Read
+ * Commands to avoid fifo overrun
+ */
+ if (i2c->is_write == 0) {
+ int rd_left;
+
+ while ((jz4780_i2c_readw(i2c, JZ4780_I2C_STA)
+ & JZ4780_I2C_STA_RFNE)) {
+ *(i2c->rbuf++) = jz4780_i2c_readw(i2c, JZ4780_I2C_DC)
+ & 0xff;
+ i2c->rd_data_xfered++;
+ if (i2c->rd_data_xfered == i2c->rd_total_len) {
+ jz4780_i2c_trans_done(i2c);
+ goto done;
+ }
+ }
+
+ rd_left = i2c->rd_total_len - i2c->rd_data_xfered;
+
+ if (rd_left <= JZ4780_I2C_FIFO_LEN)
+ jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, rd_left - 1);
+ }
+
+ if (intst & JZ4780_I2C_INTST_TXEMP) {
+ if (i2c->is_write == 0) {
+ int cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered;
+ int max_send = (JZ4780_I2C_FIFO_LEN - 1)
+ - (i2c->rd_cmd_xfered
+ - i2c->rd_data_xfered);
+ int cmd_to_send = min(cmd_left, max_send);
+
+ if (i2c->rd_cmd_xfered != 0)
+ cmd_to_send = min(cmd_to_send,
+ JZ4780_I2C_FIFO_LEN
+ - TX_LEVEL - 1);
+
+ if (cmd_to_send) {
+ jz4780_i2c_send_rcmd(i2c, cmd_to_send);
+ i2c->rd_cmd_xfered += cmd_to_send;
+ }
+
+ cmd_left = i2c->rd_total_len - i2c->rd_cmd_xfered;
+ if (cmd_left == 0) {
+ intmsk = jz4780_i2c_readw(i2c, JZ4780_I2C_INTM);
+ intmsk &= ~JZ4780_I2C_INTM_MTXEMP;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, intmsk);
+
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+ tmp &= ~JZ4780_I2C_CTRL_STPHLD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+ }
+ } else {
+ unsigned short data;
+ unsigned short i2c_sta;
+
+ i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
+
+ while ((i2c_sta & JZ4780_I2C_STA_TFNF) &&
+ (i2c->wt_len > 0)) {
+ i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
+ data = *i2c->wbuf;
+ data &= ~JZ4780_I2C_DC_READ;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_DC,
+ data);
+ i2c->wbuf++;
+ i2c->wt_len--;
+ }
+
+ if (i2c->wt_len == 0) {
+ if (!i2c->stop_hold) {
+ tmp = jz4780_i2c_readw(i2c,
+ JZ4780_I2C_CTRL);
+ tmp &= ~JZ4780_I2C_CTRL_STPHLD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL,
+ tmp);
+ }
+
+ jz4780_i2c_trans_done(i2c);
+ goto done;
+ }
+ }
+ }
+
+done:
+ spin_unlock_irqrestore(&i2c->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static void jz4780_i2c_txabrt(struct jz4780_i2c *i2c, int src)
+{
+ int i;
+
+ dev_err(&i2c->adap.dev, "txabrt: 0x%08x\n", src);
+ dev_err(&i2c->adap.dev, "device addr=%x\n",
+ jz4780_i2c_readw(i2c, JZ4780_I2C_TAR));
+ dev_err(&i2c->adap.dev, "send cmd count:%d %d\n",
+ i2c->cmd, i2c->cmd_buf[i2c->cmd]);
+ dev_err(&i2c->adap.dev, "receive data count:%d %d\n",
+ i2c->cmd, i2c->data_buf[i2c->cmd]);
+
+ for (i = 0; i < 16; i++) {
+ if (src & BIT(i))
+ dev_dbg(&i2c->adap.dev, "I2C TXABRT[%d]=%s\n",
+ i, jz4780_i2c_abrt_src[i]);
+ }
+}
+
+static inline int jz4780_i2c_xfer_read(struct jz4780_i2c *i2c,
+ unsigned char *buf, int len, int cnt,
+ int idx)
+{
+ int ret = 0;
+ long timeout;
+ int wait_time = JZ4780_I2C_TIMEOUT * (len + 5);
+ unsigned short tmp;
+ unsigned long flags;
+
+ memset(buf, 0, len);
+
+ spin_lock_irqsave(&i2c->lock, flags);
+
+ i2c->stop_hold = 0;
+ i2c->is_write = 0;
+ i2c->rbuf = buf;
+ i2c->rd_total_len = len;
+ i2c->rd_data_xfered = 0;
+ i2c->rd_cmd_xfered = 0;
+
+ if (len <= JZ4780_I2C_FIFO_LEN)
+ jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, len - 1);
+ else
+ jz4780_i2c_writew(i2c, JZ4780_I2C_RXTL, RX_LEVEL);
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL);
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_INTM,
+ JZ4780_I2C_INTM_MRXFL | JZ4780_I2C_INTM_MTXEMP
+ | JZ4780_I2C_INTM_MTXABT | JZ4780_I2C_INTM_MRXOF);
+
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+ tmp |= JZ4780_I2C_CTRL_STPHLD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ timeout = wait_for_completion_timeout(&i2c->trans_waitq,
+ msecs_to_jiffies(wait_time));
+
+ if (!timeout) {
+ dev_err(&i2c->adap.dev, "irq read timeout\n");
+ dev_dbg(&i2c->adap.dev, "send cmd count:%d %d\n",
+ i2c->cmd, i2c->cmd_buf[i2c->cmd]);
+ dev_dbg(&i2c->adap.dev, "receive data count:%d %d\n",
+ i2c->cmd, i2c->data_buf[i2c->cmd]);
+ ret = -EIO;
+ }
+
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_TXABRT);
+ if (tmp) {
+ jz4780_i2c_txabrt(i2c, tmp);
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static inline int jz4780_i2c_xfer_write(struct jz4780_i2c *i2c,
+ unsigned char *buf, int len,
+ int cnt, int idx)
+{
+ int ret = 0;
+ int wait_time = JZ4780_I2C_TIMEOUT * (len + 5);
+ long timeout;
+ unsigned short tmp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&i2c->lock, flags);
+
+ if (idx < (cnt - 1))
+ i2c->stop_hold = 1;
+ else
+ i2c->stop_hold = 0;
+
+ i2c->is_write = 1;
+ i2c->wbuf = buf;
+ i2c->wt_len = len;
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_TXTL, TX_LEVEL);
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, JZ4780_I2C_INTM_MTXEMP
+ | JZ4780_I2C_INTM_MTXABT);
+
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+ tmp |= JZ4780_I2C_CTRL_STPHLD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+ spin_unlock_irqrestore(&i2c->lock, flags);
+
+ timeout = wait_for_completion_timeout(&i2c->trans_waitq,
+ msecs_to_jiffies(wait_time));
+ if (timeout && !i2c->stop_hold) {
+ unsigned short i2c_sta;
+ int write_in_process;
+
+ timeout = JZ4780_I2C_TIMEOUT * 100;
+ for (; timeout > 0; timeout--) {
+ i2c_sta = jz4780_i2c_readw(i2c, JZ4780_I2C_STA);
+
+ write_in_process = (i2c_sta & JZ4780_I2C_STA_MSTACT) ||
+ !(i2c_sta & JZ4780_I2C_STA_TFE);
+ if (!write_in_process)
+ break;
+ udelay(10);
+ }
+ }
+
+ if (!timeout) {
+ dev_err(&i2c->adap.dev, "write wait timeout\n");
+ ret = -EIO;
+ }
+
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_TXABRT);
+ if (tmp) {
+ jz4780_i2c_txabrt(i2c, tmp);
+ ret = -EIO;
+ }
+
+ return ret;
+}
+
+static int jz4780_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msg,
+ int count)
+{
+ int i = -EIO;
+ int ret = 0;
+ struct jz4780_i2c *i2c = adap->algo_data;
+
+ ret = jz4780_i2c_prepare(i2c);
+ if (ret) {
+ dev_err(&i2c->adap.dev, "I2C prepare failed\n");
+ goto out;
+ }
+
+ if (msg->addr != jz4780_i2c_readw(i2c, JZ4780_I2C_TAR)) {
+ ret = jz4780_i2c_set_target(i2c, msg->addr);
+ if (ret)
+ goto out;
+ }
+ for (i = 0; i < count; i++, msg++) {
+ if (msg->flags & I2C_M_RD)
+ ret = jz4780_i2c_xfer_read(i2c, msg->buf, msg->len,
+ count, i);
+ else
+ ret = jz4780_i2c_xfer_write(i2c, msg->buf, msg->len,
+ count, i);
+
+ if (ret)
+ goto out;
+ }
+
+ ret = i;
+
+out:
+ jz4780_i2c_cleanup(i2c);
+ return ret;
+}
+
+static u32 jz4780_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm jz4780_i2c_algorithm = {
+ .master_xfer = jz4780_i2c_xfer,
+ .functionality = jz4780_i2c_functionality,
+};
+
+static const struct of_device_id jz4780_i2c_of_matches[] = {
+ { .compatible = "ingenic,jz4780-i2c", },
+ { /* sentinel */ }
+};
+
+static int jz4780_i2c_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ unsigned int clk_freq = 0;
+ unsigned short tmp;
+ struct resource *r;
+ struct jz4780_i2c *i2c;
+
+ i2c = devm_kzalloc(&pdev->dev, sizeof(struct jz4780_i2c), GFP_KERNEL);
+ if (!i2c)
+ return -ENOMEM;
+
+ i2c->adap.owner = THIS_MODULE;
+ i2c->adap.algo = &jz4780_i2c_algorithm;
+ i2c->adap.algo_data = i2c;
+ i2c->adap.retries = 5;
+ i2c->adap.dev.parent = &pdev->dev;
+ i2c->adap.dev.of_node = pdev->dev.of_node;
+ sprintf(i2c->adap.name, "%s", pdev->name);
+
+ init_completion(&i2c->trans_waitq);
+ spin_lock_init(&i2c->lock);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ i2c->iomem = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(i2c->iomem))
+ return PTR_ERR(i2c->iomem);
+
+ platform_set_drvdata(pdev, i2c);
+
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(i2c->clk))
+ return PTR_ERR(i2c->clk);
+
+ clk_prepare_enable(i2c->clk);
+
+ if (of_property_read_u32(pdev->dev.of_node, "clock-frequency",
+ &clk_freq)) {
+ dev_err(&pdev->dev, "clock-frequency not specified in DT");
+ return clk_freq;
+ }
+
+ i2c->speed = clk_freq / 1000;
+ jz4780_i2c_set_speed(i2c);
+
+ dev_info(&pdev->dev, "Bus frequency is %d KHz\n", i2c->speed);
+
+ tmp = jz4780_i2c_readw(i2c, JZ4780_I2C_CTRL);
+ tmp &= ~JZ4780_I2C_CTRL_STPHLD;
+ jz4780_i2c_writew(i2c, JZ4780_I2C_CTRL, tmp);
+
+ jz4780_i2c_writew(i2c, JZ4780_I2C_INTM, 0x0);
+
+ i2c->cmd = 0;
+ memset(i2c->cmd_buf, 0, BUFSIZE);
+ memset(i2c->data_buf, 0, BUFSIZE);
+
+ i2c->irq = platform_get_irq(pdev, 0);
+ ret = devm_request_irq(&pdev->dev, i2c->irq, jz4780_i2c_irq, 0,
+ dev_name(&pdev->dev), i2c);
+ if (ret) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ ret = i2c_add_adapter(&i2c->adap);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to add bus\n");
+ goto err;
+ }
+
+ return 0;
+
+err:
+ clk_disable_unprepare(i2c->clk);
+ return ret;
+}
+
+static int jz4780_i2c_remove(struct platform_device *pdev)
+{
+ struct jz4780_i2c *i2c = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(i2c->clk);
+ i2c_del_adapter(&i2c->adap);
+ return 0;
+}
+
+static struct platform_driver jz4780_i2c_driver = {
+ .probe = jz4780_i2c_probe,
+ .remove = jz4780_i2c_remove,
+ .driver = {
+ .name = "jz4780-i2c",
+ .of_match_table = of_match_ptr(jz4780_i2c_of_matches),
+ },
+};
+
+module_platform_driver(jz4780_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("ztyan<ztyan@ingenic.cn>");
+MODULE_DESCRIPTION("i2c driver for JZ4780 SoCs");
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index c74cc2be613b..48ecffecc0ed 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -29,6 +29,7 @@
#include <linux/delay.h>
#include <asm/mpc52xx.h>
+#include <asm/mpc85xx.h>
#include <sysdev/fsl_soc.h>
#define DRV_NAME "mpc-i2c"
@@ -95,8 +96,9 @@ static irqreturn_t mpc_i2c_isr(int irq, void *dev_id)
i2c->interrupt = readb(i2c->base + MPC_I2C_SR);
writeb(0, i2c->base + MPC_I2C_SR);
wake_up(&i2c->queue);
+ return IRQ_HANDLED;
}
- return IRQ_HANDLED;
+ return IRQ_NONE;
}
/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
@@ -346,6 +348,33 @@ static u32 mpc_i2c_get_sec_cfg_8xxx(void)
return val;
}
+static u32 mpc_i2c_get_prescaler_8xxx(void)
+{
+ /* mpc83xx and mpc82xx all have prescaler 1 */
+ u32 prescaler = 1;
+
+ /* mpc85xx */
+ if (pvr_version_is(PVR_VER_E500V1) || pvr_version_is(PVR_VER_E500V2)
+ || pvr_version_is(PVR_VER_E500MC)
+ || pvr_version_is(PVR_VER_E5500)
+ || pvr_version_is(PVR_VER_E6500)) {
+ unsigned int svr = mfspr(SPRN_SVR);
+
+ if ((SVR_SOC_VER(svr) == SVR_8540)
+ || (SVR_SOC_VER(svr) == SVR_8541)
+ || (SVR_SOC_VER(svr) == SVR_8560)
+ || (SVR_SOC_VER(svr) == SVR_8555)
+ || (SVR_SOC_VER(svr) == SVR_8610))
+ /* the above 85xx SoCs have prescaler 1 */
+ prescaler = 1;
+ else
+ /* all the other 85xx have prescaler 2 */
+ prescaler = 2;
+ }
+
+ return prescaler;
+}
+
static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
u32 prescaler, u32 *real_clk)
{
@@ -363,7 +392,7 @@ static int mpc_i2c_get_fdr_8xxx(struct device_node *node, u32 clock,
if (of_device_is_compatible(node, "fsl,mpc8544-i2c"))
prescaler = mpc_i2c_get_sec_cfg_8xxx() ? 3 : 2;
if (!prescaler)
- prescaler = 1;
+ prescaler = mpc_i2c_get_prescaler_8xxx();
divider = fsl_get_sys_freq() / clock / prescaler;
diff --git a/drivers/i2c/busses/i2c-mxs.c b/drivers/i2c/busses/i2c-mxs.c
index ff8b12c8d25f..3e84f6c090a5 100644
--- a/drivers/i2c/busses/i2c-mxs.c
+++ b/drivers/i2c/busses/i2c-mxs.c
@@ -568,6 +568,7 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
int ret;
int flags;
int use_pio = 0;
+ unsigned long time_left;
flags = stop ? MXS_I2C_CTRL0_POST_SEND_STOP : 0;
@@ -599,9 +600,9 @@ static int mxs_i2c_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg,
if (ret)
return ret;
- ret = wait_for_completion_timeout(&i2c->cmd_complete,
+ time_left = wait_for_completion_timeout(&i2c->cmd_complete,
msecs_to_jiffies(1000));
- if (ret == 0)
+ if (!time_left)
goto timeout;
ret = i2c->cmd_err;
@@ -912,7 +913,7 @@ static void __exit mxs_i2c_exit(void)
module_exit(mxs_i2c_exit);
MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
-MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>");
MODULE_DESCRIPTION("MXS I2C Bus Driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index 97998946c4f6..bcd17e8cbcb4 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -446,9 +446,9 @@ static void setup_i2c_controller(struct nmk_i2c_dev *dev)
*/
static int read_i2c(struct nmk_i2c_dev *dev, u16 flags)
{
- u32 status = 0;
+ int status = 0;
u32 mcr, irq_mask;
- int timeout;
+ unsigned long timeout;
mcr = load_i2c_mcr_reg(dev, flags);
writel(mcr, dev->virtbase + I2C_MCR);
@@ -517,7 +517,7 @@ static int write_i2c(struct nmk_i2c_dev *dev, u16 flags)
{
u32 status = 0;
u32 mcr, irq_mask;
- int timeout;
+ unsigned long timeout;
mcr = load_i2c_mcr_reg(dev, flags);
diff --git a/drivers/i2c/busses/i2c-opal.c b/drivers/i2c/busses/i2c-opal.c
index 16f90b1a7508..75dd6d041241 100644
--- a/drivers/i2c/busses/i2c-opal.c
+++ b/drivers/i2c/busses/i2c-opal.c
@@ -104,18 +104,8 @@ static int i2c_opal_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
req.buffer_ra = cpu_to_be64(__pa(msgs[0].buf));
break;
case 2:
- /* For two messages, we basically support only simple
- * smbus transactions of a write plus a read. We might
- * want to allow also two writes but we'd have to bounce
- * the data into a single buffer.
- */
- if ((msgs[0].flags & I2C_M_RD) || !(msgs[1].flags & I2C_M_RD))
- return -EOPNOTSUPP;
- if (msgs[0].len > 4)
- return -EOPNOTSUPP;
- if (msgs[0].addr != msgs[1].addr)
- return -EOPNOTSUPP;
- req.type = OPAL_I2C_SM_READ;
+ req.type = (msgs[1].flags & I2C_M_RD) ?
+ OPAL_I2C_SM_READ : OPAL_I2C_SM_WRITE;
req.addr = cpu_to_be16(msgs[0].addr);
req.subaddr_sz = msgs[0].len;
for (i = 0; i < msgs[0].len; i++)
@@ -210,6 +200,15 @@ static const struct i2c_algorithm i2c_opal_algo = {
.functionality = i2c_opal_func,
};
+/*
+ * For two messages, we basically support simple smbus transactions of a
+ * write-then-anything.
+ */
+static struct i2c_adapter_quirks i2c_opal_quirks = {
+ .flags = I2C_AQ_COMB | I2C_AQ_COMB_WRITE_FIRST | I2C_AQ_COMB_SAME_ADDR,
+ .max_comb_1st_msg_len = 4,
+};
+
static int i2c_opal_probe(struct platform_device *pdev)
{
struct i2c_adapter *adapter;
@@ -232,6 +231,7 @@ static int i2c_opal_probe(struct platform_device *pdev)
adapter->algo = &i2c_opal_algo;
adapter->algo_data = (void *)(unsigned long)opal_id;
+ adapter->quirks = &i2c_opal_quirks;
adapter->dev.parent = &pdev->dev;
adapter->dev.of_node = of_node_get(pdev->dev.of_node);
pname = of_get_property(pdev->dev.of_node, "ibm,port-name", NULL);
diff --git a/drivers/i2c/busses/i2c-pca-platform.c b/drivers/i2c/busses/i2c-pca-platform.c
index 6336f02ec566..3bd2e7d06e4b 100644
--- a/drivers/i2c/busses/i2c-pca-platform.c
+++ b/drivers/i2c/busses/i2c-pca-platform.c
@@ -285,6 +285,6 @@ static struct platform_driver i2c_pca_pf_driver = {
module_platform_driver(i2c_pca_pf_driver);
-MODULE_AUTHOR("Wolfram Sang <w.sang@pengutronix.de>");
+MODULE_AUTHOR("Wolfram Sang <kernel@pengutronix.de>");
MODULE_DESCRIPTION("I2C-PCA9564/PCA9665 platform driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
index d37d9db6681e..2c40edbf6224 100644
--- a/drivers/i2c/busses/i2c-pmcmsp.c
+++ b/drivers/i2c/busses/i2c-pmcmsp.c
@@ -456,14 +456,6 @@ static enum pmcmsptwi_xfer_result pmcmsptwi_xfer_cmd(
return -EINVAL;
}
- if (cmd->read_len > MSP_MAX_BYTES_PER_RW ||
- cmd->write_len > MSP_MAX_BYTES_PER_RW) {
- dev_err(&pmcmsptwi_adapter.dev,
- "%s: Cannot transfer more than %d bytes\n",
- __func__, MSP_MAX_BYTES_PER_RW);
- return -EINVAL;
- }
-
mutex_lock(&data->lock);
dev_dbg(&pmcmsptwi_adapter.dev,
"Setting address to 0x%04x\n", cmd->addr);
@@ -520,25 +512,14 @@ static int pmcmsptwi_master_xfer(struct i2c_adapter *adap,
struct pmcmsptwi_cfg oldcfg, newcfg;
int ret;
- if (num > 2) {
- dev_dbg(&adap->dev, "%d messages unsupported\n", num);
- return -EINVAL;
- } else if (num == 2) {
- /* Check for a dual write-then-read command */
+ if (num == 2) {
struct i2c_msg *nextmsg = msg + 1;
- if (!(msg->flags & I2C_M_RD) &&
- (nextmsg->flags & I2C_M_RD) &&
- msg->addr == nextmsg->addr) {
- cmd.type = MSP_TWI_CMD_WRITE_READ;
- cmd.write_len = msg->len;
- cmd.write_data = msg->buf;
- cmd.read_len = nextmsg->len;
- cmd.read_data = nextmsg->buf;
- } else {
- dev_dbg(&adap->dev,
- "Non write-read dual messages unsupported\n");
- return -EINVAL;
- }
+
+ cmd.type = MSP_TWI_CMD_WRITE_READ;
+ cmd.write_len = msg->len;
+ cmd.write_data = msg->buf;
+ cmd.read_len = nextmsg->len;
+ cmd.read_data = nextmsg->buf;
} else if (msg->flags & I2C_M_RD) {
cmd.type = MSP_TWI_CMD_READ;
cmd.read_len = msg->len;
@@ -598,6 +579,14 @@ static u32 pmcmsptwi_i2c_func(struct i2c_adapter *adapter)
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_PROC_CALL;
}
+static struct i2c_adapter_quirks pmcmsptwi_i2c_quirks = {
+ .flags = I2C_AQ_COMB_WRITE_THEN_READ,
+ .max_write_len = MSP_MAX_BYTES_PER_RW,
+ .max_read_len = MSP_MAX_BYTES_PER_RW,
+ .max_comb_1st_msg_len = MSP_MAX_BYTES_PER_RW,
+ .max_comb_2nd_msg_len = MSP_MAX_BYTES_PER_RW,
+};
+
/* -- Initialization -- */
static struct i2c_algorithm pmcmsptwi_algo = {
@@ -609,6 +598,7 @@ static struct i2c_adapter pmcmsptwi_adapter = {
.owner = THIS_MODULE,
.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
.algo = &pmcmsptwi_algo,
+ .quirks = &pmcmsptwi_i2c_quirks,
.name = DRV_NAME,
};
diff --git a/drivers/i2c/busses/i2c-powermac.c b/drivers/i2c/busses/i2c-powermac.c
index 60a53c169ed2..6abcf696e359 100644
--- a/drivers/i2c/busses/i2c-powermac.c
+++ b/drivers/i2c/busses/i2c-powermac.c
@@ -153,12 +153,6 @@ static int i2c_powermac_master_xfer( struct i2c_adapter *adap,
int read;
int addrdir;
- if (num != 1) {
- dev_err(&adap->dev,
- "Multi-message I2C transactions not supported\n");
- return -EOPNOTSUPP;
- }
-
if (msgs->flags & I2C_M_TEN)
return -EINVAL;
read = (msgs->flags & I2C_M_RD) != 0;
@@ -205,6 +199,9 @@ static const struct i2c_algorithm i2c_powermac_algorithm = {
.functionality = i2c_powermac_func,
};
+static struct i2c_adapter_quirks i2c_powermac_quirks = {
+ .max_num_msgs = 1,
+};
static int i2c_powermac_remove(struct platform_device *dev)
{
@@ -434,6 +431,7 @@ static int i2c_powermac_probe(struct platform_device *dev)
platform_set_drvdata(dev, adapter);
adapter->algo = &i2c_powermac_algorithm;
+ adapter->quirks = &i2c_powermac_quirks;
i2c_set_adapdata(adapter, bus);
adapter->dev.parent = &dev->dev;
diff --git a/drivers/i2c/busses/i2c-qup.c b/drivers/i2c/busses/i2c-qup.c
index 4dad23bdffbe..fdcbdab808e9 100644
--- a/drivers/i2c/busses/i2c-qup.c
+++ b/drivers/i2c/busses/i2c-qup.c
@@ -412,17 +412,6 @@ static int qup_i2c_read_one(struct qup_i2c_dev *qup, struct i2c_msg *msg)
unsigned long left;
int ret;
- /*
- * The QUP block will issue a NACK and STOP on the bus when reaching
- * the end of the read, the length of the read is specified as one byte
- * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
- */
- if (msg->len > QUP_READ_LIMIT) {
- dev_err(qup->dev, "HW not capable of reads over %d bytes\n",
- QUP_READ_LIMIT);
- return -EINVAL;
- }
-
qup->msg = msg;
qup->pos = 0;
@@ -534,6 +523,15 @@ static const struct i2c_algorithm qup_i2c_algo = {
.functionality = qup_i2c_func,
};
+/*
+ * The QUP block will issue a NACK and STOP on the bus when reaching
+ * the end of the read, the length of the read is specified as one byte
+ * which limits the possible read to 256 (QUP_READ_LIMIT) bytes.
+ */
+static struct i2c_adapter_quirks qup_i2c_quirks = {
+ .max_read_len = QUP_READ_LIMIT,
+};
+
static void qup_i2c_enable_clocks(struct qup_i2c_dev *qup)
{
clk_prepare_enable(qup->clk);
@@ -670,6 +668,7 @@ static int qup_i2c_probe(struct platform_device *pdev)
i2c_set_adapdata(&qup->adap, qup);
qup->adap.algo = &qup_i2c_algo;
+ qup->adap.quirks = &qup_i2c_quirks;
qup->adap.dev.parent = qup->dev;
qup->adap.dev.of_node = pdev->dev.of_node;
strlcpy(qup->adap.name, "QUP I2C adapter", sizeof(qup->adap.name));
diff --git a/drivers/i2c/busses/i2c-rcar.c b/drivers/i2c/busses/i2c-rcar.c
index 71a6e07eb7ab..5a84bea5b845 100644
--- a/drivers/i2c/busses/i2c-rcar.c
+++ b/drivers/i2c/busses/i2c-rcar.c
@@ -382,11 +382,11 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
if (ssr_filtered & SAR) {
/* read or write request */
if (ssr_raw & STM) {
- i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_START, &value);
+ i2c_slave_event(priv->slave, I2C_SLAVE_READ_REQUESTED, &value);
rcar_i2c_write(priv, ICRXTX, value);
rcar_i2c_write(priv, ICSIER, SDE | SSR | SAR);
} else {
- i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_START, &value);
+ i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_REQUESTED, &value);
rcar_i2c_read(priv, ICRXTX); /* dummy read */
rcar_i2c_write(priv, ICSIER, SDR | SSR | SAR);
}
@@ -406,17 +406,15 @@ static bool rcar_i2c_slave_irq(struct rcar_i2c_priv *priv)
int ret;
value = rcar_i2c_read(priv, ICRXTX);
- ret = i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_END, &value);
+ ret = i2c_slave_event(priv->slave, I2C_SLAVE_WRITE_RECEIVED, &value);
/* Send NACK in case of error */
rcar_i2c_write(priv, ICSCR, SIE | SDBS | (ret < 0 ? FNA : 0));
- i2c_slave_event(priv->slave, I2C_SLAVE_REQ_WRITE_START, &value);
rcar_i2c_write(priv, ICSSR, ~SDR & 0xff);
}
/* master wants to read from us */
if (ssr_filtered & SDE) {
- i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_END, &value);
- i2c_slave_event(priv->slave, I2C_SLAVE_REQ_READ_START, &value);
+ i2c_slave_event(priv->slave, I2C_SLAVE_READ_PROCESSED, &value);
rcar_i2c_write(priv, ICRXTX, value);
rcar_i2c_write(priv, ICSSR, ~SDE & 0xff);
}
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 5f96b1b3e3a5..019d5426fe52 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -833,7 +833,7 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
clk_disable(i2c->clk);
spin_unlock_irqrestore(&i2c->lock, flags);
- return ret;
+ return ret < 0 ? ret : num;
}
static u32 rk3x_i2c_func(struct i2c_adapter *adap)
diff --git a/drivers/i2c/busses/i2c-st.c b/drivers/i2c/busses/i2c-st.c
index 88057fad9dfe..ea72dca32fdf 100644
--- a/drivers/i2c/busses/i2c-st.c
+++ b/drivers/i2c/busses/i2c-st.c
@@ -10,17 +10,18 @@
* published by the Free Software Foundation.
*/
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/i2c.h>
#include <linux/clk.h>
-#include <linux/io.h>
#include <linux/delay.h>
-#include <linux/interrupt.h>
#include <linux/err.h>
-#include <linux/of.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
+#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
/* SSC registers */
#define SSC_BRG 0x000
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 29f14331dd9d..1bcd75ea0b4c 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -532,7 +532,7 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
{
u32 packet_header;
u32 int_mask;
- int ret;
+ unsigned long time_left;
tegra_i2c_flush_fifos(i2c_dev);
@@ -585,18 +585,20 @@ static int tegra_i2c_xfer_msg(struct tegra_i2c_dev *i2c_dev,
dev_dbg(i2c_dev->dev, "unmasked irq: %02x\n",
i2c_readl(i2c_dev, I2C_INT_MASK));
- ret = wait_for_completion_timeout(&i2c_dev->msg_complete, TEGRA_I2C_TIMEOUT);
+ time_left = wait_for_completion_timeout(&i2c_dev->msg_complete,
+ TEGRA_I2C_TIMEOUT);
tegra_i2c_mask_irq(i2c_dev, int_mask);
- if (ret == 0) {
+ if (time_left == 0) {
dev_err(i2c_dev->dev, "i2c transfer timed out\n");
tegra_i2c_init(i2c_dev);
return -ETIMEDOUT;
}
- dev_dbg(i2c_dev->dev, "transfer complete: %d %d %d\n",
- ret, completion_done(&i2c_dev->msg_complete), i2c_dev->msg_err);
+ dev_dbg(i2c_dev->dev, "transfer complete: %lu %d %d\n",
+ time_left, completion_done(&i2c_dev->msg_complete),
+ i2c_dev->msg_err);
if (likely(i2c_dev->msg_err == I2C_ERR_NONE))
return 0;
diff --git a/drivers/i2c/busses/i2c-viperboard.c b/drivers/i2c/busses/i2c-viperboard.c
index 7533fa34d737..47e88adf2011 100644
--- a/drivers/i2c/busses/i2c-viperboard.c
+++ b/drivers/i2c/busses/i2c-viperboard.c
@@ -288,10 +288,6 @@ static int vprbrd_i2c_xfer(struct i2c_adapter *i2c, struct i2c_msg *msgs,
i, pmsg->flags & I2C_M_RD ? "read" : "write",
pmsg->flags, pmsg->len, pmsg->addr);
- /* msgs longer than 2048 bytes are not supported by adapter */
- if (pmsg->len > 2048)
- return -EINVAL;
-
mutex_lock(&vb->lock);
/* directly send the message */
if (pmsg->flags & I2C_M_RD) {
@@ -358,6 +354,11 @@ static const struct i2c_algorithm vprbrd_algorithm = {
.functionality = vprbrd_i2c_func,
};
+static struct i2c_adapter_quirks vprbrd_quirks = {
+ .max_read_len = 2048,
+ .max_write_len = 2048,
+};
+
static int vprbrd_i2c_probe(struct platform_device *pdev)
{
struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
@@ -373,6 +374,7 @@ static int vprbrd_i2c_probe(struct platform_device *pdev)
vb_i2c->i2c.owner = THIS_MODULE;
vb_i2c->i2c.class = I2C_CLASS_HWMON;
vb_i2c->i2c.algo = &vprbrd_algorithm;
+ vb_i2c->i2c.quirks = &vprbrd_quirks;
vb_i2c->i2c.algo_data = vb;
/* save the param in usb capabable memory */
vb_i2c->bus_freq_param = i2c_bus_param;
diff --git a/drivers/i2c/busses/i2c-wmt.c b/drivers/i2c/busses/i2c-wmt.c
index 82ea34925489..e1e3a85596c5 100644
--- a/drivers/i2c/busses/i2c-wmt.c
+++ b/drivers/i2c/busses/i2c-wmt.c
@@ -128,7 +128,8 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
{
struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
u16 val, tcr_val;
- int ret, wait_result;
+ int ret;
+ unsigned long wait_result;
int xfer_len = 0;
if (!(pmsg->flags & I2C_M_NOSTART)) {
@@ -177,7 +178,7 @@ static int wmt_i2c_write(struct i2c_adapter *adap, struct i2c_msg *pmsg,
while (xfer_len < pmsg->len) {
wait_result = wait_for_completion_timeout(&i2c_dev->complete,
- 500 * HZ / 1000);
+ msecs_to_jiffies(500));
if (wait_result == 0)
return -ETIMEDOUT;
@@ -218,7 +219,8 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
{
struct wmt_i2c_dev *i2c_dev = i2c_get_adapdata(adap);
u16 val, tcr_val;
- int ret, wait_result;
+ int ret;
+ unsigned long wait_result;
u32 xfer_len = 0;
if (!(pmsg->flags & I2C_M_NOSTART)) {
@@ -266,7 +268,7 @@ static int wmt_i2c_read(struct i2c_adapter *adap, struct i2c_msg *pmsg,
while (xfer_len < pmsg->len) {
wait_result = wait_for_completion_timeout(&i2c_dev->complete,
- 500 * HZ / 1000);
+ msecs_to_jiffies(500));
if (!wait_result)
return -ETIMEDOUT;
diff --git a/drivers/i2c/busses/i2c-xlp9xx.c b/drivers/i2c/busses/i2c-xlp9xx.c
new file mode 100644
index 000000000000..c941418f06f5
--- /dev/null
+++ b/drivers/i2c/busses/i2c-xlp9xx.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2003-2015 Broadcom Corporation
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/completion.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#define XLP9XX_I2C_DIV 0x0
+#define XLP9XX_I2C_CTRL 0x1
+#define XLP9XX_I2C_CMD 0x2
+#define XLP9XX_I2C_STATUS 0x3
+#define XLP9XX_I2C_MTXFIFO 0x4
+#define XLP9XX_I2C_MRXFIFO 0x5
+#define XLP9XX_I2C_MFIFOCTRL 0x6
+#define XLP9XX_I2C_STXFIFO 0x7
+#define XLP9XX_I2C_SRXFIFO 0x8
+#define XLP9XX_I2C_SFIFOCTRL 0x9
+#define XLP9XX_I2C_SLAVEADDR 0xA
+#define XLP9XX_I2C_OWNADDR 0xB
+#define XLP9XX_I2C_FIFOWCNT 0xC
+#define XLP9XX_I2C_INTEN 0xD
+#define XLP9XX_I2C_INTST 0xE
+#define XLP9XX_I2C_WAITCNT 0xF
+#define XLP9XX_I2C_TIMEOUT 0X10
+#define XLP9XX_I2C_GENCALLADDR 0x11
+
+#define XLP9XX_I2C_CMD_START BIT(7)
+#define XLP9XX_I2C_CMD_STOP BIT(6)
+#define XLP9XX_I2C_CMD_READ BIT(5)
+#define XLP9XX_I2C_CMD_WRITE BIT(4)
+#define XLP9XX_I2C_CMD_ACK BIT(3)
+
+#define XLP9XX_I2C_CTRL_MCTLEN_SHIFT 16
+#define XLP9XX_I2C_CTRL_MCTLEN_MASK 0xffff0000
+#define XLP9XX_I2C_CTRL_RST BIT(8)
+#define XLP9XX_I2C_CTRL_EN BIT(6)
+#define XLP9XX_I2C_CTRL_MASTER BIT(4)
+#define XLP9XX_I2C_CTRL_FIFORD BIT(1)
+#define XLP9XX_I2C_CTRL_ADDMODE BIT(0)
+
+#define XLP9XX_I2C_INTEN_NACKADDR BIT(25)
+#define XLP9XX_I2C_INTEN_SADDR BIT(13)
+#define XLP9XX_I2C_INTEN_DATADONE BIT(12)
+#define XLP9XX_I2C_INTEN_ARLOST BIT(11)
+#define XLP9XX_I2C_INTEN_MFIFOFULL BIT(4)
+#define XLP9XX_I2C_INTEN_MFIFOEMTY BIT(3)
+#define XLP9XX_I2C_INTEN_MFIFOHI BIT(2)
+#define XLP9XX_I2C_INTEN_BUSERR BIT(0)
+
+#define XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT 8
+#define XLP9XX_I2C_MFIFOCTRL_LOTH_SHIFT 0
+#define XLP9XX_I2C_MFIFOCTRL_RST BIT(16)
+
+#define XLP9XX_I2C_SLAVEADDR_RW BIT(0)
+#define XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT 1
+
+#define XLP9XX_I2C_IP_CLK_FREQ 133000000UL
+#define XLP9XX_I2C_DEFAULT_FREQ 100000
+#define XLP9XX_I2C_HIGH_FREQ 400000
+#define XLP9XX_I2C_FIFO_SIZE 0x80U
+#define XLP9XX_I2C_TIMEOUT_MS 1000
+
+#define XLP9XX_I2C_FIFO_WCNT_MASK 0xff
+#define XLP9XX_I2C_STATUS_ERRMASK (XLP9XX_I2C_INTEN_ARLOST | \
+ XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_BUSERR)
+
+struct xlp9xx_i2c_dev {
+ struct device *dev;
+ struct i2c_adapter adapter;
+ struct completion msg_complete;
+ int irq;
+ bool msg_read;
+ u32 __iomem *base;
+ u32 msg_buf_remaining;
+ u32 msg_len;
+ u32 clk_hz;
+ u32 msg_err;
+ u8 *msg_buf;
+};
+
+static inline void xlp9xx_write_i2c_reg(struct xlp9xx_i2c_dev *priv,
+ unsigned long reg, u32 val)
+{
+ writel(val, priv->base + reg);
+}
+
+static inline u32 xlp9xx_read_i2c_reg(struct xlp9xx_i2c_dev *priv,
+ unsigned long reg)
+{
+ return readl(priv->base + reg);
+}
+
+static void xlp9xx_i2c_mask_irq(struct xlp9xx_i2c_dev *priv, u32 mask)
+{
+ u32 inten;
+
+ inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) & ~mask;
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten);
+}
+
+static void xlp9xx_i2c_unmask_irq(struct xlp9xx_i2c_dev *priv, u32 mask)
+{
+ u32 inten;
+
+ inten = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTEN) | mask;
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, inten);
+}
+
+static void xlp9xx_i2c_update_rx_fifo_thres(struct xlp9xx_i2c_dev *priv)
+{
+ u32 thres;
+
+ thres = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE);
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL,
+ thres << XLP9XX_I2C_MFIFOCTRL_HITH_SHIFT);
+}
+
+static void xlp9xx_i2c_fill_tx_fifo(struct xlp9xx_i2c_dev *priv)
+{
+ u32 len, i;
+ u8 *buf = priv->msg_buf;
+
+ len = min(priv->msg_buf_remaining, XLP9XX_I2C_FIFO_SIZE);
+ for (i = 0; i < len; i++)
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MTXFIFO, buf[i]);
+ priv->msg_buf_remaining -= len;
+ priv->msg_buf += len;
+}
+
+static void xlp9xx_i2c_drain_rx_fifo(struct xlp9xx_i2c_dev *priv)
+{
+ u32 len, i;
+ u8 *buf = priv->msg_buf;
+
+ len = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_FIFOWCNT) &
+ XLP9XX_I2C_FIFO_WCNT_MASK;
+ len = min(priv->msg_buf_remaining, len);
+ for (i = 0; i < len; i++, buf++)
+ *buf = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_MRXFIFO);
+
+ priv->msg_buf_remaining -= len;
+ priv->msg_buf = buf;
+
+ if (priv->msg_buf_remaining)
+ xlp9xx_i2c_update_rx_fifo_thres(priv);
+}
+
+static irqreturn_t xlp9xx_i2c_isr(int irq, void *dev_id)
+{
+ struct xlp9xx_i2c_dev *priv = dev_id;
+ u32 status;
+
+ status = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_INTST);
+ if (status == 0)
+ return IRQ_NONE;
+
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTST, status);
+ if (status & XLP9XX_I2C_STATUS_ERRMASK) {
+ priv->msg_err = status;
+ goto xfer_done;
+ }
+
+ /* SADDR ACK for SMBUS_QUICK */
+ if ((status & XLP9XX_I2C_INTEN_SADDR) && (priv->msg_len == 0))
+ goto xfer_done;
+
+ if (!priv->msg_read) {
+ if (status & XLP9XX_I2C_INTEN_MFIFOEMTY) {
+ /* TX FIFO got empty, fill it up again */
+ if (priv->msg_buf_remaining)
+ xlp9xx_i2c_fill_tx_fifo(priv);
+ else
+ xlp9xx_i2c_mask_irq(priv,
+ XLP9XX_I2C_INTEN_MFIFOEMTY);
+ }
+ } else {
+ if (status & (XLP9XX_I2C_INTEN_DATADONE |
+ XLP9XX_I2C_INTEN_MFIFOHI)) {
+ /* data is in FIFO, read it */
+ if (priv->msg_buf_remaining)
+ xlp9xx_i2c_drain_rx_fifo(priv);
+ }
+ }
+
+ /* Transfer complete */
+ if (status & XLP9XX_I2C_INTEN_DATADONE)
+ goto xfer_done;
+
+ return IRQ_HANDLED;
+
+xfer_done:
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0);
+ complete(&priv->msg_complete);
+ return IRQ_HANDLED;
+}
+
+static int xlp9xx_i2c_init(struct xlp9xx_i2c_dev *priv)
+{
+ u32 prescale;
+
+ /*
+ * The controller uses 5 * SCL clock internally.
+ * So prescale value should be divided by 5.
+ */
+ prescale = DIV_ROUND_UP(XLP9XX_I2C_IP_CLK_FREQ, priv->clk_hz);
+ prescale = ((prescale - 8) / 5) - 1;
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_RST);
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, XLP9XX_I2C_CTRL_EN |
+ XLP9XX_I2C_CTRL_MASTER);
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_DIV, prescale);
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0);
+
+ return 0;
+}
+
+static int xlp9xx_i2c_xfer_msg(struct xlp9xx_i2c_dev *priv, struct i2c_msg *msg,
+ int last_msg)
+{
+ unsigned long timeleft;
+ u32 intr_mask, cmd, val;
+
+ priv->msg_buf = msg->buf;
+ priv->msg_buf_remaining = priv->msg_len = msg->len;
+ priv->msg_err = 0;
+ priv->msg_read = (msg->flags & I2C_M_RD);
+ reinit_completion(&priv->msg_complete);
+
+ /* Reset FIFO */
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_MFIFOCTRL,
+ XLP9XX_I2C_MFIFOCTRL_RST);
+
+ /* set FIFO threshold if reading */
+ if (priv->msg_read)
+ xlp9xx_i2c_update_rx_fifo_thres(priv);
+
+ /* set slave addr */
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_SLAVEADDR,
+ (msg->addr << XLP9XX_I2C_SLAVEADDR_ADDR_SHIFT) |
+ (priv->msg_read ? XLP9XX_I2C_SLAVEADDR_RW : 0));
+
+ /* Build control word for transfer */
+ val = xlp9xx_read_i2c_reg(priv, XLP9XX_I2C_CTRL);
+ if (!priv->msg_read)
+ val &= ~XLP9XX_I2C_CTRL_FIFORD;
+ else
+ val |= XLP9XX_I2C_CTRL_FIFORD; /* read */
+
+ if (msg->flags & I2C_M_TEN)
+ val |= XLP9XX_I2C_CTRL_ADDMODE; /* 10-bit address mode*/
+ else
+ val &= ~XLP9XX_I2C_CTRL_ADDMODE;
+
+ /* set data length to be transferred */
+ val = (val & ~XLP9XX_I2C_CTRL_MCTLEN_MASK) |
+ (msg->len << XLP9XX_I2C_CTRL_MCTLEN_SHIFT);
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, val);
+
+ /* fill fifo during tx */
+ if (!priv->msg_read)
+ xlp9xx_i2c_fill_tx_fifo(priv);
+
+ /* set interrupt mask */
+ intr_mask = (XLP9XX_I2C_INTEN_ARLOST | XLP9XX_I2C_INTEN_BUSERR |
+ XLP9XX_I2C_INTEN_NACKADDR | XLP9XX_I2C_INTEN_DATADONE);
+
+ if (priv->msg_read) {
+ intr_mask |= XLP9XX_I2C_INTEN_MFIFOHI;
+ if (msg->len == 0)
+ intr_mask |= XLP9XX_I2C_INTEN_SADDR;
+ } else {
+ if (msg->len == 0)
+ intr_mask |= XLP9XX_I2C_INTEN_SADDR;
+ else
+ intr_mask |= XLP9XX_I2C_INTEN_MFIFOEMTY;
+ }
+ xlp9xx_i2c_unmask_irq(priv, intr_mask);
+
+ /* set cmd reg */
+ cmd = XLP9XX_I2C_CMD_START;
+ cmd |= (priv->msg_read ? XLP9XX_I2C_CMD_READ : XLP9XX_I2C_CMD_WRITE);
+ if (last_msg)
+ cmd |= XLP9XX_I2C_CMD_STOP;
+
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CMD, cmd);
+
+ timeleft = msecs_to_jiffies(XLP9XX_I2C_TIMEOUT_MS);
+ timeleft = wait_for_completion_timeout(&priv->msg_complete, timeleft);
+
+ if (priv->msg_err) {
+ dev_dbg(priv->dev, "transfer error %x!\n", priv->msg_err);
+ if (priv->msg_err & XLP9XX_I2C_INTEN_BUSERR)
+ xlp9xx_i2c_init(priv);
+ return -EIO;
+ }
+
+ if (timeleft == 0) {
+ dev_dbg(priv->dev, "i2c transfer timed out!\n");
+ xlp9xx_i2c_init(priv);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int xlp9xx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
+ int num)
+{
+ int i, ret;
+ struct xlp9xx_i2c_dev *priv = i2c_get_adapdata(adap);
+
+ for (i = 0; i < num; i++) {
+ ret = xlp9xx_i2c_xfer_msg(priv, &msgs[i], i == num - 1);
+ if (ret != 0)
+ return ret;
+ }
+
+ return num;
+}
+
+static u32 xlp9xx_i2c_functionality(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C |
+ I2C_FUNC_10BIT_ADDR;
+}
+
+static struct i2c_algorithm xlp9xx_i2c_algo = {
+ .master_xfer = xlp9xx_i2c_xfer,
+ .functionality = xlp9xx_i2c_functionality,
+};
+
+static int xlp9xx_i2c_get_frequency(struct platform_device *pdev,
+ struct xlp9xx_i2c_dev *priv)
+{
+ struct device_node *np = pdev->dev.of_node;
+ u32 freq;
+ int err;
+
+ err = of_property_read_u32(np, "clock-frequency", &freq);
+ if (err) {
+ freq = XLP9XX_I2C_DEFAULT_FREQ;
+ dev_dbg(&pdev->dev, "using default frequency %u\n", freq);
+ } else if (freq == 0 || freq > XLP9XX_I2C_HIGH_FREQ) {
+ dev_warn(&pdev->dev, "invalid frequency %u, using default\n",
+ freq);
+ freq = XLP9XX_I2C_DEFAULT_FREQ;
+ }
+ priv->clk_hz = freq;
+
+ return 0;
+}
+
+static int xlp9xx_i2c_probe(struct platform_device *pdev)
+{
+ struct xlp9xx_i2c_dev *priv;
+ struct resource *res;
+ int err = 0;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->base))
+ return PTR_ERR(priv->base);
+
+ priv->irq = platform_get_irq(pdev, 0);
+ if (priv->irq <= 0) {
+ dev_err(&pdev->dev, "invalid irq!\n");
+ return priv->irq;
+ }
+
+ xlp9xx_i2c_get_frequency(pdev, priv);
+ xlp9xx_i2c_init(priv);
+
+ err = devm_request_irq(&pdev->dev, priv->irq, xlp9xx_i2c_isr, 0,
+ pdev->name, priv);
+ if (err) {
+ dev_err(&pdev->dev, "IRQ request failed!\n");
+ return err;
+ }
+
+ init_completion(&priv->msg_complete);
+ priv->adapter.dev.parent = &pdev->dev;
+ priv->adapter.algo = &xlp9xx_i2c_algo;
+ priv->adapter.dev.of_node = pdev->dev.of_node;
+ priv->dev = &pdev->dev;
+
+ snprintf(priv->adapter.name, sizeof(priv->adapter.name), "xlp9xx-i2c");
+ i2c_set_adapdata(&priv->adapter, priv);
+
+ err = i2c_add_adapter(&priv->adapter);
+ if (err) {
+ dev_err(&pdev->dev, "failed to add I2C adapter!\n");
+ return err;
+ }
+
+ platform_set_drvdata(pdev, priv);
+ dev_dbg(&pdev->dev, "I2C bus:%d added\n", priv->adapter.nr);
+
+ return 0;
+}
+
+static int xlp9xx_i2c_remove(struct platform_device *pdev)
+{
+ struct xlp9xx_i2c_dev *priv;
+
+ priv = platform_get_drvdata(pdev);
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_INTEN, 0);
+ synchronize_irq(priv->irq);
+ i2c_del_adapter(&priv->adapter);
+ xlp9xx_write_i2c_reg(priv, XLP9XX_I2C_CTRL, 0);
+
+ return 0;
+}
+
+static const struct of_device_id xlp9xx_i2c_of_match[] = {
+ { .compatible = "netlogic,xlp980-i2c", },
+ { /* sentinel */ },
+};
+
+static struct platform_driver xlp9xx_i2c_driver = {
+ .probe = xlp9xx_i2c_probe,
+ .remove = xlp9xx_i2c_remove,
+ .driver = {
+ .name = "xlp9xx-i2c",
+ .of_match_table = xlp9xx_i2c_of_match,
+ },
+};
+
+module_platform_driver(xlp9xx_i2c_driver);
+
+MODULE_AUTHOR("Subhendu Sekhar Behera <sbehera@broadcom.com>");
+MODULE_DESCRIPTION("XLP9XX/5XX I2C Bus Controller Driver");
+MODULE_LICENSE("GPL v2");