Loading drivers/input/misc/qpnp-power-on.c +143 −18 Original line number Diff line number Diff line /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2012-2019, The Linux Foundation. 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 version 2 and Loading Loading @@ -167,6 +167,12 @@ enum pon_type { PON_KPDPWR_RESIN = PON_POWER_ON_TYPE_KPDPWR_RESIN, }; struct pon_reg { unsigned int val; u16 addr; struct list_head list; }; struct qpnp_pon_config { u32 pon_type; u32 support_reset; Loading Loading @@ -199,7 +205,9 @@ struct qpnp_pon { struct input_dev *pon_input; struct qpnp_pon_config *pon_cfg; struct pon_regulator *pon_reg_cfg; struct list_head restore_regs; struct list_head list; struct mutex restore_lock; struct delayed_work bark_work; struct dentry *debugfs; u16 base; Loading Loading @@ -305,6 +313,42 @@ static const char * const qpnp_poff_reason[] = { [39] = "Triggered from S3_RESET_KPDPWR_ANDOR_RESIN", }; static int qpnp_pon_store_reg(struct qpnp_pon *pon, u16 addr) { int rc; unsigned int val; struct pon_reg *reg, *pos = NULL; mutex_lock(&pon->restore_lock); rc = regmap_read(pon->regmap, addr, &val); if (rc < 0) { dev_info(pon->dev, "Register read failed, addr=0x%04X, rc=%d\n", addr, rc); } else { list_for_each_entry(pos, &pon->restore_regs, list) { if (pos->addr == addr) { pos->val = val; goto done; } } reg = devm_kzalloc(pon->dev, sizeof(*reg), GFP_KERNEL); if (!reg) { rc = -ENOMEM; goto done; } reg->addr = addr; reg->val = val; INIT_LIST_HEAD(®->list); list_add_tail(®->list, &pon->restore_regs); } done: mutex_unlock(&pon->restore_lock); return rc; } static int qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) { Loading @@ -317,6 +361,18 @@ qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) return rc; } static int qpnp_pon_masked_write_backup(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) { int rc; rc = qpnp_pon_masked_write(pon, addr, mask, val); if (rc < 0) return rc; return qpnp_pon_store_reg(pon, addr); } static int qpnp_pon_read(struct qpnp_pon *pon, u16 addr, unsigned int *val) { int rc; Loading Loading @@ -416,7 +472,7 @@ static int qpnp_pon_set_dbc(struct qpnp_pon *pon, u32 delay) } val = ilog2(val); rc = qpnp_pon_masked_write(pon, QPNP_PON_DBC_CTL(pon), rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_DBC_CTL(pon), QPNP_PON_DBC_DELAY_MASK(pon), val); if (!rc) pon->dbc_time_us = delay; Loading Loading @@ -794,10 +850,10 @@ int qpnp_pon_trigger_config(enum pon_trigger_source pon_src, bool enable) } if (is_pon_gen2(pon) && pon_src == PON_SMPL) rc = qpnp_pon_masked_write(pon, QPNP_PON_SMPL_CTL(pon), rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_SMPL_CTL(pon), QPNP_PON_SMPL_EN, enable ? QPNP_PON_SMPL_EN : 0); else rc = qpnp_pon_masked_write(pon, QPNP_PON_TRIGGER_EN(pon), rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_TRIGGER_EN(pon), BIT(pon_src), enable ? BIT(pon_src) : 0); return rc; Loading Loading @@ -834,6 +890,7 @@ static int qpnp_pon_store_and_clear_warm_reset(struct qpnp_pon *pon) QPNP_PON_WARM_RESET_REASON1(pon), rc); return rc; } qpnp_pon_store_reg(pon, QPNP_PON_WARM_RESET_REASON1(pon)); } return 0; Loading Loading @@ -1122,8 +1179,8 @@ static int qpnp_config_pull(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) return -EINVAL; } return qpnp_pon_masked_write(pon, QPNP_PON_PULL_CTL(pon), pull_bit, cfg->pull_up ? pull_bit : 0); return qpnp_pon_masked_write_backup(pon, QPNP_PON_PULL_CTL(pon), pull_bit, cfg->pull_up ? pull_bit : 0); } static int qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) Loading @@ -1150,8 +1207,8 @@ static int qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) } /* Disable S2 reset */ rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr, QPNP_PON_S2_CNTL_EN, 0); rc = qpnp_pon_masked_write_backup(pon, cfg->s2_cntl2_addr, QPNP_PON_S2_CNTL_EN, 0); if (rc) return rc; Loading @@ -1162,7 +1219,7 @@ static int qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) if (cfg->s1_timer <= s1_delay[i]) break; } rc = qpnp_pon_masked_write(pon, s1_timer_addr, rc = qpnp_pon_masked_write_backup(pon, s1_timer_addr, QPNP_PON_S1_TIMER_MASK, i); if (rc) return rc; Loading @@ -1173,18 +1230,18 @@ static int qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) i = ilog2(i + 1); } rc = qpnp_pon_masked_write(pon, s2_timer_addr, QPNP_PON_S2_TIMER_MASK, i); rc = qpnp_pon_masked_write_backup(pon, s2_timer_addr, QPNP_PON_S2_TIMER_MASK, i); if (rc) return rc; rc = qpnp_pon_masked_write(pon, cfg->s2_cntl_addr, rc = qpnp_pon_masked_write_backup(pon, cfg->s2_cntl_addr, QPNP_PON_S2_CNTL_TYPE_MASK, (u8)cfg->s2_type); if (rc) return rc; /* Enable S2 reset */ return qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr, return qpnp_pon_masked_write_backup(pon, cfg->s2_cntl2_addr, QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN); } Loading Loading @@ -1277,6 +1334,18 @@ qpnp_pon_request_irqs(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) return 0; } static int qpnp_pon_free_irqs(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) { if (cfg->state_irq > 0) devm_free_irq(pon->dev, cfg->state_irq, pon); if (cfg->use_bark && cfg->bark_irq > 0) devm_free_irq(pon->dev, cfg->bark_irq, pon); return 0; } static int qpnp_pon_config_input(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) { Loading Loading @@ -1632,7 +1701,7 @@ static int qpnp_pon_config_init(struct qpnp_pon *pon, return rc; } else if (cfg->pon_type != PON_CBLPWR) { /* Disable S2 reset */ rc = qpnp_pon_masked_write(pon, rc = qpnp_pon_masked_write_backup(pon, cfg->s2_cntl2_addr, QPNP_PON_S2_CNTL_EN, 0); if (rc) Loading Loading @@ -1847,7 +1916,7 @@ qpnp_pon_uvlo_dload_set(const char *val, const struct kernel_param *kp) reg = *(bool *)kp->arg ? QPNP_PON_UVLO_DLOAD_EN : 0; return qpnp_pon_masked_write(pon, QPNP_PON_XVDD_RB_SPARE(pon), return qpnp_pon_masked_write_backup(pon, QPNP_PON_XVDD_RB_SPARE(pon), QPNP_PON_UVLO_DLOAD_EN, reg); } Loading Loading @@ -1970,12 +2039,12 @@ static int qpnp_pon_configure_s3_reset(struct qpnp_pon *pon) debounce = ilog2(debounce); /* S3 debounce is a SEC_ACCESS register */ rc = qpnp_pon_masked_write(pon, QPNP_PON_SEC_ACCESS(pon), rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_SEC_ACCESS(pon), 0xFF, QPNP_PON_SEC_UNLOCK); if (rc) return rc; rc = qpnp_pon_masked_write(pon, QPNP_PON_S3_DBC_CTL(pon), rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_S3_DBC_CTL(pon), QPNP_PON_S3_DBC_DELAY_MASK, debounce); if (rc) return rc; Loading Loading @@ -2003,7 +2072,7 @@ static int qpnp_pon_configure_s3_reset(struct qpnp_pon *pon) * been configured by the bootloader then this operation will * not have an effect. */ rc = qpnp_pon_masked_write(pon, QPNP_PON_S3_SRC(pon), rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_S3_SRC(pon), QPNP_PON_S3_SRC_MASK, src_val); if (rc) return rc; Loading Loading @@ -2224,6 +2293,9 @@ static int qpnp_pon_probe(struct platform_device *pdev) return -EINVAL; } INIT_LIST_HEAD(&pon->restore_regs); mutex_init(&pon->restore_lock); /* Get the total number of pon configurations and regulators */ for_each_available_child_of_node(dev->of_node, node) { if (of_find_property(node, "regulator-name", NULL)) { Loading Loading @@ -2325,10 +2397,60 @@ static int qpnp_pon_remove(struct platform_device *pdev) list_del(&pon->list); spin_unlock_irqrestore(&spon_list_slock, flags); } mutex_destroy(&pon->restore_lock); return 0; } #ifdef CONFIG_PM static int qpnp_pon_restore(struct device *dev) { int i, rc = 0; struct qpnp_pon_config *cfg; struct qpnp_pon *pon = dev_get_drvdata(dev); struct pon_reg *pos = NULL; list_for_each_entry(pos, &pon->restore_regs, list) { rc = regmap_write(pon->regmap, pos->addr, pos->val); if (rc < 0) { dev_err(dev, "Failed to restore reg addr=0x%04X rc=%d\n", pos->addr, rc); return rc; } } for (i = 0; i < pon->num_pon_config; i++) { cfg = &pon->pon_cfg[i]; rc = qpnp_pon_request_irqs(pon, cfg); if (rc < 0) return rc; } return rc; } static int qpnp_pon_freeze(struct device *dev) { int i, rc = 0; struct qpnp_pon_config *cfg; struct qpnp_pon *pon = dev_get_drvdata(dev); for (i = 0; i < pon->num_pon_config; i++) { cfg = &pon->pon_cfg[i]; rc = qpnp_pon_free_irqs(pon, cfg); if (rc < 0) return rc; } return rc; } static const struct dev_pm_ops qpnp_pon_pm_ops = { .freeze = qpnp_pon_freeze, .restore = qpnp_pon_restore, }; #endif static const struct of_device_id qpnp_pon_match_table[] = { { .compatible = "qcom,qpnp-power-on" }, {} Loading @@ -2338,6 +2460,9 @@ static struct platform_driver qpnp_pon_driver = { .driver = { .name = "qcom,qpnp-power-on", .of_match_table = qpnp_pon_match_table, #ifdef CONFIG_PM .pm = &qpnp_pon_pm_ops, #endif }, .probe = qpnp_pon_probe, .remove = qpnp_pon_remove, Loading Loading
drivers/input/misc/qpnp-power-on.c +143 −18 Original line number Diff line number Diff line /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. /* Copyright (c) 2012-2019, The Linux Foundation. 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 version 2 and Loading Loading @@ -167,6 +167,12 @@ enum pon_type { PON_KPDPWR_RESIN = PON_POWER_ON_TYPE_KPDPWR_RESIN, }; struct pon_reg { unsigned int val; u16 addr; struct list_head list; }; struct qpnp_pon_config { u32 pon_type; u32 support_reset; Loading Loading @@ -199,7 +205,9 @@ struct qpnp_pon { struct input_dev *pon_input; struct qpnp_pon_config *pon_cfg; struct pon_regulator *pon_reg_cfg; struct list_head restore_regs; struct list_head list; struct mutex restore_lock; struct delayed_work bark_work; struct dentry *debugfs; u16 base; Loading Loading @@ -305,6 +313,42 @@ static const char * const qpnp_poff_reason[] = { [39] = "Triggered from S3_RESET_KPDPWR_ANDOR_RESIN", }; static int qpnp_pon_store_reg(struct qpnp_pon *pon, u16 addr) { int rc; unsigned int val; struct pon_reg *reg, *pos = NULL; mutex_lock(&pon->restore_lock); rc = regmap_read(pon->regmap, addr, &val); if (rc < 0) { dev_info(pon->dev, "Register read failed, addr=0x%04X, rc=%d\n", addr, rc); } else { list_for_each_entry(pos, &pon->restore_regs, list) { if (pos->addr == addr) { pos->val = val; goto done; } } reg = devm_kzalloc(pon->dev, sizeof(*reg), GFP_KERNEL); if (!reg) { rc = -ENOMEM; goto done; } reg->addr = addr; reg->val = val; INIT_LIST_HEAD(®->list); list_add_tail(®->list, &pon->restore_regs); } done: mutex_unlock(&pon->restore_lock); return rc; } static int qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) { Loading @@ -317,6 +361,18 @@ qpnp_pon_masked_write(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) return rc; } static int qpnp_pon_masked_write_backup(struct qpnp_pon *pon, u16 addr, u8 mask, u8 val) { int rc; rc = qpnp_pon_masked_write(pon, addr, mask, val); if (rc < 0) return rc; return qpnp_pon_store_reg(pon, addr); } static int qpnp_pon_read(struct qpnp_pon *pon, u16 addr, unsigned int *val) { int rc; Loading Loading @@ -416,7 +472,7 @@ static int qpnp_pon_set_dbc(struct qpnp_pon *pon, u32 delay) } val = ilog2(val); rc = qpnp_pon_masked_write(pon, QPNP_PON_DBC_CTL(pon), rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_DBC_CTL(pon), QPNP_PON_DBC_DELAY_MASK(pon), val); if (!rc) pon->dbc_time_us = delay; Loading Loading @@ -794,10 +850,10 @@ int qpnp_pon_trigger_config(enum pon_trigger_source pon_src, bool enable) } if (is_pon_gen2(pon) && pon_src == PON_SMPL) rc = qpnp_pon_masked_write(pon, QPNP_PON_SMPL_CTL(pon), rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_SMPL_CTL(pon), QPNP_PON_SMPL_EN, enable ? QPNP_PON_SMPL_EN : 0); else rc = qpnp_pon_masked_write(pon, QPNP_PON_TRIGGER_EN(pon), rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_TRIGGER_EN(pon), BIT(pon_src), enable ? BIT(pon_src) : 0); return rc; Loading Loading @@ -834,6 +890,7 @@ static int qpnp_pon_store_and_clear_warm_reset(struct qpnp_pon *pon) QPNP_PON_WARM_RESET_REASON1(pon), rc); return rc; } qpnp_pon_store_reg(pon, QPNP_PON_WARM_RESET_REASON1(pon)); } return 0; Loading Loading @@ -1122,8 +1179,8 @@ static int qpnp_config_pull(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) return -EINVAL; } return qpnp_pon_masked_write(pon, QPNP_PON_PULL_CTL(pon), pull_bit, cfg->pull_up ? pull_bit : 0); return qpnp_pon_masked_write_backup(pon, QPNP_PON_PULL_CTL(pon), pull_bit, cfg->pull_up ? pull_bit : 0); } static int qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) Loading @@ -1150,8 +1207,8 @@ static int qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) } /* Disable S2 reset */ rc = qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr, QPNP_PON_S2_CNTL_EN, 0); rc = qpnp_pon_masked_write_backup(pon, cfg->s2_cntl2_addr, QPNP_PON_S2_CNTL_EN, 0); if (rc) return rc; Loading @@ -1162,7 +1219,7 @@ static int qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) if (cfg->s1_timer <= s1_delay[i]) break; } rc = qpnp_pon_masked_write(pon, s1_timer_addr, rc = qpnp_pon_masked_write_backup(pon, s1_timer_addr, QPNP_PON_S1_TIMER_MASK, i); if (rc) return rc; Loading @@ -1173,18 +1230,18 @@ static int qpnp_config_reset(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) i = ilog2(i + 1); } rc = qpnp_pon_masked_write(pon, s2_timer_addr, QPNP_PON_S2_TIMER_MASK, i); rc = qpnp_pon_masked_write_backup(pon, s2_timer_addr, QPNP_PON_S2_TIMER_MASK, i); if (rc) return rc; rc = qpnp_pon_masked_write(pon, cfg->s2_cntl_addr, rc = qpnp_pon_masked_write_backup(pon, cfg->s2_cntl_addr, QPNP_PON_S2_CNTL_TYPE_MASK, (u8)cfg->s2_type); if (rc) return rc; /* Enable S2 reset */ return qpnp_pon_masked_write(pon, cfg->s2_cntl2_addr, return qpnp_pon_masked_write_backup(pon, cfg->s2_cntl2_addr, QPNP_PON_S2_CNTL_EN, QPNP_PON_S2_CNTL_EN); } Loading Loading @@ -1277,6 +1334,18 @@ qpnp_pon_request_irqs(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) return 0; } static int qpnp_pon_free_irqs(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) { if (cfg->state_irq > 0) devm_free_irq(pon->dev, cfg->state_irq, pon); if (cfg->use_bark && cfg->bark_irq > 0) devm_free_irq(pon->dev, cfg->bark_irq, pon); return 0; } static int qpnp_pon_config_input(struct qpnp_pon *pon, struct qpnp_pon_config *cfg) { Loading Loading @@ -1632,7 +1701,7 @@ static int qpnp_pon_config_init(struct qpnp_pon *pon, return rc; } else if (cfg->pon_type != PON_CBLPWR) { /* Disable S2 reset */ rc = qpnp_pon_masked_write(pon, rc = qpnp_pon_masked_write_backup(pon, cfg->s2_cntl2_addr, QPNP_PON_S2_CNTL_EN, 0); if (rc) Loading Loading @@ -1847,7 +1916,7 @@ qpnp_pon_uvlo_dload_set(const char *val, const struct kernel_param *kp) reg = *(bool *)kp->arg ? QPNP_PON_UVLO_DLOAD_EN : 0; return qpnp_pon_masked_write(pon, QPNP_PON_XVDD_RB_SPARE(pon), return qpnp_pon_masked_write_backup(pon, QPNP_PON_XVDD_RB_SPARE(pon), QPNP_PON_UVLO_DLOAD_EN, reg); } Loading Loading @@ -1970,12 +2039,12 @@ static int qpnp_pon_configure_s3_reset(struct qpnp_pon *pon) debounce = ilog2(debounce); /* S3 debounce is a SEC_ACCESS register */ rc = qpnp_pon_masked_write(pon, QPNP_PON_SEC_ACCESS(pon), rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_SEC_ACCESS(pon), 0xFF, QPNP_PON_SEC_UNLOCK); if (rc) return rc; rc = qpnp_pon_masked_write(pon, QPNP_PON_S3_DBC_CTL(pon), rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_S3_DBC_CTL(pon), QPNP_PON_S3_DBC_DELAY_MASK, debounce); if (rc) return rc; Loading Loading @@ -2003,7 +2072,7 @@ static int qpnp_pon_configure_s3_reset(struct qpnp_pon *pon) * been configured by the bootloader then this operation will * not have an effect. */ rc = qpnp_pon_masked_write(pon, QPNP_PON_S3_SRC(pon), rc = qpnp_pon_masked_write_backup(pon, QPNP_PON_S3_SRC(pon), QPNP_PON_S3_SRC_MASK, src_val); if (rc) return rc; Loading Loading @@ -2224,6 +2293,9 @@ static int qpnp_pon_probe(struct platform_device *pdev) return -EINVAL; } INIT_LIST_HEAD(&pon->restore_regs); mutex_init(&pon->restore_lock); /* Get the total number of pon configurations and regulators */ for_each_available_child_of_node(dev->of_node, node) { if (of_find_property(node, "regulator-name", NULL)) { Loading Loading @@ -2325,10 +2397,60 @@ static int qpnp_pon_remove(struct platform_device *pdev) list_del(&pon->list); spin_unlock_irqrestore(&spon_list_slock, flags); } mutex_destroy(&pon->restore_lock); return 0; } #ifdef CONFIG_PM static int qpnp_pon_restore(struct device *dev) { int i, rc = 0; struct qpnp_pon_config *cfg; struct qpnp_pon *pon = dev_get_drvdata(dev); struct pon_reg *pos = NULL; list_for_each_entry(pos, &pon->restore_regs, list) { rc = regmap_write(pon->regmap, pos->addr, pos->val); if (rc < 0) { dev_err(dev, "Failed to restore reg addr=0x%04X rc=%d\n", pos->addr, rc); return rc; } } for (i = 0; i < pon->num_pon_config; i++) { cfg = &pon->pon_cfg[i]; rc = qpnp_pon_request_irqs(pon, cfg); if (rc < 0) return rc; } return rc; } static int qpnp_pon_freeze(struct device *dev) { int i, rc = 0; struct qpnp_pon_config *cfg; struct qpnp_pon *pon = dev_get_drvdata(dev); for (i = 0; i < pon->num_pon_config; i++) { cfg = &pon->pon_cfg[i]; rc = qpnp_pon_free_irqs(pon, cfg); if (rc < 0) return rc; } return rc; } static const struct dev_pm_ops qpnp_pon_pm_ops = { .freeze = qpnp_pon_freeze, .restore = qpnp_pon_restore, }; #endif static const struct of_device_id qpnp_pon_match_table[] = { { .compatible = "qcom,qpnp-power-on" }, {} Loading @@ -2338,6 +2460,9 @@ static struct platform_driver qpnp_pon_driver = { .driver = { .name = "qcom,qpnp-power-on", .of_match_table = qpnp_pon_match_table, #ifdef CONFIG_PM .pm = &qpnp_pon_pm_ops, #endif }, .probe = qpnp_pon_probe, .remove = qpnp_pon_remove, Loading