1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * OnKey device driver for DA9063, DA9062 and DA9061 PMICs 4 * Copyright (C) 2015 Dialog Semiconductor Ltd. 5 */ 6 7 #include <linux/module.h> 8 #include <linux/errno.h> 9 #include <linux/input.h> 10 #include <linux/interrupt.h> 11 #include <linux/platform_device.h> 12 #include <linux/workqueue.h> 13 #include <linux/regmap.h> 14 #include <linux/of.h> 15 #include <linux/mfd/da9063/core.h> 16 #include <linux/mfd/da9063/pdata.h> 17 #include <linux/mfd/da9063/registers.h> 18 #include <linux/mfd/da9062/core.h> 19 #include <linux/mfd/da9062/registers.h> 20 21 struct da906x_chip_config { 22 /* REGS */ 23 int onkey_status; 24 int onkey_pwr_signalling; 25 int onkey_fault_log; 26 int onkey_shutdown; 27 /* MASKS */ 28 int onkey_nonkey_mask; 29 int onkey_nonkey_lock_mask; 30 int onkey_key_reset_mask; 31 int onkey_shutdown_mask; 32 /* NAMES */ 33 const char *name; 34 }; 35 36 struct da9063_onkey { 37 struct delayed_work work; 38 struct input_dev *input; 39 struct device *dev; 40 struct regmap *regmap; 41 const struct da906x_chip_config *config; 42 char phys[32]; 43 bool key_power; 44 }; 45 46 static const struct da906x_chip_config da9063_regs = { 47 /* REGS */ 48 .onkey_status = DA9063_REG_STATUS_A, 49 .onkey_pwr_signalling = DA9063_REG_CONTROL_B, 50 .onkey_fault_log = DA9063_REG_FAULT_LOG, 51 .onkey_shutdown = DA9063_REG_CONTROL_F, 52 /* MASKS */ 53 .onkey_nonkey_mask = DA9063_NONKEY, 54 .onkey_nonkey_lock_mask = DA9063_NONKEY_LOCK, 55 .onkey_key_reset_mask = DA9063_KEY_RESET, 56 .onkey_shutdown_mask = DA9063_SHUTDOWN, 57 /* NAMES */ 58 .name = DA9063_DRVNAME_ONKEY, 59 }; 60 61 static const struct da906x_chip_config da9062_regs = { 62 /* REGS */ 63 .onkey_status = DA9062AA_STATUS_A, 64 .onkey_pwr_signalling = DA9062AA_CONTROL_B, 65 .onkey_fault_log = DA9062AA_FAULT_LOG, 66 .onkey_shutdown = DA9062AA_CONTROL_F, 67 /* MASKS */ 68 .onkey_nonkey_mask = DA9062AA_NONKEY_MASK, 69 .onkey_nonkey_lock_mask = DA9062AA_NONKEY_LOCK_MASK, 70 .onkey_key_reset_mask = DA9062AA_KEY_RESET_MASK, 71 .onkey_shutdown_mask = DA9062AA_SHUTDOWN_MASK, 72 /* NAMES */ 73 .name = "da9062-onkey", 74 }; 75 76 static const struct of_device_id da9063_compatible_reg_id_table[] = { 77 { .compatible = "dlg,da9063-onkey", .data = &da9063_regs }, 78 { .compatible = "dlg,da9062-onkey", .data = &da9062_regs }, 79 { }, 80 }; 81 MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table); 82 83 static void da9063_poll_on(struct work_struct *work) 84 { 85 struct da9063_onkey *onkey = container_of(work, 86 struct da9063_onkey, 87 work.work); 88 const struct da906x_chip_config *config = onkey->config; 89 unsigned int val; 90 int fault_log = 0; 91 bool poll = true; 92 int error; 93 94 /* Poll to see when the pin is released */ 95 error = regmap_read(onkey->regmap, 96 config->onkey_status, 97 &val); 98 if (error) { 99 dev_err(onkey->dev, 100 "Failed to read ON status: %d\n", error); 101 goto err_poll; 102 } 103 104 if (!(val & config->onkey_nonkey_mask)) { 105 error = regmap_update_bits(onkey->regmap, 106 config->onkey_pwr_signalling, 107 config->onkey_nonkey_lock_mask, 108 0); 109 if (error) { 110 dev_err(onkey->dev, 111 "Failed to reset the Key Delay %d\n", error); 112 goto err_poll; 113 } 114 115 input_report_key(onkey->input, KEY_POWER, 0); 116 input_sync(onkey->input); 117 118 poll = false; 119 } 120 121 /* 122 * If the fault log KEY_RESET is detected, then clear it 123 * and shut down the system. 124 */ 125 error = regmap_read(onkey->regmap, 126 config->onkey_fault_log, 127 &fault_log); 128 if (error) { 129 dev_warn(&onkey->input->dev, 130 "Cannot read FAULT_LOG: %d\n", error); 131 } else if (fault_log & config->onkey_key_reset_mask) { 132 error = regmap_write(onkey->regmap, 133 config->onkey_fault_log, 134 config->onkey_key_reset_mask); 135 if (error) { 136 dev_warn(&onkey->input->dev, 137 "Cannot reset KEY_RESET fault log: %d\n", 138 error); 139 } else { 140 /* at this point we do any S/W housekeeping 141 * and then send shutdown command 142 */ 143 dev_dbg(&onkey->input->dev, 144 "Sending SHUTDOWN to PMIC ...\n"); 145 error = regmap_write(onkey->regmap, 146 config->onkey_shutdown, 147 config->onkey_shutdown_mask); 148 if (error) 149 dev_err(&onkey->input->dev, 150 "Cannot SHUTDOWN PMIC: %d\n", 151 error); 152 } 153 } 154 155 err_poll: 156 if (poll) 157 schedule_delayed_work(&onkey->work, msecs_to_jiffies(50)); 158 } 159 160 static irqreturn_t da9063_onkey_irq_handler(int irq, void *data) 161 { 162 struct da9063_onkey *onkey = data; 163 const struct da906x_chip_config *config = onkey->config; 164 unsigned int val; 165 int error; 166 167 error = regmap_read(onkey->regmap, 168 config->onkey_status, 169 &val); 170 if (onkey->key_power && !error && (val & config->onkey_nonkey_mask)) { 171 input_report_key(onkey->input, KEY_POWER, 1); 172 input_sync(onkey->input); 173 schedule_delayed_work(&onkey->work, 0); 174 dev_dbg(onkey->dev, "KEY_POWER long press.\n"); 175 } else { 176 input_report_key(onkey->input, KEY_POWER, 1); 177 input_sync(onkey->input); 178 input_report_key(onkey->input, KEY_POWER, 0); 179 input_sync(onkey->input); 180 dev_dbg(onkey->dev, "KEY_POWER short press.\n"); 181 } 182 183 return IRQ_HANDLED; 184 } 185 186 static void da9063_cancel_poll(void *data) 187 { 188 struct da9063_onkey *onkey = data; 189 190 cancel_delayed_work_sync(&onkey->work); 191 } 192 193 static int da9063_onkey_probe(struct platform_device *pdev) 194 { 195 struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); 196 struct da9063_pdata *pdata = dev_get_platdata(da9063->dev); 197 struct da9063_onkey *onkey; 198 const struct of_device_id *match; 199 int irq; 200 int error; 201 202 match = of_match_node(da9063_compatible_reg_id_table, 203 pdev->dev.of_node); 204 if (!match) 205 return -ENXIO; 206 207 onkey = devm_kzalloc(&pdev->dev, sizeof(struct da9063_onkey), 208 GFP_KERNEL); 209 if (!onkey) { 210 dev_err(&pdev->dev, "Failed to allocate memory.\n"); 211 return -ENOMEM; 212 } 213 214 onkey->config = match->data; 215 onkey->dev = &pdev->dev; 216 217 onkey->regmap = dev_get_regmap(pdev->dev.parent, NULL); 218 if (!onkey->regmap) { 219 dev_err(&pdev->dev, "Parent regmap unavailable.\n"); 220 return -ENXIO; 221 } 222 223 if (pdata) 224 onkey->key_power = pdata->key_power; 225 else 226 onkey->key_power = 227 !of_property_read_bool(pdev->dev.of_node, 228 "dlg,disable-key-power"); 229 230 onkey->input = devm_input_allocate_device(&pdev->dev); 231 if (!onkey->input) { 232 dev_err(&pdev->dev, "Failed to allocated input device.\n"); 233 return -ENOMEM; 234 } 235 236 onkey->input->name = onkey->config->name; 237 snprintf(onkey->phys, sizeof(onkey->phys), "%s/input0", 238 onkey->config->name); 239 onkey->input->phys = onkey->phys; 240 onkey->input->dev.parent = &pdev->dev; 241 242 if (onkey->key_power) 243 input_set_capability(onkey->input, EV_KEY, KEY_POWER); 244 245 input_set_capability(onkey->input, EV_KEY, KEY_SLEEP); 246 247 INIT_DELAYED_WORK(&onkey->work, da9063_poll_on); 248 249 error = devm_add_action(&pdev->dev, da9063_cancel_poll, onkey); 250 if (error) { 251 dev_err(&pdev->dev, 252 "Failed to add cancel poll action: %d\n", 253 error); 254 return error; 255 } 256 257 irq = platform_get_irq_byname(pdev, "ONKEY"); 258 if (irq < 0) { 259 error = irq; 260 dev_err(&pdev->dev, "Failed to get platform IRQ: %d\n", error); 261 return error; 262 } 263 264 error = devm_request_threaded_irq(&pdev->dev, irq, 265 NULL, da9063_onkey_irq_handler, 266 IRQF_TRIGGER_LOW | IRQF_ONESHOT, 267 "ONKEY", onkey); 268 if (error) { 269 dev_err(&pdev->dev, 270 "Failed to request IRQ %d: %d\n", irq, error); 271 return error; 272 } 273 274 error = input_register_device(onkey->input); 275 if (error) { 276 dev_err(&pdev->dev, 277 "Failed to register input device: %d\n", error); 278 return error; 279 } 280 281 return 0; 282 } 283 284 static struct platform_driver da9063_onkey_driver = { 285 .probe = da9063_onkey_probe, 286 .driver = { 287 .name = DA9063_DRVNAME_ONKEY, 288 .of_match_table = da9063_compatible_reg_id_table, 289 }, 290 }; 291 module_platform_driver(da9063_onkey_driver); 292 293 MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>"); 294 MODULE_DESCRIPTION("Onkey device driver for Dialog DA9063, DA9062 and DA9061"); 295 MODULE_LICENSE("GPL"); 296 MODULE_ALIAS("platform:" DA9063_DRVNAME_ONKEY); 297