summaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2010-10-10 19:36:19 +0200
committerSascha Hauer <s.hauer@pengutronix.de>2010-10-11 13:22:13 +0200
commit2ebb440e1d92c60f47a0d89b7666f190caf38561 (patch)
tree3e361fe34257ce37463dec5b6d129bc52258fb7b /drivers/mfd
parent8f14d065e1e39d88949ee489acfe6f7faa51f1b1 (diff)
downloadbarebox-2ebb440e1d92c60f47a0d89b7666f190caf38561.tar.gz
barebox-2ebb440e1d92c60f47a0d89b7666f190caf38561.tar.xz
Move mfd drivers to drivers/mfd
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig28
-rw-r--r--drivers/mfd/Makefile6
-rw-r--r--drivers/mfd/lp3972.c110
-rw-r--r--drivers/mfd/mc13783.c237
-rw-r--r--drivers/mfd/mc13892.c164
-rw-r--r--drivers/mfd/mc34704.c140
-rw-r--r--drivers/mfd/mc9sdz60.c153
-rw-r--r--drivers/mfd/twl4030.c186
8 files changed, 1024 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
new file mode 100644
index 0000000000..7c27418bf1
--- /dev/null
+++ b/drivers/mfd/Kconfig
@@ -0,0 +1,28 @@
+menu MFD
+
+config I2C_MC13892
+ depends on I2C
+ bool "MC13892 a.k.a. PMIC driver"
+
+config I2C_MC34704
+ depends on I2C
+ bool "MC34704 PMIC driver"
+
+config I2C_MC9SDZ60
+ depends on I2C
+ bool "MC9SDZ60 driver"
+
+config I2C_LP3972
+ depends on I2C
+ bool "LP3972 driver"
+
+config I2C_TWL4030
+ depends on I2C
+ bool "TWL4030 driver"
+ select GPIO
+
+config DRIVER_SPI_MC13783
+ depends on SPI
+ bool "MC13783 a.k.a. PMIC driver"
+
+endmenu
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
new file mode 100644
index 0000000000..d411f23b69
--- /dev/null
+++ b/drivers/mfd/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_I2C_MC13892) += mc13892.o
+obj-$(CONFIG_I2C_MC34704) += mc34704.o
+obj-$(CONFIG_I2C_MC9SDZ60) += mc9sdz60.o
+obj-$(CONFIG_I2C_LP3972) += lp3972.o
+obj-$(CONFIG_I2C_TWL4030) += twl4030.o
+obj-$(CONFIG_DRIVER_SPI_MC13783) += mc13783.o
diff --git a/drivers/mfd/lp3972.c b/drivers/mfd/lp3972.c
new file mode 100644
index 0000000000..98266990dc
--- /dev/null
+++ b/drivers/mfd/lp3972.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 Sascha Hauer, Pengutronix
+ * 2009 Marc Kleine-Budde <mkl@pengutronix.de>
+ * 2009 Eric Benard <eric@eukrea.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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <xfuncs.h>
+#include <errno.h>
+
+#include <i2c/i2c.h>
+
+#include <asm/byteorder.h>
+
+#define DRIVERNAME "lp3972"
+
+struct lp_priv {
+ struct cdev cdev;
+ struct i2c_client *client;
+};
+
+#define to_lp_priv(a) container_of(a, struct lp_priv, cdev)
+
+static struct lp_priv *lp_dev;
+
+struct i2c_client *lp3972_get_client(void)
+{
+ if (!lp_dev)
+ return NULL;
+
+ return lp_dev->client;
+}
+
+static u32 lp_read_reg(struct lp_priv *lp, int reg)
+{
+ u8 buf;
+
+ i2c_read_reg(lp->client, reg, &buf, sizeof(buf));
+
+ return buf;
+}
+
+static ssize_t lp_read(struct cdev *cdev, void *_buf, size_t count, ulong offset, ulong flags)
+{
+ struct lp_priv *priv = to_lp_priv(cdev);
+ int i = count;
+ u8 *buf = _buf;
+
+ while (i) {
+ *buf = lp_read_reg(priv, offset);
+ buf++;
+ i--;
+ offset++;
+ }
+
+ return count;
+}
+
+static struct file_operations lp_fops = {
+ .lseek = dev_lseek_default,
+ .read = lp_read,
+};
+
+static int lp_probe(struct device_d *dev)
+{
+ if (lp_dev)
+ return -EBUSY;
+
+ lp_dev = xzalloc(sizeof(struct lp_priv));
+ lp_dev->cdev.name = DRIVERNAME;
+ lp_dev->client = to_i2c_client(dev);
+ lp_dev->cdev.size = 256;
+ lp_dev->cdev.dev = dev;
+ lp_dev->cdev.ops = &lp_fops;
+
+ devfs_create(&lp_dev->cdev);
+
+ return 0;
+}
+
+static struct driver_d lp_driver = {
+ .name = DRIVERNAME,
+ .probe = lp_probe,
+};
+
+static int lp_init(void)
+{
+ register_driver(&lp_driver);
+ return 0;
+}
+
+device_initcall(lp_init);
diff --git a/drivers/mfd/mc13783.c b/drivers/mfd/mc13783.c
new file mode 100644
index 0000000000..19e2780920
--- /dev/null
+++ b/drivers/mfd/mc13783.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2007 Sascha Hauer, Pengutronix
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <spi/spi.h>
+#include <xfuncs.h>
+#include <errno.h>
+#include <mach/pmic.h>
+
+#define REG_INTERRUPT_STATUS_0 0x0
+#define REG_INTERRUPT_MASK 0x1
+#define REG_INTERRUPT_SENSE_0 0x2
+#define REG_INTERRUPT_STATUS_1 0x3
+#define REG_INTERRUPT_MASK_1 0x4
+#define REG_INTERRUPT_SENSE_1 0x5
+#define REG_POWER_UP_MODE_SENSE 0x6
+#define REG_REVISION 0x7
+#define REG_SEMAPHORE 0x8
+#define REG_ARBITRATION_PERIPHERAL_AUDIO 0x9
+#define REG_ARBITRATION_SWITCHERS 0xa
+#define REG_ARBITRATION_REGULATORS(x) (0xb + (x)) /* 0 .. 1 */
+#define REG_POWER_CONTROL(x) (0xd + (x)) /* 0 .. 2 */
+#define REG_REGEN_ASSIGNMENT 0x10
+#define REG_CONTROL_SPARE 0x11
+#define REG_MEMORY_A 0x12
+#define REG_MEMORY_B 0x13
+#define REG_RTC_TIME 0x14
+#define REG_RTC_ALARM 0x15
+#define REG_RTC_DAY 0x16
+#define REG_RTC_DAY_ALARM 0x17
+#define REG_SWITCHERS(x) (0x18 + (x)) /* 0 .. 5 */
+#define REG_REGULATOR_SETTING(x) (0x1e + (x)) /* 0 .. 1 */
+#define REG_REGULATOR_MODE(x) (0x20 + (x)) /* 0 .. 1 */
+#define REG_POWER_MISCELLANEOUS 0x22
+#define REG_POWER_SPARE 0x23
+#define REG_AUDIO_RX_0 0x24
+#define REG_AUDIO_RX_1 0x25
+#define REG_AUDIO_TX 0x26
+#define REG_AUDIO_SSI_NETWORK 0x27
+#define REG_AUDIO_CODEC 0x28
+#define REG_AUDIO_STEREO_DAC 0x29
+#define REG_AUDIO_SPARE 0x2a
+#define REG_ADC(x) (0x2b + (x)) /* 0 .. 4 */
+#define REG_CHARGER 0x30
+#define REG_USB 0x31
+#define REG_CHARGE_USB_SPARE 0x32
+#define REG_LED_CONTROL(x) (0x33 + (x)) /* 0 .. 5 */
+#define REG_SPARE 0x39
+#define REG_TRIM(x) (0x3a + (x)) /* 0 .. 1 */
+#define REG_TEST(x) (0x3c + (x)) /* 0 .. 3 */
+
+#define MXC_PMIC_REG_NUM(reg) (((reg) & 0x3f) << 25)
+#define MXC_PMIC_WRITE (1 << 31)
+
+#define SWX_VOLTAGE(x) ((x) & 0x3f)
+#define SWX_VOLTAGE_DVS(x) (((x) & 0x3f) << 6)
+#define SWX_VOLTAGE_STANDBY(x) (((x) & 0x3f) << 12)
+#define SWX_VOLTAGE_1_450 0x16
+
+#define SWX_MODE_OFF 0
+#define SWX_MODE_NO_PULSE_SKIP 1
+#define SWX_MODE_PULSE_SKIP 2
+#define SWX_MODE_LOW_POWER_PFM 3
+
+#define SW1A_MODE(x) (((x) & 0x3) << 0)
+#define SW1A_MODE_STANDBY(x) (((x) & 0x3) << 2)
+#define SW1B_MODE(x) (((x) & 0x3) << 10)
+#define SW1B_MODE_STANDBY(x) (((x) & 0x3) << 12)
+#define SW1A_SOFTSTART (1 << 9)
+#define SW1B_SOFTSTART (1 << 17)
+#define SW_PLL_FACTOR(x) (((x) - 28) << 19)
+
+struct pmic_priv {
+ struct cdev cdev;
+ struct spi_device *spi;
+};
+
+static int spi_rw(struct spi_device *spi, void * buf, size_t len)
+{
+ int ret;
+
+ struct spi_transfer t = {
+ .tx_buf = (const void *)buf,
+ .rx_buf = buf,
+ .len = len,
+ .cs_change = 0,
+ .delay_usecs = 0,
+ };
+ struct spi_message m;
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t, &m);
+ if ((ret = spi_sync(spi, &m)))
+ return ret;
+ return 0;
+}
+
+static uint32_t pmic_read_reg(struct pmic_priv *pmic, int reg)
+{
+ uint32_t buf;
+
+ buf = MXC_PMIC_REG_NUM(reg);
+
+ spi_rw(pmic->spi, &buf, 4);
+
+ return buf;
+}
+
+static void pmic_write_reg(struct pmic_priv *pmic, int reg, uint32_t val)
+{
+ uint32_t buf = MXC_PMIC_REG_NUM(reg) | MXC_PMIC_WRITE | (val & 0xffffff);
+
+ spi_rw(pmic->spi, &buf, 4);
+}
+
+static struct pmic_priv *pmic_device;
+
+int pmic_power(void)
+{
+ if(!pmic_device) {
+ printf("%s: no pmic device available\n", __FUNCTION__);
+ return -ENODEV;
+ }
+
+ pmic_write_reg(pmic_device, REG_SWITCHERS(0),
+ SWX_VOLTAGE(SWX_VOLTAGE_1_450) |
+ SWX_VOLTAGE_DVS(SWX_VOLTAGE_1_450) |
+ SWX_VOLTAGE_STANDBY(SWX_VOLTAGE_1_450));
+
+ pmic_write_reg(pmic_device, REG_SWITCHERS(4),
+ SW1A_MODE(SWX_MODE_NO_PULSE_SKIP) |
+ SW1A_MODE_STANDBY(SWX_MODE_NO_PULSE_SKIP)|
+ SW1A_SOFTSTART |
+ SW1B_MODE(SWX_MODE_NO_PULSE_SKIP) |
+ SW1B_MODE_STANDBY(SWX_MODE_NO_PULSE_SKIP) |
+ SW1B_SOFTSTART |
+ SW_PLL_FACTOR(32)
+ );
+
+ return 0;
+}
+
+ssize_t pmic_read(struct cdev *cdev, void *_buf, size_t count, ulong offset, ulong flags)
+{
+ int i = count >> 2;
+ uint32_t *buf = _buf;
+
+ offset >>= 2;
+
+ while (i) {
+ *buf = pmic_read_reg(pmic_device, offset);
+ buf++;
+ i--;
+ offset++;
+ }
+
+ return count;
+}
+
+ssize_t pmic_write(struct cdev *cdev, const void *_buf, size_t count, ulong offset, ulong flags)
+{
+ int i = count >> 2;
+ const uint32_t *buf = _buf;
+
+ offset >>= 2;
+
+ while (i) {
+ pmic_write_reg(pmic_device, offset, *buf);
+ buf++;
+ i--;
+ offset++;
+ }
+
+ return count;
+}
+
+static struct file_operations pmic_fops = {
+ .lseek = dev_lseek_default,
+ .read = pmic_read,
+ .write = pmic_write,
+};
+
+static int pmic_probe(struct device_d *dev)
+{
+ struct spi_device *spi = (struct spi_device *)dev->type_data;
+
+ if (pmic_device)
+ return -EBUSY;
+
+ pmic_device = xzalloc(sizeof(*pmic_device));
+
+ pmic_device->cdev.name = "pmic";
+ pmic_device->cdev.size = 256;
+ pmic_device->cdev.dev = dev;
+ pmic_device->cdev.ops = &pmic_fops;
+
+ spi->mode = SPI_MODE_0 | SPI_CS_HIGH;
+ spi->bits_per_word = 32;
+ pmic_device->spi = spi;
+
+ devfs_create(&pmic_device->cdev);
+
+ return 0;
+}
+
+static struct driver_d pmic_driver = {
+ .name = "mc13783",
+ .probe = pmic_probe,
+};
+
+static int pmic_init(void)
+{
+ register_driver(&pmic_driver);
+ return 0;
+}
+
+device_initcall(pmic_init);
+
diff --git a/drivers/mfd/mc13892.c b/drivers/mfd/mc13892.c
new file mode 100644
index 0000000000..67d4232a23
--- /dev/null
+++ b/drivers/mfd/mc13892.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 Sascha Hauer, Pengutronix
+ * 2009 Marc Kleine-Budde <mkl@pengutronix.de>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <xfuncs.h>
+#include <errno.h>
+
+#include <i2c/i2c.h>
+#include <i2c/mc13892.h>
+
+#define DRIVERNAME "mc13892"
+
+#define to_mc13892(a) container_of(a, struct mc13892, cdev)
+
+static struct mc13892 *mc_dev;
+
+struct mc13892 *mc13892_get(void)
+{
+ if (!mc_dev)
+ return NULL;
+
+ return mc_dev;
+}
+EXPORT_SYMBOL(mc13892_get);
+
+int mc13892_reg_read(struct mc13892 *mc13892, enum mc13892_reg reg, u32 *val)
+{
+ u8 buf[3];
+ int ret;
+
+ ret = i2c_read_reg(mc13892->client, reg, buf, 3);
+ *val = buf[0] << 16 | buf[1] << 8 | buf[2] << 0;
+
+ return ret == 3 ? 0 : ret;
+}
+EXPORT_SYMBOL(mc13892_reg_read)
+
+int mc13892_reg_write(struct mc13892 *mc13892, enum mc13892_reg reg, u32 val)
+{
+ u8 buf[] = {
+ val >> 16,
+ val >> 8,
+ val >> 0,
+ };
+ int ret;
+
+ ret = i2c_write_reg(mc13892->client, reg, buf, 3);
+
+ return ret == 3 ? 0 : ret;
+}
+EXPORT_SYMBOL(mc13892_reg_write)
+
+int mc13892_set_bits(struct mc13892 *mc13892, enum mc13892_reg reg, u32 mask, u32 val)
+{
+ u32 tmp;
+ int err;
+
+ err = mc13892_reg_read(mc13892, reg, &tmp);
+ tmp = (tmp & ~mask) | val;
+
+ if (!err)
+ err = mc13892_reg_write(mc13892, reg, tmp);
+
+ return err;
+}
+EXPORT_SYMBOL(mc13892_set_bits);
+
+static ssize_t mc_read(struct cdev *cdev, void *_buf, size_t count, ulong offset, ulong flags)
+{
+ struct mc13892 *priv = to_mc13892(cdev);
+ u32 *buf = _buf;
+ size_t i = count >> 2;
+ int err;
+
+ offset >>= 2;
+
+ while (i) {
+ err = mc13892_reg_read(priv, offset, buf);
+ if (err)
+ return (ssize_t)err;
+ buf++;
+ i--;
+ offset++;
+ }
+
+ return count;
+}
+
+static ssize_t mc_write(struct cdev *cdev, const void *_buf, size_t count, ulong offset, ulong flags)
+{
+ struct mc13892 *mc13892 = to_mc13892(cdev);
+ const u32 *buf = _buf;
+ size_t i = count >> 2;
+ int err;
+
+ offset >>= 2;
+
+ while (i) {
+ err = mc13892_reg_write(mc13892, offset, *buf);
+ if (err)
+ return (ssize_t)err;
+ buf++;
+ i--;
+ offset++;
+ }
+
+ return count;
+}
+
+static struct file_operations mc_fops = {
+ .lseek = dev_lseek_default,
+ .read = mc_read,
+ .write = mc_write,
+};
+
+static int mc_probe(struct device_d *dev)
+{
+ if (mc_dev)
+ return -EBUSY;
+
+ mc_dev = xzalloc(sizeof(struct mc13892));
+ mc_dev->cdev.name = DRIVERNAME;
+ mc_dev->client = to_i2c_client(dev);
+ mc_dev->cdev.size = 256;
+ mc_dev->cdev.dev = dev;
+ mc_dev->cdev.ops = &mc_fops;
+
+ devfs_create(&mc_dev->cdev);
+
+ return 0;
+}
+
+static struct driver_d mc_driver = {
+ .name = DRIVERNAME,
+ .probe = mc_probe,
+};
+
+static int mc_init(void)
+{
+ register_driver(&mc_driver);
+ return 0;
+}
+
+device_initcall(mc_init);
diff --git a/drivers/mfd/mc34704.c b/drivers/mfd/mc34704.c
new file mode 100644
index 0000000000..51a8737209
--- /dev/null
+++ b/drivers/mfd/mc34704.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2007 Sascha Hauer, Pengutronix
+ * 2009 Marc Kleine-Budde <mkl@pengutronix.de>
+ * Copyright (C) 2010 Baruch Siach <baruch@tkos.co.il>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <xfuncs.h>
+#include <errno.h>
+
+#include <i2c/i2c.h>
+#include <i2c/mc34704.h>
+
+#define DRIVERNAME "mc34704"
+
+#define to_mc34704(a) container_of(a, struct mc34704, cdev)
+
+static struct mc34704 *mc34704_dev;
+
+struct mc34704 *mc34704_get(void)
+{
+ if (!mc34704_dev)
+ return NULL;
+
+ return mc34704_dev;
+}
+EXPORT_SYMBOL(mc34704_get);
+
+int mc34704_reg_read(struct mc34704 *mc34704, u8 reg, u8 *val)
+{
+ int ret;
+
+ ret = i2c_read_reg(mc34704->client, reg, val, 1);
+
+ return ret == 1 ? 0 : ret;
+}
+EXPORT_SYMBOL(mc34704_reg_read)
+
+int mc34704_reg_write(struct mc34704 *mc34704, u8 reg, u8 val)
+{
+ int ret;
+
+ ret = i2c_write_reg(mc34704->client, reg, &val, 1);
+
+ return ret == 1 ? 0 : ret;
+}
+EXPORT_SYMBOL(mc34704_reg_write)
+
+static ssize_t mc34704_read(struct cdev *cdev, void *_buf, size_t count,
+ ulong offset, ulong flags)
+{
+ struct mc34704 *priv = to_mc34704(cdev);
+ u8 *buf = _buf;
+ size_t i = count;
+ int err;
+
+ while (i) {
+ err = mc34704_reg_read(priv, offset, buf);
+ if (err)
+ return (ssize_t)err;
+ buf++;
+ i--;
+ offset++;
+ }
+
+ return count;
+}
+
+static ssize_t mc34704_write(struct cdev *cdev, const void *_buf, size_t count,
+ ulong offset, ulong flags)
+{
+ struct mc34704 *mc34704 = to_mc34704(cdev);
+ const u8 *buf = _buf;
+ size_t i = count;
+ int err;
+
+ while (i) {
+ err = mc34704_reg_write(mc34704, offset, *buf);
+ if (err)
+ return (ssize_t)err;
+ buf++;
+ i--;
+ offset++;
+ }
+
+ return count;
+}
+
+static struct file_operations mc34704_fops = {
+ .lseek = dev_lseek_default,
+ .read = mc34704_read,
+ .write = mc34704_write,
+};
+
+static int mc34704_probe(struct device_d *dev)
+{
+ if (mc34704_dev)
+ return -EBUSY;
+
+ mc34704_dev = xzalloc(sizeof(struct mc34704));
+ mc34704_dev->cdev.name = DRIVERNAME;
+ mc34704_dev->client = to_i2c_client(dev);
+ mc34704_dev->cdev.size = 256;
+ mc34704_dev->cdev.dev = dev;
+ mc34704_dev->cdev.ops = &mc34704_fops;
+
+ devfs_create(&mc34704_dev->cdev);
+
+ return 0;
+}
+
+static struct driver_d mc34704_driver = {
+ .name = DRIVERNAME,
+ .probe = mc34704_probe,
+};
+
+static int mc34704_init(void)
+{
+ register_driver(&mc34704_driver);
+ return 0;
+}
+device_initcall(mc34704_init);
diff --git a/drivers/mfd/mc9sdz60.c b/drivers/mfd/mc9sdz60.c
new file mode 100644
index 0000000000..3580af8852
--- /dev/null
+++ b/drivers/mfd/mc9sdz60.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2007 Sascha Hauer, Pengutronix
+ * 2009 Marc Kleine-Budde <mkl@pengutronix.de>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <xfuncs.h>
+#include <errno.h>
+
+#include <i2c/i2c.h>
+#include <i2c/mc9sdz60.h>
+
+#define DRIVERNAME "mc9sdz60"
+
+#define to_mc9sdz60(a) container_of(a, struct mc9sdz60, cdev)
+
+static struct mc9sdz60 *mc_dev;
+
+struct mc9sdz60 *mc9sdz60_get(void)
+{
+ if (!mc_dev)
+ return NULL;
+
+ return mc_dev;
+}
+EXPORT_SYMBOL(mc9sdz60_get);
+
+int mc9sdz60_reg_read(struct mc9sdz60 *mc9sdz60, enum mc9sdz60_reg reg, u8 *val)
+{
+ int ret;
+
+ ret = i2c_read_reg(mc9sdz60->client, reg, val, 1);
+
+ return ret == 1 ? 0 : ret;
+}
+EXPORT_SYMBOL(mc9sdz60_reg_read)
+
+int mc9sdz60_reg_write(struct mc9sdz60 *mc9sdz60, enum mc9sdz60_reg reg, u8 val)
+{
+ int ret;
+
+ ret = i2c_write_reg(mc9sdz60->client, reg, &val, 1);
+
+ return ret == 1 ? 0 : ret;
+}
+EXPORT_SYMBOL(mc9sdz60_reg_write)
+
+int mc9sdz60_set_bits(struct mc9sdz60 *mc9sdz60, enum mc9sdz60_reg reg, u8 mask, u8 val)
+{
+ u8 tmp;
+ int err;
+
+ err = mc9sdz60_reg_read(mc9sdz60, reg, &tmp);
+ tmp = (tmp & ~mask) | val;
+
+ if (!err)
+ err = mc9sdz60_reg_write(mc9sdz60, reg, tmp);
+
+ return err;
+}
+EXPORT_SYMBOL(mc9sdz60_set_bits);
+
+static ssize_t mc_read(struct cdev *cdev, void *_buf, size_t count, ulong offset, ulong flags)
+{
+ struct mc9sdz60 *mc9sdz60 = to_mc9sdz60(cdev);
+ u8 *buf = _buf;
+ size_t i = count;
+ int err;
+
+ while (i) {
+ err = mc9sdz60_reg_read(mc9sdz60, offset, buf);
+ if (err)
+ return (ssize_t)err;
+ buf++;
+ i--;
+ offset++;
+ }
+
+ return count;
+}
+
+static ssize_t mc_write(struct cdev *cdev, const void *_buf, size_t count, ulong offset, ulong flags)
+{
+ struct mc9sdz60 *mc9sdz60 = to_mc9sdz60(cdev);
+ const u8 *buf = _buf;
+ size_t i = count;
+ int err;
+
+ while (i) {
+ err = mc9sdz60_reg_write(mc9sdz60, offset, *buf);
+ if (err)
+ return (ssize_t)err;
+ buf++;
+ i--;
+ offset++;
+ }
+
+ return count;
+}
+
+static struct file_operations mc_fops = {
+ .lseek = dev_lseek_default,
+ .read = mc_read,
+ .write = mc_write,
+};
+
+static int mc_probe(struct device_d *dev)
+{
+ if (mc_dev)
+ return -EBUSY;
+
+ mc_dev = xzalloc(sizeof(struct mc9sdz60));
+ mc_dev->cdev.name = DRIVERNAME;
+ mc_dev->client = to_i2c_client(dev);
+ mc_dev->cdev.size = 64; /* 35 known registers */
+ mc_dev->cdev.dev = dev;
+ mc_dev->cdev.ops = &mc_fops;
+
+ devfs_create(&mc_dev->cdev);
+
+ return 0;
+}
+
+static struct driver_d mc_driver = {
+ .name = DRIVERNAME,
+ .probe = mc_probe,
+};
+
+static int mc_init(void)
+{
+ register_driver(&mc_driver);
+ return 0;
+}
+
+device_initcall(mc_init);
diff --git a/drivers/mfd/twl4030.c b/drivers/mfd/twl4030.c
new file mode 100644
index 0000000000..5305ec67e3
--- /dev/null
+++ b/drivers/mfd/twl4030.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2010 Michael Grzeschik <mgr@pengutronix.de>
+ *
+ * This file is released under the GPLv2
+ *
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <xfuncs.h>
+#include <errno.h>
+
+#include <i2c/i2c.h>
+#include <i2c/twl4030.h>
+
+#define DRIVERNAME "twl4030"
+
+#define to_twl4030(a) container_of(a, struct twl4030, cdev)
+
+static struct twl4030 *twl_dev;
+
+struct twl4030 *twl4030_get(void)
+{
+ if (!twl_dev)
+ return NULL;
+
+ return twl_dev;
+}
+EXPORT_SYMBOL(twl4030_get);
+
+int twl4030_reg_read(struct twl4030 *twl4030, u16 reg, u8 *val)
+{
+ int ret;
+ struct i2c_msg xfer_msg[2];
+ struct i2c_msg *msg;
+ int i2c_addr;
+ unsigned char buf = reg & 0xff;
+
+ i2c_addr = twl4030->client->addr + (reg / 0x100);
+
+ /* [MSG1] fill the register address data */
+ msg = &xfer_msg[0];
+ msg->addr = i2c_addr;
+ msg->len = 1;
+ msg->flags = 0; /* Read the register value */
+ msg->buf = &buf;
+ /* [MSG2] fill the data rx buffer */
+ msg = &xfer_msg[1];
+ msg->addr = i2c_addr;
+ msg->flags = I2C_M_RD; /* Read the register value */
+ msg->len = 1; /* only n bytes */
+ msg->buf = val;
+ ret = i2c_transfer(twl4030->client->adapter, xfer_msg, 2);
+
+ /* i2c_transfer returns number of messages transferred */
+ if (ret < 0) {
+ pr_err("%s: failed to transfer all messages: %s\n", __func__, strerror(-ret));
+ return ret;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(twl4030_reg_read)
+
+int twl4030_reg_write(struct twl4030 *twl4030, u16 reg, u8 val)
+{
+ int ret;
+ struct i2c_msg xfer_msg[1];
+ struct i2c_msg *msg;
+ int i2c_addr;
+ u8 buf[2];
+
+ buf[0] = reg & 0xff;
+ buf[1] = val;
+
+ i2c_addr = twl4030->client->addr + (reg / 0x100);
+
+ /*
+ * [MSG1]: fill the register address data
+ * fill the data Tx buffer
+ */
+ msg = xfer_msg;
+ msg->addr = i2c_addr;
+ msg->len = 2;
+ msg->flags = 0;
+ msg->buf = buf;
+ /* over write the first byte of buffer with the register address */
+ ret = i2c_transfer(twl4030->client->adapter, xfer_msg, 1);
+
+ /* i2c_transfer returns number of messages transferred */
+ if (ret < 0) {
+ pr_err("%s: failed to transfer all messages: %s\n", __func__, strerror(-ret));
+ return ret;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(twl4030_reg_write)
+
+int twl4030_set_bits(struct twl4030 *twl4030, enum twl4030_reg reg, u8 mask, u8 val)
+{
+ u8 tmp;
+ int err;
+
+ err = twl4030_reg_read(twl4030, reg, &tmp);
+ tmp = (tmp & ~mask) | val;
+
+ if (!err)
+ err = twl4030_reg_write(twl4030, reg, tmp);
+
+ return err;
+}
+EXPORT_SYMBOL(twl4030_set_bits);
+
+static ssize_t twl_read(struct cdev *cdev, void *_buf, size_t count, ulong offset, ulong flags)
+{
+ struct twl4030 *priv = to_twl4030(cdev);
+ u8 *buf = _buf;
+ size_t i = count;
+ int err;
+
+ while (i) {
+ err = twl4030_reg_read(priv, offset, buf);
+ if (err)
+ return (ssize_t)err;
+ buf++;
+ i--;
+ offset++;
+ }
+
+ return count;
+}
+
+static ssize_t twl_write(struct cdev *cdev, const void *_buf, size_t count, ulong offset, ulong flags)
+{
+ struct twl4030 *twl4030 = to_twl4030(cdev);
+ const u8 *buf = _buf;
+ size_t i = count;
+ int err;
+
+ while (i) {
+ err = twl4030_reg_write(twl4030, offset, *buf);
+ if (err)
+ return (ssize_t)err;
+ buf++;
+ i--;
+ offset++;
+ }
+
+ return count;
+}
+
+static struct file_operations twl_fops = {
+ .lseek = dev_lseek_default,
+ .read = twl_read,
+ .write = twl_write,
+};
+
+static int twl_probe(struct device_d *dev)
+{
+ if (twl_dev)
+ return -EBUSY;
+
+ twl_dev = xzalloc(sizeof(struct twl4030));
+ twl_dev->cdev.name = DRIVERNAME;
+ twl_dev->client = to_i2c_client(dev);
+ twl_dev->cdev.size = 1024;
+ twl_dev->cdev.dev = dev;
+ twl_dev->cdev.ops = &twl_fops;
+
+ devfs_create(&twl_dev->cdev);
+
+ return 0;
+}
+
+static struct driver_d twl_driver = {
+ .name = DRIVERNAME,
+ .probe = twl_probe,
+};
+
+static int twl_init(void)
+{
+ register_driver(&twl_driver);
+ return 0;
+}
+
+device_initcall(twl_init);