diff options
author | Jin Park <jinyoungp@nvidia.com> | 2010-10-28 18:04:04 +0900 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:42:58 -0800 |
commit | 1d3e3a22b939ccb5b0bf4a9181d0b8aa090519d2 (patch) | |
tree | e0309c3f5c16bb4bcb1d363ecb9755188a495a6c | |
parent | 4769a334cc487563e5817af1910cdf2e73730138 (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/Kconfig | 10 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 1 | ||||
-rw-r--r-- | drivers/mfd/max8907c.c | 251 | ||||
-rw-r--r-- | include/linux/mfd/max8907c.h | 183 |
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 = ® + + 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 |