cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

pm8941-pwrkey.c (11946B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2010-2011, 2020-2021, The Linux Foundation. All rights reserved.
      4 * Copyright (c) 2014, Sony Mobile Communications Inc.
      5 */
      6
      7#include <linux/delay.h>
      8#include <linux/errno.h>
      9#include <linux/input.h>
     10#include <linux/interrupt.h>
     11#include <linux/kernel.h>
     12#include <linux/ktime.h>
     13#include <linux/log2.h>
     14#include <linux/module.h>
     15#include <linux/of.h>
     16#include <linux/of_address.h>
     17#include <linux/of_device.h>
     18#include <linux/platform_device.h>
     19#include <linux/reboot.h>
     20#include <linux/regmap.h>
     21
     22#define PON_REV2			0x01
     23
     24#define PON_SUBTYPE			0x05
     25
     26#define PON_SUBTYPE_PRIMARY		0x01
     27#define PON_SUBTYPE_SECONDARY		0x02
     28#define PON_SUBTYPE_1REG		0x03
     29#define PON_SUBTYPE_GEN2_PRIMARY	0x04
     30#define PON_SUBTYPE_GEN2_SECONDARY	0x05
     31#define PON_SUBTYPE_GEN3_PBS		0x08
     32#define PON_SUBTYPE_GEN3_HLOS		0x09
     33
     34#define PON_RT_STS			0x10
     35#define  PON_KPDPWR_N_SET		BIT(0)
     36#define  PON_RESIN_N_SET		BIT(1)
     37#define  PON_GEN3_RESIN_N_SET		BIT(6)
     38#define  PON_GEN3_KPDPWR_N_SET		BIT(7)
     39
     40#define PON_PS_HOLD_RST_CTL		0x5a
     41#define PON_PS_HOLD_RST_CTL2		0x5b
     42#define  PON_PS_HOLD_ENABLE		BIT(7)
     43#define  PON_PS_HOLD_TYPE_MASK		0x0f
     44#define  PON_PS_HOLD_TYPE_WARM_RESET	1
     45#define  PON_PS_HOLD_TYPE_SHUTDOWN	4
     46#define  PON_PS_HOLD_TYPE_HARD_RESET	7
     47
     48#define PON_PULL_CTL			0x70
     49#define  PON_KPDPWR_PULL_UP		BIT(1)
     50#define  PON_RESIN_PULL_UP		BIT(0)
     51
     52#define PON_DBC_CTL			0x71
     53#define  PON_DBC_DELAY_MASK		0x7
     54
     55struct pm8941_data {
     56	unsigned int	pull_up_bit;
     57	unsigned int	status_bit;
     58	bool		supports_ps_hold_poff_config;
     59	bool		supports_debounce_config;
     60	bool		has_pon_pbs;
     61	const char	*name;
     62	const char	*phys;
     63};
     64
     65struct pm8941_pwrkey {
     66	struct device *dev;
     67	int irq;
     68	u32 baseaddr;
     69	u32 pon_pbs_baseaddr;
     70	struct regmap *regmap;
     71	struct input_dev *input;
     72
     73	unsigned int revision;
     74	unsigned int subtype;
     75	struct notifier_block reboot_notifier;
     76
     77	u32 code;
     78	u32 sw_debounce_time_us;
     79	ktime_t sw_debounce_end_time;
     80	bool last_status;
     81	const struct pm8941_data *data;
     82};
     83
     84static int pm8941_reboot_notify(struct notifier_block *nb,
     85				unsigned long code, void *unused)
     86{
     87	struct pm8941_pwrkey *pwrkey = container_of(nb, struct pm8941_pwrkey,
     88						    reboot_notifier);
     89	unsigned int enable_reg;
     90	unsigned int reset_type;
     91	int error;
     92
     93	/* PMICs with revision 0 have the enable bit in same register as ctrl */
     94	if (pwrkey->revision == 0)
     95		enable_reg = PON_PS_HOLD_RST_CTL;
     96	else
     97		enable_reg = PON_PS_HOLD_RST_CTL2;
     98
     99	error = regmap_update_bits(pwrkey->regmap,
    100				   pwrkey->baseaddr + enable_reg,
    101				   PON_PS_HOLD_ENABLE,
    102				   0);
    103	if (error)
    104		dev_err(pwrkey->dev,
    105			"unable to clear ps hold reset enable: %d\n",
    106			error);
    107
    108	/*
    109	 * Updates of PON_PS_HOLD_ENABLE requires 3 sleep cycles between
    110	 * writes.
    111	 */
    112	usleep_range(100, 1000);
    113
    114	switch (code) {
    115	case SYS_HALT:
    116	case SYS_POWER_OFF:
    117		reset_type = PON_PS_HOLD_TYPE_SHUTDOWN;
    118		break;
    119	case SYS_RESTART:
    120	default:
    121		if (reboot_mode == REBOOT_WARM)
    122			reset_type = PON_PS_HOLD_TYPE_WARM_RESET;
    123		else
    124			reset_type = PON_PS_HOLD_TYPE_HARD_RESET;
    125		break;
    126	}
    127
    128	error = regmap_update_bits(pwrkey->regmap,
    129				   pwrkey->baseaddr + PON_PS_HOLD_RST_CTL,
    130				   PON_PS_HOLD_TYPE_MASK,
    131				   reset_type);
    132	if (error)
    133		dev_err(pwrkey->dev, "unable to set ps hold reset type: %d\n",
    134			error);
    135
    136	error = regmap_update_bits(pwrkey->regmap,
    137				   pwrkey->baseaddr + enable_reg,
    138				   PON_PS_HOLD_ENABLE,
    139				   PON_PS_HOLD_ENABLE);
    140	if (error)
    141		dev_err(pwrkey->dev, "unable to re-set enable: %d\n", error);
    142
    143	return NOTIFY_DONE;
    144}
    145
    146static irqreturn_t pm8941_pwrkey_irq(int irq, void *_data)
    147{
    148	struct pm8941_pwrkey *pwrkey = _data;
    149	unsigned int sts;
    150	int err;
    151
    152	if (pwrkey->sw_debounce_time_us) {
    153		if (ktime_before(ktime_get(), pwrkey->sw_debounce_end_time)) {
    154			dev_dbg(pwrkey->dev,
    155				"ignoring key event received before debounce end %llu us\n",
    156				pwrkey->sw_debounce_end_time);
    157			return IRQ_HANDLED;
    158		}
    159	}
    160
    161	err = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_RT_STS, &sts);
    162	if (err)
    163		return IRQ_HANDLED;
    164
    165	sts &= pwrkey->data->status_bit;
    166
    167	if (pwrkey->sw_debounce_time_us && !sts)
    168		pwrkey->sw_debounce_end_time = ktime_add_us(ktime_get(),
    169						pwrkey->sw_debounce_time_us);
    170
    171	/*
    172	 * Simulate a press event in case a release event occurred without a
    173	 * corresponding press event.
    174	 */
    175	if (!pwrkey->last_status && !sts) {
    176		input_report_key(pwrkey->input, pwrkey->code, 1);
    177		input_sync(pwrkey->input);
    178	}
    179	pwrkey->last_status = sts;
    180
    181	input_report_key(pwrkey->input, pwrkey->code, sts);
    182	input_sync(pwrkey->input);
    183
    184	return IRQ_HANDLED;
    185}
    186
    187static int pm8941_pwrkey_sw_debounce_init(struct pm8941_pwrkey *pwrkey)
    188{
    189	unsigned int val, addr, mask;
    190	int error;
    191
    192	if (pwrkey->data->has_pon_pbs && !pwrkey->pon_pbs_baseaddr) {
    193		dev_err(pwrkey->dev,
    194			"PON_PBS address missing, can't read HW debounce time\n");
    195		return 0;
    196	}
    197
    198	if (pwrkey->pon_pbs_baseaddr)
    199		addr = pwrkey->pon_pbs_baseaddr + PON_DBC_CTL;
    200	else
    201		addr = pwrkey->baseaddr + PON_DBC_CTL;
    202	error = regmap_read(pwrkey->regmap, addr, &val);
    203	if (error)
    204		return error;
    205
    206	if (pwrkey->subtype >= PON_SUBTYPE_GEN2_PRIMARY)
    207		mask = 0xf;
    208	else
    209		mask = 0x7;
    210
    211	pwrkey->sw_debounce_time_us =
    212		2 * USEC_PER_SEC / (1 << (mask - (val & mask)));
    213
    214	dev_dbg(pwrkey->dev, "SW debounce time = %u us\n",
    215		pwrkey->sw_debounce_time_us);
    216
    217	return 0;
    218}
    219
    220static int __maybe_unused pm8941_pwrkey_suspend(struct device *dev)
    221{
    222	struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev);
    223
    224	if (device_may_wakeup(dev))
    225		enable_irq_wake(pwrkey->irq);
    226
    227	return 0;
    228}
    229
    230static int __maybe_unused pm8941_pwrkey_resume(struct device *dev)
    231{
    232	struct pm8941_pwrkey *pwrkey = dev_get_drvdata(dev);
    233
    234	if (device_may_wakeup(dev))
    235		disable_irq_wake(pwrkey->irq);
    236
    237	return 0;
    238}
    239
    240static SIMPLE_DEV_PM_OPS(pm8941_pwr_key_pm_ops,
    241			 pm8941_pwrkey_suspend, pm8941_pwrkey_resume);
    242
    243static int pm8941_pwrkey_probe(struct platform_device *pdev)
    244{
    245	struct pm8941_pwrkey *pwrkey;
    246	bool pull_up;
    247	struct device *parent;
    248	struct device_node *regmap_node;
    249	const __be32 *addr;
    250	u32 req_delay;
    251	int error;
    252
    253	if (of_property_read_u32(pdev->dev.of_node, "debounce", &req_delay))
    254		req_delay = 15625;
    255
    256	if (req_delay > 2000000 || req_delay == 0) {
    257		dev_err(&pdev->dev, "invalid debounce time: %u\n", req_delay);
    258		return -EINVAL;
    259	}
    260
    261	pull_up = of_property_read_bool(pdev->dev.of_node, "bias-pull-up");
    262
    263	pwrkey = devm_kzalloc(&pdev->dev, sizeof(*pwrkey), GFP_KERNEL);
    264	if (!pwrkey)
    265		return -ENOMEM;
    266
    267	pwrkey->dev = &pdev->dev;
    268	pwrkey->data = of_device_get_match_data(&pdev->dev);
    269
    270	parent = pdev->dev.parent;
    271	regmap_node = pdev->dev.of_node;
    272	pwrkey->regmap = dev_get_regmap(parent, NULL);
    273	if (!pwrkey->regmap) {
    274		regmap_node = parent->of_node;
    275		/*
    276		 * We failed to get regmap for parent. Let's see if we are
    277		 * a child of pon node and read regmap and reg from its
    278		 * parent.
    279		 */
    280		pwrkey->regmap = dev_get_regmap(parent->parent, NULL);
    281		if (!pwrkey->regmap) {
    282			dev_err(&pdev->dev, "failed to locate regmap\n");
    283			return -ENODEV;
    284		}
    285	}
    286
    287	addr = of_get_address(regmap_node, 0, NULL, NULL);
    288	if (!addr) {
    289		dev_err(&pdev->dev, "reg property missing\n");
    290		return -EINVAL;
    291	}
    292	pwrkey->baseaddr = be32_to_cpup(addr);
    293
    294	if (pwrkey->data->has_pon_pbs) {
    295		/* PON_PBS base address is optional */
    296		addr = of_get_address(regmap_node, 1, NULL, NULL);
    297		if (addr)
    298			pwrkey->pon_pbs_baseaddr = be32_to_cpup(addr);
    299	}
    300
    301	pwrkey->irq = platform_get_irq(pdev, 0);
    302	if (pwrkey->irq < 0)
    303		return pwrkey->irq;
    304
    305	error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_REV2,
    306			    &pwrkey->revision);
    307	if (error) {
    308		dev_err(&pdev->dev, "failed to read revision: %d\n", error);
    309		return error;
    310	}
    311
    312	error = regmap_read(pwrkey->regmap, pwrkey->baseaddr + PON_SUBTYPE,
    313			    &pwrkey->subtype);
    314	if (error) {
    315		dev_err(&pdev->dev, "failed to read subtype: %d\n", error);
    316		return error;
    317	}
    318
    319	error = of_property_read_u32(pdev->dev.of_node, "linux,code",
    320				     &pwrkey->code);
    321	if (error) {
    322		dev_dbg(&pdev->dev,
    323			"no linux,code assuming power (%d)\n", error);
    324		pwrkey->code = KEY_POWER;
    325	}
    326
    327	pwrkey->input = devm_input_allocate_device(&pdev->dev);
    328	if (!pwrkey->input) {
    329		dev_dbg(&pdev->dev, "unable to allocate input device\n");
    330		return -ENOMEM;
    331	}
    332
    333	input_set_capability(pwrkey->input, EV_KEY, pwrkey->code);
    334
    335	pwrkey->input->name = pwrkey->data->name;
    336	pwrkey->input->phys = pwrkey->data->phys;
    337
    338	if (pwrkey->data->supports_debounce_config) {
    339		req_delay = (req_delay << 6) / USEC_PER_SEC;
    340		req_delay = ilog2(req_delay);
    341
    342		error = regmap_update_bits(pwrkey->regmap,
    343					   pwrkey->baseaddr + PON_DBC_CTL,
    344					   PON_DBC_DELAY_MASK,
    345					   req_delay);
    346		if (error) {
    347			dev_err(&pdev->dev, "failed to set debounce: %d\n",
    348				error);
    349			return error;
    350		}
    351	}
    352
    353	error = pm8941_pwrkey_sw_debounce_init(pwrkey);
    354	if (error)
    355		return error;
    356
    357	if (pwrkey->data->pull_up_bit) {
    358		error = regmap_update_bits(pwrkey->regmap,
    359					   pwrkey->baseaddr + PON_PULL_CTL,
    360					   pwrkey->data->pull_up_bit,
    361					   pull_up ? pwrkey->data->pull_up_bit :
    362						     0);
    363		if (error) {
    364			dev_err(&pdev->dev, "failed to set pull: %d\n", error);
    365			return error;
    366		}
    367	}
    368
    369	error = devm_request_threaded_irq(&pdev->dev, pwrkey->irq,
    370					  NULL, pm8941_pwrkey_irq,
    371					  IRQF_ONESHOT,
    372					  pwrkey->data->name, pwrkey);
    373	if (error) {
    374		dev_err(&pdev->dev, "failed requesting IRQ: %d\n", error);
    375		return error;
    376	}
    377
    378	error = input_register_device(pwrkey->input);
    379	if (error) {
    380		dev_err(&pdev->dev, "failed to register input device: %d\n",
    381			error);
    382		return error;
    383	}
    384
    385	if (pwrkey->data->supports_ps_hold_poff_config) {
    386		pwrkey->reboot_notifier.notifier_call = pm8941_reboot_notify;
    387		error = register_reboot_notifier(&pwrkey->reboot_notifier);
    388		if (error) {
    389			dev_err(&pdev->dev, "failed to register reboot notifier: %d\n",
    390				error);
    391			return error;
    392		}
    393	}
    394
    395	platform_set_drvdata(pdev, pwrkey);
    396	device_init_wakeup(&pdev->dev, 1);
    397
    398	return 0;
    399}
    400
    401static int pm8941_pwrkey_remove(struct platform_device *pdev)
    402{
    403	struct pm8941_pwrkey *pwrkey = platform_get_drvdata(pdev);
    404
    405	if (pwrkey->data->supports_ps_hold_poff_config)
    406		unregister_reboot_notifier(&pwrkey->reboot_notifier);
    407
    408	return 0;
    409}
    410
    411static const struct pm8941_data pwrkey_data = {
    412	.pull_up_bit = PON_KPDPWR_PULL_UP,
    413	.status_bit = PON_KPDPWR_N_SET,
    414	.name = "pm8941_pwrkey",
    415	.phys = "pm8941_pwrkey/input0",
    416	.supports_ps_hold_poff_config = true,
    417	.supports_debounce_config = true,
    418	.has_pon_pbs = false,
    419};
    420
    421static const struct pm8941_data resin_data = {
    422	.pull_up_bit = PON_RESIN_PULL_UP,
    423	.status_bit = PON_RESIN_N_SET,
    424	.name = "pm8941_resin",
    425	.phys = "pm8941_resin/input0",
    426	.supports_ps_hold_poff_config = true,
    427	.supports_debounce_config = true,
    428	.has_pon_pbs = false,
    429};
    430
    431static const struct pm8941_data pon_gen3_pwrkey_data = {
    432	.status_bit = PON_GEN3_KPDPWR_N_SET,
    433	.name = "pmic_pwrkey",
    434	.phys = "pmic_pwrkey/input0",
    435	.supports_ps_hold_poff_config = false,
    436	.supports_debounce_config = false,
    437	.has_pon_pbs = true,
    438};
    439
    440static const struct pm8941_data pon_gen3_resin_data = {
    441	.status_bit = PON_GEN3_RESIN_N_SET,
    442	.name = "pmic_resin",
    443	.phys = "pmic_resin/input0",
    444	.supports_ps_hold_poff_config = false,
    445	.supports_debounce_config = false,
    446	.has_pon_pbs = true,
    447};
    448
    449static const struct of_device_id pm8941_pwr_key_id_table[] = {
    450	{ .compatible = "qcom,pm8941-pwrkey", .data = &pwrkey_data },
    451	{ .compatible = "qcom,pm8941-resin", .data = &resin_data },
    452	{ .compatible = "qcom,pmk8350-pwrkey", .data = &pon_gen3_pwrkey_data },
    453	{ .compatible = "qcom,pmk8350-resin", .data = &pon_gen3_resin_data },
    454	{ }
    455};
    456MODULE_DEVICE_TABLE(of, pm8941_pwr_key_id_table);
    457
    458static struct platform_driver pm8941_pwrkey_driver = {
    459	.probe = pm8941_pwrkey_probe,
    460	.remove = pm8941_pwrkey_remove,
    461	.driver = {
    462		.name = "pm8941-pwrkey",
    463		.pm = &pm8941_pwr_key_pm_ops,
    464		.of_match_table = of_match_ptr(pm8941_pwr_key_id_table),
    465	},
    466};
    467module_platform_driver(pm8941_pwrkey_driver);
    468
    469MODULE_DESCRIPTION("PM8941 Power Key driver");
    470MODULE_LICENSE("GPL v2");