msm: qpnp-power-on: Add reset configuration support
The PON module supports various reset sources (physical pins)
such as KPDPWR, RESIN, RESIN+KPDPWR. These pins can be configured
for different reset types (such as warm, soft, hard) and can also
be used as push buttons (keys).
In the push-button configuration these pins act as gpios, only
reporting the state on the line (high/low) and no additional
pon based configuration being done in the hardware or software.
They can be used for generic buttons (such as volume up/down,
directional keys)
Change-Id: Icde78b49b1037c1b5a13d7e90f772f72ac822b2a
Signed-off-by: Anirudh Ghayal <aghayal@codeaurora.org>
diff --git a/drivers/platform/msm/qpnp-power-on.c b/drivers/platform/msm/qpnp-power-on.c
index d8bb884..aeaca85 100644
--- a/drivers/platform/msm/qpnp-power-on.c
+++ b/drivers/platform/msm/qpnp-power-on.c
@@ -16,141 +16,545 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/spmi.h>
+#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/interrupt.h>
#include <linux/input.h>
+#include <linux/log2.h>
+/* PON common register addresses */
#define QPNP_PON_RT_STS(base) (base + 0x10)
#define QPNP_PON_PULL_CTL(base) (base + 0x70)
#define QPNP_PON_DBC_CTL(base) (base + 0x71)
-#define QPNP_PON_CNTL_PULL_UP BIT(1)
-#define QPNP_PON_CNTL_TRIG_DELAY_MASK (0x7)
+/* PON/RESET sources register addresses */
+#define QPNP_PON_KPDPWR_S1_TIMER(base) (base + 0x40)
+#define QPNP_PON_KPDPWR_S2_TIMER(base) (base + 0x41)
+#define QPNP_PON_KPDPWR_S2_CNTL(base) (base + 0x42)
+#define QPNP_PON_RESIN_S1_TIMER(base) (base + 0x44)
+#define QPNP_PON_RESIN_S2_TIMER(base) (base + 0x45)
+#define QPNP_PON_RESIN_S2_CNTL(base) (base + 0x46)
+
+#define QPNP_PON_RESIN_PULL_UP BIT(0)
+#define QPNP_PON_KPDPWR_PULL_UP BIT(1)
+#define QPNP_PON_S2_CNTL_EN BIT(7)
+#define QPNP_PON_S2_RESET_ENABLE BIT(7)
+
+#define QPNP_PON_S1_TIMER_MASK (0xF)
+#define QPNP_PON_S2_TIMER_MASK (0x7)
+#define QPNP_PON_S2_CNTL_TYPE_MASK (0xF)
+
+#define QPNP_PON_DBC_DELAY_MASK (0x7)
#define QPNP_PON_KPDPWR_N_SET BIT(0)
+#define QPNP_PON_RESIN_N_SET BIT(1)
+
+/* Ranges */
+#define QPNP_PON_S1_TIMER_MAX 10256
+#define QPNP_PON_S2_TIMER_MAX 2000
+#define QPNP_PON_RESET_TYPE_MAX 0xF
+#define PON_S1_COUNT_MAX 0xF
+
+enum pon_type {
+ PON_KPDPWR,
+ PON_RESIN,
+};
+
+struct qpnp_pon_config {
+ u32 pon_type;
+ u32 support_reset;
+ u32 key_code;
+ u32 s1_timer;
+ u32 s2_timer;
+ u32 s2_type;
+ u32 pull_up;
+ u32 state_irq;
+ u32 bark_irq;
+};
struct qpnp_pon {
struct spmi_device *spmi;
struct input_dev *pon_input;
- u32 key_status_irq;
+ struct qpnp_pon_config *pon_cfg;
+ int num_pon_config;
u16 base;
};
-static irqreturn_t qpnp_pon_key_irq(int irq, void *_pon)
-{
- u8 pon_rt_sts;
- int rc;
- struct qpnp_pon *pon = _pon;
+static u32 s1_delay[PON_S1_COUNT_MAX + 1] = {
+ 0 , 32, 56, 80, 138, 184, 272, 408, 608, 904, 1352, 2048,
+ 3072, 4480, 6720, 10256
+};
+static int
+qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val)
+{
+ int rc;
+ u8 reg;
+
+ rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
+ addr, ®, 1);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read from addr=%x, rc(%d)\n", addr, rc);
+ return rc;
+ }
+
+ reg &= ~mask;
+ reg |= val & mask;
+ rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
+ addr, ®, 1);
+ if (rc)
+ dev_err(&pon->spmi->dev,
+ "Unable to write to addr=%x, rc(%d)\n", addr, rc);
+ return rc;
+}
+
+static int
+qpnp_pon_input_dispatch(struct qpnp_pon *pon, u32 pon_type)
+{
+ int i, rc;
+ struct qpnp_pon_config *cfg = NULL;
+ u8 pon_rt_sts = 0, pon_rt_bit = 0;
+
+ for (i = 0; i < pon->num_pon_config; i++) {
+ /* get the configuration infor for that pon type */
+ if (pon_type == pon->pon_cfg[i].pon_type) {
+ cfg = &pon->pon_cfg[i];
+ break;
+ }
+ }
+
+ if (!cfg)
+ return -EINVAL;
+
+ /* Check if key reporting is supported */
+ if (!cfg->key_code)
+ return 0;
+
+ /* check the RT status to get the current status of the line */
rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
QPNP_PON_RT_STS(pon->base), &pon_rt_sts, 1);
if (rc) {
dev_err(&pon->spmi->dev, "Unable to read PON RT status\n");
- return IRQ_HANDLED;
+ return rc;
}
- input_report_key(pon->pon_input, KEY_POWER,
- !(pon_rt_sts & QPNP_PON_KPDPWR_N_SET));
+ switch (cfg->pon_type) {
+ case PON_KPDPWR:
+ pon_rt_bit = QPNP_PON_KPDPWR_N_SET;
+ break;
+ case PON_RESIN:
+ pon_rt_bit = QPNP_PON_RESIN_N_SET;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ input_report_key(pon->pon_input, cfg->key_code,
+ (pon_rt_sts & pon_rt_bit));
input_sync(pon->pon_input);
+ return 0;
+}
+
+static irqreturn_t qpnp_kpdpwr_irq(int irq, void *_pon)
+{
+ int rc;
+ struct qpnp_pon *pon = _pon;
+
+ rc = qpnp_pon_input_dispatch(pon, PON_KPDPWR);
+ if (rc)
+ dev_err(&pon->spmi->dev, "Unable to send input event\n");
+
return IRQ_HANDLED;
}
-static int __devinit qpnp_pon_key_init(struct qpnp_pon *pon)
+static irqreturn_t qpnp_kpdpwr_bark_irq(int irq, void *_pon)
+{
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qpnp_resin_irq(int irq, void *_pon)
+{
+ int rc;
+ struct qpnp_pon *pon = _pon;
+
+ rc = qpnp_pon_input_dispatch(pon, PON_RESIN);
+ if (rc)
+ dev_err(&pon->spmi->dev, "Unable to send input event\n");
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qpnp_resin_bark_irq(int irq, void *_pon)
+{
+ return IRQ_HANDLED;
+}
+
+static int __devinit
+qpnp_config_pull(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
+{
+ int rc;
+ u8 pull_bit;
+
+ switch (cfg->pon_type) {
+ case PON_KPDPWR:
+ pull_bit = QPNP_PON_KPDPWR_PULL_UP;
+ break;
+ case PON_RESIN:
+ pull_bit = QPNP_PON_RESIN_PULL_UP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_PULL_CTL(pon->base),
+ pull_bit, cfg->pull_up ? pull_bit : 0);
+ if (rc)
+ dev_err(&pon->spmi->dev, "Unable to config pull-up\n");
+
+ return rc;
+}
+
+static int __devinit
+qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
+{
+ int rc;
+ u8 i;
+ u16 s1_timer_addr, s2_cntl_addr, s2_timer_addr;
+
+ switch (cfg->pon_type) {
+ case PON_KPDPWR:
+ s1_timer_addr = QPNP_PON_KPDPWR_S1_TIMER(pon->base);
+ s2_timer_addr = QPNP_PON_KPDPWR_S2_TIMER(pon->base);
+ s2_cntl_addr = QPNP_PON_KPDPWR_S2_CNTL(pon->base);
+ break;
+ case PON_RESIN:
+ s1_timer_addr = QPNP_PON_RESIN_S1_TIMER(pon->base);
+ s2_timer_addr = QPNP_PON_RESIN_S2_TIMER(pon->base);
+ s2_cntl_addr = QPNP_PON_RESIN_S2_CNTL(pon->base);
+ break;
+ default:
+ return -EINVAL;
+ }
+ /* disable S2 reset */
+ rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+ QPNP_PON_S2_CNTL_EN, 0);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+ return rc;
+ }
+
+ usleep(100);
+
+ /* configure s1 timer, s2 timer and reset type */
+ for (i = 0; i < PON_S1_COUNT_MAX + 1; i++) {
+ if (cfg->s1_timer <= s1_delay[i])
+ break;
+ }
+ rc = qpnp_pon_masked_write(pon, s1_timer_addr,
+ QPNP_PON_S1_TIMER_MASK, i);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S1 timer\n");
+ return rc;
+ }
+
+ i = 0;
+ if (cfg->s2_timer) {
+ i = cfg->s2_timer / 10;
+ i = ilog2(i + 1);
+ }
+
+ rc = qpnp_pon_masked_write(pon, s2_timer_addr,
+ QPNP_PON_S2_TIMER_MASK, i);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 timer\n");
+ return rc;
+ }
+
+ rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+ QPNP_PON_S2_CNTL_TYPE_MASK, (u8)cfg->s2_type);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 reset type\n");
+ return rc;
+ }
+
+ /* enable S2 reset */
+ rc = qpnp_pon_masked_write(pon, s2_cntl_addr,
+ QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to configure S2 enable\n");
+ return rc;
+ }
+
+ return 0;
+}
+
+static int __devinit
+qpnp_pon_request_irqs(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
{
int rc = 0;
- u32 pullup, delay;
- u8 pon_cntl;
- pon->key_status_irq = spmi_get_irq_byname(pon->spmi,
- NULL, "power-key");
- if (pon->key_status_irq < 0) {
- dev_err(&pon->spmi->dev, "Unable to get pon key irq\n");
- return -ENXIO;
- }
-
- rc = of_property_read_u32(pon->spmi->dev.of_node,
- "qcom,pon-key-dbc-delay", &delay);
- if (rc) {
- delay = (delay << 6) / USEC_PER_SEC;
- delay = ilog2(delay);
-
- rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
- QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
- if (rc) {
- dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
- QPNP_PON_DBC_CTL(pon->base));
- return rc;
- }
- pon_cntl &= ~QPNP_PON_CNTL_TRIG_DELAY_MASK;
- pon_cntl |= (delay & QPNP_PON_CNTL_TRIG_DELAY_MASK);
- rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
- QPNP_PON_DBC_CTL(pon->base), &pon_cntl, 1);
- if (rc) {
- dev_err(&pon->spmi->dev, "spmi write addre=%x failed\n",
- QPNP_PON_DBC_CTL(pon->base));
- return rc;
- }
- }
-
- rc = of_property_read_u32(pon->spmi->dev.of_node,
- "qcom,pon-key-pull-up", &pullup);
- if (!rc) {
- rc = spmi_ext_register_readl(pon->spmi->ctrl, pon->spmi->sid,
- QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
- if (rc) {
- dev_err(&pon->spmi->dev, "spmi read addr=%x failed\n",
- QPNP_PON_PULL_CTL(pon->base));
- return rc;
- }
- if (pullup)
- pon_cntl |= QPNP_PON_CNTL_PULL_UP;
- else
- pon_cntl &= ~QPNP_PON_CNTL_PULL_UP;
-
- rc = spmi_ext_register_writel(pon->spmi->ctrl, pon->spmi->sid,
- QPNP_PON_PULL_CTL(pon->base), &pon_cntl, 1);
- if (rc) {
- dev_err(&pon->spmi->dev, "spmi write addr=%x failed\n",
- QPNP_PON_PULL_CTL(pon->base));
- return rc;
- }
- }
-
- pon->pon_input = input_allocate_device();
- if (!pon->pon_input) {
- dev_err(&pon->spmi->dev, "Can't allocate pon button\n");
- return -ENOMEM;
- }
-
- input_set_capability(pon->pon_input, EV_KEY, KEY_POWER);
- pon->pon_input->name = "qpnp_pon_key";
- pon->pon_input->phys = "qpnp_pon_key/input0";
-
- rc = input_register_device(pon->pon_input);
- if (rc) {
- dev_err(&pon->spmi->dev, "Can't register pon key: %d\n", rc);
- goto free_input_dev;
- }
-
- rc = request_any_context_irq(pon->key_status_irq, qpnp_pon_key_irq,
+ switch (cfg->pon_type) {
+ case PON_KPDPWR:
+ rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
+ qpnp_kpdpwr_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
- "qpnp_pon_key_status", pon);
- if (rc < 0) {
- dev_err(&pon->spmi->dev, "Can't request %d IRQ for pon: %d\n",
- pon->key_status_irq, rc);
- goto unreg_input_dev;
+ "qpnp_kpdpwr_status", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
+ cfg->state_irq);
+ return rc;
+ }
+ if (cfg->support_reset) {
+ rc = devm_request_irq(&pon->spmi->dev, cfg->bark_irq,
+ qpnp_kpdpwr_bark_irq,
+ IRQF_TRIGGER_RISING,
+ "qpnp_kpdpwr_bark", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev,
+ "Can't request %d IRQ\n",
+ cfg->bark_irq);
+ return rc;
+ }
+ }
+ break;
+ case PON_RESIN:
+ rc = devm_request_irq(&pon->spmi->dev, cfg->state_irq,
+ qpnp_resin_irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+ "qpnp_resin_status", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev, "Can't request %d IRQ\n",
+ cfg->state_irq);
+ return rc;
+ }
+ if (cfg->support_reset) {
+ rc = devm_request_irq(&pon->spmi->dev, cfg->bark_irq,
+ qpnp_resin_bark_irq,
+ IRQF_TRIGGER_RISING,
+ "qpnp_resin_bark", pon);
+ if (rc < 0) {
+ dev_err(&pon->spmi->dev,
+ "Can't request %d IRQ\n",
+ cfg->bark_irq);
+ return rc;
+ }
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return rc;
+}
+
+static int __devinit
+qpnp_pon_config_input(struct qpnp_pon *pon, struct qpnp_pon_config *cfg)
+{
+ if (!pon->pon_input) {
+ pon->pon_input = input_allocate_device();
+ if (!pon->pon_input) {
+ dev_err(&pon->spmi->dev,
+ "Can't allocate pon input device\n");
+ return -ENOMEM;
+ }
+ pon->pon_input->name = "qpnp_pon";
+ pon->pon_input->phys = "qpnp_pon/input0";
+ }
+
+ input_set_capability(pon->pon_input, EV_KEY, cfg->key_code);
+
+ return 0;
+}
+
+static int __devinit qpnp_pon_config_init(struct qpnp_pon *pon)
+{
+ int rc = 0, i = 0;
+ struct device_node *pp = NULL;
+ struct qpnp_pon_config *cfg;
+
+ /* iterate through the list of pon configs */
+ while ((pp = of_get_next_child(pon->spmi->dev.of_node, pp))) {
+
+ cfg = &pon->pon_cfg[i++];
+
+ rc = of_property_read_u32(pp, "qcom,pon-type", &cfg->pon_type);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "PON type not specified\n");
+ return rc;
+ }
+
+ switch (cfg->pon_type) {
+ case PON_KPDPWR:
+ cfg->state_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "kpdpwr");
+ if (cfg->state_irq < 0) {
+ dev_err(&pon->spmi->dev,
+ "Unable to get kpdpwr irq\n");
+ return cfg->state_irq;
+ }
+
+ rc = of_property_read_u32(pp, "qcom,support-reset",
+ &cfg->support_reset);
+ if (rc && rc != -EINVAL) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read 'support-reset'\n");
+ return rc;
+ }
+
+ if (cfg->support_reset) {
+ cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "kpdpwr-bark");
+ if (cfg->bark_irq < 0) {
+ dev_err(&pon->spmi->dev,
+ "Unable to get kpdpwr-bark irq\n");
+ return cfg->bark_irq;
+ }
+ }
+ break;
+ case PON_RESIN:
+ cfg->state_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "resin");
+ if (cfg->state_irq < 0) {
+ dev_err(&pon->spmi->dev,
+ "Unable to get resin irq\n");
+ return cfg->bark_irq;
+ }
+
+ rc = of_property_read_u32(pp, "qcom,support-reset",
+ &cfg->support_reset);
+ if (rc && rc != -EINVAL) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read 'support-reset'\n");
+ return rc;
+ }
+
+ if (cfg->support_reset) {
+ cfg->bark_irq = spmi_get_irq_byname(pon->spmi,
+ NULL, "resin-bark");
+ if (cfg->bark_irq < 0) {
+ dev_err(&pon->spmi->dev,
+ "Unable to get resin-bark irq\n");
+ return cfg->bark_irq;
+ }
+ }
+ break;
+ default:
+ dev_err(&pon->spmi->dev, "PON RESET %d not supported",
+ cfg->pon_type);
+ return -EINVAL;
+ }
+
+ if (cfg->support_reset) {
+ /*
+ * Get the reset parameters (bark debounce time and
+ * reset debounce time) for the reset line.
+ */
+ rc = of_property_read_u32(pp, "qcom,s1-timer",
+ &cfg->s1_timer);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read s1-timer\n");
+ return rc;
+ }
+ if (cfg->s1_timer > QPNP_PON_S1_TIMER_MAX) {
+ dev_err(&pon->spmi->dev,
+ "Incorrect S1 debounce time\n");
+ return -EINVAL;
+ }
+ rc = of_property_read_u32(pp, "qcom,s2-timer",
+ &cfg->s2_timer);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read s2-timer\n");
+ return rc;
+ }
+ if (cfg->s2_timer > QPNP_PON_S2_TIMER_MAX) {
+ dev_err(&pon->spmi->dev,
+ "Incorrect S2 debounce time\n");
+ return -EINVAL;
+ }
+ rc = of_property_read_u32(pp, "qcom,s2-type",
+ &cfg->s2_type);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read s2-type\n");
+ return rc;
+ }
+ if (cfg->s2_type > QPNP_PON_RESET_TYPE_MAX) {
+ dev_err(&pon->spmi->dev,
+ "Incorrect reset type specified\n");
+ return -EINVAL;
+ }
+ }
+ /*
+ * Get the standard-key parameters. This might not be
+ * specified if there is no key mapping on the reset line.
+ */
+ rc = of_property_read_u32(pp, "linux,code", &cfg->key_code);
+ if (rc && rc == -EINVAL) {
+ dev_err(&pon->spmi->dev,
+ "Unable to read key-code\n");
+ return rc;
+ }
+ /* Register key configuration */
+ if (cfg->key_code) {
+ rc = qpnp_pon_config_input(pon, cfg);
+ if (rc < 0)
+ return rc;
+ }
+ /* get the pull-up configuration */
+ rc = of_property_read_u32(pp, "qcom,pull-up", &cfg->pull_up);
+ if (rc && rc != -EINVAL) {
+ dev_err(&pon->spmi->dev, "Unable to read pull-up\n");
+ return rc;
+ }
+ }
+
+ /* register the input device */
+ if (pon->pon_input) {
+ rc = input_register_device(pon->pon_input);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Can't register pon key: %d\n", rc);
+ goto free_input_dev;
+ }
+ }
+
+ for (i = 0; i < pon->num_pon_config; i++) {
+ cfg = &pon->pon_cfg[i];
+ /* Configure the pull-up */
+ rc = qpnp_config_pull(pon, cfg);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to config pull-up\n");
+ goto unreg_input_dev;
+ }
+ /* Configure the reset-configuration */
+ if (cfg->support_reset) {
+ rc = qpnp_config_reset(pon, cfg);
+ if (rc) {
+ dev_err(&pon->spmi->dev,
+ "Unable to config pon reset\n");
+ goto unreg_input_dev;
+ }
+ }
+ rc = qpnp_pon_request_irqs(pon, cfg);
+ if (rc) {
+ dev_err(&pon->spmi->dev, "Unable to request-irq's\n");
+ goto unreg_input_dev;
+ }
}
device_init_wakeup(&pon->spmi->dev, 1);
- enable_irq_wake(pon->key_status_irq);
return rc;
unreg_input_dev:
- input_unregister_device(pon->pon_input);
+ if (pon->pon_input)
+ input_unregister_device(pon->pon_input);
free_input_dev:
- input_free_device(pon->pon_input);
+ if (pon->pon_input)
+ input_free_device(pon->pon_input);
return rc;
}
@@ -158,7 +562,8 @@
{
struct qpnp_pon *pon;
struct resource *pon_resource;
- u32 pon_key_enable = 0;
+ struct device_node *itr = NULL;
+ u32 delay = 0;
int rc = 0;
pon = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_pon),
@@ -170,6 +575,20 @@
pon->spmi = spmi;
+ /* get the total number of pon configurations */
+ while ((itr = of_get_next_child(spmi->dev.of_node, itr)))
+ pon->num_pon_config++;
+
+ if (!pon->num_pon_config) {
+ /* No PON config., do not register the driver */
+ dev_err(&spmi->dev, "No PON config. specified\n");
+ return -EINVAL;
+ }
+
+ pon->pon_cfg = devm_kzalloc(&spmi->dev,
+ sizeof(struct qpnp_pon_config) * pon->num_pon_config,
+ GFP_KERNEL);
+
pon_resource = spmi_get_resource(spmi, NULL, IORESOURCE_MEM, 0);
if (!pon_resource) {
dev_err(&spmi->dev, "Unable to get PON base address\n");
@@ -177,36 +596,41 @@
}
pon->base = pon_resource->start;
- dev_set_drvdata(&spmi->dev, pon);
-
- /* pon-key-enable property must be set to register pon key */
- rc = of_property_read_u32(spmi->dev.of_node, "qcom,pon-key-enable",
- &pon_key_enable);
+ rc = of_property_read_u32(pon->spmi->dev.of_node,
+ "qcom,pon-dbc-delay", &delay);
if (rc && rc != -EINVAL) {
- dev_err(&spmi->dev,
- "Error reading 'pon-key-enable' property (%d)", rc);
+ dev_err(&spmi->dev, "Unable to read debounce delay\n");
return rc;
- }
-
- if (pon_key_enable) {
- rc = qpnp_pon_key_init(pon);
- if (rc < 0) {
- dev_err(&spmi->dev, "Failed to register pon-key\n");
+ } else {
+ delay = (delay << 6) / USEC_PER_SEC;
+ delay = ilog2(delay);
+ rc = qpnp_pon_masked_write(pon, QPNP_PON_DBC_CTL(pon->base),
+ QPNP_PON_DBC_DELAY_MASK, delay);
+ if (rc) {
+ dev_err(&spmi->dev, "Unable to set PON debounce\n");
return rc;
}
}
- return 0;
+ dev_set_drvdata(&spmi->dev, pon);
+
+ /* register the PON configurations */
+ rc = qpnp_pon_config_init(pon);
+ if (rc) {
+ dev_err(&spmi->dev,
+ "Unable to intialize PON configurations\n");
+ return rc;
+ }
+
+ return rc;
}
static int qpnp_pon_remove(struct spmi_device *spmi)
{
struct qpnp_pon *pon = dev_get_drvdata(&spmi->dev);
- if (pon->pon_input) {
- free_irq(pon->key_status_irq, pon);
+ if (pon->pon_input)
input_unregister_device(pon->pon_input);
- }
return 0;
}