diff options
author | Robby Cai <R63905@freescale.com> | 2011-05-06 07:27:17 +0800 |
---|---|---|
committer | Robby Cai <R63905@freescale.com> | 2011-05-09 11:16:21 +0800 |
commit | c494f62c48ca4342fc0a5ce6324d72180013fd3f (patch) | |
tree | 3f98ce2ac72551ae2e67303ca996b0483fa5d2dc /drivers | |
parent | 8080f3db2bf0865063018a59f155002ed7220890 (diff) |
ENGR00143050-1 PMIC: Generalize the interface for PMIC via I2C
Abstract the interfaces in pmic_core_i2c.c, in order to
accept new PMIC via I2C interface.
Signed-off-by: Robby Cai <R63905@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mxc/pmic/core/Makefile | 2 | ||||
-rw-r--r-- | drivers/mxc/pmic/core/mc13892.c | 4 | ||||
-rw-r--r-- | drivers/mxc/pmic/core/pmic.h | 4 | ||||
-rw-r--r-- | drivers/mxc/pmic/core/pmic_core_i2c.c | 146 | ||||
-rw-r--r-- | drivers/mxc/pmic/core/pmic_external.c | 74 | ||||
-rw-r--r-- | drivers/mxc/pmic/mc34708/mc34708_adc.c | 2 |
6 files changed, 185 insertions, 47 deletions
diff --git a/drivers/mxc/pmic/core/Makefile b/drivers/mxc/pmic/core/Makefile index 17b0751de988..e4d4edc708b0 100644 --- a/drivers/mxc/pmic/core/Makefile +++ b/drivers/mxc/pmic/core/Makefile @@ -20,7 +20,7 @@ pmic_mxc_mod-objs += pmic_core_spi.o endif ifneq ($(CONFIG_MXC_PMIC_I2C),) -pmic_mc13892_mod-objs += pmic_core_i2c.o +pmic_mxc_mod-objs += pmic_core_i2c.o endif obj-$(CONFIG_MXC_PMIC_MC34704) += pmic_mc34704_mod.o diff --git a/drivers/mxc/pmic/core/mc13892.c b/drivers/mxc/pmic/core/mc13892.c index 37a0a16ab661..260d3e2812b0 100644 --- a/drivers/mxc/pmic/core/mc13892.c +++ b/drivers/mxc/pmic/core/mc13892.c @@ -44,10 +44,6 @@ #include "pmic.h" -#ifndef CONFIG_MXC_PMIC_I2C -struct i2c_client *mc13892_client; -#endif - void *mc13892_alloc_data(struct device *dev) { struct mc13892 *mc13892; diff --git a/drivers/mxc/pmic/core/pmic.h b/drivers/mxc/pmic/core/pmic.h index b9a0ea328932..2e9d444d77fb 100644 --- a/drivers/mxc/pmic/core/pmic.h +++ b/drivers/mxc/pmic/core/pmic.h @@ -29,6 +29,7 @@ */ #include <linux/spi/spi.h> +#include <linux/i2c.h> #define MAX_ACTIVE_EVENTS 10 @@ -40,9 +41,10 @@ */ struct mxc_pmic { /*! - * Master side proxy for an SPI slave device(PMIC) + * Master side proxy for an SPI/I2C slave device(PMIC) */ struct spi_device *spi; + struct i2c_client *i2c; }; struct pmic_internal { diff --git a/drivers/mxc/pmic/core/pmic_core_i2c.c b/drivers/mxc/pmic/core/pmic_core_i2c.c index 8dfec5ad4976..e8b90ec2142e 100644 --- a/drivers/mxc/pmic/core/pmic_core_i2c.c +++ b/drivers/mxc/pmic/core/pmic_core_i2c.c @@ -1,14 +1,19 @@ /* - * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. - */ - -/* - * The code contained herein is licensed under the GNU General Public - * License. You may obtain a copy of the GNU General Public License - * Version 2 or later at the following locations: + * Copyright 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved. + * + * 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. * - * http://www.opensource.org/licenses/gpl-license.html - * http://www.gnu.org/copyleft/gpl.html + * 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 */ /*! @@ -51,8 +56,6 @@ /* * Global variables */ -struct i2c_client *mc13892_client; - extern pmic_version_t mxc_pmic_version; extern irqreturn_t pmic_irq_handler(int irq, void *dev_id); /* @@ -91,6 +94,71 @@ static struct platform_device bleds_ldm = { .id = 'b', }; +enum pmic_id { + PMIC_ID_MC13892, + PMIC_ID_INVALID, +}; + +static struct pmic_internal pmic_internal[] = { + [PMIC_ID_MC13892] = _PMIC_INTERNAL_INITIALIZER(mc13892), +}; + +static int get_index_pmic_internal(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(pmic_internal); i++) + if (!strcmp(name, pmic_internal[i].name)) + return i; + + return PMIC_ID_INVALID; +} + +static const char *get_client_device_name(const char *name, const char *format) +{ + char buf[30]; + const char *client_devname; + + if (snprintf(buf, sizeof(buf), format, name) > sizeof(buf)) + return NULL; + + client_devname = kmemdup(buf, strlen(buf) + 1, GFP_KERNEL); + if (!client_devname) + return NULL; + + return client_devname; +} + +static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, + const struct i2c_client *client) +{ + while (id->name[0]) { + if (strcmp(client->name, id->name) == 0) + return id; + id++; + } + return NULL; +} + +static const struct i2c_device_id *i2c_get_device_id( + const struct i2c_client *idev) +{ + const struct i2c_driver *idrv = to_i2c_driver(idev->dev.driver); + + return i2c_match_id(idrv->id_table, idev); +} + +static const char *get_chipname(struct i2c_client *idev) +{ + const struct i2c_device_id *devid = + i2c_get_device_id(idev); + + if (!devid) + return NULL; + + return devid->name; +} + static void pmic_pdev_register(struct device *dev) { platform_device_register(&adc_ldm); @@ -139,7 +207,7 @@ static int __devinit is_chip_onboard(struct i2c_client *client) return 0; } -static ssize_t mc13892_show(struct device *dev, +static ssize_t pmic_show(struct device *dev, struct device_attribute *attr, char *buf) { int i, value; @@ -159,7 +227,7 @@ static ssize_t mc13892_show(struct device *dev, return 0; } -static ssize_t mc13892_store(struct device *dev, +static ssize_t pmic_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { @@ -190,13 +258,13 @@ static ssize_t mc13892_store(struct device *dev, return count; } -static struct device_attribute mc13892_dev_attr = { +static struct device_attribute pmic_dev_attr = { .attr = { - .name = "mc13892_ctl", + .name = "pmic_ctl", .mode = S_IRUSR | S_IWUSR, }, - .show = mc13892_show, - .store = mc13892_store, + .show = pmic_show, + .store = pmic_store, }; static int __devinit pmic_probe(struct i2c_client *client, @@ -204,24 +272,32 @@ static int __devinit pmic_probe(struct i2c_client *client, { int ret = 0; int pmic_irq; - struct mc13892 *mc13892; - struct mc13892_platform_data *plat_data = client->dev.platform_data; + struct pmic_platform_data *plat_data = client->dev.platform_data; + const char *name; + int pmic_index; ret = is_chip_onboard(client); if (ret == -1) return -ENODEV; - mc13892 = kzalloc(sizeof(struct mc13892), GFP_KERNEL); - if (mc13892 == NULL) - return -ENOMEM; + name = get_chipname(client); + if (!name) + return PMIC_ERROR; + pmic_index = get_index_pmic_internal(name); + if (pmic_index == PMIC_ID_INVALID) + return PMIC_ERROR; + + adc_ldm.name = get_client_device_name(name, "%s_adc"); + battery_ldm.name = get_client_device_name(name, "%s_battery"); + light_ldm.name = get_client_device_name(name, "%s_light"); + rtc_ldm.name = get_client_device_name(name, "%s_rtc"); - i2c_set_clientdata(client, mc13892); - mc13892->dev = &client->dev; - mc13892->i2c_client = client; + i2c_set_clientdata(client, + pmic_internal[pmic_index].pmic_alloc_data(&client->dev)); /* so far, we got matched chip on board */ - mc13892_client = client; + pmic_i2c_setup(client); /* Initialize the PMIC event handling */ pmic_event_list_init(); @@ -230,7 +306,7 @@ static int __devinit pmic_probe(struct i2c_client *client, gpio_pmic_active(); /* Get the PMIC Version */ - pmic_get_revision(&mxc_pmic_version); + pmic_internal[pmic_index].pmic_get_revision(&mxc_pmic_version); if (mxc_pmic_version.revision < 0) { dev_err((struct device *)client, "PMIC not detected!!! Access Failed\n"); @@ -242,7 +318,7 @@ static int __devinit pmic_probe(struct i2c_client *client, } /* Initialize the PMIC parameters */ - ret = pmic_init_registers(); + ret = pmic_internal[pmic_index].pmic_init_registers(); if (ret != PMIC_SUCCESS) return PMIC_ERROR; @@ -252,7 +328,7 @@ static int __devinit pmic_probe(struct i2c_client *client, ret = pmic_start_event_thread(pmic_irq); if (ret) { - pr_err("mc13892 pmic driver init: \ + pr_err("pmic driver init: \ fail to start event thread\n"); return PMIC_ERROR; } @@ -272,12 +348,12 @@ static int __devinit pmic_probe(struct i2c_client *client, enable_irq_wake(pmic_irq); if (plat_data && plat_data->init) { - ret = plat_data->init(mc13892); + ret = plat_data->init(i2c_get_clientdata(client)); if (ret != 0) return PMIC_ERROR; } - ret = device_create_file(&client->dev, &mc13892_dev_attr); + ret = device_create_file(&client->dev, &pmic_dev_attr); if (ret) dev_err(&client->dev, "create device file failed!\n"); @@ -308,23 +384,23 @@ static int pmic_resume(struct i2c_client *client) return 0; } -static const struct i2c_device_id mc13892_id[] = { +static const struct i2c_device_id pmic_id[] = { {"mc13892", 0}, {}, }; -MODULE_DEVICE_TABLE(i2c, mc13892_id); +MODULE_DEVICE_TABLE(i2c, pmic_id); static struct i2c_driver pmic_driver = { .driver = { - .name = "mc13892", + .name = "pmic", .bus = NULL, }, .probe = pmic_probe, .remove = pmic_remove, .suspend = pmic_suspend, .resume = pmic_resume, - .id_table = mc13892_id, + .id_table = pmic_id, }; static int __init pmic_init(void) diff --git a/drivers/mxc/pmic/core/pmic_external.c b/drivers/mxc/pmic/core/pmic_external.c index 11814907f046..0330e2475e64 100644 --- a/drivers/mxc/pmic/core/pmic_external.c +++ b/drivers/mxc/pmic/core/pmic_external.c @@ -30,6 +30,7 @@ #include <linux/interrupt.h> #include <linux/wait.h> #include <linux/init.h> +#include <linux/delay.h> #include <linux/errno.h> #include <linux/pmic_external.h> @@ -42,7 +43,9 @@ #define MXC_PMIC_REG_NUM_SHIFT 0x19 #define MXC_PMIC_WRITE_BIT_SHIFT 31 -struct mxc_pmic pmic_drv_data; +#define PMIC_I2C_RETRY_TIMES 10 + +static struct mxc_pmic pmic_drv_data; static unsigned int events_enabled0; static unsigned int events_enabled1; @@ -60,6 +63,60 @@ int pmic_spi_setup(struct spi_device *spi) return spi_setup(spi); } +int pmic_i2c_setup(struct i2c_client *i2c) +{ + pmic_drv_data.i2c = i2c; + + return 0; +} + +int pmic_i2c_24bit_read(struct i2c_client *client, unsigned int reg_num, + unsigned int *value) +{ + unsigned char buf[3]; + int ret; + int i; + + memset(buf, 0, 3); + for (i = 0; i < PMIC_I2C_RETRY_TIMES; i++) { + ret = i2c_smbus_read_i2c_block_data(client, reg_num, 3, buf); + if (ret == 3) + break; + msleep(1); + } + + if (ret == 3) { + *value = buf[0] << 16 | buf[1] << 8 | buf[2]; + return ret; + } else { + pr_err("24bit read error, ret = %d\n", ret); + return -1; /* return -1 on failure */ + } +} + +int pmic_i2c_24bit_write(struct i2c_client *client, + unsigned int reg_num, unsigned int reg_val) +{ + char buf[3]; + int ret; + int i; + + buf[0] = (reg_val >> 16) & 0xff; + buf[1] = (reg_val >> 8) & 0xff; + buf[2] = (reg_val) & 0xff; + + for (i = 0; i < PMIC_I2C_RETRY_TIMES; i++) { + ret = i2c_smbus_write_i2c_block_data(client, reg_num, 3, buf); + if (ret == 0) + break; + msleep(1); + } + if (i == PMIC_I2C_RETRY_TIMES) + pr_err("24bit write error, ret = %d\n", ret); + + return ret; +} + int pmic_read(int reg_num, unsigned int *reg_val) { unsigned int frame = 0; @@ -75,8 +132,12 @@ int pmic_read(int reg_num, unsigned int *reg_val) *reg_val = frame & MXC_PMIC_FRAME_MASK; } else { - pr_err("SPI dev Not set\n"); - return PMIC_ERROR; + if (pmic_drv_data.i2c == NULL) + return PMIC_ERROR; + + if (pmic_i2c_24bit_read(pmic_drv_data.i2c, reg_num, reg_val) + == -1) + return PMIC_ERROR; } return PMIC_SUCCESS; @@ -101,8 +162,11 @@ int pmic_write(int reg_num, const unsigned int reg_val) return ret; } else { - pr_err("SPI dev Not set\n"); - return PMIC_ERROR; + if (pmic_drv_data.i2c == NULL) + return PMIC_ERROR; + + return pmic_i2c_24bit_write(pmic_drv_data.i2c, + reg_num, reg_val); } } #endif diff --git a/drivers/mxc/pmic/mc34708/mc34708_adc.c b/drivers/mxc/pmic/mc34708/mc34708_adc.c index a08c21ae4bd3..a72fc26dd539 100644 --- a/drivers/mxc/pmic/mc34708/mc34708_adc.c +++ b/drivers/mxc/pmic/mc34708/mc34708_adc.c @@ -597,7 +597,7 @@ static struct platform_driver mc34708_pmic_adc_driver_ldm = { static int __init mc34708_pmic_adc_module_init(void) { - pr_info("MC34708 PMIC ADC driver loading...\n"); + pr_debug("MC34708 PMIC ADC driver loading...\n"); return platform_driver_register(&mc34708_pmic_adc_driver_ldm); } |