162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2010-2011, 2020-2021, The Linux Foundation. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2014, Sony Mobile Communications Inc. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/delay.h> 862306a36Sopenharmony_ci#include <linux/errno.h> 962306a36Sopenharmony_ci#include <linux/input.h> 1062306a36Sopenharmony_ci#include <linux/interrupt.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/ktime.h> 1362306a36Sopenharmony_ci#include <linux/log2.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/of.h> 1662306a36Sopenharmony_ci#include <linux/of_address.h> 1762306a36Sopenharmony_ci#include <linux/platform_device.h> 1862306a36Sopenharmony_ci#include <linux/reboot.h> 1962306a36Sopenharmony_ci#include <linux/regmap.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define PON_REV2 0x01 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#define PON_SUBTYPE 0x05 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define PON_SUBTYPE_PRIMARY 0x01 2662306a36Sopenharmony_ci#define PON_SUBTYPE_SECONDARY 0x02 2762306a36Sopenharmony_ci#define PON_SUBTYPE_1REG 0x03 2862306a36Sopenharmony_ci#define PON_SUBTYPE_GEN2_PRIMARY 0x04 2962306a36Sopenharmony_ci#define PON_SUBTYPE_GEN2_SECONDARY 0x05 3062306a36Sopenharmony_ci#define PON_SUBTYPE_GEN3_PBS 0x08 3162306a36Sopenharmony_ci#define PON_SUBTYPE_GEN3_HLOS 0x09 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#define PON_RT_STS 0x10 3462306a36Sopenharmony_ci#define PON_KPDPWR_N_SET BIT(0) 3562306a36Sopenharmony_ci#define PON_RESIN_N_SET BIT(1) 3662306a36Sopenharmony_ci#define PON_GEN3_RESIN_N_SET BIT(6) 3762306a36Sopenharmony_ci#define PON_GEN3_KPDPWR_N_SET BIT(7) 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#define PON_PS_HOLD_RST_CTL 0x5a 4062306a36Sopenharmony_ci#define PON_PS_HOLD_RST_CTL2 0x5b 4162306a36Sopenharmony_ci#define PON_PS_HOLD_ENABLE BIT(7) 4262306a36Sopenharmony_ci#define PON_PS_HOLD_TYPE_MASK 0x0f 4362306a36Sopenharmony_ci#define PON_PS_HOLD_TYPE_WARM_RESET 1 4462306a36Sopenharmony_ci#define PON_PS_HOLD_TYPE_SHUTDOWN 4 4562306a36Sopenharmony_ci#define PON_PS_HOLD_TYPE_HARD_RESET 7 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define PON_PULL_CTL 0x70 4862306a36Sopenharmony_ci#define PON_KPDPWR_PULL_UP BIT(1) 4962306a36Sopenharmony_ci#define PON_RESIN_PULL_UP BIT(0) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define PON_DBC_CTL 0x71 5262306a36Sopenharmony_ci#define PON_DBC_DELAY_MASK_GEN1 0x7 5362306a36Sopenharmony_ci#define PON_DBC_DELAY_MASK_GEN2 0xf 5462306a36Sopenharmony_ci#define PON_DBC_SHIFT_GEN1 6 5562306a36Sopenharmony_ci#define PON_DBC_SHIFT_GEN2 14 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistruct pm8941_data { 5862306a36Sopenharmony_ci unsigned int pull_up_bit; 5962306a36Sopenharmony_ci unsigned int status_bit; 6062306a36Sopenharmony_ci bool supports_ps_hold_poff_config; 6162306a36Sopenharmony_ci bool supports_debounce_config; 6262306a36Sopenharmony_ci bool has_pon_pbs; 6362306a36Sopenharmony_ci const char *name; 6462306a36Sopenharmony_ci const char *phys; 6562306a36Sopenharmony_ci}; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistruct pm8941_pwrkey { 6862306a36Sopenharmony_ci struct device *dev; 6962306a36Sopenharmony_ci int irq; 7062306a36Sopenharmony_ci u32 baseaddr; 7162306a36Sopenharmony_ci u32 pon_pbs_baseaddr; 7262306a36Sopenharmony_ci struct regmap *regmap; 7362306a36Sopenharmony_ci struct input_dev *input; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci unsigned int revision; 7662306a36Sopenharmony_ci unsigned int subtype; 7762306a36Sopenharmony_ci struct notifier_block reboot_notifier; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci u32 code; 8062306a36Sopenharmony_ci u32 sw_debounce_time_us; 8162306a36Sopenharmony_ci ktime_t sw_debounce_end_time; 8262306a36Sopenharmony_ci bool last_status; 8362306a36Sopenharmony_ci const struct pm8941_data *data; 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic int pm8941_reboot_notify(struct notifier_block *nb, 8762306a36Sopenharmony_ci unsigned long code, void *unused) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci struct pm8941_pwrkey *pwrkey = container_of(nb, struct pm8941_pwrkey, 9062306a36Sopenharmony_ci reboot_notifier); 9162306a36Sopenharmony_ci unsigned int enable_reg; 9262306a36Sopenharmony_ci unsigned int reset_type; 9362306a36Sopenharmony_ci int error; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci /* PMICs with revision 0 have the enable bit in same register as ctrl */ 9662306a36Sopenharmony_ci if (pwrkey->revision == 0) 9762306a36Sopenharmony_ci enable_reg = PON_PS_HOLD_RST_CTL; 9862306a36Sopenharmony_ci else 9962306a36Sopenharmony_ci enable_reg = PON_PS_HOLD_RST_CTL2; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci error = regmap_update_bits(pwrkey->regmap, 10262306a36Sopenharmony_ci pwrkey->baseaddr + enable_reg, 10362306a36Sopenharmony_ci PON_PS_HOLD_ENABLE, 10462306a36Sopenharmony_ci 0); 10562306a36Sopenharmony_ci if (error) 10662306a36Sopenharmony_ci dev_err(pwrkey->dev, 10762306a36Sopenharmony_ci "unable to clear ps hold reset enable: %d\n", 10862306a36Sopenharmony_ci error); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* 11162306a36Sopenharmony_ci * Updates of PON_PS_HOLD_ENABLE requires 3 sleep cycles between 11262306a36Sopenharmony_ci * writes. 11362306a36Sopenharmony_ci */ 11462306a36Sopenharmony_ci usleep_range(100, 1000); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci switch (code) { 11762306a36Sopenharmony_ci case SYS_HALT: 11862306a36Sopenharmony_ci case SYS_POWER_OFF: 11962306a36Sopenharmony_ci reset_type = PON_PS_HOLD_TYPE_SHUTDOWN; 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci case SYS_RESTART: 12262306a36Sopenharmony_ci default: 12362306a36Sopenharmony_ci if (reboot_mode == REBOOT_WARM) 12462306a36Sopenharmony_ci reset_type = PON_PS_HOLD_TYPE_WARM_RESET; 12562306a36Sopenharmony_ci else 12662306a36Sopenharmony_ci reset_type = PON_PS_HOLD_TYPE_HARD_RESET; 12762306a36Sopenharmony_ci break; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci error = regmap_update_bits(pwrkey->regmap, 13162306a36Sopenharmony_ci pwrkey->baseaddr + PON_PS_HOLD_RST_CTL, 13262306a36Sopenharmony_ci PON_PS_HOLD_TYPE_MASK, 13362306a36Sopenharmony_ci reset_type); 13462306a36Sopenharmony_ci if (error) 13562306a36Sopenharmony_ci dev_err(pwrkey->dev, "unable to set ps hold reset type: %d\n", 13662306a36Sopenharmony_ci error); 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci error = regmap_update_bits(pwrkey->regmap, 13962306a36Sopenharmony_ci pwrkey->baseaddr + enable_reg, 14062306a36Sopenharmony_ci PON_PS_HOLD_ENABLE, 14162306a36Sopenharmony_ci PON_PS_HOLD_ENABLE); 14262306a36Sopenharmony_ci if (error) 14362306a36Sopenharmony_ci dev_err(pwrkey->dev, "unable to re-set enable: %d\n", error); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return NOTIFY_DONE; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic irqreturn_t pm8941_pwrkey_irq(int irq, void *_data) 14962306a36Sopenharmony_ci{ 15062306a36Sopenharmony_ci struct pm8941_pwrkey *pwrkey = _data; 15162306a36Sopenharmony_ci unsigned int sts; 15262306a36Sopenharmony_ci int err; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci if (pwrkey->sw_debounce_time_us) { 15562306a36Sopenharmony_ci if (ktime_before(ktime_get(), pwrkey->sw_debounce_end_time)) { 15662306a36Sopenharmony_ci dev_dbg(pwrkey->dev, 15762306a36Sopenharmony_ci "ignoring key event received before debounce end %llu us\n", 15862306a36Sopenharmony_ci pwrkey->sw_debounce_end_time); 15962306a36Sopenharmony_ci return IRQ_HANDLED; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci } 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci err = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_RT_STS, &sts); 16462306a36Sopenharmony_ci if (err) 16562306a36Sopenharmony_ci return IRQ_HANDLED; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci sts &= pwrkey->data->status_bit; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (pwrkey->sw_debounce_time_us && !sts) 17062306a36Sopenharmony_ci pwrkey->sw_debounce_end_time = ktime_add_us(ktime_get(), 17162306a36Sopenharmony_ci pwrkey->sw_debounce_time_us); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* 17462306a36Sopenharmony_ci * Simulate a press event in case a release event occurred without a 17562306a36Sopenharmony_ci * corresponding press event. 17662306a36Sopenharmony_ci */ 17762306a36Sopenharmony_ci if (!pwrkey->last_status && !sts) { 17862306a36Sopenharmony_ci input_report_key(pwrkey->input, pwrkey->code, 1); 17962306a36Sopenharmony_ci input_sync(pwrkey->input); 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci pwrkey->last_status = sts; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci input_report_key(pwrkey->input, pwrkey->code, sts); 18462306a36Sopenharmony_ci input_sync(pwrkey->input); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci return IRQ_HANDLED; 18762306a36Sopenharmony_ci} 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_cistatic int pm8941_pwrkey_sw_debounce_init(struct pm8941_pwrkey *pwrkey) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci unsigned int val, addr, mask; 19262306a36Sopenharmony_ci int error; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (pwrkey->data->has_pon_pbs && !pwrkey->pon_pbs_baseaddr) { 19562306a36Sopenharmony_ci dev_err(pwrkey->dev, 19662306a36Sopenharmony_ci "PON_PBS address missing, can't read HW debounce time\n"); 19762306a36Sopenharmony_ci return 0; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci if (pwrkey->pon_pbs_baseaddr) 20162306a36Sopenharmony_ci addr = pwrkey->pon_pbs_baseaddr + PON_DBC_CTL; 20262306a36Sopenharmony_ci else 20362306a36Sopenharmony_ci addr = pwrkey->baseaddr + PON_DBC_CTL; 20462306a36Sopenharmony_ci error = regmap_read(pwrkey->regmap, addr, &val); 20562306a36Sopenharmony_ci if (error) 20662306a36Sopenharmony_ci return error; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci if (pwrkey->subtype >= PON_SUBTYPE_GEN2_PRIMARY) 20962306a36Sopenharmony_ci mask = 0xf; 21062306a36Sopenharmony_ci else 21162306a36Sopenharmony_ci mask = 0x7; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci pwrkey->sw_debounce_time_us = 21462306a36Sopenharmony_ci 2 * USEC_PER_SEC / (1 << (mask - (val & mask))); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci dev_dbg(pwrkey->dev, "SW debounce time = %u us\n", 21762306a36Sopenharmony_ci pwrkey->sw_debounce_time_us); 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci return 0; 22062306a36Sopenharmony_ci} 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_cistatic int pm8941_pwrkey_suspend(struct device *dev) 22362306a36Sopenharmony_ci{ 22462306a36Sopenharmony_ci struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci if (device_may_wakeup(dev)) 22762306a36Sopenharmony_ci enable_irq_wake(pwrkey->irq); 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci return 0; 23062306a36Sopenharmony_ci} 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_cistatic int pm8941_pwrkey_resume(struct device *dev) 23362306a36Sopenharmony_ci{ 23462306a36Sopenharmony_ci struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (device_may_wakeup(dev)) 23762306a36Sopenharmony_ci disable_irq_wake(pwrkey->irq); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return 0; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic DEFINE_SIMPLE_DEV_PM_OPS(pm8941_pwr_key_pm_ops, 24362306a36Sopenharmony_ci pm8941_pwrkey_suspend, pm8941_pwrkey_resume); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistatic int pm8941_pwrkey_probe(struct platform_device *pdev) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci struct pm8941_pwrkey *pwrkey; 24862306a36Sopenharmony_ci bool pull_up; 24962306a36Sopenharmony_ci struct device *parent; 25062306a36Sopenharmony_ci struct device_node *regmap_node; 25162306a36Sopenharmony_ci const __be32 *addr; 25262306a36Sopenharmony_ci u32 req_delay, mask, delay_shift; 25362306a36Sopenharmony_ci int error; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci if (of_property_read_u32(pdev->dev.of_node, "debounce", &req_delay)) 25662306a36Sopenharmony_ci req_delay = 15625; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci if (req_delay > 2000000 || req_delay == 0) { 25962306a36Sopenharmony_ci dev_err(&pdev->dev, "invalid debounce time: %u\n", req_delay); 26062306a36Sopenharmony_ci return -EINVAL; 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci pull_up = of_property_read_bool(pdev->dev.of_node, "bias-pull-up"); 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci pwrkey = devm_kzalloc(&pdev->dev, sizeof(*pwrkey), GFP_KERNEL); 26662306a36Sopenharmony_ci if (!pwrkey) 26762306a36Sopenharmony_ci return -ENOMEM; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci pwrkey->dev = &pdev->dev; 27062306a36Sopenharmony_ci pwrkey->data = of_device_get_match_data(&pdev->dev); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci parent = pdev->dev.parent; 27362306a36Sopenharmony_ci regmap_node = pdev->dev.of_node; 27462306a36Sopenharmony_ci pwrkey->regmap = dev_get_regmap(parent, NULL); 27562306a36Sopenharmony_ci if (!pwrkey->regmap) { 27662306a36Sopenharmony_ci regmap_node = parent->of_node; 27762306a36Sopenharmony_ci /* 27862306a36Sopenharmony_ci * We failed to get regmap for parent. Let's see if we are 27962306a36Sopenharmony_ci * a child of pon node and read regmap and reg from its 28062306a36Sopenharmony_ci * parent. 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_ci pwrkey->regmap = dev_get_regmap(parent->parent, NULL); 28362306a36Sopenharmony_ci if (!pwrkey->regmap) { 28462306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to locate regmap\n"); 28562306a36Sopenharmony_ci return -ENODEV; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci addr = of_get_address(regmap_node, 0, NULL, NULL); 29062306a36Sopenharmony_ci if (!addr) { 29162306a36Sopenharmony_ci dev_err(&pdev->dev, "reg property missing\n"); 29262306a36Sopenharmony_ci return -EINVAL; 29362306a36Sopenharmony_ci } 29462306a36Sopenharmony_ci pwrkey->baseaddr = be32_to_cpup(addr); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci if (pwrkey->data->has_pon_pbs) { 29762306a36Sopenharmony_ci /* PON_PBS base address is optional */ 29862306a36Sopenharmony_ci addr = of_get_address(regmap_node, 1, NULL, NULL); 29962306a36Sopenharmony_ci if (addr) 30062306a36Sopenharmony_ci pwrkey->pon_pbs_baseaddr = be32_to_cpup(addr); 30162306a36Sopenharmony_ci } 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci pwrkey->irq = platform_get_irq(pdev, 0); 30462306a36Sopenharmony_ci if (pwrkey->irq < 0) 30562306a36Sopenharmony_ci return pwrkey->irq; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_REV2, 30862306a36Sopenharmony_ci &pwrkey->revision); 30962306a36Sopenharmony_ci if (error) { 31062306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to read revision: %d\n", error); 31162306a36Sopenharmony_ci return error; 31262306a36Sopenharmony_ci } 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_SUBTYPE, 31562306a36Sopenharmony_ci &pwrkey->subtype); 31662306a36Sopenharmony_ci if (error) { 31762306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to read subtype: %d\n", error); 31862306a36Sopenharmony_ci return error; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci error = of_property_read_u32(pdev->dev.of_node, "linux,code", 32262306a36Sopenharmony_ci &pwrkey->code); 32362306a36Sopenharmony_ci if (error) { 32462306a36Sopenharmony_ci dev_dbg(&pdev->dev, 32562306a36Sopenharmony_ci "no linux,code assuming power (%d)\n", error); 32662306a36Sopenharmony_ci pwrkey->code = KEY_POWER; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci pwrkey->input = devm_input_allocate_device(&pdev->dev); 33062306a36Sopenharmony_ci if (!pwrkey->input) { 33162306a36Sopenharmony_ci dev_dbg(&pdev->dev, "unable to allocate input device\n"); 33262306a36Sopenharmony_ci return -ENOMEM; 33362306a36Sopenharmony_ci } 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci input_set_capability(pwrkey->input, EV_KEY, pwrkey->code); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci pwrkey->input->name = pwrkey->data->name; 33862306a36Sopenharmony_ci pwrkey->input->phys = pwrkey->data->phys; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (pwrkey->data->supports_debounce_config) { 34162306a36Sopenharmony_ci if (pwrkey->subtype >= PON_SUBTYPE_GEN2_PRIMARY) { 34262306a36Sopenharmony_ci mask = PON_DBC_DELAY_MASK_GEN2; 34362306a36Sopenharmony_ci delay_shift = PON_DBC_SHIFT_GEN2; 34462306a36Sopenharmony_ci } else { 34562306a36Sopenharmony_ci mask = PON_DBC_DELAY_MASK_GEN1; 34662306a36Sopenharmony_ci delay_shift = PON_DBC_SHIFT_GEN1; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci req_delay = (req_delay << delay_shift) / USEC_PER_SEC; 35062306a36Sopenharmony_ci req_delay = ilog2(req_delay); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci error = regmap_update_bits(pwrkey->regmap, 35362306a36Sopenharmony_ci pwrkey->baseaddr + PON_DBC_CTL, 35462306a36Sopenharmony_ci mask, 35562306a36Sopenharmony_ci req_delay); 35662306a36Sopenharmony_ci if (error) { 35762306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to set debounce: %d\n", 35862306a36Sopenharmony_ci error); 35962306a36Sopenharmony_ci return error; 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci } 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci error = pm8941_pwrkey_sw_debounce_init(pwrkey); 36462306a36Sopenharmony_ci if (error) 36562306a36Sopenharmony_ci return error; 36662306a36Sopenharmony_ci 36762306a36Sopenharmony_ci if (pwrkey->data->pull_up_bit) { 36862306a36Sopenharmony_ci error = regmap_update_bits(pwrkey->regmap, 36962306a36Sopenharmony_ci pwrkey->baseaddr + PON_PULL_CTL, 37062306a36Sopenharmony_ci pwrkey->data->pull_up_bit, 37162306a36Sopenharmony_ci pull_up ? pwrkey->data->pull_up_bit : 37262306a36Sopenharmony_ci 0); 37362306a36Sopenharmony_ci if (error) { 37462306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to set pull: %d\n", error); 37562306a36Sopenharmony_ci return error; 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci error = devm_request_threaded_irq(&pdev->dev, pwrkey->irq, 38062306a36Sopenharmony_ci NULL, pm8941_pwrkey_irq, 38162306a36Sopenharmony_ci IRQF_ONESHOT, 38262306a36Sopenharmony_ci pwrkey->data->name, pwrkey); 38362306a36Sopenharmony_ci if (error) { 38462306a36Sopenharmony_ci dev_err(&pdev->dev, "failed requesting IRQ: %d\n", error); 38562306a36Sopenharmony_ci return error; 38662306a36Sopenharmony_ci } 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci error = input_register_device(pwrkey->input); 38962306a36Sopenharmony_ci if (error) { 39062306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register input device: %d\n", 39162306a36Sopenharmony_ci error); 39262306a36Sopenharmony_ci return error; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (pwrkey->data->supports_ps_hold_poff_config) { 39662306a36Sopenharmony_ci pwrkey->reboot_notifier.notifier_call = pm8941_reboot_notify; 39762306a36Sopenharmony_ci error = register_reboot_notifier(&pwrkey->reboot_notifier); 39862306a36Sopenharmony_ci if (error) { 39962306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register reboot notifier: %d\n", 40062306a36Sopenharmony_ci error); 40162306a36Sopenharmony_ci return error; 40262306a36Sopenharmony_ci } 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci platform_set_drvdata(pdev, pwrkey); 40662306a36Sopenharmony_ci device_init_wakeup(&pdev->dev, 1); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci return 0; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic int pm8941_pwrkey_remove(struct platform_device *pdev) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct pm8941_pwrkey *pwrkey = platform_get_drvdata(pdev); 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (pwrkey->data->supports_ps_hold_poff_config) 41662306a36Sopenharmony_ci unregister_reboot_notifier(&pwrkey->reboot_notifier); 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci return 0; 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic const struct pm8941_data pwrkey_data = { 42262306a36Sopenharmony_ci .pull_up_bit = PON_KPDPWR_PULL_UP, 42362306a36Sopenharmony_ci .status_bit = PON_KPDPWR_N_SET, 42462306a36Sopenharmony_ci .name = "pm8941_pwrkey", 42562306a36Sopenharmony_ci .phys = "pm8941_pwrkey/input0", 42662306a36Sopenharmony_ci .supports_ps_hold_poff_config = true, 42762306a36Sopenharmony_ci .supports_debounce_config = true, 42862306a36Sopenharmony_ci .has_pon_pbs = false, 42962306a36Sopenharmony_ci}; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic const struct pm8941_data resin_data = { 43262306a36Sopenharmony_ci .pull_up_bit = PON_RESIN_PULL_UP, 43362306a36Sopenharmony_ci .status_bit = PON_RESIN_N_SET, 43462306a36Sopenharmony_ci .name = "pm8941_resin", 43562306a36Sopenharmony_ci .phys = "pm8941_resin/input0", 43662306a36Sopenharmony_ci .supports_ps_hold_poff_config = true, 43762306a36Sopenharmony_ci .supports_debounce_config = true, 43862306a36Sopenharmony_ci .has_pon_pbs = false, 43962306a36Sopenharmony_ci}; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic const struct pm8941_data pon_gen3_pwrkey_data = { 44262306a36Sopenharmony_ci .status_bit = PON_GEN3_KPDPWR_N_SET, 44362306a36Sopenharmony_ci .name = "pmic_pwrkey", 44462306a36Sopenharmony_ci .phys = "pmic_pwrkey/input0", 44562306a36Sopenharmony_ci .supports_ps_hold_poff_config = false, 44662306a36Sopenharmony_ci .supports_debounce_config = false, 44762306a36Sopenharmony_ci .has_pon_pbs = true, 44862306a36Sopenharmony_ci}; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic const struct pm8941_data pon_gen3_resin_data = { 45162306a36Sopenharmony_ci .status_bit = PON_GEN3_RESIN_N_SET, 45262306a36Sopenharmony_ci .name = "pmic_resin", 45362306a36Sopenharmony_ci .phys = "pmic_resin/input0", 45462306a36Sopenharmony_ci .supports_ps_hold_poff_config = false, 45562306a36Sopenharmony_ci .supports_debounce_config = false, 45662306a36Sopenharmony_ci .has_pon_pbs = true, 45762306a36Sopenharmony_ci}; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic const struct of_device_id pm8941_pwr_key_id_table[] = { 46062306a36Sopenharmony_ci { .compatible = "qcom,pm8941-pwrkey", .data = &pwrkey_data }, 46162306a36Sopenharmony_ci { .compatible = "qcom,pm8941-resin", .data = &resin_data }, 46262306a36Sopenharmony_ci { .compatible = "qcom,pmk8350-pwrkey", .data = &pon_gen3_pwrkey_data }, 46362306a36Sopenharmony_ci { .compatible = "qcom,pmk8350-resin", .data = &pon_gen3_resin_data }, 46462306a36Sopenharmony_ci { } 46562306a36Sopenharmony_ci}; 46662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, pm8941_pwr_key_id_table); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic struct platform_driver pm8941_pwrkey_driver = { 46962306a36Sopenharmony_ci .probe = pm8941_pwrkey_probe, 47062306a36Sopenharmony_ci .remove = pm8941_pwrkey_remove, 47162306a36Sopenharmony_ci .driver = { 47262306a36Sopenharmony_ci .name = "pm8941-pwrkey", 47362306a36Sopenharmony_ci .pm = pm_sleep_ptr(&pm8941_pwr_key_pm_ops), 47462306a36Sopenharmony_ci .of_match_table = of_match_ptr(pm8941_pwr_key_id_table), 47562306a36Sopenharmony_ci }, 47662306a36Sopenharmony_ci}; 47762306a36Sopenharmony_cimodule_platform_driver(pm8941_pwrkey_driver); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ciMODULE_DESCRIPTION("PM8941 Power Key driver"); 48062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 481