summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJin Park <jinyoungp@nvidia.com>2010-10-28 18:04:04 +0900
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:42:58 -0800
commit1d3e3a22b939ccb5b0bf4a9181d0b8aa090519d2 (patch)
treee0309c3f5c16bb4bcb1d363ecb9755188a495a6c
parent4769a334cc487563e5817af1910cdf2e73730138 (diff)
Regulators: Add max8907c and max8952
Add max8907c regulator and mfd driver. Add max8952 regulator driver. Original-Change-Id: If63b724647d887a8088da0f2deb8af91e4fe3cfa Signed-off-by: Jin Park <jinyoungp@nvidia.com> Reviewed-on: http://git-master/r/9902 Reviewed-by: Thomas Cherry <tcherry@nvidia.com> Reviewed-by: Bharat Nihalani <bnihalani@nvidia.com> Tested-by: Bharat Nihalani <bnihalani@nvidia.com> Rebase-Id: R01d66b7af18617a764bd378b7f71e6294ebcabc8
-rw-r--r--drivers/mfd/Kconfig10
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/max8907c.c251
-rw-r--r--include/linux/mfd/max8907c.h183
4 files changed, 445 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 21574bdf485f..a6c974292728 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -386,6 +386,16 @@ config MFD_MAX8998
additional drivers must be enabled in order to use the functionality
of the device.
+config MFD_MAX8907C
+ tristate "Maxim Semiconductor MAX8907C PMIC Support"
+ select MFD_CORE
+ depends on I2C
+ help
+ Say yes here to support for Maxim Semiconductor MAX8907C. This is
+ a Power Management IC. This driver provies common support for
+ accessing the device, additional drivers must be enabled in order
+ to use the functionality of the device.
+
config MFD_WM8400
tristate "Support Wolfson Microelectronics WM8400"
select MFD_CORE
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index c58020303d18..ae6c2e7f8151 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -102,3 +102,4 @@ obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o
obj-$(CONFIG_MFD_PM8XXX_IRQ) += pm8xxx-irq.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
+obj-$(CONFIG_MFD_MAX8907C) += max8907c.o
diff --git a/drivers/mfd/max8907c.c b/drivers/mfd/max8907c.c
new file mode 100644
index 000000000000..0ceccbab7e37
--- /dev/null
+++ b/drivers/mfd/max8907c.c
@@ -0,0 +1,251 @@
+/*
+ * max8907c.c - mfd driver for MAX8907c
+ *
+ * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com>
+ *
+ * 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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/max8907c.h>
+
+static struct mfd_cell cells[] = {
+ {.name = "max8907-regulator",},
+};
+
+int max8907c_reg_read(struct device *dev, u8 reg)
+{
+ struct i2c_client *i2c = to_i2c_client(dev);
+ struct max8907c *max8907c = dev_get_drvdata(dev);
+ u8 val;
+ int ret;
+
+ mutex_lock(&max8907c->io_lock);
+
+ ret = max8907c->read_dev(i2c, reg, 1, &val);
+
+ mutex_unlock(&max8907c->io_lock);
+ pr_debug("max8907c: reg read reg=%x, val=%x\n",
+ (unsigned int)reg, (unsigned int)val);
+
+ if (ret != 0)
+ pr_err("Failed to read max8907c I2C driver: %d\n", ret);
+ return val;
+}
+EXPORT_SYMBOL_GPL(max8907c_reg_read);
+
+int max8907c_reg_write(struct device *dev, u8 reg, u8 val)
+{
+ struct i2c_client *i2c = to_i2c_client(dev);
+ struct max8907c *max8907c = dev_get_drvdata(dev);
+ int ret;
+
+ pr_debug("max8907c: reg write reg=%x, val=%x\n",
+ (unsigned int)reg, (unsigned int)val);
+ mutex_lock(&max8907c->io_lock);
+
+ ret = max8907c->write_dev(i2c, reg, 1, &val);
+
+ mutex_unlock(&max8907c->io_lock);
+
+ if (ret != 0)
+ pr_err("Failed to write max8907c I2C driver: %d\n", ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(max8907c_reg_write);
+
+int max8907c_set_bits(struct device *dev, u8 reg, u8 mask, u8 val)
+{
+ struct i2c_client *i2c = to_i2c_client(dev);
+ struct max8907c *max8907c = dev_get_drvdata(dev);
+ u8 tmp;
+ int ret;
+
+ pr_debug("max8907c: reg write reg=%02X, val=%02X, mask=%02X\n",
+ (unsigned int)reg, (unsigned int)val, (unsigned int)mask);
+ mutex_lock(&max8907c->io_lock);
+
+ ret = max8907c->read_dev(i2c, reg, 1, &tmp);
+ if (ret == 0) {
+ val = (tmp & ~mask) | (val & mask);
+ ret = max8907c->write_dev(i2c, reg, 1, &val);
+ }
+
+ mutex_unlock(&max8907c->io_lock);
+
+ if (ret != 0)
+ pr_err("Failed to write max8907c I2C driver: %d\n", ret);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(max8907c_set_bits);
+
+static int max8907c_i2c_read(void *io_data, u8 reg, u8 count, u8 * dest)
+{
+ struct i2c_client *i2c = (struct i2c_client *)io_data;
+ struct i2c_msg xfer[2];
+ int ret = 0;
+
+ xfer[0].addr = i2c->addr;
+ xfer[0].flags = I2C_M_NOSTART;
+ xfer[0].len = 1;
+ xfer[0].buf = &reg;
+
+ xfer[1].addr = i2c->addr;
+ xfer[1].flags = I2C_M_RD;
+ xfer[1].len = count;
+ xfer[1].buf = dest;
+
+ ret = i2c_transfer(i2c->adapter, xfer, 2);
+ if (ret < 0)
+ return ret;
+ if (ret != 2)
+ return -EIO;
+
+ return 0;
+}
+
+static int max8907c_i2c_write(void *io_data, u8 reg, u8 count, const u8 * src)
+{
+ struct i2c_client *i2c = (struct i2c_client *)io_data;
+ u8 msg[0x100 + 1];
+ int ret = 0;
+
+ msg[0] = reg;
+ memcpy(&msg[1], src, count);
+
+ ret = i2c_master_send(i2c, msg, count + 1);
+ if (ret < 0)
+ return ret;
+ if (ret != count + 1)
+ return -EIO;
+
+ return 0;
+}
+
+static int max8907c_remove_subdev(struct device *dev, void *unused)
+{
+ platform_device_unregister(to_platform_device(dev));
+ return 0;
+}
+
+static int max8907c_remove_subdevs(struct max8907c *max8907c)
+{
+ return device_for_each_child(max8907c->dev, NULL,
+ max8907c_remove_subdev);
+}
+
+static int max8097c_add_subdevs(struct max8907c *max8907c,
+ struct max8907c_platform_data *pdata)
+{
+ struct platform_device *pdev;
+ int ret;
+ int i;
+
+ for (i = 0; i < pdata->num_subdevs; i++) {
+ pdev = platform_device_alloc(pdata->subdevs[i]->name,
+ pdata->subdevs[i]->id);
+
+ pdev->dev.parent = max8907c->dev;
+ pdev->dev.platform_data = pdata->subdevs[i]->dev.platform_data;
+
+ ret = platform_device_add(pdev);
+ if (ret)
+ goto error;
+ }
+ return 0;
+
+error:
+ max8907c_remove_subdevs(max8907c);
+ return ret;
+}
+
+static int max8907c_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct max8907c *max8907c;
+ struct max8907c_platform_data *pdata = i2c->dev.platform_data;
+ int ret;
+ int i;
+
+ max8907c = kzalloc(sizeof(struct max8907c), GFP_KERNEL);
+ if (max8907c == NULL)
+ return -ENOMEM;
+
+ max8907c->read_dev = max8907c_i2c_read;
+ max8907c->write_dev = max8907c_i2c_write;
+ max8907c->dev = &i2c->dev;
+ i2c_set_clientdata(i2c, max8907c);
+
+ mutex_init(&max8907c->io_lock);
+
+ for (i = 0; i < ARRAY_SIZE(cells); i++)
+ cells[i].driver_data = max8907c;
+ ret = mfd_add_devices(max8907c->dev, -1, cells, ARRAY_SIZE(cells),
+ NULL, 0);
+ if (ret != 0) {
+ kfree(max8907c);
+ pr_debug("max8907c: failed to add MFD devices %X\n", ret);
+ return ret;
+ }
+
+ ret = max8097c_add_subdevs(max8907c, pdata);
+
+ return ret;
+}
+
+static int max8907c_i2c_remove(struct i2c_client *i2c)
+{
+ struct max8907c *max8907c = i2c_get_clientdata(i2c);
+
+ mfd_remove_devices(max8907c->dev);
+ kfree(max8907c);
+
+ return 0;
+}
+
+static const struct i2c_device_id max8907c_i2c_id[] = {
+ {"max8907c", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, max8907c_i2c_id);
+
+static struct i2c_driver max8907c_i2c_driver = {
+ .driver = {
+ .name = "max8907c",
+ .owner = THIS_MODULE,
+ },
+ .probe = max8907c_i2c_probe,
+ .remove = max8907c_i2c_remove,
+ .id_table = max8907c_i2c_id,
+};
+
+static int __init max8907c_i2c_init(void)
+{
+ int ret = -ENODEV;
+
+ ret = i2c_add_driver(&max8907c_i2c_driver);
+ if (ret != 0)
+ pr_err("Failed to register I2C driver: %d\n", ret);
+
+ return ret;
+}
+
+subsys_initcall(max8907c_i2c_init);
+
+static void __exit max8907c_i2c_exit(void)
+{
+ i2c_del_driver(&max8907c_i2c_driver);
+}
+
+module_exit(max8907c_i2c_exit);
+
+MODULE_DESCRIPTION("MAX8907C multi-function core driver");
+MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@maxim-ic.com>");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/max8907c.h b/include/linux/mfd/max8907c.h
new file mode 100644
index 000000000000..c78849a32860
--- /dev/null
+++ b/include/linux/mfd/max8907c.h
@@ -0,0 +1,183 @@
+/* linux/mfd/max8907c.h
+ *
+ * Functions to access MAX8907C power management chip.
+ *
+ * Copyright (C) 2010 Gyungoh Yoo <jack.yoo@maxim-ic.com>
+ *
+ * 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.
+ */
+
+#ifndef __LINUX_MFD_MAX8907C_H
+#define __LINUX_MFD_MAX8907C_H
+
+/* MAX8907C register map */
+#define MAX8907C_REG_SYSENSEL 0x00
+#define MAX8907C_REG_ON_OFF_IRQ1 0x01
+#define MAX8907C_REG_ON_OFF_IRQ1_MASK 0x02
+#define MAX8907C_REG_ON_OFF_STAT 0x03
+#define MAX8907C_REG_SDCTL1 0x04
+#define MAX8907C_REG_SDSEQCNT1 0x05
+#define MAX8907C_REG_SDV1 0x06
+#define MAX8907C_REG_SDCTL2 0x07
+#define MAX8907C_REG_SDSEQCNT2 0x08
+#define MAX8907C_REG_SDV2 0x09
+#define MAX8907C_REG_SDCTL3 0x0A
+#define MAX8907C_REG_SDSEQCNT3 0x0B
+#define MAX8907C_REG_SDV3 0x0C
+#define MAX8907C_REG_ON_OFF_IRQ2 0x0D
+#define MAX8907C_REG_ON_OFF_IRQ2_MASK 0x0E
+#define MAX8907C_REG_RESET_CNFG 0x0F
+#define MAX8907C_REG_LDOCTL16 0x10
+#define MAX8907C_REG_LDOSEQCNT16 0x11
+#define MAX8907C_REG_LDO16VOUT 0x12
+#define MAX8907C_REG_SDBYSEQCNT 0x13
+#define MAX8907C_REG_LDOCTL17 0x14
+#define MAX8907C_REG_LDOSEQCNT17 0x15
+#define MAX8907C_REG_LDO17VOUT 0x16
+#define MAX8907C_REG_LDOCTL1 0x18
+#define MAX8907C_REG_LDOSEQCNT1 0x19
+#define MAX8907C_REG_LDO1VOUT 0x1A
+#define MAX8907C_REG_LDOCTL2 0x1C
+#define MAX8907C_REG_LDOSEQCNT2 0x1D
+#define MAX8907C_REG_LDO2VOUT 0x1E
+#define MAX8907C_REG_LDOCTL3 0x20
+#define MAX8907C_REG_LDOSEQCNT3 0x21
+#define MAX8907C_REG_LDO3VOUT 0x22
+#define MAX8907C_REG_LDOCTL4 0x24
+#define MAX8907C_REG_LDOSEQCNT4 0x25
+#define MAX8907C_REG_LDO4VOUT 0x26
+#define MAX8907C_REG_LDOCTL5 0x28
+#define MAX8907C_REG_LDOSEQCNT5 0x29
+#define MAX8907C_REG_LDO5VOUT 0x2A
+#define MAX8907C_REG_LDOCTL6 0x2C
+#define MAX8907C_REG_LDOSEQCNT6 0x2D
+#define MAX8907C_REG_LDO6VOUT 0x2E
+#define MAX8907C_REG_LDOCTL7 0x30
+#define MAX8907C_REG_LDOSEQCNT7 0x31
+#define MAX8907C_REG_LDO7VOUT 0x32
+#define MAX8907C_REG_LDOCTL8 0x34
+#define MAX8907C_REG_LDOSEQCNT8 0x35
+#define MAX8907C_REG_LDO8VOUT 0x36
+#define MAX8907C_REG_LDOCTL9 0x38
+#define MAX8907C_REG_LDOSEQCNT9 0x39
+#define MAX8907C_REG_LDO9VOUT 0x3A
+#define MAX8907C_REG_LDOCTL10 0x3C
+#define MAX8907C_REG_LDOSEQCNT10 0x3D
+#define MAX8907C_REG_LDO10VOUT 0x3E
+#define MAX8907C_REG_LDOCTL11 0x40
+#define MAX8907C_REG_LDOSEQCNT11 0x41
+#define MAX8907C_REG_LDO11VOUT 0x42
+#define MAX8907C_REG_LDOCTL12 0x44
+#define MAX8907C_REG_LDOSEQCNT12 0x45
+#define MAX8907C_REG_LDO12VOUT 0x46
+#define MAX8907C_REG_LDOCTL13 0x48
+#define MAX8907C_REG_LDOSEQCNT13 0x49
+#define MAX8907C_REG_LDO13VOUT 0x4A
+#define MAX8907C_REG_LDOCTL14 0x4C
+#define MAX8907C_REG_LDOSEQCNT14 0x4D
+#define MAX8907C_REG_LDO14VOUT 0x4E
+#define MAX8907C_REG_LDOCTL15 0x50
+#define MAX8907C_REG_LDOSEQCNT15 0x51
+#define MAX8907C_REG_LDO15VOUT 0x52
+#define MAX8907C_REG_OUT5VEN 0x54
+#define MAX8907C_REG_OUT5VSEQ 0x55
+#define MAX8907C_REG_OUT33VEN 0x58
+#define MAX8907C_REG_OUT33VSEQ 0x59
+#define MAX8907C_REG_LDOCTL19 0x5C
+#define MAX8907C_REG_LDOSEQCNT19 0x5D
+#define MAX8907C_REG_LDO19VOUT 0x5E
+#define MAX8907C_REG_LBCNFG 0x60
+#define MAX8907C_REG_SEQ1CNFG 0x64
+#define MAX8907C_REG_SEQ2CNFG 0x65
+#define MAX8907C_REG_SEQ3CNFG 0x66
+#define MAX8907C_REG_SEQ4CNFG 0x67
+#define MAX8907C_REG_SEQ5CNFG 0x68
+#define MAX8907C_REG_SEQ6CNFG 0x69
+#define MAX8907C_REG_SEQ7CNFG 0x6A
+#define MAX8907C_REG_LDOCTL18 0x72
+#define MAX8907C_REG_LDOSEQCNT18 0x73
+#define MAX8907C_REG_LDO18VOUT 0x74
+#define MAX8907C_REG_BBAT_CNFG 0x78
+#define MAX8907C_REG_CHG_CNTL1 0x7C
+#define MAX8907C_REG_CHG_CNTL2 0x7D
+#define MAX8907C_REG_CHG_IRQ1 0x7E
+#define MAX8907C_REG_CHG_IRQ2 0x7F
+#define MAX8907C_REG_CHG_IRQ1_MASK 0x80
+#define MAX8907C_REG_CHG_IRQ2_MASK 0x81
+#define MAX8907C_REG_CHG_STAT 0x82
+#define MAX8907C_REG_WLED_MODE_CNTL 0x84
+#define MAX8907C_REG_ILED_CNTL 0x84
+#define MAX8907C_REG_II1RR 0x8E
+#define MAX8907C_REG_II2RR 0x8F
+#define MAX8907C_REG_LDOCTL20 0x9C
+#define MAX8907C_REG_LDOSEQCNT20 0x9D
+#define MAX8907C_REG_LDO20VOUT 0x9E
+
+/* RTC register */
+#define MAX8907C_REG_RTC_SEC 0x00
+#define MAX8907C_REG_RTC_MIN 0x01
+#define MAX8907C_REG_RTC_HOURS 0x02
+#define MAX8907C_REG_RTC_WEEKDAY 0x03
+#define MAX8907C_REG_RTC_DATE 0x04
+#define MAX8907C_REG_RTC_MONTH 0x05
+#define MAX8907C_REG_RTC_YEAR1 0x06
+#define MAX8907C_REG_RTC_YEAR2 0x07
+#define MAX8907C_REG_ALARM0_SEC 0x08
+#define MAX8907C_REG_ALARM0_MIN 0x09
+#define MAX8907C_REG_ALARM0_HOURS 0x0A
+#define MAX8907C_REG_ALARM0_WEEKDAY 0x0B
+#define MAX8907C_REG_ALARM0_DATE 0x0C
+#define MAX8907C_REG_ALARM0_MONTH 0x0D
+#define MAX8907C_REG_ALARM0_YEAR1 0x0E
+#define MAX8907C_REG_ALARM0_YEAR2 0x0F
+#define MAX8907C_REG_ALARM1_SEC 0x10
+#define MAX8907C_REG_ALARM1_MIN 0x11
+#define MAX8907C_REG_ALARM1_HOURS 0x12
+#define MAX8907C_REG_ALARM1_WEEKDAY 0x13
+#define MAX8907C_REG_ALARM1_DATE 0x14
+#define MAX8907C_REG_ALARM1_MONTH 0x15
+#define MAX8907C_REG_ALARM1_YEAR1 0x16
+#define MAX8907C_REG_ALARM1_YEAR2 0x17
+#define MAX8907C_REG_ALARM0_CNTL 0x18
+#define MAX8907C_REG_ALARM1_CNTL 0x19
+#define MAX8907C_REG_RTC_STATUS 0x1A
+#define MAX8907C_REG_RTC_CNTL 0x1B
+#define MAX8907C_REG_RTC_IRQ 0x1C
+#define MAX8907C_REG_IRQ_IRQ_MASK 0x1D
+#define MAX8907C_REG_MPL_CNTL 0x1E
+
+/* ADC and Touch Screen Controller register map */
+
+#define MAX8907C_CTL 0
+#define MAX8907C_SEQCNT 1
+#define MAX8907C_VOUT 2
+
+/* mask bit fields */
+#define MAX8907C_MASK_LDO_SEQ 0x1C
+#define MAX8907C_MASK_LDO_EN 0x01
+#define MAX8907C_MASK_VBBATTCV 0x03
+#define MAX8907C_MASK_OUT5V_VINEN 0x10
+#define MAX8907C_MASK_OUT5V_ENSRC 0x0E
+#define MAX8907C_MASK_OUT5V_EN 0x01
+
+struct max8907c {
+ struct device *dev;
+
+ int (*read_dev) (void *io_data, u8 reg, u8 count, u8 * dst);
+ int (*write_dev) (void *io_data, u8 reg, u8 count, const u8 * src);
+
+ struct mutex io_lock;
+};
+
+struct max8907c_platform_data {
+ int num_subdevs;
+ struct platform_device **subdevs;
+};
+
+int max8907c_reg_read(struct device *dev, u8 reg);
+int max8907c_reg_write(struct device *dev, u8 reg, u8 val);
+int max8907c_set_bits(struct device *dev, u8 reg, u8 mask, u8 val);
+
+#endif