summaryrefslogtreecommitdiff
path: root/drivers/mxc/pmic/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mxc/pmic/core')
-rw-r--r--drivers/mxc/pmic/core/Makefile10
-rw-r--r--drivers/mxc/pmic/core/max8660.c149
-rw-r--r--drivers/mxc/pmic/core/max8660.h45
-rw-r--r--drivers/mxc/pmic/core/mc9sdz60.c111
-rw-r--r--drivers/mxc/pmic/core/mc9sdz60.h69
-rw-r--r--drivers/mxc/pmic/core/mcu_pmic_core.c540
6 files changed, 924 insertions, 0 deletions
diff --git a/drivers/mxc/pmic/core/Makefile b/drivers/mxc/pmic/core/Makefile
index 2fe13f764c61..2945dd3d411a 100644
--- a/drivers/mxc/pmic/core/Makefile
+++ b/drivers/mxc/pmic/core/Makefile
@@ -2,6 +2,11 @@
# Makefile for the PMIC core drivers.
#
obj-$(CONFIG_MXC_SPI_PMIC_CORE) += pmic_core_spi_mod.o
+
+obj-$(CONFIG_MXC_I2C_MCU_PMIC_CORE) += pmic_core_i2c_mod.o
+
+pmic_core_i2c_mod-objs := pmic_external.o pmic_event.o mcu_pmic_core.o
+
obj-$(CONFIG_MXC_PMIC_CHARDEV) += pmic-dev.o
pmic_core_spi_mod-objs := pmic_external.o pmic_event.o pmic_core_spi.o
@@ -13,3 +18,8 @@ endif
ifeq ($(CONFIG_MXC_PMIC_SC55112),y)
pmic_core_spi_mod-objs += sc55112.o
endif
+
+ifeq ($(CONFIG_MXC_PMIC_MC9SDZ60), y)
+pmic_core_i2c_mod-objs += mc9sdz60.o
+pmic_core_i2c_mod-objs += max8660.o
+endif
diff --git a/drivers/mxc/pmic/core/max8660.c b/drivers/mxc/pmic/core/max8660.c
new file mode 100644
index 000000000000..5214739d03b3
--- /dev/null
+++ b/drivers/mxc/pmic/core/max8660.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2008 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:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file max8660.c
+ * @brief Driver for max8660
+ *
+ * @ingroup pmic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#include <linux/i2c.h>
+#include <asm/arch/clock.h>
+#include <asm/uaccess.h>
+#include <asm/arch/pmic_external.h>
+#include "max8660.h"
+
+/* I2C bus id and device address of mcu */
+#define I2C1_BUS 0
+#define MAX8660_I2C_ADDR 0x68
+
+#define DEBUG_MAX8660 1
+#if DEBUG_MAX8660
+#define DPRINTK(format, args...) printk(KERN_ERR "max8660"format"\n", ##args)
+#else
+#define DPRINTK(format, args...)
+#endif
+
+static struct i2c_client *max8660_i2c_client;
+
+ /* reg names for max8660
+ REG_MAX8660_OUTPUT_ENABLE_1,
+ REG_MAX8660_OUTPUT_ENABLE_2,
+ REG_MAX8660_VOLT__CHANGE_1,
+ REG_MAX8660_V3_TARGET_VOLT_1,
+ REG_MAX8660_V3_TARGET_VOLT_2,
+ REG_MAX8660_V4_TARGET_VOLT_1,
+ REG_MAX8660_V4_TARGET_VOLT_2,
+ REG_MAX8660_V5_TARGET_VOLT_1,
+ REG_MAX8660_V5_TARGET_VOLT_2,
+ REG_MAX8660_V6V7_TARGET_VOLT,
+ REG_MAX8660_FORCE_PWM
+ */
+
+ /* save down the reg values for the device is write only */
+static u8 max8660_reg_value_table[] =
+ { 0x0, 0x0, 0x0, 0x17, 0x17, 0x1F, 0x1F, 0x04, 0x04, 0x0, 0x0
+};
+int max8660_get_buffered_reg_val(int reg_name, u8 *value)
+{
+
+ /* outof range */
+ if (reg_name < REG_MAX8660_OUTPUT_ENABLE_1
+ || reg_name > REG_MAX8660_FORCE_PWM) {
+ DPRINTK("reg_name=%d outof range", reg_name);
+ return -1;
+ }
+ *value =
+ max8660_reg_value_table[reg_name - REG_MAX8660_OUTPUT_ENABLE_1];
+ return 0;
+}
+int max8660_save_buffered_reg_val(int reg_name, u8 value)
+{
+
+ /* outof range */
+ if (reg_name < REG_MAX8660_OUTPUT_ENABLE_1
+ || reg_name > REG_MAX8660_FORCE_PWM) {
+ DPRINTK("reg_name=%d outof range", reg_name);
+ return -1;
+ }
+ max8660_reg_value_table[reg_name - REG_MAX8660_OUTPUT_ENABLE_1] = value;
+ return 0;
+}
+
+int max8660_write_reg(u8 reg, u8 value)
+{
+ DPRINTK("max8660_i2c_client = %p", max8660_i2c_client);
+ if (i2c_smbus_write_byte_data(max8660_i2c_client, reg, value) < 0) {
+ printk(KERN_ERR "%s:write reg errorr:reg=%x,val=%x\n",
+ __func__, reg, value);
+ return -1;
+ }
+ return 0;
+}
+
+/*!
+ * max8660 I2C attach function
+ *
+ * @param adapter struct i2c_client *
+ * @return Always 0 because max8660 is write-only and can not be detected
+ */
+static int max8660_probe(struct i2c_client *client)
+{
+ max8660_i2c_client = client;
+ DPRINTK("max8660_i2c_client = %p", max8660_i2c_client);
+ return 0;
+}
+
+/*!
+ * max8660 I2C detach function
+ *
+ * @param client struct i2c_client *
+ * @return 0
+ */
+static int max8660_remove(struct i2c_client *client)
+{
+ return 0;
+}
+static struct i2c_driver max8660_i2c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "max8660",},
+ .probe = max8660_probe,
+ .remove = max8660_remove,
+};
+
+/* called by pmic core when init*/
+int max8660_init(void)
+{
+ int err;
+ DPRINTK("Freescale max8660 driver loaded\n");
+ err = i2c_add_driver(&max8660_i2c_driver);
+ if (err) {
+ printk(KERN_ERR
+ "max8660: driver registration failed err = %d\n", err);
+ return err;
+ }
+ DPRINTK("max8660 inited\n");
+ return 0;
+}
+void max8660_exit(void)
+{
+ i2c_del_driver(&max8660_i2c_driver);
+}
diff --git a/drivers/mxc/pmic/core/max8660.h b/drivers/mxc/pmic/core/max8660.h
new file mode 100644
index 000000000000..54638a4ed2fa
--- /dev/null
+++ b/drivers/mxc/pmic/core/max8660.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2008 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:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file max8660.h
+ * @brief Driver for max8660
+ *
+ * @ingroup pmic
+ */
+#ifndef _MAX8660_H_
+#define _MAX8660_H_
+
+#ifdef __KERNEL__
+
+#define MAX8660_OUTPUT_ENABLE_1 0x10
+#define MAX8660_OUTPUT_ENABLE_2 0x12
+#define MAX8660_VOLT_CHANGE_CONTROL 0x20
+#define MAX8660_V3_TARGET_VOLT_1 0x23
+#define MAX8660_V3_TARGET_VOLT_2 0x24
+#define MAX8660_V4_TARGET_VOLT_1 0x29
+#define MAX8660_V4_TARGET_VOLT_2 0x2A
+#define MAX8660_V5_TARGET_VOLT_1 0x32
+#define MAX8660_V5_TARGET_VOLT_2 0x33
+#define MAX8660_V6V7_TARGET_VOLT 0x39
+#define MAX8660_FORCE_PWM 0x80
+int max8660_write_reg(u8 reg, u8 value);
+int max8660_save_buffered_reg_val(int reg_name, u8 value);
+int max8660_get_buffered_reg_val(int reg_name, u8 *value);
+int max8660_init(void);
+
+extern int reg_max8660_probe(void);
+
+#endif /* __KERNEL__ */
+
+#endif /* _MAX8660_H_ */
diff --git a/drivers/mxc/pmic/core/mc9sdz60.c b/drivers/mxc/pmic/core/mc9sdz60.c
new file mode 100644
index 000000000000..e367cb5aee15
--- /dev/null
+++ b/drivers/mxc/pmic/core/mc9sdz60.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2008 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:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+ /*!
+ * @file mc9sdz60.c
+ * @brief Driver for MC9sdz60
+ *
+ * @ingroup pmic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/proc_fs.h>
+#include <linux/i2c.h>
+
+#include <asm/arch/clock.h>
+#include <asm/uaccess.h>
+#include "mc9sdz60.h"
+
+/* I2C bus id and device address of mcu */
+#define I2C1_BUS 0
+#define MC9SDZ60_I2C_ADDR 0xD2 /* 7bits I2C address */
+static struct i2c_client *mc9sdz60_i2c_client;
+
+#define DEBUG_MC9SDZ60 1
+#if DEBUG_MC9SDZ60
+#define DPRINTK(format, args...) printk(KERN_ERR "mc9sdz60: "format"\n", ##args)
+#else
+#define DPRINTK(format, args...)
+#endif
+
+int mc9sdz60_read_reg(u8 reg, u8 *value)
+{
+ *value = (u8) i2c_smbus_read_byte_data(mc9sdz60_i2c_client, reg);
+ return 0;
+}
+
+int mc9sdz60_write_reg(u8 reg, u8 value)
+{
+ if (i2c_smbus_write_byte_data(mc9sdz60_i2c_client, reg, value) < 0) {
+ printk(KERN_ERR "%s:write reg errorr:reg=%x,val=%x\n",
+ __func__, reg, value);
+ return -1;
+ }
+ return 0;
+}
+
+/*!
+ * mc9sdz60 I2C attach function
+ *
+ * @param adapter struct i2c_adapter *
+ * @return 0
+ */
+static int mc9sdz60_probe(struct i2c_client *client)
+{
+ mc9sdz60_i2c_client = client;
+ DPRINTK("mc9sdz60_i2c_client = %p", mc9sdz60_i2c_client);
+ return 0;
+}
+
+/*!
+ * mc9sdz60 I2C detach function
+ *
+ * @param client struct i2c_client *
+ * @return 0
+ */
+static int mc9sdz60_remove(struct i2c_client *client)
+{
+ return 0;
+}
+static struct i2c_driver mc9sdz60_i2c_driver = {
+ .driver = {.owner = THIS_MODULE,
+ .name = "mc9sdz60",
+ },
+ .probe = mc9sdz60_probe,
+ .remove = mc9sdz60_remove,
+};
+
+#define SET_BIT_IN_BYTE(byte, pos) (byte |= (0x01 << pos))
+#define CLEAR_BIT_IN_BYTE(byte, pos) (byte &= ~(0x01 << pos))
+
+int mc9sdz60_init(void)
+{
+ int err;
+ DPRINTK("Freescale mc9sdz60 driver,\
+ (c) 2008 Freescale Semiconductor, Inc.\n");
+ err = i2c_add_driver(&mc9sdz60_i2c_driver);
+ if (err) {
+ printk(KERN_ERR "mc9sdz60: driver registration failed\n");
+ return err;
+ }
+ DPRINTK("mc9sdz60 inited\n");
+ return 0;
+}
+void mc9sdz60_exit(void)
+{
+ i2c_del_driver(&mc9sdz60_i2c_driver);
+}
diff --git a/drivers/mxc/pmic/core/mc9sdz60.h b/drivers/mxc/pmic/core/mc9sdz60.h
new file mode 100644
index 000000000000..c1af168d88a9
--- /dev/null
+++ b/drivers/mxc/pmic/core/mc9sdz60.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2008 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:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file mc9sdz60.h
+ * @brief Driver for mc9sdz60
+ *
+ * @ingroup pmic
+ */
+#ifndef _MC9SDZ60_H_
+#define _MC9SDZ60_H_
+
+#define MCU_VERSION 0x00
+/*#define Reserved 0x01*/
+#define MCU_SECS 0x02
+#define MCU_MINS 0x03
+#define MCU_HRS 0x04
+#define MCU_DAY 0x05
+#define MCU_DATE 0x06
+#define MCU_MONTH 0x07
+#define MCU_YEAR 0x08
+
+#define MCU_ALARM_SECS 0x09
+#define MCU_ALARM_MINS 0x0A
+#define MCU_ALARM_HRS 0x0B
+/* #define Reserved 0x0C*/
+/* #define Reserved 0x0D*/
+#define MCU_TS_CONTROL 0x0E
+#define MCU_X_LOW 0x0F
+#define MCU_Y_LOW 0x10
+#define MCU_XY_HIGH 0x11
+#define MCU_X_LEFT_LOW 0x12
+#define MCU_X_LEFT_HIGH 0x13
+#define MCU_X_RIGHT 0x14
+#define MCU_Y_TOP_LOW 0x15
+#define MCU_Y_TOP_HIGH 0x16
+#define MCU_Y_BOTTOM 0x17
+/* #define Reserved 0x18*/
+/* #define Reserved 0x19*/
+#define MCU_RESET_1 0x1A
+#define MCU_RESET_2 0x1B
+#define MCU_POWER_CTL 0x1C
+#define MCU_DELAY_CONFIG 0x1D
+/* #define Reserved 0x1E */
+/* #define Reserved 0x1F */
+#define MCU_GPIO_1 0x20
+#define MCU_GPIO_2 0x21
+#define MCU_KPD_1 0x22
+#define MCU_KPD_2 0x23
+#define MCU_KPD_CONTROL 0x24
+#define MCU_INT_ENABLE_1 0x25
+#define MCU_INT_ENABLE_2 0x26
+#define MCU_INT_FLAG_1 0x27
+#define MCU_INT_FLAG_2 0x28
+int mc9sdz60_read_reg(u8 reg, u8 *value);
+int mc9sdz60_write_reg(u8 reg, u8 value);
+int mc9sdz60_init(void);
+
+#endif /* _MC9SDZ60_H_ */
+
diff --git a/drivers/mxc/pmic/core/mcu_pmic_core.c b/drivers/mxc/pmic/core/mcu_pmic_core.c
new file mode 100644
index 000000000000..807e45eecd64
--- /dev/null
+++ b/drivers/mxc/pmic/core/mcu_pmic_core.c
@@ -0,0 +1,540 @@
+/*
+ * Copyright 2008 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:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+/*!
+ * @file mc9sdz60/mcu_pmic_core.c
+ * @brief This is the main file of mc9sdz60 Power Control driver.
+ *
+ * @ingroup PMIC_POWER
+ */
+
+/*
+ * Includes
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <asm/ioctl.h>
+#include <asm/uaccess.h>
+#include <asm/arch/gpio.h>
+
+#include <../arch/arm/mach-mx3/iomux.h>
+
+#include <asm/arch/pmic_status.h>
+#include <asm/arch/pmic_external.h>
+#include "pmic.h"
+#include "mc9sdz60.h"
+#include "max8660.h"
+
+/* bitfield macros for mcu pmic*/
+#define SET_BIT_IN_BYTE(byte, pos) (byte |= (0x01 << pos))
+#define CLEAR_BIT_IN_BYTE(byte, pos) (byte &= ~(0x01 << pos))
+
+/*
+ * Global variables
+ */
+static pmic_version_t mxc_pmic_version;
+unsigned int active_events[11];
+
+/* default event-enable-value after reset*/
+static u8 events_enabled1 = 0x40;
+static u8 events_enabled2;
+
+/*
+ * Platform device structure for PMIC client drivers
+ */
+static struct platform_device power_ldm = {
+ .name = "pmic_power",
+ .id = 1,
+};
+static struct platform_device rtc_ldm = {
+ .name = "pmic_rtc",
+ .id = 1,
+};
+
+/* map reg names (enum pmic_reg in pmic_external.h) to real addr*/
+const static u8 mcu_pmic_reg_addr_table[] = {
+ MCU_VERSION,
+ MCU_SECS,
+ MCU_MINS,
+ MCU_HRS,
+ MCU_DAY,
+ MCU_DATE,
+ MCU_MONTH,
+ MCU_YEAR,
+ MCU_ALARM_SECS,
+ MCU_ALARM_MINS,
+ MCU_ALARM_HRS,
+ MCU_TS_CONTROL,
+ MCU_X_LOW,
+ MCU_Y_LOW,
+ MCU_XY_HIGH,
+ MCU_X_LEFT_LOW,
+ MCU_X_LEFT_HIGH,
+ MCU_X_RIGHT,
+ MCU_Y_TOP_LOW,
+ MCU_Y_TOP_HIGH,
+ MCU_Y_BOTTOM,
+ MCU_RESET_1,
+ MCU_RESET_2,
+ MCU_POWER_CTL,
+ MCU_DELAY_CONFIG,
+ MCU_GPIO_1,
+ MCU_GPIO_2,
+ MCU_KPD_1,
+ MCU_KPD_2,
+ MCU_KPD_CONTROL,
+ MCU_INT_ENABLE_1,
+ MCU_INT_ENABLE_2,
+ MCU_INT_FLAG_1,
+ MCU_INT_FLAG_2,
+ MAX8660_OUTPUT_ENABLE_1,
+ MAX8660_OUTPUT_ENABLE_2,
+ MAX8660_VOLT_CHANGE_CONTROL,
+ MAX8660_V3_TARGET_VOLT_1,
+ MAX8660_V3_TARGET_VOLT_2,
+ MAX8660_V4_TARGET_VOLT_1,
+ MAX8660_V4_TARGET_VOLT_2,
+ MAX8660_V5_TARGET_VOLT_1,
+ MAX8660_V5_TARGET_VOLT_2,
+ MAX8660_V6V7_TARGET_VOLT,
+ MAX8660_FORCE_PWM
+};
+
+#define DPRINTK(format, args...) printk(KERN_ERR "pmic-core "format"\n", ##args)
+
+int pmic_read(int reg_num, unsigned int *reg_val)
+{
+ int ret;
+ u8 value = 0;
+ /* mcu ops */
+ if (reg_num >= REG_MCU_VERSION && reg_num <= REG_MCU_INT_FLAG_2) {
+
+ ret =
+ mc9sdz60_read_reg(mcu_pmic_reg_addr_table[reg_num], &value);
+ if (ret < 0)
+ goto error1;
+ *reg_val = value;
+ } else if (reg_num >= REG_MAX8660_OUTPUT_ENABLE_1
+ && reg_num <= REG_MAX8660_FORCE_PWM) {
+ ret = max8660_get_buffered_reg_val(reg_num, &value);
+ if (ret < 0)
+ goto error1;
+ *reg_val = value;
+ } else {
+ DPRINTK("reg_num=%d out of range", reg_num);
+ goto error1;
+ }
+
+ return 0;
+
+error1:
+ return -1;
+}
+
+int pmic_write(int reg_num, const unsigned int reg_val)
+{
+ int ret;
+ u8 value = reg_val;
+ /* mcu ops */
+ if (reg_num >= REG_MCU_VERSION && reg_num <= REG_MCU_INT_FLAG_2) {
+
+ ret =
+ mc9sdz60_write_reg(mcu_pmic_reg_addr_table[reg_num], value);
+ if (ret < 0)
+ goto error1;
+ } else if (reg_num >= REG_MAX8660_OUTPUT_ENABLE_1
+ && reg_num <= REG_MAX8660_FORCE_PWM) {
+ ret =
+ max8660_write_reg(mcu_pmic_reg_addr_table[reg_num], value);
+
+ if (ret < 0)
+ goto error1;
+
+ ret = max8660_save_buffered_reg_val(reg_num, value);
+ } else {
+ DPRINTK("reg_num=%d out of range", reg_num);
+ goto error1;
+ }
+
+ return 0;
+
+error1:
+ DPRINTK(" reg_num = %d, write failed", reg_num);
+ return -1;
+
+}
+
+/* for debug*/
+void dump_pmic_reg(void)
+{
+#define REG_DUMP(reg) do {\
+ pmic_read_reg(reg, &reg_val, 0xff);\
+ DPRINTK("%s = %x", #reg, reg_val); } while (0)
+ unsigned int reg_val;
+
+ REG_DUMP(REG_MCU_VERSION);
+ REG_DUMP(REG_MCU_SECS);
+ REG_DUMP(REG_MCU_MINS);
+ REG_DUMP(REG_MCU_HRS);
+ REG_DUMP(REG_MCU_DAY);
+ REG_DUMP(REG_MCU_DATE);
+ REG_DUMP(REG_MCU_MONTH);
+ REG_DUMP(REG_MCU_YEAR);
+ REG_DUMP(REG_MCU_ALARM_SECS);
+ REG_DUMP(REG_MCU_ALARM_MINS);
+ REG_DUMP(REG_MCU_ALARM_HRS);
+ REG_DUMP(REG_MCU_TS_CONTROL);
+ REG_DUMP(REG_MCU_X_LOW);
+ REG_DUMP(REG_MCU_Y_LOW);
+ REG_DUMP(REG_MCU_XY_HIGH);
+ REG_DUMP(REG_MCU_X_LEFT_LOW);
+ REG_DUMP(REG_MCU_X_LEFT_HIGH);
+ REG_DUMP(REG_MCU_X_RIGHT);
+ REG_DUMP(REG_MCU_Y_TOP_LOW);
+ REG_DUMP(REG_MCU_Y_TOP_HIGH);
+ REG_DUMP(REG_MCU_Y_BOTTOM);
+ REG_DUMP(REG_MCU_RESET_1);
+ REG_DUMP(REG_MCU_RESET_2);
+ REG_DUMP(REG_MCU_POWER_CTL);
+ REG_DUMP(REG_MCU_DELAY_CONFIG);
+ REG_DUMP(REG_MCU_GPIO_1);
+ REG_DUMP(REG_MCU_GPIO_2);
+ REG_DUMP(REG_MCU_KPD_1);
+ REG_DUMP(REG_MCU_KPD_2);
+ REG_DUMP(REG_MCU_KPD_CONTROL);
+ REG_DUMP(REG_MCU_INT_ENABLE_1);
+ REG_DUMP(REG_MCU_INT_ENABLE_2);
+ REG_DUMP(REG_MCU_INT_FLAG_1);
+ REG_DUMP(REG_MCU_INT_FLAG_2);
+}
+
+/*!
+ * This function unsets a bit in mask register of pmic to unmask an event IT.
+ *
+ * @param event the event to be unmasked
+ *
+ * @return This function returns PMIC_SUCCESS on SUCCESS, error on FAILURE.
+ */
+int pmic_event_unmask(type_event event)
+{
+ int reg_name;
+ u8 reg_mask = 0;
+ unsigned int event_bit = 0;
+ int ret = -1;
+
+ switch (event) {
+ case EVENT_HEADPHONE_DET:
+ reg_name = REG_MCU_INT_ENABLE_1;
+ event_bit = 0;
+ break;
+ case EVENT_SD1_DET:
+ reg_name = REG_MCU_INT_ENABLE_1;
+ event_bit = 2;
+ break;
+ case EVENT_SD1_WP:
+ reg_name = REG_MCU_INT_ENABLE_1;
+ event_bit = 3;
+ break;
+ case EVENT_SD2_DET:
+ reg_name = REG_MCU_INT_ENABLE_1;
+ event_bit = 4;
+ break;
+ case EVENT_SD2_WP:
+ reg_name = REG_MCU_INT_ENABLE_1;
+ event_bit = 5;
+ break;
+ case EVENT_GPS_INT:
+ reg_name = REG_MCU_INT_ENABLE_1;
+ event_bit = 1;
+ break;
+ case EVENT_POWER_KEY:
+ reg_name = REG_MCU_INT_ENABLE_1;
+ event_bit = 6;
+ break;
+ case EVENT_KEYPAD:
+ reg_name = REG_MCU_INT_ENABLE_2;
+ event_bit = 2;
+ break;
+ case EVENT_RTC:
+ reg_name = REG_MCU_INT_ENABLE_2;
+ event_bit = 0;
+ break;
+ case EVENT_TS_ADC:
+ reg_name = REG_MCU_INT_ENABLE_2;
+ event_bit = 1;
+ break;
+ default:
+ return PMIC_ERROR;
+ }
+ SET_BIT_IN_BYTE(reg_mask, event_bit);
+ ret = pmic_write_reg(reg_name, reg_mask, reg_mask);
+ if (PMIC_SUCCESS == ret) {
+
+ if (REG_MCU_INT_ENABLE_2 == reg_name)
+ events_enabled2 |= reg_mask;
+ else if (REG_MCU_INT_ENABLE_1 == reg_name)
+ events_enabled1 |= reg_mask;
+ pr_debug("Enable Event : %d\n", event);
+ }
+
+ return ret;
+}
+
+/*!
+ * This function sets a bit in mask register of pmic to disable an event IT.
+ *
+ * @param event the event to be masked
+ *
+ * @return This function returns PMIC_SUCCESS on SUCCESS, error on FAILURE.
+ */
+int pmic_event_mask(type_event event)
+{
+ int reg_name;
+ u8 reg_mask = 0;
+ unsigned int event_bit = 0;
+ int ret = -1;
+
+ switch (event) {
+ case EVENT_HEADPHONE_DET:
+ reg_name = REG_MCU_INT_ENABLE_1;
+ event_bit = 0;
+ break;
+ case EVENT_SD1_DET:
+ reg_name = REG_MCU_INT_ENABLE_1;
+ event_bit = 2;
+ break;
+ case EVENT_SD1_WP:
+ reg_name = REG_MCU_INT_ENABLE_1;
+ event_bit = 3;
+ break;
+ case EVENT_SD2_DET:
+ reg_name = REG_MCU_INT_ENABLE_1;
+ event_bit = 4;
+ break;
+ case EVENT_SD2_WP:
+ reg_name = REG_MCU_INT_ENABLE_1;
+ event_bit = 5;
+ break;
+ case EVENT_GPS_INT:
+ reg_name = REG_MCU_INT_ENABLE_1;
+ event_bit = 1;
+ break;
+ case EVENT_POWER_KEY:
+ reg_name = REG_MCU_INT_ENABLE_1;
+ event_bit = 6;
+ break;
+ case EVENT_KEYPAD:
+ reg_name = REG_MCU_INT_ENABLE_2;
+ event_bit = 2;
+ break;
+ case EVENT_RTC:
+ reg_name = REG_MCU_INT_ENABLE_2;
+ event_bit = 0;
+ break;
+ case EVENT_TS_ADC:
+ reg_name = REG_MCU_INT_ENABLE_2;
+ event_bit = 1;
+ break;
+ default:
+ return PMIC_ERROR;
+ }
+ SET_BIT_IN_BYTE(reg_mask, event_bit);
+
+ ret = pmic_write_reg(reg_name, 0, reg_mask);
+ if (PMIC_SUCCESS == ret) {
+
+ if (REG_MCU_INT_ENABLE_2 == reg_name)
+ events_enabled2 &= ~reg_mask;
+ else if (REG_MCU_INT_ENABLE_1 == reg_name)
+ events_enabled1 &= ~reg_mask;
+ pr_debug("Disable Event : %d\n", event);
+ }
+
+ return ret;
+}
+
+/*!
+ * This function reads the interrupt status registers of PMIC
+ * and determine the current active events.
+ *
+ * @param active_events array pointer to be used to return active
+ * event numbers.
+ *
+ * @return This function returns PMIC version.
+ */
+unsigned int pmic_get_active_events(unsigned int *active_events)
+{
+ unsigned int count = 0;
+ unsigned int flag1, flag2;
+ int bit_set;
+
+ /* read int flags and ack int */
+ pmic_read(REG_MCU_INT_FLAG_1, &flag1);
+ pmic_read(REG_MCU_INT_FLAG_2, &flag2);
+ pmic_write(REG_MCU_INT_FLAG_1, 0);
+ pmic_write(REG_MCU_INT_FLAG_2, 0);
+ DPRINTK("pmic interrupt flag1=%x, flag2=%x", flag1, flag2);
+
+ flag1 &= events_enabled1;
+ flag2 &= events_enabled2;
+
+ while (flag1) {
+ bit_set = ffs(flag1) - 1;
+ *(active_events + count) = bit_set;
+ count++;
+ flag1 ^= (1 << bit_set);
+ }
+ while (flag2) {
+ bit_set = ffs(flag2) - 1;
+ *(active_events + count) = bit_set + 7;
+ count++;
+ flag2 ^= (1 << bit_set);
+ }
+
+ return count;
+}
+
+void pmic_bh_handler(struct work_struct *work);
+
+/*
+ * External functions
+ */
+extern void pmic_event_list_init(void);
+extern void pmic_event_callback(type_event event);
+extern void gpio_pmic_active(void);
+
+/*!
+ * Bottom half handler of PMIC event handling.
+ */
+DECLARE_WORK(pmic_ws, pmic_bh_handler);
+
+/*!
+ * This function registers platform device structures for
+ * PMIC client drivers.
+ */
+static void pmic_pdev_register(void)
+{
+ platform_device_register(&rtc_ldm);
+ platform_device_register(&power_ldm);
+ reg_max8660_probe();
+}
+
+/*!
+ * This function unregisters platform device structures for
+ * PMIC client drivers.
+ */
+static void pmic_pdev_unregister(void)
+{
+ platform_device_unregister(&rtc_ldm);
+}
+
+/*!
+ * This function is called when pmic interrupt occurs on the processor.
+ * It is the interrupt handler for the pmic module.
+ *
+ * @param irq the irq number
+ * @param dev_id the pointer on the device
+ *
+ * @return The function returns IRQ_HANDLED when handled.
+ */
+static irqreturn_t pmic_irq_handler(int irq, void *dev_id)
+{
+ /* prepare a task */
+ schedule_work(&pmic_ws);
+
+ return IRQ_HANDLED;
+}
+
+/*!
+ * This function is the bottom half handler of the PMIC interrupt.
+ * It checks for active events and launches callback for the
+ * active events.
+ */
+void pmic_bh_handler(struct work_struct *work)
+{
+ unsigned int loop;
+ unsigned int count = 0;
+
+ count = pmic_get_active_events(active_events);
+
+ for (loop = 0; loop < count; loop++)
+ pmic_event_callback(active_events[loop]);
+}
+
+/*!
+ * This function is used to determine the PMIC type and its revision.
+ *
+ * @return Returns the PMIC type and its revision.
+ */
+
+pmic_version_t pmic_get_version(void)
+{
+ return mxc_pmic_version;
+}
+EXPORT_SYMBOL(pmic_get_version);
+
+static int __init mcu_pmic_init(void)
+{
+ int err;
+
+ /* init chips */
+ err = max8660_init();
+ if (err)
+ goto fail1;
+
+ err = mc9sdz60_init();
+ if (err)
+ goto fail1;
+
+ /* Initialize the PMIC event handling */
+ pmic_event_list_init();
+
+ /* Set and install PMIC IRQ handler */
+ mxc_request_iomux(MX35_PIN_GPIO1_0, OUTPUTCONFIG_GPIO,
+ INPUTCONFIG_GPIO);
+ mxc_iomux_set_pad(MX35_PIN_GPIO1_0, PAD_CTL_PKE_NONE);
+ mxc_set_gpio_direction(MX35_PIN_GPIO1_0, 1); /* input */
+
+ err = set_irq_type(IOMUX_TO_IRQ(MX35_PIN_GPIO1_0), IRQT_RISING);
+ err = request_irq(IOMUX_TO_IRQ(MX35_PIN_GPIO1_0), pmic_irq_handler,
+ 0, "PMIC_IRQ", 0);
+ if (err) {
+ DPRINTK("mcu pmic request irq failed");
+ goto fail1;
+ }
+
+ pmic_pdev_register();
+
+ return 0;
+
+fail1:
+ return err;
+}
+
+static void __exit mcu_pmic_exit(void)
+{
+ free_irq(IOMUX_TO_IRQ(MX35_PIN_GPIO1_1), 0);
+ pmic_pdev_unregister();
+}
+
+subsys_initcall_sync(mcu_pmic_init);
+module_exit(mcu_pmic_exit);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("mcu pmic driver");
+MODULE_LICENSE("GPL");