summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorRobby Cai <R63905@freescale.com>2011-05-06 07:27:17 +0800
committerRobby Cai <R63905@freescale.com>2011-05-09 11:16:21 +0800
commitc494f62c48ca4342fc0a5ce6324d72180013fd3f (patch)
tree3f98ce2ac72551ae2e67303ca996b0483fa5d2dc /drivers
parent8080f3db2bf0865063018a59f155002ed7220890 (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/Makefile2
-rw-r--r--drivers/mxc/pmic/core/mc13892.c4
-rw-r--r--drivers/mxc/pmic/core/pmic.h4
-rw-r--r--drivers/mxc/pmic/core/pmic_core_i2c.c146
-rw-r--r--drivers/mxc/pmic/core/pmic_external.c74
-rw-r--r--drivers/mxc/pmic/mc34708/mc34708_adc.c2
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);
}