From 063755ab1d1c1127adc09703185967862584935b Mon Sep 17 00:00:00 2001 From: Philippe Schenker Date: Fri, 21 Dec 2018 14:46:31 +0100 Subject: mfd: stmpe: Move ADC related defines to MFD header Move defines that are ADC related to the header of the overlying MFD, so they can be used from multiple sub-devices. Signed-off-by: Philippe Schenker Acked-by: Dmitry Torokhov Signed-off-by: Lee Jones --- drivers/input/touchscreen/stmpe-ts.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index 2a78e27b4495..c5d9006588a2 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -49,17 +49,6 @@ #define STMPE_IRQ_TOUCH_DET 0 -#define SAMPLE_TIME(x) ((x & 0xf) << 4) -#define MOD_12B(x) ((x & 0x1) << 3) -#define REF_SEL(x) ((x & 0x1) << 1) -#define ADC_FREQ(x) (x & 0x3) -#define AVE_CTRL(x) ((x & 0x3) << 6) -#define DET_DELAY(x) ((x & 0x7) << 3) -#define SETTLING(x) (x & 0x7) -#define FRACTION_Z(x) (x & 0x7) -#define I_DRIVE(x) (x & 0x1) -#define OP_MODE(x) ((x & 0x7) << 1) - #define STMPE_TS_NAME "stmpe-ts" #define XY_MASK 0xfff @@ -213,9 +202,10 @@ static int stmpe_init_hw(struct stmpe_touch *ts) return ret; } - adc_ctrl1 = SAMPLE_TIME(ts->sample_time) | MOD_12B(ts->mod_12b) | - REF_SEL(ts->ref_sel); - adc_ctrl1_mask = SAMPLE_TIME(0xff) | MOD_12B(0xff) | REF_SEL(0xff); + adc_ctrl1 = STMPE_SAMPLE_TIME(ts->sample_time) | + STMPE_MOD_12B(ts->mod_12b) | STMPE_REF_SEL(ts->ref_sel); + adc_ctrl1_mask = STMPE_SAMPLE_TIME(0xff) | STMPE_MOD_12B(0xff) | + STMPE_REF_SEL(0xff); ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL1, adc_ctrl1_mask, adc_ctrl1); @@ -225,15 +215,17 @@ static int stmpe_init_hw(struct stmpe_touch *ts) } ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL2, - ADC_FREQ(0xff), ADC_FREQ(ts->adc_freq)); + STMPE_ADC_FREQ(0xff), STMPE_ADC_FREQ(ts->adc_freq)); if (ret) { dev_err(dev, "Could not setup ADC\n"); return ret; } - tsc_cfg = AVE_CTRL(ts->ave_ctrl) | DET_DELAY(ts->touch_det_delay) | - SETTLING(ts->settling); - tsc_cfg_mask = AVE_CTRL(0xff) | DET_DELAY(0xff) | SETTLING(0xff); + tsc_cfg = STMPE_AVE_CTRL(ts->ave_ctrl) | + STMPE_DET_DELAY(ts->touch_det_delay) | + STMPE_SETTLING(ts->settling); + tsc_cfg_mask = STMPE_AVE_CTRL(0xff) | STMPE_DET_DELAY(0xff) | + STMPE_SETTLING(0xff); ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_CFG, tsc_cfg_mask, tsc_cfg); if (ret) { @@ -242,14 +234,14 @@ static int stmpe_init_hw(struct stmpe_touch *ts) } ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_FRACTION_Z, - FRACTION_Z(0xff), FRACTION_Z(ts->fraction_z)); + STMPE_FRACTION_Z(0xff), STMPE_FRACTION_Z(ts->fraction_z)); if (ret) { dev_err(dev, "Could not config touch\n"); return ret; } ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_I_DRIVE, - I_DRIVE(0xff), I_DRIVE(ts->i_drive)); + STMPE_I_DRIVE(0xff), STMPE_I_DRIVE(ts->i_drive)); if (ret) { dev_err(dev, "Could not config touch\n"); return ret; @@ -263,7 +255,7 @@ static int stmpe_init_hw(struct stmpe_touch *ts) } ret = stmpe_set_bits(stmpe, STMPE_REG_TSC_CTRL, - OP_MODE(0xff), OP_MODE(OP_MOD_XYZ)); + STMPE_OP_MODE(0xff), STMPE_OP_MODE(OP_MOD_XYZ)); if (ret) { dev_err(dev, "Could not set mode\n"); return ret; -- cgit v1.2.3 From 88f29d0f2c8f0d8097dfca9fc3619dfe893e0b15 Mon Sep 17 00:00:00 2001 From: Philippe Schenker Date: Fri, 21 Dec 2018 14:46:33 +0100 Subject: Input: stmpe-ts: preparations for STMPE ADC driver This patch removes common ADC settings in favor to use stmpe811_adc_common_init that is present in MFD. This is necessary in preparation for the stmpe-adc driver, because those two drivers have common settings for the ADC. Signed-off-by: Philippe Schenker Acked-by: Dmitry Torokhov Signed-off-by: Lee Jones --- drivers/input/touchscreen/stmpe-ts.c | 42 ++++++------------------------------ 1 file changed, 7 insertions(+), 35 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/stmpe-ts.c b/drivers/input/touchscreen/stmpe-ts.c index c5d9006588a2..cf9c9aa39f6e 100644 --- a/drivers/input/touchscreen/stmpe-ts.c +++ b/drivers/input/touchscreen/stmpe-ts.c @@ -30,8 +30,6 @@ * with touchscreen controller */ #define STMPE_REG_INT_STA 0x0B -#define STMPE_REG_ADC_CTRL1 0x20 -#define STMPE_REG_ADC_CTRL2 0x21 #define STMPE_REG_TSC_CTRL 0x40 #define STMPE_REG_TSC_CFG 0x41 #define STMPE_REG_FIFO_TH 0x4A @@ -58,15 +56,6 @@ * @idev: registered input device * @work: a work item used to scan the device * @dev: a pointer back to the MFD cell struct device* - * @sample_time: ADC converstion time in number of clock. - * (0 -> 36 clocks, 1 -> 44 clocks, 2 -> 56 clocks, 3 -> 64 clocks, - * 4 -> 80 clocks, 5 -> 96 clocks, 6 -> 144 clocks), - * recommended is 4. - * @mod_12b: ADC Bit mode (0 -> 10bit ADC, 1 -> 12bit ADC) - * @ref_sel: ADC reference source - * (0 -> internal reference, 1 -> external reference) - * @adc_freq: ADC Clock speed - * (0 -> 1.625 MHz, 1 -> 3.25 MHz, 2 || 3 -> 6.5 MHz) * @ave_ctrl: Sample average control * (0 -> 1 sample, 1 -> 2 samples, 2 -> 4 samples, 3 -> 8 samples) * @touch_det_delay: Touch detect interrupt delay @@ -88,10 +77,6 @@ struct stmpe_touch { struct input_dev *idev; struct delayed_work work; struct device *dev; - u8 sample_time; - u8 mod_12b; - u8 ref_sel; - u8 adc_freq; u8 ave_ctrl; u8 touch_det_delay; u8 settling; @@ -192,7 +177,7 @@ static irqreturn_t stmpe_ts_handler(int irq, void *data) static int stmpe_init_hw(struct stmpe_touch *ts) { int ret; - u8 adc_ctrl1, adc_ctrl1_mask, tsc_cfg, tsc_cfg_mask; + u8 tsc_cfg, tsc_cfg_mask; struct stmpe *stmpe = ts->stmpe; struct device *dev = ts->dev; @@ -202,22 +187,9 @@ static int stmpe_init_hw(struct stmpe_touch *ts) return ret; } - adc_ctrl1 = STMPE_SAMPLE_TIME(ts->sample_time) | - STMPE_MOD_12B(ts->mod_12b) | STMPE_REF_SEL(ts->ref_sel); - adc_ctrl1_mask = STMPE_SAMPLE_TIME(0xff) | STMPE_MOD_12B(0xff) | - STMPE_REF_SEL(0xff); - - ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL1, - adc_ctrl1_mask, adc_ctrl1); - if (ret) { - dev_err(dev, "Could not setup ADC\n"); - return ret; - } - - ret = stmpe_set_bits(stmpe, STMPE_REG_ADC_CTRL2, - STMPE_ADC_FREQ(0xff), STMPE_ADC_FREQ(ts->adc_freq)); + ret = stmpe811_adc_common_init(stmpe); if (ret) { - dev_err(dev, "Could not setup ADC\n"); + stmpe_disable(stmpe, STMPE_BLOCK_TOUCHSCREEN | STMPE_BLOCK_ADC); return ret; } @@ -295,13 +267,13 @@ static void stmpe_ts_get_platform_info(struct platform_device *pdev, if (np) { if (!of_property_read_u32(np, "st,sample-time", &val)) - ts->sample_time = val; + ts->stmpe->sample_time = val; if (!of_property_read_u32(np, "st,mod-12b", &val)) - ts->mod_12b = val; + ts->stmpe->mod_12b = val; if (!of_property_read_u32(np, "st,ref-sel", &val)) - ts->ref_sel = val; + ts->stmpe->ref_sel = val; if (!of_property_read_u32(np, "st,adc-freq", &val)) - ts->adc_freq = val; + ts->stmpe->adc_freq = val; if (!of_property_read_u32(np, "st,ave-ctrl", &val)) ts->ave_ctrl = val; if (!of_property_read_u32(np, "st,touch-det-delay", &val)) -- cgit v1.2.3 From 9eb9cc932cfa43ac53d82b1b8d593a3a975be99e Mon Sep 17 00:00:00 2001 From: Pascal PAILLET-LME Date: Mon, 14 Jan 2019 10:05:17 +0000 Subject: input: stpmic1: Add STPMIC1 onkey driver The STPMIC1 pmic is able to manage an onkey button. This driver exposes the STPMIC1 onkey as an input device. It can also be configured to shut-down the power supplies on a long key-press with an adjustable duration. Signed-off-by: Pascal Paillet Acked-by: Dmitry Torokhov Signed-off-by: Lee Jones --- drivers/input/misc/Kconfig | 11 +++ drivers/input/misc/Makefile | 2 + drivers/input/misc/stpmic1_onkey.c | 198 +++++++++++++++++++++++++++++++++++++ 3 files changed, 211 insertions(+) create mode 100644 drivers/input/misc/stpmic1_onkey.c (limited to 'drivers/input') diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index ca59a2be9bc5..279fb02a0f14 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -851,4 +851,15 @@ config INPUT_SC27XX_VIBRA To compile this driver as a module, choose M here. The module will be called sc27xx_vibra. +config INPUT_STPMIC1_ONKEY + tristate "STPMIC1 PMIC Onkey support" + depends on MFD_STPMIC1 + help + Say Y to enable support of onkey embedded into STPMIC1 PMIC. onkey + can be used to wakeup from low power modes and force a shut-down on + long press. + + To compile this driver as a module, choose M here: the + module will be called stpmic1_onkey. + endif diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile index 9d0f9d1ff68f..1b44202ad8f7 100644 --- a/drivers/input/misc/Makefile +++ b/drivers/input/misc/Makefile @@ -71,6 +71,7 @@ obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o +obj-$(CONFIG_INPUT_STPMIC1_ONKEY) += stpmic1_onkey.o obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON) += tps65218-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o @@ -81,3 +82,4 @@ obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR) += ideapad_slidebar.o + diff --git a/drivers/input/misc/stpmic1_onkey.c b/drivers/input/misc/stpmic1_onkey.c new file mode 100644 index 000000000000..7b49c9997df7 --- /dev/null +++ b/drivers/input/misc/stpmic1_onkey.c @@ -0,0 +1,198 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) STMicroelectronics 2018 +// Author: Pascal Paillet for STMicroelectronics. + +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct stpmic1_onkey - OnKey data + * @input_dev: pointer to input device + * @irq_falling: irq that we are hooked on to + * @irq_rising: irq that we are hooked on to + */ +struct stpmic1_onkey { + struct input_dev *input_dev; + int irq_falling; + int irq_rising; +}; + +static irqreturn_t onkey_falling_irq(int irq, void *ponkey) +{ + struct stpmic1_onkey *onkey = ponkey; + struct input_dev *input_dev = onkey->input_dev; + + input_report_key(input_dev, KEY_POWER, 1); + pm_wakeup_event(input_dev->dev.parent, 0); + input_sync(input_dev); + + return IRQ_HANDLED; +} + +static irqreturn_t onkey_rising_irq(int irq, void *ponkey) +{ + struct stpmic1_onkey *onkey = ponkey; + struct input_dev *input_dev = onkey->input_dev; + + input_report_key(input_dev, KEY_POWER, 0); + pm_wakeup_event(input_dev->dev.parent, 0); + input_sync(input_dev); + + return IRQ_HANDLED; +} + +static int stpmic1_onkey_probe(struct platform_device *pdev) +{ + struct stpmic1 *pmic = dev_get_drvdata(pdev->dev.parent); + struct device *dev = &pdev->dev; + struct input_dev *input_dev; + struct stpmic1_onkey *onkey; + unsigned int val, reg = 0; + int error; + + onkey = devm_kzalloc(dev, sizeof(*onkey), GFP_KERNEL); + if (!onkey) + return -ENOMEM; + + onkey->irq_falling = platform_get_irq_byname(pdev, "onkey-falling"); + if (onkey->irq_falling < 0) { + dev_err(dev, "failed: request IRQ onkey-falling %d\n", + onkey->irq_falling); + return onkey->irq_falling; + } + + onkey->irq_rising = platform_get_irq_byname(pdev, "onkey-rising"); + if (onkey->irq_rising < 0) { + dev_err(dev, "failed: request IRQ onkey-rising %d\n", + onkey->irq_rising); + return onkey->irq_rising; + } + + if (!device_property_read_u32(dev, "power-off-time-sec", &val)) { + if (val > 0 && val <= 16) { + dev_dbg(dev, "power-off-time=%d seconds\n", val); + reg |= PONKEY_PWR_OFF; + reg |= ((16 - val) & PONKEY_TURNOFF_TIMER_MASK); + } else { + dev_err(dev, "power-off-time-sec out of range\n"); + return -EINVAL; + } + } + + if (device_property_present(dev, "st,onkey-clear-cc-flag")) + reg |= PONKEY_CC_FLAG_CLEAR; + + error = regmap_update_bits(pmic->regmap, PKEY_TURNOFF_CR, + PONKEY_TURNOFF_MASK, reg); + if (error) { + dev_err(dev, "PKEY_TURNOFF_CR write failed: %d\n", error); + return error; + } + + if (device_property_present(dev, "st,onkey-pu-inactive")) { + error = regmap_update_bits(pmic->regmap, PADS_PULL_CR, + PONKEY_PU_INACTIVE, + PONKEY_PU_INACTIVE); + if (error) { + dev_err(dev, "ONKEY Pads configuration failed: %d\n", + error); + return error; + } + } + + input_dev = devm_input_allocate_device(dev); + if (!input_dev) { + dev_err(dev, "Can't allocate Pwr Onkey Input Device\n"); + return -ENOMEM; + } + + input_dev->name = "pmic_onkey"; + input_dev->phys = "pmic_onkey/input0"; + + input_set_capability(input_dev, EV_KEY, KEY_POWER); + + onkey->input_dev = input_dev; + + /* interrupt is nested in a thread */ + error = devm_request_threaded_irq(dev, onkey->irq_falling, NULL, + onkey_falling_irq, IRQF_ONESHOT, + dev_name(dev), onkey); + if (error) { + dev_err(dev, "Can't get IRQ Onkey Falling: %d\n", error); + return error; + } + + error = devm_request_threaded_irq(dev, onkey->irq_rising, NULL, + onkey_rising_irq, IRQF_ONESHOT, + dev_name(dev), onkey); + if (error) { + dev_err(dev, "Can't get IRQ Onkey Rising: %d\n", error); + return error; + } + + error = input_register_device(input_dev); + if (error) { + dev_err(dev, "Can't register power button: %d\n", error); + return error; + } + + platform_set_drvdata(pdev, onkey); + device_init_wakeup(dev, true); + + return 0; +} + +static int __maybe_unused stpmic1_onkey_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct stpmic1_onkey *onkey = platform_get_drvdata(pdev); + + if (device_may_wakeup(dev)) { + enable_irq_wake(onkey->irq_falling); + enable_irq_wake(onkey->irq_rising); + } + return 0; +} + +static int __maybe_unused stpmic1_onkey_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct stpmic1_onkey *onkey = platform_get_drvdata(pdev); + + if (device_may_wakeup(dev)) { + disable_irq_wake(onkey->irq_falling); + disable_irq_wake(onkey->irq_rising); + } + return 0; +} + +static SIMPLE_DEV_PM_OPS(stpmic1_onkey_pm, + stpmic1_onkey_suspend, + stpmic1_onkey_resume); + +static const struct of_device_id of_stpmic1_onkey_match[] = { + { .compatible = "st,stpmic1-onkey" }, + { }, +}; + +MODULE_DEVICE_TABLE(of, of_stpmic1_onkey_match); + +static struct platform_driver stpmic1_onkey_driver = { + .probe = stpmic1_onkey_probe, + .driver = { + .name = "stpmic1_onkey", + .of_match_table = of_match_ptr(of_stpmic1_onkey_match), + .pm = &stpmic1_onkey_pm, + }, +}; +module_platform_driver(stpmic1_onkey_driver); + +MODULE_DESCRIPTION("Onkey driver for STPMIC1"); +MODULE_AUTHOR("Pascal Paillet "); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3