summaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/busses/Kconfig20
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-highlander.c498
-rw-r--r--drivers/i2c/busses/i2c-mpc.c1
-rw-r--r--drivers/i2c/busses/i2c-parport-light.c39
-rw-r--r--drivers/i2c/busses/i2c-pca-isa.c22
-rw-r--r--drivers/i2c/busses/i2c-viapro.c17
-rw-r--r--drivers/i2c/chips/Kconfig11
-rw-r--r--drivers/i2c/chips/Makefile1
-rw-r--r--drivers/i2c/chips/isp1301_omap.c141
-rw-r--r--drivers/i2c/chips/mcu_mpc8349emitx.c209
-rw-r--r--drivers/i2c/chips/tps65010.c12
-rw-r--r--drivers/i2c/i2c-core.c35
13 files changed, 877 insertions, 130 deletions
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 6ee997b2817c..acadbc51fc0f 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -55,7 +55,7 @@ config I2C_AMD756
config I2C_AMD756_S4882
tristate "SMBus multiplexing on the Tyan S4882"
- depends on I2C_AMD756 && EXPERIMENTAL
+ depends on I2C_AMD756 && X86 && EXPERIMENTAL
help
Enabling this option will add specific SMBus support for the Tyan
S4882 motherboard. On this 4-CPU board, the SMBus is multiplexed
@@ -148,7 +148,7 @@ config I2C_NFORCE2
config I2C_NFORCE2_S4985
tristate "SMBus multiplexing on the Tyan S4985"
- depends on I2C_NFORCE2 && EXPERIMENTAL
+ depends on I2C_NFORCE2 && X86 && EXPERIMENTAL
help
Enabling this option will add specific SMBus support for the Tyan
S4985 motherboard. On this 4-CPU board, the SMBus is multiplexed
@@ -209,7 +209,7 @@ config I2C_VIA
will be called i2c-via.
config I2C_VIAPRO
- tristate "VIA VT82C596/82C686/82xx and CX700"
+ tristate "VIA VT82C596/82C686/82xx and CX700/VX800/VX820"
depends on PCI
help
If you say yes to this option, support will be included for the VIA
@@ -223,6 +223,8 @@ config I2C_VIAPRO
VT8237R/A/S
VT8251
CX700
+ VX800
+ VX820
This driver can also be built as a module. If so, the module
will be called i2c-viapro.
@@ -330,6 +332,18 @@ config I2C_GPIO
This is a very simple bitbanging I2C driver utilizing the
arch-neutral GPIO API to control the SCL and SDA lines.
+config I2C_HIGHLANDER
+ tristate "Highlander FPGA SMBus interface"
+ depends on SH_HIGHLANDER
+ help
+ If you say yes to this option, support will be included for
+ the SMBus interface located in the FPGA on various Highlander
+ boards, particularly the R0P7780LC0011RL and R0P7785LC0011RL
+ FPGAs. This is wholly unrelated to the SoC I2C.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-highlander.
+
config I2C_IBM_IIC
tristate "IBM PPC 4xx on-chip I2C interface"
depends on 4xx
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 97dbfa2107fe..0c2c4b26cdf1 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -31,6 +31,7 @@ obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
obj-$(CONFIG_I2C_CPM) += i2c-cpm.o
obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
obj-$(CONFIG_I2C_GPIO) += i2c-gpio.o
+obj-$(CONFIG_I2C_HIGHLANDER) += i2c-highlander.o
obj-$(CONFIG_I2C_IBM_IIC) += i2c-ibm_iic.o
obj-$(CONFIG_I2C_IOP3XX) += i2c-iop3xx.o
obj-$(CONFIG_I2C_IXP2000) += i2c-ixp2000.o
diff --git a/drivers/i2c/busses/i2c-highlander.c b/drivers/i2c/busses/i2c-highlander.c
new file mode 100644
index 000000000000..f4d22ae9d294
--- /dev/null
+++ b/drivers/i2c/busses/i2c-highlander.c
@@ -0,0 +1,498 @@
+/*
+ * Renesas Solutions Highlander FPGA I2C/SMBus support.
+ *
+ * Supported devices: R0P7780LC0011RL, R0P7785LC0011RL
+ *
+ * Copyright (C) 2008 Paul Mundt
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Copyright (C) 2008 Atom Create Engineering Co., Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file "COPYING" in the main directory
+ * of this archive for more details.
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#define SMCR 0x00
+#define SMCR_START (1 << 0)
+#define SMCR_IRIC (1 << 1)
+#define SMCR_BBSY (1 << 2)
+#define SMCR_ACKE (1 << 3)
+#define SMCR_RST (1 << 4)
+#define SMCR_IEIC (1 << 6)
+
+#define SMSMADR 0x02
+
+#define SMMR 0x04
+#define SMMR_MODE0 (1 << 0)
+#define SMMR_MODE1 (1 << 1)
+#define SMMR_CAP (1 << 3)
+#define SMMR_TMMD (1 << 4)
+#define SMMR_SP (1 << 7)
+
+#define SMSADR 0x06
+#define SMTRDR 0x46
+
+struct highlander_i2c_dev {
+ struct device *dev;
+ void __iomem *base;
+ struct i2c_adapter adapter;
+ struct completion cmd_complete;
+ unsigned long last_read_time;
+ int irq;
+ u8 *buf;
+ size_t buf_len;
+};
+
+static int iic_force_poll, iic_force_normal;
+static int iic_timeout = 1000, iic_read_delay;
+
+static inline void highlander_i2c_irq_enable(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_IEIC, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_irq_disable(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) & ~SMCR_IEIC, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_start(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_START, dev->base + SMCR);
+}
+
+static inline void highlander_i2c_done(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_IRIC, dev->base + SMCR);
+}
+
+static void highlander_i2c_setup(struct highlander_i2c_dev *dev)
+{
+ u16 smmr;
+
+ smmr = ioread16(dev->base + SMMR);
+ smmr |= SMMR_TMMD;
+
+ if (iic_force_normal)
+ smmr &= ~SMMR_SP;
+ else
+ smmr |= SMMR_SP;
+
+ iowrite16(smmr, dev->base + SMMR);
+}
+
+static void smbus_write_data(u8 *src, u16 *dst, int len)
+{
+ for (; len > 1; len -= 2) {
+ *dst++ = be16_to_cpup((u16 *)src);
+ src += 2;
+ }
+
+ if (len)
+ *dst = *src << 8;
+}
+
+static void smbus_read_data(u16 *src, u8 *dst, int len)
+{
+ for (; len > 1; len -= 2) {
+ *(u16 *)dst = cpu_to_be16p(src++);
+ dst += 2;
+ }
+
+ if (len)
+ *dst = *src >> 8;
+}
+
+static void highlander_i2c_command(struct highlander_i2c_dev *dev,
+ u8 command, int len)
+{
+ unsigned int i;
+ u16 cmd = (command << 8) | command;
+
+ for (i = 0; i < len; i += 2) {
+ if (len - i == 1)
+ cmd = command << 8;
+ iowrite16(cmd, dev->base + SMSADR + i);
+ dev_dbg(dev->dev, "command data[%x] 0x%04x\n", i/2, cmd);
+ }
+}
+
+static int highlander_i2c_wait_for_bbsy(struct highlander_i2c_dev *dev)
+{
+ unsigned long timeout;
+
+ timeout = jiffies + msecs_to_jiffies(iic_timeout);
+ while (ioread16(dev->base + SMCR) & SMCR_BBSY) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(dev->dev, "timeout waiting for bus ready\n");
+ return -ETIMEDOUT;
+ }
+
+ msleep(1);
+ }
+
+ return 0;
+}
+
+static int highlander_i2c_reset(struct highlander_i2c_dev *dev)
+{
+ iowrite16(ioread16(dev->base + SMCR) | SMCR_RST, dev->base + SMCR);
+ return highlander_i2c_wait_for_bbsy(dev);
+}
+
+static int highlander_i2c_wait_for_ack(struct highlander_i2c_dev *dev)
+{
+ u16 tmp = ioread16(dev->base + SMCR);
+
+ if ((tmp & (SMCR_IRIC | SMCR_ACKE)) == SMCR_ACKE) {
+ dev_warn(dev->dev, "ack abnormality\n");
+ return highlander_i2c_reset(dev);
+ }
+
+ return 0;
+}
+
+static irqreturn_t highlander_i2c_irq(int irq, void *dev_id)
+{
+ struct highlander_i2c_dev *dev = dev_id;
+
+ highlander_i2c_done(dev);
+ complete(&dev->cmd_complete);
+
+ return IRQ_HANDLED;
+}
+
+static void highlander_i2c_poll(struct highlander_i2c_dev *dev)
+{
+ unsigned long timeout;
+ u16 smcr;
+
+ timeout = jiffies + msecs_to_jiffies(iic_timeout);
+ for (;;) {
+ smcr = ioread16(dev->base + SMCR);
+
+ /*
+ * Don't bother checking ACKE here, this and the reset
+ * are handled in highlander_i2c_wait_xfer_done() when
+ * waiting for the ACK.
+ */
+
+ if (smcr & SMCR_IRIC)
+ return;
+ if (time_after(jiffies, timeout))
+ break;
+
+ cpu_relax();
+ cond_resched();
+ }
+
+ dev_err(dev->dev, "polling timed out\n");
+}
+
+static inline int highlander_i2c_wait_xfer_done(struct highlander_i2c_dev *dev)
+{
+ if (dev->irq)
+ wait_for_completion_timeout(&dev->cmd_complete,
+ msecs_to_jiffies(iic_timeout));
+ else
+ /* busy looping, the IRQ of champions */
+ highlander_i2c_poll(dev);
+
+ return highlander_i2c_wait_for_ack(dev);
+}
+
+static int highlander_i2c_read(struct highlander_i2c_dev *dev)
+{
+ int i, cnt;
+ u16 data[16];
+
+ if (highlander_i2c_wait_for_bbsy(dev))
+ return -EAGAIN;
+
+ highlander_i2c_start(dev);
+
+ if (highlander_i2c_wait_xfer_done(dev)) {
+ dev_err(dev->dev, "Arbitration loss\n");
+ return -EAGAIN;
+ }
+
+ /*
+ * The R0P7780LC0011RL FPGA needs a significant delay between
+ * data read cycles, otherwise the transciever gets confused and
+ * garbage is returned when the read is subsequently aborted.
+ *
+ * It is not sufficient to wait for BBSY.
+ *
+ * While this generally only applies to the older SH7780-based
+ * Highlanders, the same issue can be observed on SH7785 ones,
+ * albeit less frequently. SH7780-based Highlanders may need
+ * this to be as high as 1000 ms.
+ */
+ if (iic_read_delay && time_before(jiffies, dev->last_read_time +
+ msecs_to_jiffies(iic_read_delay)))
+ msleep(jiffies_to_msecs((dev->last_read_time +
+ msecs_to_jiffies(iic_read_delay)) - jiffies));
+
+ cnt = (dev->buf_len + 1) >> 1;
+ for (i = 0; i < cnt; i++) {
+ data[i] = ioread16(dev->base + SMTRDR + (i * sizeof(u16)));
+ dev_dbg(dev->dev, "read data[%x] 0x%04x\n", i, data[i]);
+ }
+
+ smbus_read_data(data, dev->buf, dev->buf_len);
+
+ dev->last_read_time = jiffies;
+
+ return 0;
+}
+
+static int highlander_i2c_write(struct highlander_i2c_dev *dev)
+{
+ int i, cnt;
+ u16 data[16];
+
+ smbus_write_data(dev->buf, data, dev->buf_len);
+
+ cnt = (dev->buf_len + 1) >> 1;
+ for (i = 0; i < cnt; i++) {
+ iowrite16(data[i], dev->base + SMTRDR + (i * sizeof(u16)));
+ dev_dbg(dev->dev, "write data[%x] 0x%04x\n", i, data[i]);
+ }
+
+ if (highlander_i2c_wait_for_bbsy(dev))
+ return -EAGAIN;
+
+ highlander_i2c_start(dev);
+
+ return highlander_i2c_wait_xfer_done(dev);
+}
+
+static int highlander_i2c_smbus_xfer(struct i2c_adapter *adap, u16 addr,
+ unsigned short flags, char read_write,
+ u8 command, int size,
+ union i2c_smbus_data *data)
+{
+ struct highlander_i2c_dev *dev = i2c_get_adapdata(adap);
+ int read = read_write & I2C_SMBUS_READ;
+ u16 tmp;
+
+ init_completion(&dev->cmd_complete);
+
+ dev_dbg(dev->dev, "addr %04x, command %02x, read_write %d, size %d\n",
+ addr, command, read_write, size);
+
+ /*
+ * Set up the buffer and transfer size
+ */
+ switch (size) {
+ case I2C_SMBUS_BYTE_DATA:
+ dev->buf = &data->byte;
+ dev->buf_len = 1;
+ break;
+ case I2C_SMBUS_I2C_BLOCK_DATA:
+ dev->buf = &data->block[1];
+ dev->buf_len = data->block[0];
+ break;
+ default:
+ dev_err(dev->dev, "unsupported command %d\n", size);
+ return -EINVAL;
+ }
+
+ /*
+ * Encode the mode setting
+ */
+ tmp = ioread16(dev->base + SMMR);
+ tmp &= ~(SMMR_MODE0 | SMMR_MODE1);
+
+ switch (dev->buf_len) {
+ case 1:
+ /* default */
+ break;
+ case 8:
+ tmp |= SMMR_MODE0;
+ break;
+ case 16:
+ tmp |= SMMR_MODE1;
+ break;
+ case 32:
+ tmp |= (SMMR_MODE0 | SMMR_MODE1);
+ break;
+ default:
+ dev_err(dev->dev, "unsupported xfer size %d\n", dev->buf_len);
+ return -EINVAL;
+ }
+
+ iowrite16(tmp, dev->base + SMMR);
+
+ /* Ensure we're in a sane state */
+ highlander_i2c_done(dev);
+
+ /* Set slave address */
+ iowrite16((addr << 1) | read, dev->base + SMSMADR);
+
+ highlander_i2c_command(dev, command, dev->buf_len);
+
+ if (read)
+ return highlander_i2c_read(dev);
+ else
+ return highlander_i2c_write(dev);
+}
+
+static u32 highlander_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm highlander_i2c_algo = {
+ .smbus_xfer = highlander_i2c_smbus_xfer,
+ .functionality = highlander_i2c_func,
+};
+
+static int __devinit highlander_i2c_probe(struct platform_device *pdev)
+{
+ struct highlander_i2c_dev *dev;
+ struct i2c_adapter *adap;
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (unlikely(!res)) {
+ dev_err(&pdev->dev, "no mem resource\n");
+ return -ENODEV;
+ }
+
+ dev = kzalloc(sizeof(struct highlander_i2c_dev), GFP_KERNEL);
+ if (unlikely(!dev))
+ return -ENOMEM;
+
+ dev->base = ioremap_nocache(res->start, res->end - res->start + 1);
+ if (unlikely(!dev->base)) {
+ ret = -ENXIO;
+ goto err;
+ }
+
+ dev->dev = &pdev->dev;
+ platform_set_drvdata(pdev, dev);
+
+ dev->irq = platform_get_irq(pdev, 0);
+ if (iic_force_poll)
+ dev->irq = 0;
+
+ if (dev->irq) {
+ ret = request_irq(dev->irq, highlander_i2c_irq, IRQF_DISABLED,
+ pdev->name, dev);
+ if (unlikely(ret))
+ goto err_unmap;
+
+ highlander_i2c_irq_enable(dev);
+ } else {
+ dev_notice(&pdev->dev, "no IRQ, using polling mode\n");
+ highlander_i2c_irq_disable(dev);
+ }
+
+ dev->last_read_time = jiffies; /* initial read jiffies */
+
+ highlander_i2c_setup(dev);
+
+ adap = &dev->adapter;
+ i2c_set_adapdata(adap, dev);
+ adap->owner = THIS_MODULE;
+ adap->class = I2C_CLASS_HWMON;
+ strlcpy(adap->name, "HL FPGA I2C adapter", sizeof(adap->name));
+ adap->algo = &highlander_i2c_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->nr = pdev->id;
+
+ /*
+ * Reset the adapter
+ */
+ ret = highlander_i2c_reset(dev);
+ if (unlikely(ret)) {
+ dev_err(&pdev->dev, "controller didn't come up\n");
+ goto err_free_irq;
+ }
+
+ ret = i2c_add_numbered_adapter(adap);
+ if (unlikely(ret)) {
+ dev_err(&pdev->dev, "failure adding adapter\n");
+ goto err_free_irq;
+ }
+
+ return 0;
+
+err_free_irq:
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+err_unmap:
+ iounmap(dev->base);
+err:
+ kfree(dev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return ret;
+}
+
+static int __devexit highlander_i2c_remove(struct platform_device *pdev)
+{
+ struct highlander_i2c_dev *dev = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&dev->adapter);
+
+ if (dev->irq)
+ free_irq(dev->irq, dev);
+
+ iounmap(dev->base);
+ kfree(dev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver highlander_i2c_driver = {
+ .driver = {
+ .name = "i2c-highlander",
+ .owner = THIS_MODULE,
+ },
+
+ .probe = highlander_i2c_probe,
+ .remove = __devexit_p(highlander_i2c_remove),
+};
+
+static int __init highlander_i2c_init(void)
+{
+ return platform_driver_register(&highlander_i2c_driver);
+}
+
+static void __exit highlander_i2c_exit(void)
+{
+ platform_driver_unregister(&highlander_i2c_driver);
+}
+
+module_init(highlander_i2c_init);
+module_exit(highlander_i2c_exit);
+
+MODULE_AUTHOR("Paul Mundt");
+MODULE_DESCRIPTION("Renesas Highlander FPGA I2C/SMBus adapter");
+MODULE_LICENSE("GPL v2");
+
+module_param(iic_force_poll, bool, 0);
+module_param(iic_force_normal, bool, 0);
+module_param(iic_timeout, int, 0);
+module_param(iic_read_delay, int, 0);
+
+MODULE_PARM_DESC(iic_force_poll, "Force polling mode");
+MODULE_PARM_DESC(iic_force_normal,
+ "Force normal mode (100 kHz), default is fast mode (400 kHz)");
+MODULE_PARM_DESC(iic_timeout, "Set timeout value in msecs (default 1000 ms)");
+MODULE_PARM_DESC(iic_read_delay,
+ "Delay between data read cycles (default 0 ms)");
diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 27443f073bc9..a9a45fcc8544 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -312,7 +312,6 @@ static struct i2c_adapter mpc_ops = {
.name = "MPC adapter",
.id = I2C_HW_MPC107,
.algo = &mpc_algo,
- .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
.timeout = 1,
};
diff --git a/drivers/i2c/busses/i2c-parport-light.c b/drivers/i2c/busses/i2c-parport-light.c
index c6faf9bdad18..b2b8380f6602 100644
--- a/drivers/i2c/busses/i2c-parport-light.c
+++ b/drivers/i2c/busses/i2c-parport-light.c
@@ -123,11 +123,6 @@ static struct i2c_adapter parport_adapter = {
static int __devinit i2c_parport_probe(struct platform_device *pdev)
{
int err;
- struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- if (!request_region(res->start, res->end - res->start + 1, DRVNAME))
- return -EBUSY;
/* Reset hardware to a sane state (SCL and SDA high) */
parport_setsda(NULL, 1);
@@ -138,29 +133,19 @@ static int __devinit i2c_parport_probe(struct platform_device *pdev)
parport_adapter.dev.parent = &pdev->dev;
err = i2c_bit_add_bus(&parport_adapter);
- if (err) {
+ if (err)
dev_err(&pdev->dev, "Unable to register with I2C\n");
- goto exit_region;
- }
- return 0;
-
-exit_region:
- release_region(res->start, res->end - res->start + 1);
return err;
}
static int __devexit i2c_parport_remove(struct platform_device *pdev)
{
- struct resource *res;
-
i2c_del_adapter(&parport_adapter);
/* Un-init if needed (power off...) */
if (adapter_parm[type].init.val)
line_set(0, &adapter_parm[type].init);
- res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- release_region(res->start, res->end - res->start + 1);
return 0;
}
@@ -175,12 +160,6 @@ static struct platform_driver i2c_parport_driver = {
static int __init i2c_parport_device_add(u16 address)
{
- struct resource res = {
- .start = address,
- .end = address + 2,
- .name = DRVNAME,
- .flags = IORESOURCE_IO,
- };
int err;
pdev = platform_device_alloc(DRVNAME, -1);
@@ -190,13 +169,6 @@ static int __init i2c_parport_device_add(u16 address)
goto exit;
}
- err = platform_device_add_resources(pdev, &res, 1);
- if (err) {
- printk(KERN_ERR DRVNAME ": Device resource addition failed "
- "(%d)\n", err);
- goto exit_device_put;
- }
-
err = platform_device_add(pdev);
if (err) {
printk(KERN_ERR DRVNAME ": Device addition failed (%d)\n",
@@ -231,13 +203,16 @@ static int __init i2c_parport_init(void)
base = DEFAULT_BASE;
}
+ if (!request_region(base, 3, DRVNAME))
+ return -EBUSY;
+
if (!adapter_parm[type].getscl.val)
parport_algo_data.getscl = NULL;
/* Sets global pdev as a side effect */
err = i2c_parport_device_add(base);
if (err)
- goto exit;
+ goto exit_release;
err = platform_driver_register(&i2c_parport_driver);
if (err)
@@ -247,7 +222,8 @@ static int __init i2c_parport_init(void)
exit_device:
platform_device_unregister(pdev);
-exit:
+exit_release:
+ release_region(base, 3);
return err;
}
@@ -255,6 +231,7 @@ static void __exit i2c_parport_exit(void)
{
platform_driver_unregister(&i2c_parport_driver);
platform_device_unregister(pdev);
+ release_region(base, 3);
}
MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
diff --git a/drivers/i2c/busses/i2c-pca-isa.c b/drivers/i2c/busses/i2c-pca-isa.c
index a119784bae10..9eb76268ec78 100644
--- a/drivers/i2c/busses/i2c-pca-isa.c
+++ b/drivers/i2c/busses/i2c-pca-isa.c
@@ -36,8 +36,8 @@
#define DRIVER "i2c-pca-isa"
#define IO_SIZE 4
-static unsigned long base = 0x330;
-static int irq = 10;
+static unsigned long base;
+static int irq = -1;
/* Data sheet recommends 59kHz for 100kHz operation due to variation
* in the actual clock rate */
@@ -107,13 +107,26 @@ static struct i2c_adapter pca_isa_ops = {
.timeout = 100,
};
+static int __devinit pca_isa_match(struct device *dev, unsigned int id)
+{
+ int match = base != 0;
+
+ if (match) {
+ if (irq <= -1)
+ dev_warn(dev, "Using polling mode (specify irq)\n");
+ } else
+ dev_err(dev, "Please specify I/O base\n");
+
+ return match;
+}
+
static int __devinit pca_isa_probe(struct device *dev, unsigned int id)
{
init_waitqueue_head(&pca_wait);
dev_info(dev, "i/o base %#08lx. irq %d\n", base, irq);
-#ifdef CONFIG_PPC_MERGE
+#ifdef CONFIG_PPC
if (check_legacy_ioport(base)) {
dev_err(dev, "I/O address %#08lx is not available\n", base);
goto out;
@@ -153,7 +166,7 @@ static int __devexit pca_isa_remove(struct device *dev, unsigned int id)
{
i2c_del_adapter(&pca_isa_ops);
- if (irq > 0) {
+ if (irq > -1) {
disable_irq(irq);
free_irq(irq, &pca_isa_ops);
}
@@ -163,6 +176,7 @@ static int __devexit pca_isa_remove(struct device *dev, unsigned int id)
}
static struct isa_driver pca_isa_driver = {
+ .match = pca_isa_match,
.probe = pca_isa_probe,
.remove = __devexit_p(pca_isa_remove),
.driver = {
diff --git a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
index 862eb352a2d9..73dc52e114eb 100644
--- a/drivers/i2c/busses/i2c-viapro.c
+++ b/drivers/i2c/busses/i2c-viapro.c
@@ -36,6 +36,7 @@
VT8237S 0x3372 yes
VT8251 0x3287 yes
CX700 0x8324 yes
+ VX800/VX820 0x8353 yes
Note: we assume there can only be one device, with one SMBus interface.
*/
@@ -82,6 +83,7 @@ static unsigned short SMBHSTCFG = 0xD2;
#define VT596_BYTE 0x04
#define VT596_BYTE_DATA 0x08
#define VT596_WORD_DATA 0x0C
+#define VT596_PROC_CALL 0x10
#define VT596_BLOCK_DATA 0x14
#define VT596_I2C_BLOCK_DATA 0x34
@@ -232,6 +234,12 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
}
size = VT596_WORD_DATA;
break;
+ case I2C_SMBUS_PROC_CALL:
+ outb_p(command, SMBHSTCMD);
+ outb_p(data->word & 0xff, SMBHSTDAT0);
+ outb_p((data->word & 0xff00) >> 8, SMBHSTDAT1);
+ size = VT596_PROC_CALL;
+ break;
case I2C_SMBUS_I2C_BLOCK_DATA:
if (!(vt596_features & FEATURE_I2CBLOCK))
goto exit_unsupported;
@@ -262,6 +270,9 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
if (status)
return status;
+ if (size == VT596_PROC_CALL)
+ read_write = I2C_SMBUS_READ;
+
if ((read_write == I2C_SMBUS_WRITE) || (size == VT596_QUICK))
return 0;
@@ -271,6 +282,7 @@ static s32 vt596_access(struct i2c_adapter *adap, u16 addr,
data->byte = inb_p(SMBHSTDAT0);
break;
case VT596_WORD_DATA:
+ case VT596_PROC_CALL:
data->word = inb_p(SMBHSTDAT0) + (inb_p(SMBHSTDAT1) << 8);
break;
case VT596_I2C_BLOCK_DATA:
@@ -295,7 +307,7 @@ static u32 vt596_func(struct i2c_adapter *adapter)
{
u32 func = I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
- I2C_FUNC_SMBUS_BLOCK_DATA;
+ I2C_SMBUS_PROC_CALL | I2C_FUNC_SMBUS_BLOCK_DATA;
if (vt596_features & FEATURE_I2CBLOCK)
func |= I2C_FUNC_SMBUS_I2C_BLOCK;
@@ -396,6 +408,7 @@ found:
switch (pdev->device) {
case PCI_DEVICE_ID_VIA_CX700:
+ case PCI_DEVICE_ID_VIA_VX800:
case PCI_DEVICE_ID_VIA_8251:
case PCI_DEVICE_ID_VIA_8237:
case PCI_DEVICE_ID_VIA_8237A:
@@ -459,6 +472,8 @@ static struct pci_device_id vt596_ids[] = {
.driver_data = SMBBA3 },
{ PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700),
.driver_data = SMBBA3 },
+ { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800),
+ .driver_data = SMBBA3 },
{ 0, }
};
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index a95cb9465d65..17356827b93d 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -172,4 +172,15 @@ config MENELAUS
and other features that are often used in portable devices like
cell phones and PDAs.
+config MCU_MPC8349EMITX
+ tristate "MPC8349E-mITX MCU driver"
+ depends on I2C && PPC_83xx
+ select GENERIC_GPIO
+ select ARCH_REQUIRE_GPIOLIB
+ help
+ Say Y here to enable soft power-off functionality on the Freescale
+ boards with the MPC8349E-mITX-compatible MCU chips. This driver will
+ also register MCU GPIOs with the generic GPIO API, so you'll able
+ to use MCU pins as GPIOs.
+
endmenu
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index 39e3e69ed125..ca520fa143d6 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TPS65010) += tps65010.o
obj-$(CONFIG_MENELAUS) += menelaus.o
obj-$(CONFIG_SENSORS_TSL2550) += tsl2550.o
+obj-$(CONFIG_MCU_MPC8349EMITX) += mcu_mpc8349emitx.o
ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index 4655b794ebe3..28902ebd5539 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -49,10 +49,9 @@ MODULE_LICENSE("GPL");
struct isp1301 {
struct otg_transceiver otg;
- struct i2c_client client;
+ struct i2c_client *client;
void (*i2c_release)(struct device *dev);
- int irq;
int irq_type;
u32 last_otg_ctrl;
@@ -138,14 +137,6 @@ static inline void notresponding(struct isp1301 *isp)
/*-------------------------------------------------------------------------*/
-/* only two addresses possible */
-#define ISP_BASE 0x2c
-static unsigned short normal_i2c[] = {
- ISP_BASE, ISP_BASE + 1,
- I2C_CLIENT_END };
-
-I2C_CLIENT_INSMOD;
-
static struct i2c_driver isp1301_driver;
/* smbus apis are used for portability */
@@ -153,25 +144,25 @@ static struct i2c_driver isp1301_driver;
static inline u8
isp1301_get_u8(struct isp1301 *isp, u8 reg)
{
- return i2c_smbus_read_byte_data(&isp->client, reg + 0);
+ return i2c_smbus_read_byte_data(isp->client, reg + 0);
}
static inline int
isp1301_get_u16(struct isp1301 *isp, u8 reg)
{
- return i2c_smbus_read_word_data(&isp->client, reg);
+ return i2c_smbus_read_word_data(isp->client, reg);
}
static inline int
isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits)
{
- return i2c_smbus_write_byte_data(&isp->client, reg + 0, bits);
+ return i2c_smbus_write_byte_data(isp->client, reg + 0, bits);
}
static inline int
isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
{
- return i2c_smbus_write_byte_data(&isp->client, reg + 1, bits);
+ return i2c_smbus_write_byte_data(isp->client, reg + 1, bits);
}
/*-------------------------------------------------------------------------*/
@@ -349,10 +340,10 @@ isp1301_defer_work(struct isp1301 *isp, int work)
int status;
if (isp && !test_and_set_bit(work, &isp->todo)) {
- (void) get_device(&isp->client.dev);
+ (void) get_device(&isp->client->dev);
status = schedule_work(&isp->work);
if (!status && !isp->working)
- dev_vdbg(&isp->client.dev,
+ dev_vdbg(&isp->client->dev,
"work item %d may be lost\n", work);
}
}
@@ -1135,7 +1126,7 @@ isp1301_work(struct work_struct *work)
/* transfer state from otg engine to isp1301 */
if (test_and_clear_bit(WORK_UPDATE_ISP, &isp->todo)) {
otg_update_isp(isp);
- put_device(&isp->client.dev);
+ put_device(&isp->client->dev);
}
#endif
/* transfer state from isp1301 to otg engine */
@@ -1143,7 +1134,7 @@ isp1301_work(struct work_struct *work)
u8 stat = isp1301_clear_latch(isp);
isp_update_otg(isp, stat);
- put_device(&isp->client.dev);
+ put_device(&isp->client->dev);
}
if (test_and_clear_bit(WORK_HOST_RESUME, &isp->todo)) {
@@ -1178,7 +1169,7 @@ isp1301_work(struct work_struct *work)
}
host_resume(isp);
// mdelay(10);
- put_device(&isp->client.dev);
+ put_device(&isp->client->dev);
}
if (test_and_clear_bit(WORK_TIMER, &isp->todo)) {
@@ -1187,15 +1178,15 @@ isp1301_work(struct work_struct *work)
if (!stop)
mod_timer(&isp->timer, jiffies + TIMER_JIFFIES);
#endif
- put_device(&isp->client.dev);
+ put_device(&isp->client->dev);
}
if (isp->todo)
- dev_vdbg(&isp->client.dev,
+ dev_vdbg(&isp->client->dev,
"work done, todo = 0x%lx\n",
isp->todo);
if (stop) {
- dev_dbg(&isp->client.dev, "stop\n");
+ dev_dbg(&isp->client->dev, "stop\n");
break;
}
} while (isp->todo);
@@ -1219,7 +1210,7 @@ static void isp1301_release(struct device *dev)
{
struct isp1301 *isp;
- isp = container_of(dev, struct isp1301, client.dev);
+ isp = dev_get_drvdata(dev);
/* ugly -- i2c hijacks our memory hook to wait_for_completion() */
if (isp->i2c_release)
@@ -1229,15 +1220,15 @@ static void isp1301_release(struct device *dev)
static struct isp1301 *the_transceiver;
-static int isp1301_detach_client(struct i2c_client *i2c)
+static int __exit isp1301_remove(struct i2c_client *i2c)
{
struct isp1301 *isp;
- isp = container_of(i2c, struct isp1301, client);
+ isp = i2c_get_clientdata(i2c);
isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
- free_irq(isp->irq, isp);
+ free_irq(i2c->irq, isp);
#ifdef CONFIG_USB_OTG
otg_unbind(isp);
#endif
@@ -1252,7 +1243,7 @@ static int isp1301_detach_client(struct i2c_client *i2c)
put_device(&i2c->dev);
the_transceiver = 0;
- return i2c_detach_client(i2c);
+ return 0;
}
/*-------------------------------------------------------------------------*/
@@ -1285,7 +1276,7 @@ static int isp1301_otg_enable(struct isp1301 *isp)
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
- dev_info(&isp->client.dev, "ready for dual-role USB ...\n");
+ dev_info(&isp->client->dev, "ready for dual-role USB ...\n");
return 0;
}
@@ -1310,7 +1301,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
#ifdef CONFIG_USB_OTG
isp->otg.host = host;
- dev_dbg(&isp->client.dev, "registered host\n");
+ dev_dbg(&isp->client->dev, "registered host\n");
host_suspend(isp);
if (isp->otg.gadget)
return isp1301_otg_enable(isp);
@@ -1325,7 +1316,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
if (machine_is_omap_h2())
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
- dev_info(&isp->client.dev, "A-Host sessions ok\n");
+ dev_info(&isp->client->dev, "A-Host sessions ok\n");
isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
INTR_ID_GND);
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
@@ -1343,7 +1334,7 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
return 0;
#else
- dev_dbg(&isp->client.dev, "host sessions not allowed\n");
+ dev_dbg(&isp->client->dev, "host sessions not allowed\n");
return -EINVAL;
#endif
@@ -1370,7 +1361,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
#ifdef CONFIG_USB_OTG
isp->otg.gadget = gadget;
- dev_dbg(&isp->client.dev, "registered gadget\n");
+ dev_dbg(&isp->client->dev, "registered gadget\n");
/* gadget driver may be suspended until vbus_connect () */
if (isp->otg.host)
return isp1301_otg_enable(isp);
@@ -1395,7 +1386,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
INTR_SESS_VLD);
isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
INTR_VBUS_VLD);
- dev_info(&isp->client.dev, "B-Peripheral sessions ok\n");
+ dev_info(&isp->client->dev, "B-Peripheral sessions ok\n");
dump_regs(isp, __func__);
/* If this has a Mini-AB connector, this mode is highly
@@ -1408,7 +1399,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
return 0;
#else
- dev_dbg(&isp->client.dev, "peripheral sessions not allowed\n");
+ dev_dbg(&isp->client->dev, "peripheral sessions not allowed\n");
return -EINVAL;
#endif
}
@@ -1508,12 +1499,10 @@ isp1301_start_hnp(struct otg_transceiver *dev)
/*-------------------------------------------------------------------------*/
-/* no error returns, they'd just make bus scanning stop */
-static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
+static int __init isp1301_probe(struct i2c_client *i2c)
{
int status;
struct isp1301 *isp;
- struct i2c_client *i2c;
if (the_transceiver)
return 0;
@@ -1527,37 +1516,19 @@ static int isp1301_probe(struct i2c_adapter *bus, int address, int kind)
isp->timer.function = isp1301_timer;
isp->timer.data = (unsigned long) isp;
- isp->irq = -1;
- isp->client.addr = address;
- i2c_set_clientdata(&isp->client, isp);
- isp->client.adapter = bus;
- isp->client.driver = &isp1301_driver;
- strlcpy(isp->client.name, DRIVER_NAME, I2C_NAME_SIZE);
- i2c = &isp->client;
-
- /* if this is a true probe, verify the chip ... */
- if (kind < 0) {
- status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
- if (status != I2C_VENDOR_ID_PHILIPS) {
- dev_dbg(&bus->dev, "addr %d not philips id: %d\n",
- address, status);
- goto fail1;
- }
- status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
- if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
- dev_dbg(&bus->dev, "%d not isp1301, %d\n",
- address, status);
- goto fail1;
- }
- }
+ i2c_set_clientdata(i2c, isp);
+ isp->client = i2c;
- status = i2c_attach_client(i2c);
- if (status < 0) {
- dev_dbg(&bus->dev, "can't attach %s to device %d, err %d\n",
- DRIVER_NAME, address, status);
-fail1:
- kfree(isp);
- return 0;
+ /* verify the chip (shouldn't be necesary) */
+ status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
+ if (status != I2C_VENDOR_ID_PHILIPS) {
+ dev_dbg(&i2c->dev, "not philips id: %d\n", status);
+ goto fail;
+ }
+ status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
+ if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
+ dev_dbg(&i2c->dev, "not isp1301, %d\n", status);
+ goto fail;
}
isp->i2c_release = i2c->dev.release;
i2c->dev.release = isp1301_release;
@@ -1586,7 +1557,7 @@ fail1:
status = otg_bind(isp);
if (status < 0) {
dev_dbg(&i2c->dev, "can't bind OTG\n");
- goto fail2;
+ goto fail;
}
#endif
@@ -1599,26 +1570,21 @@ fail1:
/* IRQ wired at M14 */
omap_cfg_reg(M14_1510_GPIO2);
- isp->irq = OMAP_GPIO_IRQ(2);
if (gpio_request(2, "isp1301") == 0)
gpio_direction_input(2);
isp->irq_type = IRQF_TRIGGER_FALLING;
}
isp->irq_type |= IRQF_SAMPLE_RANDOM;
- status = request_irq(isp->irq, isp1301_irq,
+ status = request_irq(i2c->irq, isp1301_irq,
isp->irq_type, DRIVER_NAME, isp);
if (status < 0) {
dev_dbg(&i2c->dev, "can't get IRQ %d, err %d\n",
- isp->irq, status);
-#ifdef CONFIG_USB_OTG
-fail2:
-#endif
- i2c_detach_client(i2c);
- goto fail1;
+ i2c->irq, status);
+ goto fail;
}
- isp->otg.dev = &isp->client.dev;
+ isp->otg.dev = &i2c->dev;
isp->otg.label = DRIVER_NAME;
isp->otg.set_host = isp1301_set_host,
@@ -1649,22 +1615,25 @@ fail2:
status);
return 0;
-}
-static int isp1301_scan_bus(struct i2c_adapter *bus)
-{
- if (!i2c_check_functionality(bus, I2C_FUNC_SMBUS_BYTE_DATA
- | I2C_FUNC_SMBUS_READ_WORD_DATA))
- return -EINVAL;
- return i2c_probe(bus, &addr_data, isp1301_probe);
+fail:
+ kfree(isp);
+ return -ENODEV;
}
+static const struct i2c_device_id isp1301_id[] = {
+ { "isp1301_omap", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, isp1301_id);
+
static struct i2c_driver isp1301_driver = {
.driver = {
.name = "isp1301_omap",
},
- .attach_adapter = isp1301_scan_bus,
- .detach_client = isp1301_detach_client,
+ .probe = isp1301_probe,
+ .remove = __exit_p(isp1301_remove),
+ .id_table = isp1301_id,
};
/*-------------------------------------------------------------------------*/
diff --git a/drivers/i2c/chips/mcu_mpc8349emitx.c b/drivers/i2c/chips/mcu_mpc8349emitx.c
new file mode 100644
index 000000000000..82a9bcb858b6
--- /dev/null
+++ b/drivers/i2c/chips/mcu_mpc8349emitx.c
@@ -0,0 +1,209 @@
+/*
+ * Power Management and GPIO expander driver for MPC8349E-mITX-compatible MCU
+ *
+ * Copyright (c) 2008 MontaVista Software, Inc.
+ *
+ * Author: Anton Vorontsov <avorontsov@ru.mvista.com>
+ *
+ * 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.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <asm/prom.h>
+#include <asm/machdep.h>
+
+/*
+ * I don't have specifications for the MCU firmware, I found this register
+ * and bits positions by the trial&error method.
+ */
+#define MCU_REG_CTRL 0x20
+#define MCU_CTRL_POFF 0x40
+
+#define MCU_NUM_GPIO 2
+
+struct mcu {
+ struct mutex lock;
+ struct device_node *np;
+ struct i2c_client *client;
+ struct of_gpio_chip of_gc;
+ u8 reg_ctrl;
+};
+
+static struct mcu *glob_mcu;
+
+static void mcu_power_off(void)
+{
+ struct mcu *mcu = glob_mcu;
+
+ pr_info("Sending power-off request to the MCU...\n");
+ mutex_lock(&mcu->lock);
+ i2c_smbus_write_byte_data(glob_mcu->client, MCU_REG_CTRL,
+ mcu->reg_ctrl | MCU_CTRL_POFF);
+ mutex_unlock(&mcu->lock);
+}
+
+static void mcu_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ struct of_gpio_chip *of_gc = to_of_gpio_chip(gc);
+ struct mcu *mcu = container_of(of_gc, struct mcu, of_gc);
+ u8 bit = 1 << (4 + gpio);
+
+ mutex_lock(&mcu->lock);
+ if (val)
+ mcu->reg_ctrl &= ~bit;
+ else
+ mcu->reg_ctrl |= bit;
+
+ i2c_smbus_write_byte_data(mcu->client, MCU_REG_CTRL, mcu->reg_ctrl);
+ mutex_unlock(&mcu->lock);
+}
+
+static int mcu_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+ mcu_gpio_set(gc, gpio, val);
+ return 0;
+}
+
+static int mcu_gpiochip_add(struct mcu *mcu)
+{
+ struct device_node *np;
+ struct of_gpio_chip *of_gc = &mcu->of_gc;
+ struct gpio_chip *gc = &of_gc->gc;
+ int ret;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,mcu-mpc8349emitx");
+ if (!np)
+ return -ENODEV;
+
+ gc->owner = THIS_MODULE;
+ gc->label = np->full_name;
+ gc->can_sleep = 1;
+ gc->ngpio = MCU_NUM_GPIO;
+ gc->base = -1;
+ gc->set = mcu_gpio_set;
+ gc->direction_output = mcu_gpio_dir_out;
+ of_gc->gpio_cells = 2;
+ of_gc->xlate = of_gpio_simple_xlate;
+
+ np->data = of_gc;
+ mcu->np = np;
+
+ /*
+ * We don't want to lose the node, its ->data and ->full_name...
+ * So, if succeeded, we don't put the node here.
+ */
+ ret = gpiochip_add(gc);
+ if (ret)
+ of_node_put(np);
+ return ret;
+}
+
+static int mcu_gpiochip_remove(struct mcu *mcu)
+{
+ int ret;
+
+ ret = gpiochip_remove(&mcu->of_gc.gc);
+ if (ret)
+ return ret;
+ of_node_put(mcu->np);
+
+ return 0;
+}
+
+static int __devinit mcu_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct mcu *mcu;
+ int ret;
+
+ mcu = kzalloc(sizeof(*mcu), GFP_KERNEL);
+ if (!mcu)
+ return -ENOMEM;
+
+ mutex_init(&mcu->lock);
+ mcu->client = client;
+ i2c_set_clientdata(client, mcu);
+
+ ret = i2c_smbus_read_byte_data(mcu->client, MCU_REG_CTRL);
+ if (ret < 0)
+ goto err;
+ mcu->reg_ctrl = ret;
+
+ ret = mcu_gpiochip_add(mcu);
+ if (ret)
+ goto err;
+
+ /* XXX: this is potentially racy, but there is no lock for ppc_md */
+ if (!ppc_md.power_off) {
+ glob_mcu = mcu;
+ ppc_md.power_off = mcu_power_off;
+ dev_info(&client->dev, "will provide power-off service\n");
+ }
+
+ return 0;
+err:
+ kfree(mcu);
+ return ret;
+}
+
+static int __devexit mcu_remove(struct i2c_client *client)
+{
+ struct mcu *mcu = i2c_get_clientdata(client);
+ int ret;
+
+ if (glob_mcu == mcu) {
+ ppc_md.power_off = NULL;
+ glob_mcu = NULL;
+ }
+
+ ret = mcu_gpiochip_remove(mcu);
+ if (ret)
+ return ret;
+ i2c_set_clientdata(client, NULL);
+ kfree(mcu);
+ return 0;
+}
+
+static const struct i2c_device_id mcu_ids[] = {
+ { "mcu-mpc8349emitx", },
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, mcu_ids);
+
+static struct i2c_driver mcu_driver = {
+ .driver = {
+ .name = "mcu-mpc8349emitx",
+ .owner = THIS_MODULE,
+ },
+ .probe = mcu_probe,
+ .remove = __devexit_p(mcu_remove),
+ .id_table = mcu_ids,
+};
+
+static int __init mcu_init(void)
+{
+ return i2c_add_driver(&mcu_driver);
+}
+module_init(mcu_init);
+
+static void __exit mcu_exit(void)
+{
+ i2c_del_driver(&mcu_driver);
+}
+module_exit(mcu_exit);
+
+MODULE_DESCRIPTION("Power Management and GPIO expander driver for "
+ "MPC8349E-mITX-compatible MCU");
+MODULE_AUTHOR("Anton Vorontsov <avorontsov@ru.mvista.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/i2c/chips/tps65010.c b/drivers/i2c/chips/tps65010.c
index cf02e8fceb42..acf8b9d5f575 100644
--- a/drivers/i2c/chips/tps65010.c
+++ b/drivers/i2c/chips/tps65010.c
@@ -456,14 +456,17 @@ static irqreturn_t tps65010_irq(int irq, void *_tps)
/* offsets 0..3 == GPIO1..GPIO4
* offsets 4..5 == LED1/nPG, LED2 (we set one of the non-BLINK modes)
+ * offset 6 == vibrator motor driver
*/
static void
tps65010_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
if (offset < 4)
tps65010_set_gpio_out_value(offset + 1, value);
- else
+ else if (offset < 6)
tps65010_set_led(offset - 3, value ? ON : OFF);
+ else
+ tps65010_set_vib(value);
}
static int
@@ -477,8 +480,10 @@ tps65010_output(struct gpio_chip *chip, unsigned offset, int value)
if (!(tps->outmask & (1 << offset)))
return -EINVAL;
tps65010_set_gpio_out_value(offset + 1, value);
- } else
+ } else if (offset < 6)
tps65010_set_led(offset - 3, value ? ON : OFF);
+ else
+ tps65010_set_vib(value);
return 0;
}
@@ -646,7 +651,7 @@ static int tps65010_probe(struct i2c_client *client,
tps->chip.get = tps65010_gpio_get;
tps->chip.base = board->base;
- tps->chip.ngpio = 6;
+ tps->chip.ngpio = 7;
tps->chip.can_sleep = 1;
status = gpiochip_add(&tps->chip);
@@ -675,6 +680,7 @@ static const struct i2c_device_id tps65010_id[] = {
{ "tps65011", TPS65011 },
{ "tps65012", TPS65012 },
{ "tps65013", TPS65013 },
+ { "tps65014", TPS65011 }, /* tps65011 charging at 6.5V max */
{ }
};
MODULE_DEVICE_TABLE(i2c, tps65010_id);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index b346a687ab59..42e852d79ffa 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -437,6 +437,10 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
{
int res = 0, dummy;
+ /* Can't register until after driver model init */
+ if (unlikely(WARN_ON(!i2c_bus_type.p)))
+ return -EAGAIN;
+
mutex_init(&adap->bus_lock);
mutex_init(&adap->clist_lock);
INIT_LIST_HEAD(&adap->clients);
@@ -696,6 +700,10 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
{
int res;
+ /* Can't register until after driver model init */
+ if (unlikely(WARN_ON(!i2c_bus_type.p)))
+ return -EAGAIN;
+
/* new style driver methods can't mix with legacy ones */
if (is_newstyle_driver(driver)) {
if (driver->attach_adapter || driver->detach_adapter
@@ -978,7 +986,10 @@ static void __exit i2c_exit(void)
bus_unregister(&i2c_bus_type);
}
-subsys_initcall(i2c_init);
+/* We must initialize early, because some subsystems register i2c drivers
+ * in subsys_initcall() code, but are linked (and initialized) before i2c.
+ */
+postcore_initcall(i2c_init);
module_exit(i2c_exit);
/* ----------------------------------------------------
@@ -1677,6 +1688,28 @@ s32 i2c_smbus_write_word_data(struct i2c_client *client, u8 command, u16 value)
EXPORT_SYMBOL(i2c_smbus_write_word_data);
/**
+ * i2c_smbus_process_call - SMBus "process call" protocol
+ * @client: Handle to slave device
+ * @command: Byte interpreted by slave
+ * @value: 16-bit "word" being written
+ *
+ * This executes the SMBus "process call" protocol, returning negative errno
+ * else a 16-bit unsigned "word" received from the device.
+ */
+s32 i2c_smbus_process_call(struct i2c_client *client, u8 command, u16 value)
+{
+ union i2c_smbus_data data;
+ int status;
+ data.word = value;
+
+ status = i2c_smbus_xfer(client->adapter, client->addr, client->flags,
+ I2C_SMBUS_WRITE, command,
+ I2C_SMBUS_PROC_CALL, &data);
+ return (status < 0) ? status : data.word;
+}
+EXPORT_SYMBOL(i2c_smbus_process_call);
+
+/**
* i2c_smbus_read_block_data - SMBus "block read" protocol
* @client: Handle to slave device
* @command: Byte interpreted by slave
OpenPOWER on IntegriCloud