summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xdrivers/mfd/ab5500-core.c100
-rw-r--r--include/linux/mfd/abx500.h9
2 files changed, 105 insertions, 4 deletions
diff --git a/drivers/mfd/ab5500-core.c b/drivers/mfd/ab5500-core.c
index cf7de4d7443..91f6d25f6e9 100755
--- a/drivers/mfd/ab5500-core.c
+++ b/drivers/mfd/ab5500-core.c
@@ -51,6 +51,18 @@
#define AB5500_CHIP_ID (0x20)
#define AB5500_INTERRUPTS 0x01FFFFFF
+/* Turn On Status Event */
+#define RTC_ALARM 0x80
+#define POW_KEY_2_ON 0x20
+#define POW_KEY_1_ON 0x08
+#define POR_ON_VBAT 0x01
+#define VBUS_DET 0x02
+#define VBUS_CH_DROP_R 0x08
+#define USB_CH_DET_DONE 0x02
+
+/* Global Variables */
+u8 turn_on_stat = 0x00;
+
/**
* struct ab5500_bank
* @slave_addr: I2C slave_addr found in AB5500 specification
@@ -794,6 +806,34 @@ static struct mfd_cell ab5500_devs[AB5500_NUM_DEVICES] = {
},
};
+static ssize_t show_chip_id(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ab5500 *ab5500;
+
+ ab5500 = dev_get_drvdata(dev);
+ return sprintf(buf, "%#x\n", ab5500 ? ab5500->chip_id : -EINVAL);
+}
+
+static ssize_t show_turn_on_status(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%#x\n", turn_on_stat);
+}
+
+static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
+static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
+
+static struct attribute *ab5500_sysfs_entries[] = {
+ &dev_attr_chip_id.attr,
+ &dev_attr_turn_on_status.attr,
+ NULL,
+};
+
+static struct attribute_group ab5500_attr_group = {
+ .attrs = ab5500_sysfs_entries,
+};
+
/*
* Functionality for getting/setting register values.
*/
@@ -2357,6 +2397,7 @@ static int __init ab5500_probe(struct platform_device *pdev)
struct resource *res;
int err;
int i;
+ u8 val;
ab = kzalloc(sizeof(struct ab5500), GFP_KERNEL);
if (!ab) {
@@ -2413,11 +2454,52 @@ static int __init ab5500_probe(struct platform_device *pdev)
ab->num_event_reg = AB5500_NUM_IRQ_REGS;
else
ab->num_event_reg = AB5500_NUM_EVENT_V1_REG;
+
+ /* Read the latch regs to know the reason for turn on */
+ err = get_register_interruptible(ab, AB5500_BANK_IT,
+ AB5500_IT_LATCH0_REG + 1, &val);
+ if (err)
+ goto exit_no_detect;
+ if (val & RTC_ALARM) /* RTCAlarm */
+ turn_on_stat = RTC_ALARM_EVENT;
+ if (val & POW_KEY_2_ON) /* PonKey2dbR */
+ turn_on_stat |= P_ON_KEY2_EVENT;
+ if (val & POW_KEY_1_ON) /* PonKey1dbR */
+ turn_on_stat |= P_ON_KEY1_EVENT;
+
+ err = get_register_interruptible(ab, AB5500_BANK_IT,
+ AB5500_IT_LATCH0_REG + 2, &val);
+ if (err)
+ goto exit_no_detect;
+ if (val & POR_ON_VBAT)
+ /* PORnVbat */
+ turn_on_stat |= POR_ON_VBAT_EVENT ;
+ err = get_register_interruptible(ab, AB5500_BANK_IT,
+ AB5500_IT_LATCH0_REG + 8, &val);
+ if (err)
+ goto exit_no_detect;
+ if (val & VBUS_DET)
+ /* VbusDet */
+ turn_on_stat |= VBUS_DET_EVENT;
+ err = get_register_interruptible(ab, AB5500_BANK_IT,
+ AB5500_IT_LATCH0_REG + 18, &val);
+ if (err)
+ goto exit_no_detect;
+ if (val & VBUS_CH_DROP_R)
+ /* VBUSChDrop */
+ turn_on_stat |= VBUS_DET_EVENT;
+ err = get_register_interruptible(ab, AB5500_BANK_IT,
+ AB5500_IT_LATCH0_REG + 9, &val);
+ if (err)
+ goto exit_no_detect;
+ if (val & USB_CH_DET_DONE)
+ /* VBUSChDrop */
+ turn_on_stat |= VBUS_DET_EVENT;
+
/* Clear and mask all interrupts */
for (i = 0; i < ab->num_event_reg; i++) {
u8 latchreg = AB5500_IT_LATCH0_REG + i;
u8 maskreg = AB5500_IT_MASK0_REG + i;
- u8 val;
get_register_interruptible(ab, AB5500_BANK_IT, latchreg, &val);
set_register_interruptible(ab, AB5500_BANK_IT, maskreg, 0xff);
@@ -2456,17 +2538,26 @@ static int __init ab5500_probe(struct platform_device *pdev)
ab5500_plf_data->irq.base);
if (err) {
dev_err(&pdev->dev, "ab5500_mfd_add_device error\n");
- goto exit_no_irq;
+ goto exit_no_add_dev;
}
err = ab5500_setup(ab, ab5500_plf_data->init_settings,
ab5500_plf_data->init_settings_sz);
if (err) {
dev_err(&pdev->dev, "ab5500_setup error\n");
- goto exit_no_irq;
+ goto exit_no_add_dev;
}
ab5500_setup_debugfs(ab);
- return 0;
+ err = sysfs_create_group(&ab->dev->kobj, &ab5500_attr_group);
+ if (err) {
+ dev_err(&pdev->dev, "error creating sysfs entries\n");
+ goto exit_no_debugfs;
+ }
+ return 0;
+exit_no_debugfs:
+ ab5500_remove_debugfs();
+exit_no_add_dev:
+ mfd_remove_devices(&pdev->dev);
exit_no_irq:
if (ab->irq_base) {
free_irq(ab->ab5500_irq, ab);
@@ -2486,6 +2577,7 @@ static int __exit ab5500_remove(struct platform_device *pdev)
* At this point, all subscribers should have unregistered
* their notifiers so deactivate IRQ
*/
+ sysfs_remove_group(&ab->dev->kobj, &ab5500_attr_group);
ab5500_remove_debugfs();
mfd_remove_devices(&pdev->dev);
if (ab->irq_base) {
diff --git a/include/linux/mfd/abx500.h b/include/linux/mfd/abx500.h
index cd2e36d0108..a0a1386774f 100644
--- a/include/linux/mfd/abx500.h
+++ b/include/linux/mfd/abx500.h
@@ -99,6 +99,15 @@
*/
#define AB3100_NUM_REGULATORS 10
+/* Turn On Events */
+#define POR_ON_VBAT_EVENT (0x01 << 0)
+#define P_ON_KEY1_EVENT (0x01 << 1)
+#define P_ON_KEY2_EVENT (0x01 << 2)
+#define RTC_ALARM_EVENT (0x01 << 3)
+#define MAIN_CH_DET_EVENT (0x01 << 4)
+#define VBUS_DET_EVENT (0x01 << 5)
+#define USB_ID_DET_EVENT (0x01 << 6)
+
/**
* struct ab3100
* @access_mutex: lock out concurrent accesses to the AB3100 registers