1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
25179f0ceSSteve Twiss /*
304d7ad83SSteve Twiss  * OnKey device driver for DA9063, DA9062 and DA9061 PMICs
45179f0ceSSteve Twiss  * Copyright (C) 2015  Dialog Semiconductor Ltd.
55179f0ceSSteve Twiss  */
65179f0ceSSteve Twiss 
7dfafa560SChristophe JAILLET #include <linux/devm-helpers.h>
85179f0ceSSteve Twiss #include <linux/module.h>
95179f0ceSSteve Twiss #include <linux/errno.h>
105179f0ceSSteve Twiss #include <linux/input.h>
115179f0ceSSteve Twiss #include <linux/interrupt.h>
125179f0ceSSteve Twiss #include <linux/platform_device.h>
13*d7781232SSamuel Holland #include <linux/pm_wakeirq.h>
145179f0ceSSteve Twiss #include <linux/workqueue.h>
155179f0ceSSteve Twiss #include <linux/regmap.h>
165179f0ceSSteve Twiss #include <linux/of.h>
175179f0ceSSteve Twiss #include <linux/mfd/da9063/core.h>
185179f0ceSSteve Twiss #include <linux/mfd/da9063/registers.h>
19a27b5e0aSS Twiss #include <linux/mfd/da9062/core.h>
20a27b5e0aSS Twiss #include <linux/mfd/da9062/registers.h>
21a27b5e0aSS Twiss 
22a27b5e0aSS Twiss struct da906x_chip_config {
23a27b5e0aSS Twiss 	/* REGS */
24a27b5e0aSS Twiss 	int onkey_status;
25a27b5e0aSS Twiss 	int onkey_pwr_signalling;
26a27b5e0aSS Twiss 	int onkey_fault_log;
27a27b5e0aSS Twiss 	int onkey_shutdown;
28a27b5e0aSS Twiss 	/* MASKS */
29a27b5e0aSS Twiss 	int onkey_nonkey_mask;
30a27b5e0aSS Twiss 	int onkey_nonkey_lock_mask;
31a27b5e0aSS Twiss 	int onkey_key_reset_mask;
32a27b5e0aSS Twiss 	int onkey_shutdown_mask;
33a27b5e0aSS Twiss 	/* NAMES */
34a27b5e0aSS Twiss 	const char *name;
35a27b5e0aSS Twiss };
365179f0ceSSteve Twiss 
375179f0ceSSteve Twiss struct da9063_onkey {
385179f0ceSSteve Twiss 	struct delayed_work work;
395179f0ceSSteve Twiss 	struct input_dev *input;
405179f0ceSSteve Twiss 	struct device *dev;
41a27b5e0aSS Twiss 	struct regmap *regmap;
42a27b5e0aSS Twiss 	const struct da906x_chip_config *config;
43a27b5e0aSS Twiss 	char phys[32];
445179f0ceSSteve Twiss 	bool key_power;
455179f0ceSSteve Twiss };
465179f0ceSSteve Twiss 
47a27b5e0aSS Twiss static const struct da906x_chip_config da9063_regs = {
48a27b5e0aSS Twiss 	/* REGS */
49a27b5e0aSS Twiss 	.onkey_status = DA9063_REG_STATUS_A,
50a27b5e0aSS Twiss 	.onkey_pwr_signalling = DA9063_REG_CONTROL_B,
51a27b5e0aSS Twiss 	.onkey_fault_log = DA9063_REG_FAULT_LOG,
52a27b5e0aSS Twiss 	.onkey_shutdown = DA9063_REG_CONTROL_F,
53a27b5e0aSS Twiss 	/* MASKS */
54a27b5e0aSS Twiss 	.onkey_nonkey_mask = DA9063_NONKEY,
55a27b5e0aSS Twiss 	.onkey_nonkey_lock_mask = DA9063_NONKEY_LOCK,
56a27b5e0aSS Twiss 	.onkey_key_reset_mask = DA9063_KEY_RESET,
57a27b5e0aSS Twiss 	.onkey_shutdown_mask = DA9063_SHUTDOWN,
58a27b5e0aSS Twiss 	/* NAMES */
59a27b5e0aSS Twiss 	.name = DA9063_DRVNAME_ONKEY,
60a27b5e0aSS Twiss };
61a27b5e0aSS Twiss 
62a27b5e0aSS Twiss static const struct da906x_chip_config da9062_regs = {
63a27b5e0aSS Twiss 	/* REGS */
64a27b5e0aSS Twiss 	.onkey_status = DA9062AA_STATUS_A,
65a27b5e0aSS Twiss 	.onkey_pwr_signalling = DA9062AA_CONTROL_B,
66a27b5e0aSS Twiss 	.onkey_fault_log = DA9062AA_FAULT_LOG,
67a27b5e0aSS Twiss 	.onkey_shutdown = DA9062AA_CONTROL_F,
68a27b5e0aSS Twiss 	/* MASKS */
69a27b5e0aSS Twiss 	.onkey_nonkey_mask = DA9062AA_NONKEY_MASK,
70a27b5e0aSS Twiss 	.onkey_nonkey_lock_mask = DA9062AA_NONKEY_LOCK_MASK,
71a27b5e0aSS Twiss 	.onkey_key_reset_mask = DA9062AA_KEY_RESET_MASK,
72a27b5e0aSS Twiss 	.onkey_shutdown_mask = DA9062AA_SHUTDOWN_MASK,
73a27b5e0aSS Twiss 	/* NAMES */
74a27b5e0aSS Twiss 	.name = "da9062-onkey",
75a27b5e0aSS Twiss };
76a27b5e0aSS Twiss 
77a27b5e0aSS Twiss static const struct of_device_id da9063_compatible_reg_id_table[] = {
78a27b5e0aSS Twiss 	{ .compatible = "dlg,da9063-onkey", .data = &da9063_regs },
79a27b5e0aSS Twiss 	{ .compatible = "dlg,da9062-onkey", .data = &da9062_regs },
80a27b5e0aSS Twiss 	{ },
81a27b5e0aSS Twiss };
828dd5e0b3SJavier Martinez Canillas MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table);
83a27b5e0aSS Twiss 
da9063_poll_on(struct work_struct * work)845179f0ceSSteve Twiss static void da9063_poll_on(struct work_struct *work)
855179f0ceSSteve Twiss {
86a27b5e0aSS Twiss 	struct da9063_onkey *onkey = container_of(work,
87a27b5e0aSS Twiss 						struct da9063_onkey,
885179f0ceSSteve Twiss 						work.work);
89a27b5e0aSS Twiss 	const struct da906x_chip_config *config = onkey->config;
905179f0ceSSteve Twiss 	unsigned int val;
915179f0ceSSteve Twiss 	int fault_log = 0;
925179f0ceSSteve Twiss 	bool poll = true;
935179f0ceSSteve Twiss 	int error;
945179f0ceSSteve Twiss 
955179f0ceSSteve Twiss 	/* Poll to see when the pin is released */
96a27b5e0aSS Twiss 	error = regmap_read(onkey->regmap,
97a27b5e0aSS Twiss 			    config->onkey_status,
98a27b5e0aSS Twiss 			    &val);
995179f0ceSSteve Twiss 	if (error) {
1005179f0ceSSteve Twiss 		dev_err(onkey->dev,
1015179f0ceSSteve Twiss 			"Failed to read ON status: %d\n", error);
1025179f0ceSSteve Twiss 		goto err_poll;
1035179f0ceSSteve Twiss 	}
1045179f0ceSSteve Twiss 
105a27b5e0aSS Twiss 	if (!(val & config->onkey_nonkey_mask)) {
106a27b5e0aSS Twiss 		error = regmap_update_bits(onkey->regmap,
107a27b5e0aSS Twiss 					   config->onkey_pwr_signalling,
108a27b5e0aSS Twiss 					   config->onkey_nonkey_lock_mask,
109a27b5e0aSS Twiss 					   0);
1105179f0ceSSteve Twiss 		if (error) {
1115179f0ceSSteve Twiss 			dev_err(onkey->dev,
1125179f0ceSSteve Twiss 				"Failed to reset the Key Delay %d\n", error);
1135179f0ceSSteve Twiss 			goto err_poll;
1145179f0ceSSteve Twiss 		}
1155179f0ceSSteve Twiss 
1165179f0ceSSteve Twiss 		input_report_key(onkey->input, KEY_POWER, 0);
1175179f0ceSSteve Twiss 		input_sync(onkey->input);
1185179f0ceSSteve Twiss 
1195179f0ceSSteve Twiss 		poll = false;
1205179f0ceSSteve Twiss 	}
1215179f0ceSSteve Twiss 
1225179f0ceSSteve Twiss 	/*
1235179f0ceSSteve Twiss 	 * If the fault log KEY_RESET is detected, then clear it
1245179f0ceSSteve Twiss 	 * and shut down the system.
1255179f0ceSSteve Twiss 	 */
126a27b5e0aSS Twiss 	error = regmap_read(onkey->regmap,
127a27b5e0aSS Twiss 			    config->onkey_fault_log,
128a27b5e0aSS Twiss 			    &fault_log);
1295179f0ceSSteve Twiss 	if (error) {
1305179f0ceSSteve Twiss 		dev_warn(&onkey->input->dev,
1315179f0ceSSteve Twiss 			 "Cannot read FAULT_LOG: %d\n", error);
132a27b5e0aSS Twiss 	} else if (fault_log & config->onkey_key_reset_mask) {
133a27b5e0aSS Twiss 		error = regmap_write(onkey->regmap,
134a27b5e0aSS Twiss 				     config->onkey_fault_log,
135a27b5e0aSS Twiss 				     config->onkey_key_reset_mask);
1365179f0ceSSteve Twiss 		if (error) {
1375179f0ceSSteve Twiss 			dev_warn(&onkey->input->dev,
1385179f0ceSSteve Twiss 				 "Cannot reset KEY_RESET fault log: %d\n",
1395179f0ceSSteve Twiss 				 error);
1405179f0ceSSteve Twiss 		} else {
1415179f0ceSSteve Twiss 			/* at this point we do any S/W housekeeping
1425179f0ceSSteve Twiss 			 * and then send shutdown command
1435179f0ceSSteve Twiss 			 */
1445179f0ceSSteve Twiss 			dev_dbg(&onkey->input->dev,
14504d7ad83SSteve Twiss 				"Sending SHUTDOWN to PMIC ...\n");
146a27b5e0aSS Twiss 			error = regmap_write(onkey->regmap,
147a27b5e0aSS Twiss 					     config->onkey_shutdown,
148a27b5e0aSS Twiss 					     config->onkey_shutdown_mask);
1495179f0ceSSteve Twiss 			if (error)
1505179f0ceSSteve Twiss 				dev_err(&onkey->input->dev,
15104d7ad83SSteve Twiss 					"Cannot SHUTDOWN PMIC: %d\n",
1525179f0ceSSteve Twiss 					error);
1535179f0ceSSteve Twiss 		}
1545179f0ceSSteve Twiss 	}
1555179f0ceSSteve Twiss 
1565179f0ceSSteve Twiss err_poll:
1575179f0ceSSteve Twiss 	if (poll)
1585179f0ceSSteve Twiss 		schedule_delayed_work(&onkey->work, msecs_to_jiffies(50));
1595179f0ceSSteve Twiss }
1605179f0ceSSteve Twiss 
da9063_onkey_irq_handler(int irq,void * data)1615179f0ceSSteve Twiss static irqreturn_t da9063_onkey_irq_handler(int irq, void *data)
1625179f0ceSSteve Twiss {
1635179f0ceSSteve Twiss 	struct da9063_onkey *onkey = data;
164a27b5e0aSS Twiss 	const struct da906x_chip_config *config = onkey->config;
1655179f0ceSSteve Twiss 	unsigned int val;
1665179f0ceSSteve Twiss 	int error;
1675179f0ceSSteve Twiss 
168a27b5e0aSS Twiss 	error = regmap_read(onkey->regmap,
169a27b5e0aSS Twiss 			    config->onkey_status,
170a27b5e0aSS Twiss 			    &val);
171a27b5e0aSS Twiss 	if (onkey->key_power && !error && (val & config->onkey_nonkey_mask)) {
1725179f0ceSSteve Twiss 		input_report_key(onkey->input, KEY_POWER, 1);
1735179f0ceSSteve Twiss 		input_sync(onkey->input);
1745179f0ceSSteve Twiss 		schedule_delayed_work(&onkey->work, 0);
175f889beaaSSteve Twiss 		dev_dbg(onkey->dev, "KEY_POWER long press.\n");
1765179f0ceSSteve Twiss 	} else {
177f889beaaSSteve Twiss 		input_report_key(onkey->input, KEY_POWER, 1);
1785179f0ceSSteve Twiss 		input_sync(onkey->input);
179f889beaaSSteve Twiss 		input_report_key(onkey->input, KEY_POWER, 0);
1805179f0ceSSteve Twiss 		input_sync(onkey->input);
181f889beaaSSteve Twiss 		dev_dbg(onkey->dev, "KEY_POWER short press.\n");
1825179f0ceSSteve Twiss 	}
1835179f0ceSSteve Twiss 
1845179f0ceSSteve Twiss 	return IRQ_HANDLED;
1855179f0ceSSteve Twiss }
1865179f0ceSSteve Twiss 
da9063_onkey_probe(struct platform_device * pdev)1875179f0ceSSteve Twiss static int da9063_onkey_probe(struct platform_device *pdev)
1885179f0ceSSteve Twiss {
1895179f0ceSSteve Twiss 	struct da9063_onkey *onkey;
190a27b5e0aSS Twiss 	const struct of_device_id *match;
1915179f0ceSSteve Twiss 	int irq;
1925179f0ceSSteve Twiss 	int error;
1935179f0ceSSteve Twiss 
194a27b5e0aSS Twiss 	match = of_match_node(da9063_compatible_reg_id_table,
195a27b5e0aSS Twiss 			      pdev->dev.of_node);
196a27b5e0aSS Twiss 	if (!match)
197a27b5e0aSS Twiss 		return -ENXIO;
198a27b5e0aSS Twiss 
1995179f0ceSSteve Twiss 	onkey = devm_kzalloc(&pdev->dev, sizeof(struct da9063_onkey),
2005179f0ceSSteve Twiss 			     GFP_KERNEL);
2015179f0ceSSteve Twiss 	if (!onkey) {
2025179f0ceSSteve Twiss 		dev_err(&pdev->dev, "Failed to allocate memory.\n");
2035179f0ceSSteve Twiss 		return -ENOMEM;
2045179f0ceSSteve Twiss 	}
2055179f0ceSSteve Twiss 
206a27b5e0aSS Twiss 	onkey->config = match->data;
2075179f0ceSSteve Twiss 	onkey->dev = &pdev->dev;
208a27b5e0aSS Twiss 
209a27b5e0aSS Twiss 	onkey->regmap = dev_get_regmap(pdev->dev.parent, NULL);
210a27b5e0aSS Twiss 	if (!onkey->regmap) {
211a27b5e0aSS Twiss 		dev_err(&pdev->dev, "Parent regmap unavailable.\n");
212a27b5e0aSS Twiss 		return -ENXIO;
213a27b5e0aSS Twiss 	}
2145179f0ceSSteve Twiss 
2156981a235SWolfram Sang 	onkey->key_power = !of_property_read_bool(pdev->dev.of_node,
2165179f0ceSSteve Twiss 						  "dlg,disable-key-power");
2175179f0ceSSteve Twiss 
2185179f0ceSSteve Twiss 	onkey->input = devm_input_allocate_device(&pdev->dev);
2195179f0ceSSteve Twiss 	if (!onkey->input) {
2205179f0ceSSteve Twiss 		dev_err(&pdev->dev, "Failed to allocated input device.\n");
2215179f0ceSSteve Twiss 		return -ENOMEM;
2225179f0ceSSteve Twiss 	}
2235179f0ceSSteve Twiss 
224a27b5e0aSS Twiss 	onkey->input->name = onkey->config->name;
225a27b5e0aSS Twiss 	snprintf(onkey->phys, sizeof(onkey->phys), "%s/input0",
226a27b5e0aSS Twiss 		 onkey->config->name);
227a27b5e0aSS Twiss 	onkey->input->phys = onkey->phys;
2285179f0ceSSteve Twiss 	onkey->input->dev.parent = &pdev->dev;
2295179f0ceSSteve Twiss 
2305179f0ceSSteve Twiss 	input_set_capability(onkey->input, EV_KEY, KEY_POWER);
2315179f0ceSSteve Twiss 
232dfafa560SChristophe JAILLET 	error = devm_delayed_work_autocancel(&pdev->dev, &onkey->work,
233dfafa560SChristophe JAILLET 					     da9063_poll_on);
2345179f0ceSSteve Twiss 	if (error) {
2355179f0ceSSteve Twiss 		dev_err(&pdev->dev,
2365179f0ceSSteve Twiss 			"Failed to add cancel poll action: %d\n",
2375179f0ceSSteve Twiss 			error);
2385179f0ceSSteve Twiss 		return error;
2395179f0ceSSteve Twiss 	}
2405179f0ceSSteve Twiss 
2415179f0ceSSteve Twiss 	irq = platform_get_irq_byname(pdev, "ONKEY");
2420bec8b7eSStephen Boyd 	if (irq < 0)
2430bec8b7eSStephen Boyd 		return irq;
2445179f0ceSSteve Twiss 
2455179f0ceSSteve Twiss 	error = devm_request_threaded_irq(&pdev->dev, irq,
2465179f0ceSSteve Twiss 					  NULL, da9063_onkey_irq_handler,
2475179f0ceSSteve Twiss 					  IRQF_TRIGGER_LOW | IRQF_ONESHOT,
2485179f0ceSSteve Twiss 					  "ONKEY", onkey);
2495179f0ceSSteve Twiss 	if (error) {
2505179f0ceSSteve Twiss 		dev_err(&pdev->dev,
2515179f0ceSSteve Twiss 			"Failed to request IRQ %d: %d\n", irq, error);
2525179f0ceSSteve Twiss 		return error;
2535179f0ceSSteve Twiss 	}
2545179f0ceSSteve Twiss 
255*d7781232SSamuel Holland 	error = dev_pm_set_wake_irq(&pdev->dev, irq);
256*d7781232SSamuel Holland 	if (error)
257*d7781232SSamuel Holland 		dev_warn(&pdev->dev,
258*d7781232SSamuel Holland 			 "Failed to set IRQ %d as a wake IRQ: %d\n",
259*d7781232SSamuel Holland 			 irq, error);
260*d7781232SSamuel Holland 	else
261*d7781232SSamuel Holland 		device_init_wakeup(&pdev->dev, true);
262*d7781232SSamuel Holland 
2635179f0ceSSteve Twiss 	error = input_register_device(onkey->input);
2645179f0ceSSteve Twiss 	if (error) {
2655179f0ceSSteve Twiss 		dev_err(&pdev->dev,
2665179f0ceSSteve Twiss 			"Failed to register input device: %d\n", error);
2675179f0ceSSteve Twiss 		return error;
2685179f0ceSSteve Twiss 	}
2695179f0ceSSteve Twiss 
2705179f0ceSSteve Twiss 	return 0;
2715179f0ceSSteve Twiss }
2725179f0ceSSteve Twiss 
2735179f0ceSSteve Twiss static struct platform_driver da9063_onkey_driver = {
2745179f0ceSSteve Twiss 	.probe	= da9063_onkey_probe,
2755179f0ceSSteve Twiss 	.driver	= {
2765179f0ceSSteve Twiss 		.name	= DA9063_DRVNAME_ONKEY,
277a27b5e0aSS Twiss 		.of_match_table = da9063_compatible_reg_id_table,
2785179f0ceSSteve Twiss 	},
2795179f0ceSSteve Twiss };
2805179f0ceSSteve Twiss module_platform_driver(da9063_onkey_driver);
2815179f0ceSSteve Twiss 
2825179f0ceSSteve Twiss MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
28304d7ad83SSteve Twiss MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063, DA9062 and DA9061");
2845179f0ceSSteve Twiss MODULE_LICENSE("GPL");
2855179f0ceSSteve Twiss MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY);
286