11af2b76fSBartosz Golaszewski // SPDX-License-Identifier: GPL-2.0 21af2b76fSBartosz Golaszewski // 31af2b76fSBartosz Golaszewski // Copyright (C) 2018 BayLibre SAS 41af2b76fSBartosz Golaszewski // Author: Bartosz Golaszewski <bgolaszewski@baylibre.com> 51af2b76fSBartosz Golaszewski // 61af2b76fSBartosz Golaszewski // ONKEY driver for MAXIM 77650/77651 charger/power-supply. 71af2b76fSBartosz Golaszewski 81af2b76fSBartosz Golaszewski #include <linux/i2c.h> 91af2b76fSBartosz Golaszewski #include <linux/input.h> 101af2b76fSBartosz Golaszewski #include <linux/interrupt.h> 111af2b76fSBartosz Golaszewski #include <linux/mfd/max77650.h> 121af2b76fSBartosz Golaszewski #include <linux/module.h> 131af2b76fSBartosz Golaszewski #include <linux/platform_device.h> 141af2b76fSBartosz Golaszewski #include <linux/regmap.h> 151af2b76fSBartosz Golaszewski 161af2b76fSBartosz Golaszewski #define MAX77650_ONKEY_MODE_MASK BIT(3) 171af2b76fSBartosz Golaszewski #define MAX77650_ONKEY_MODE_PUSH 0x00 181af2b76fSBartosz Golaszewski #define MAX77650_ONKEY_MODE_SLIDE BIT(3) 191af2b76fSBartosz Golaszewski 201af2b76fSBartosz Golaszewski struct max77650_onkey { 211af2b76fSBartosz Golaszewski struct input_dev *input; 221af2b76fSBartosz Golaszewski unsigned int code; 231af2b76fSBartosz Golaszewski }; 241af2b76fSBartosz Golaszewski 251af2b76fSBartosz Golaszewski static irqreturn_t max77650_onkey_falling(int irq, void *data) 261af2b76fSBartosz Golaszewski { 271af2b76fSBartosz Golaszewski struct max77650_onkey *onkey = data; 281af2b76fSBartosz Golaszewski 291af2b76fSBartosz Golaszewski input_report_key(onkey->input, onkey->code, 0); 301af2b76fSBartosz Golaszewski input_sync(onkey->input); 311af2b76fSBartosz Golaszewski 321af2b76fSBartosz Golaszewski return IRQ_HANDLED; 331af2b76fSBartosz Golaszewski } 341af2b76fSBartosz Golaszewski 351af2b76fSBartosz Golaszewski static irqreturn_t max77650_onkey_rising(int irq, void *data) 361af2b76fSBartosz Golaszewski { 371af2b76fSBartosz Golaszewski struct max77650_onkey *onkey = data; 381af2b76fSBartosz Golaszewski 391af2b76fSBartosz Golaszewski input_report_key(onkey->input, onkey->code, 1); 401af2b76fSBartosz Golaszewski input_sync(onkey->input); 411af2b76fSBartosz Golaszewski 421af2b76fSBartosz Golaszewski return IRQ_HANDLED; 431af2b76fSBartosz Golaszewski } 441af2b76fSBartosz Golaszewski 451af2b76fSBartosz Golaszewski static int max77650_onkey_probe(struct platform_device *pdev) 461af2b76fSBartosz Golaszewski { 471af2b76fSBartosz Golaszewski int irq_r, irq_f, error, mode; 481af2b76fSBartosz Golaszewski struct max77650_onkey *onkey; 491af2b76fSBartosz Golaszewski struct device *dev, *parent; 501af2b76fSBartosz Golaszewski struct regmap *map; 511af2b76fSBartosz Golaszewski unsigned int type; 521af2b76fSBartosz Golaszewski 531af2b76fSBartosz Golaszewski dev = &pdev->dev; 541af2b76fSBartosz Golaszewski parent = dev->parent; 551af2b76fSBartosz Golaszewski 561af2b76fSBartosz Golaszewski map = dev_get_regmap(parent, NULL); 571af2b76fSBartosz Golaszewski if (!map) 581af2b76fSBartosz Golaszewski return -ENODEV; 591af2b76fSBartosz Golaszewski 601af2b76fSBartosz Golaszewski onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL); 611af2b76fSBartosz Golaszewski if (!onkey) 621af2b76fSBartosz Golaszewski return -ENOMEM; 631af2b76fSBartosz Golaszewski 641af2b76fSBartosz Golaszewski error = device_property_read_u32(dev, "linux,code", &onkey->code); 651af2b76fSBartosz Golaszewski if (error) 661af2b76fSBartosz Golaszewski onkey->code = KEY_POWER; 671af2b76fSBartosz Golaszewski 681af2b76fSBartosz Golaszewski if (device_property_read_bool(dev, "maxim,onkey-slide")) { 691af2b76fSBartosz Golaszewski mode = MAX77650_ONKEY_MODE_SLIDE; 701af2b76fSBartosz Golaszewski type = EV_SW; 711af2b76fSBartosz Golaszewski } else { 721af2b76fSBartosz Golaszewski mode = MAX77650_ONKEY_MODE_PUSH; 731af2b76fSBartosz Golaszewski type = EV_KEY; 741af2b76fSBartosz Golaszewski } 751af2b76fSBartosz Golaszewski 761af2b76fSBartosz Golaszewski error = regmap_update_bits(map, MAX77650_REG_CNFG_GLBL, 771af2b76fSBartosz Golaszewski MAX77650_ONKEY_MODE_MASK, mode); 781af2b76fSBartosz Golaszewski if (error) 791af2b76fSBartosz Golaszewski return error; 801af2b76fSBartosz Golaszewski 811af2b76fSBartosz Golaszewski irq_f = platform_get_irq_byname(pdev, "nEN_F"); 821af2b76fSBartosz Golaszewski if (irq_f < 0) 831af2b76fSBartosz Golaszewski return irq_f; 841af2b76fSBartosz Golaszewski 851af2b76fSBartosz Golaszewski irq_r = platform_get_irq_byname(pdev, "nEN_R"); 861af2b76fSBartosz Golaszewski if (irq_r < 0) 871af2b76fSBartosz Golaszewski return irq_r; 881af2b76fSBartosz Golaszewski 891af2b76fSBartosz Golaszewski onkey->input = devm_input_allocate_device(dev); 901af2b76fSBartosz Golaszewski if (!onkey->input) 911af2b76fSBartosz Golaszewski return -ENOMEM; 921af2b76fSBartosz Golaszewski 931af2b76fSBartosz Golaszewski onkey->input->name = "max77650_onkey"; 941af2b76fSBartosz Golaszewski onkey->input->phys = "max77650_onkey/input0"; 951af2b76fSBartosz Golaszewski onkey->input->id.bustype = BUS_I2C; 961af2b76fSBartosz Golaszewski input_set_capability(onkey->input, type, onkey->code); 971af2b76fSBartosz Golaszewski 981af2b76fSBartosz Golaszewski error = devm_request_any_context_irq(dev, irq_f, max77650_onkey_falling, 991af2b76fSBartosz Golaszewski IRQF_ONESHOT, "onkey-down", onkey); 1001af2b76fSBartosz Golaszewski if (error < 0) 1011af2b76fSBartosz Golaszewski return error; 1021af2b76fSBartosz Golaszewski 1031af2b76fSBartosz Golaszewski error = devm_request_any_context_irq(dev, irq_r, max77650_onkey_rising, 1041af2b76fSBartosz Golaszewski IRQF_ONESHOT, "onkey-up", onkey); 1051af2b76fSBartosz Golaszewski if (error < 0) 1061af2b76fSBartosz Golaszewski return error; 1071af2b76fSBartosz Golaszewski 1081af2b76fSBartosz Golaszewski return input_register_device(onkey->input); 1091af2b76fSBartosz Golaszewski } 1101af2b76fSBartosz Golaszewski 1111af2b76fSBartosz Golaszewski static struct platform_driver max77650_onkey_driver = { 1121af2b76fSBartosz Golaszewski .driver = { 1131af2b76fSBartosz Golaszewski .name = "max77650-onkey", 1141af2b76fSBartosz Golaszewski }, 1151af2b76fSBartosz Golaszewski .probe = max77650_onkey_probe, 1161af2b76fSBartosz Golaszewski }; 1171af2b76fSBartosz Golaszewski module_platform_driver(max77650_onkey_driver); 1181af2b76fSBartosz Golaszewski 1191af2b76fSBartosz Golaszewski MODULE_DESCRIPTION("MAXIM 77650/77651 ONKEY driver"); 1201af2b76fSBartosz Golaszewski MODULE_AUTHOR("Bartosz Golaszewski <bgolaszewski@baylibre.com>"); 1211af2b76fSBartosz Golaszewski MODULE_LICENSE("GPL v2"); 122