Merge branches 'ib-mfd-iio-input-5.1', 'ib-mfd-input-watchdog-5.1' and 'ib-mfd-platfo...
authorLee Jones <lee.jones@linaro.org>
Fri, 1 Feb 2019 08:20:04 +0000 (08:20 +0000)
committerLee Jones <lee.jones@linaro.org>
Fri, 1 Feb 2019 08:20:04 +0000 (08:20 +0000)
23 files changed:
Documentation/devicetree/bindings/iio/adc/stmpe-adc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/st,stpmic1-onkey.txt [new file with mode: 0644]
Documentation/devicetree/bindings/input/touchscreen/stmpe.txt
Documentation/devicetree/bindings/mfd/st,stpmic1.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mfd/stmpe.txt
Documentation/devicetree/bindings/watchdog/st,stpmic1-wdt.txt [new file with mode: 0644]
drivers/iio/adc/Kconfig
drivers/iio/adc/Makefile
drivers/iio/adc/stmpe-adc.c [new file with mode: 0644]
drivers/input/misc/Kconfig
drivers/input/misc/Makefile
drivers/input/misc/stpmic1_onkey.c [new file with mode: 0644]
drivers/input/touchscreen/stmpe-ts.c
drivers/mfd/Kconfig
drivers/mfd/Makefile
drivers/mfd/stmpe.c
drivers/mfd/stpmic1.c [new file with mode: 0644]
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/stpmic1_wdt.c [new file with mode: 0644]
include/dt-bindings/mfd/st,stpmic1.h [new file with mode: 0644]
include/linux/mfd/stmpe.h
include/linux/mfd/stpmic1.h [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/iio/adc/stmpe-adc.txt b/Documentation/devicetree/bindings/iio/adc/stmpe-adc.txt
new file mode 100644 (file)
index 0000000..480e664
--- /dev/null
@@ -0,0 +1,21 @@
+STMPE ADC driver
+----------------
+
+Required properties:
+ - compatible: "st,stmpe-adc"
+
+Optional properties:
+Note that the ADC is shared with the STMPE touchscreen. ADC related settings
+have to be done in the mfd.
+- st,norequest-mask: bitmask specifying which ADC channels should _not_ be
+  requestable due to different usage (e.g. touch)
+
+Node name must be stmpe_adc and should be child node of stmpe node to
+which it belongs.
+
+Example:
+
+       stmpe_adc {
+               compatible = "st,stmpe-adc";
+               st,norequest-mask = <0x0F>; /* dont use ADC CH3-0 */
+       };
diff --git a/Documentation/devicetree/bindings/input/st,stpmic1-onkey.txt b/Documentation/devicetree/bindings/input/st,stpmic1-onkey.txt
new file mode 100644 (file)
index 0000000..4494613
--- /dev/null
@@ -0,0 +1,28 @@
+STMicroelectronics STPMIC1 Onkey
+
+Required properties:
+
+- compatible = "st,stpmic1-onkey";
+- interrupts: interrupt line to use
+- interrupt-names = "onkey-falling", "onkey-rising"
+       onkey-falling: happens when onkey is pressed; IT_PONKEY_F of pmic
+       onkey-rising: happens when onkey is released; IT_PONKEY_R of pmic
+
+Optional properties:
+
+- st,onkey-clear-cc-flag: onkey is able power on after an
+  over-current shutdown event.
+- st,onkey-pu-inactive: onkey pull up is not active
+- power-off-time-sec: Duration in seconds which the key should be kept
+        pressed for device to power off automatically (from 1 to 16 seconds).
+        see See Documentation/devicetree/bindings/input/keys.txt
+
+Example:
+
+onkey {
+       compatible = "st,stpmic1-onkey";
+       interrupt-parent = <&pmic>;
+       interrupts = <IT_PONKEY_F 0>,<IT_PONKEY_R 1>;
+       interrupt-names = "onkey-falling", "onkey-rising";
+       power-off-time-sec = <10>;
+};
index 127baa3..c549924 100644 (file)
@@ -5,39 +5,105 @@ Required properties:
  - compatible: "st,stmpe-ts"
 
 Optional properties:
-- st,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.
-- st,mod-12b: ADC Bit mode (0 -> 10bit ADC, 1 -> 12bit ADC)
-- st,ref-sel: ADC reference source (0 -> internal reference, 1 -> external
-  reference)
-- st,adc-freq: ADC Clock speed (0 -> 1.625 MHz, 1 -> 3.25 MHz, 2 || 3 -> 6.5 MHz)
-- st,ave-ctrl: Sample average control (0 -> 1 sample, 1 -> 2 samples, 2 -> 4
-  samples, 3 -> 8 samples)
-- st,touch-det-delay: Touch detect interrupt delay (0 -> 10 us, 1 -> 50 us, 2 ->
-  100 us, 3 -> 500 us, 4-> 1 ms, 5 -> 5 ms, 6 -> 10 ms, 7 -> 50 ms) recommended
-  is 3
-- st,settling: Panel driver settling time (0 -> 10 us, 1 -> 100 us, 2 -> 500 us, 3
-  -> 1 ms, 4 -> 5 ms, 5 -> 10 ms, 6 for 50 ms, 7 -> 100 ms) recommended is 2
-- st,fraction-z: Length of the fractional part in z (fraction-z ([0..7]) = Count of
-  the fractional part) recommended is 7
-- st,i-drive: current limit value of the touchscreen drivers (0 -> 20 mA typical 35
-  mA max, 1 -> 50 mA typical 80 mA max)
+- st,ave-ctrl          : Sample average control
+                               0 -> 1 sample
+                               1 -> 2 samples
+                               2 -> 4 samples
+                               3 -> 8 samples
+- st,touch-det-delay   : Touch detect interrupt delay (recommended is 3)
+                               0 -> 10 us
+                               1 -> 50 us
+                               2 -> 100 us
+                               3 -> 500 us
+                               4 -> 1 ms
+                               5 -> 5 ms
+                               6 -> 10 ms
+                               7 -> 50 ms
+- st,settling          : Panel driver settling time (recommended is 2)
+                               0 -> 10 us
+                               1 -> 100 us
+                               2 -> 500 us
+                               3 -> 1 ms
+                               4 -> 5 ms
+                               5 -> 10 ms
+                               6 -> 50 ms
+                               7 -> 100 ms
+- st,fraction-z                : Length of the fractional part in z (recommended is 7)
+                         (fraction-z ([0..7]) = Count of the fractional part)
+- st,i-drive           : current limit value of the touchscreen drivers
+                               0 -> 20 mA (typical 35mA max)
+                               1 -> 50 mA (typical 80 mA max)
+
+Optional properties common with MFD (deprecated):
+ - st,sample-time      : ADC conversion time in number of clock.
+                               0 -> 36 clocks
+                               1 -> 44 clocks
+                               2 -> 56 clocks
+                               3 -> 64 clocks
+                               4 -> 80 clocks (recommended)
+                               5 -> 96 clocks
+                               6 -> 124 clocks
+ - st,mod-12b          : ADC Bit mode
+                               0 -> 10bit ADC
+                               1 -> 12bit ADC
+ - st,ref-sel          : ADC reference source
+                               0 -> internal
+                               1 -> external
+ - st,adc-freq         : ADC Clock speed
+                               0 -> 1.625 MHz
+                               1 -> 3.25 MHz
+                               2 || 3 -> 6.5 MHz
 
 Node name must be stmpe_touchscreen and should be child node of stmpe node to
 which it belongs.
 
+Note that common ADC settings of stmpe_touchscreen (child) will take precedence
+over the settings done in MFD.
+
 Example:
 
+stmpe811@41 {
+       compatible = "st,stmpe811";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_touch_int>;
+       #address-cells = <1>;
+       #size-cells = <0>;
+       reg = <0x41>;
+       interrupts = <10 IRQ_TYPE_LEVEL_LOW>;
+       interrupt-parent = <&gpio4>;
+       interrupt-controller;
+       id = <0>;
+       blocks = <0x5>;
+       irq-trigger = <0x1>;
+       /* Common ADC settings */
+       /* 3.25 MHz ADC clock speed */
+       st,adc-freq = <1>;
+       /* 12-bit ADC */
+       st,mod-12b = <1>;
+       /* internal ADC reference */
+       st,ref-sel = <0>;
+       /* ADC converstion time: 80 clocks */
+       st,sample-time = <4>;
+
        stmpe_touchscreen {
                compatible = "st,stmpe-ts";
-               st,sample-time = <4>;
-               st,mod-12b = <1>;
-               st,ref-sel = <0>;
-               st,adc-freq = <1>;
-               st,ave-ctrl = <1>;
-               st,touch-det-delay = <2>;
-               st,settling = <2>;
+               reg = <0>;
+               /* 8 sample average control */
+               st,ave-ctrl = <3>;
+               /* 5 ms touch detect interrupt delay */
+               st,touch-det-delay = <5>;
+               /* 1 ms panel driver settling time */
+               st,settling = <3>;
+               /* 7 length fractional part in z */
                st,fraction-z = <7>;
+               /*
+                * 50 mA typical 80 mA max touchscreen drivers
+                * current limit value
+                */
                st,i-drive = <1>;
        };
+       stmpe_adc {
+               compatible = "st,stmpe-adc";
+               st,norequest-mask = <0x0F>;
+       };
+};
diff --git a/Documentation/devicetree/bindings/mfd/st,stpmic1.txt b/Documentation/devicetree/bindings/mfd/st,stpmic1.txt
new file mode 100644 (file)
index 0000000..afd45c0
--- /dev/null
@@ -0,0 +1,61 @@
+* STMicroelectronics STPMIC1 Power Management IC
+
+Required properties:
+- compatible:          : "st,stpmic1"
+- reg:                 : The I2C slave address for the STPMIC1 chip.
+- interrupts:          : The interrupt line the device is connected to.
+- #interrupt-cells:    : Should be 1.
+- interrupt-controller:        : Marks the device node as an interrupt controller.
+                           Interrupt numbers are defined at
+                           dt-bindings/mfd/st,stpmic1.h.
+
+STPMIC1 consists in a varied group of sub-devices.
+Each sub-device binding is be described in own documentation file.
+
+Device                  Description
+------                 ------------
+st,stpmic1-onkey       : Power on key, see ../input/st,stpmic1-onkey.txt
+st,stpmic1-regulators  : Regulators, see ../regulator/st,stpmic1-regulator.txt
+st,stpmic1-wdt         : Watchdog, see ../watchdog/st,stpmic1-wdt.txt
+
+Example:
+
+#include <dt-bindings/mfd/st,stpmic1.h>
+
+pmic: pmic@33 {
+       compatible = "st,stpmic1";
+       reg = <0x33>;
+       interrupt-parent = <&gpioa>;
+       interrupts = <0 2>;
+
+       interrupt-controller;
+       #interrupt-cells = <2>;
+
+       onkey {
+               compatible = "st,stpmic1-onkey";
+               interrupts = <IT_PONKEY_F 0>,<IT_PONKEY_R 1>;
+               interrupt-names = "onkey-falling", "onkey-rising";
+               power-off-time-sec = <10>;
+       };
+
+       watchdog {
+               compatible = "st,stpmic1-wdt";
+       };
+
+       regulators {
+               compatible = "st,stpmic1-regulators";
+
+               vdd_core: buck1 {
+                       regulator-name = "vdd_core";
+                       regulator-boot-on;
+                       regulator-min-microvolt = <700000>;
+                       regulator-max-microvolt = <1200000>;
+               };
+               vdd: buck3 {
+                       regulator-name = "vdd";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-boot-on;
+                       regulator-pull-down;
+               };
+       };
index c797c05..d4408a4 100644 (file)
@@ -4,15 +4,29 @@ STMPE is an MFD device which may expose the following inbuilt devices: gpio,
 keypad, touchscreen, adc, pwm, rotator.
 
 Required properties:
- - compatible                   : "st,stmpe[610|801|811|1600|1601|2401|2403]"
- - reg                          : I2C/SPI address of the device
+ - compatible                  : "st,stmpe[610|801|811|1600|1601|2401|2403]"
+ - reg                         : I2C/SPI address of the device
 
 Optional properties:
- - interrupts                   : The interrupt outputs from the controller
- - interrupt-controller         : Marks the device node as an interrupt controller
- - wakeup-source                : Marks the input device as wakable
- - st,autosleep-timeout         : Valid entries (ms); 4, 16, 32, 64, 128, 256, 512 and 1024
- - irq-gpio                     : If present, which GPIO to use for event IRQ
+ - interrupts                  : The interrupt outputs from the controller
+ - interrupt-controller                : Marks the device node as an interrupt controller
+ - wakeup-source               : Marks the input device as wakable
+ - st,autosleep-timeout                : Valid entries (ms); 4, 16, 32, 64, 128, 256, 512 and 1024
+ - irq-gpio                    : If present, which GPIO to use for event IRQ
+
+Optional properties for devices with touch and ADC (STMPE811|STMPE610):
+ - st,sample-time              : ADC conversion time in number of clock.
+                                       0 -> 36 clocks          4 -> 80 clocks (recommended)
+                                       1 -> 44 clocks          5 -> 96 clocks
+                                       2 -> 56 clocks          6 -> 124 clocks
+                                       3 -> 64 clocks
+ - st,mod-12b                  : ADC Bit mode
+                                       0 -> 10bit ADC          1 -> 12bit ADC
+ - st,ref-sel                  : ADC reference source
+                                       0 -> internal           1 -> external
+ - st,adc-freq                 : ADC Clock speed
+                                       0 -> 1.625 MHz          2 || 3 -> 6.5 MHz
+                                       1 -> 3.25 MHz
 
 Example:
 
diff --git a/Documentation/devicetree/bindings/watchdog/st,stpmic1-wdt.txt b/Documentation/devicetree/bindings/watchdog/st,stpmic1-wdt.txt
new file mode 100644 (file)
index 0000000..7cc1407
--- /dev/null
@@ -0,0 +1,11 @@
+STMicroelectronics STPMIC1 Watchdog
+
+Required properties:
+
+- compatible : should be "st,stpmic1-wdt"
+
+Example:
+
+watchdog {
+       compatible = "st,stpmic1-wdt";
+};
index 7a3ca4e..5b72e29 100644 (file)
@@ -755,6 +755,13 @@ config STM32_DFSDM_ADC
          This driver can also be built as a module.  If so, the module
          will be called stm32-dfsdm-adc.
 
+config STMPE_ADC
+       tristate "STMicroelectronics STMPE ADC driver"
+       depends on OF && MFD_STMPE
+       help
+         Say yes here to build support for ST Microelectronics STMPE
+         built-in ADC block (stmpe811).
+
 config STX104
        tristate "Apex Embedded Systems STX104 driver"
        depends on PC104 && X86
index 07df37f..6d4e314 100644 (file)
@@ -71,6 +71,7 @@ obj-$(CONFIG_STM32_ADC_CORE) += stm32-adc-core.o
 obj-$(CONFIG_STM32_ADC) += stm32-adc.o
 obj-$(CONFIG_STM32_DFSDM_CORE) += stm32-dfsdm-core.o
 obj-$(CONFIG_STM32_DFSDM_ADC) += stm32-dfsdm-adc.o
+obj-$(CONFIG_STMPE_ADC) += stmpe-adc.o
 obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
 obj-$(CONFIG_TI_ADC0832) += ti-adc0832.o
 obj-$(CONFIG_TI_ADC084S021) += ti-adc084s021.o
diff --git a/drivers/iio/adc/stmpe-adc.c b/drivers/iio/adc/stmpe-adc.c
new file mode 100644 (file)
index 0000000..37f4b74
--- /dev/null
@@ -0,0 +1,363 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  STMicroelectronics STMPE811 IIO ADC Driver
+ *
+ *  4 channel, 10/12-bit ADC
+ *
+ *  Copyright (C) 2013-2018 Toradex AG <stefan.agner@toradex.com>
+ */
+
+#include <linux/completion.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/stmpe.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+
+#define STMPE_REG_INT_STA              0x0B
+#define STMPE_REG_ADC_INT_EN           0x0E
+#define STMPE_REG_ADC_INT_STA          0x0F
+
+#define STMPE_REG_ADC_CTRL1            0x20
+#define STMPE_REG_ADC_CTRL2            0x21
+#define STMPE_REG_ADC_CAPT             0x22
+#define STMPE_REG_ADC_DATA_CH(channel) (0x30 + 2 * (channel))
+
+#define STMPE_REG_TEMP_CTRL            0x60
+#define STMPE_TEMP_CTRL_ENABLE         BIT(0)
+#define STMPE_TEMP_CTRL_ACQ            BIT(1)
+#define STMPE_TEMP_CTRL_THRES_EN       BIT(3)
+#define STMPE_START_ONE_TEMP_CONV      (STMPE_TEMP_CTRL_ENABLE | \
+                                       STMPE_TEMP_CTRL_ACQ | \
+                                       STMPE_TEMP_CTRL_THRES_EN)
+#define STMPE_REG_TEMP_DATA            0x61
+#define STMPE_REG_TEMP_TH              0x63
+#define STMPE_ADC_LAST_NR              7
+#define STMPE_TEMP_CHANNEL             (STMPE_ADC_LAST_NR + 1)
+
+#define STMPE_ADC_CH(channel)          ((1 << (channel)) & 0xff)
+
+#define STMPE_ADC_TIMEOUT              msecs_to_jiffies(1000)
+
+struct stmpe_adc {
+       struct stmpe *stmpe;
+       struct clk *clk;
+       struct device *dev;
+       struct mutex lock;
+
+       /* We are allocating plus one for the temperature channel */
+       struct iio_chan_spec stmpe_adc_iio_channels[STMPE_ADC_LAST_NR + 2];
+
+       struct completion completion;
+
+       u8 channel;
+       u32 value;
+};
+
+static int stmpe_read_voltage(struct stmpe_adc *info,
+               struct iio_chan_spec const *chan, int *val)
+{
+       long ret;
+
+       mutex_lock(&info->lock);
+
+       info->channel = (u8)chan->channel;
+
+       if (info->channel > STMPE_ADC_LAST_NR) {
+               mutex_unlock(&info->lock);
+               return -EINVAL;
+       }
+
+       stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_EN,
+                       STMPE_ADC_CH(info->channel));
+
+       stmpe_reg_write(info->stmpe, STMPE_REG_ADC_CAPT,
+                       STMPE_ADC_CH(info->channel));
+
+       *val = info->value;
+
+       ret = wait_for_completion_interruptible_timeout
+               (&info->completion, STMPE_ADC_TIMEOUT);
+
+       if (ret <= 0) {
+               mutex_unlock(&info->lock);
+               if (ret == 0)
+                       return -ETIMEDOUT;
+               else
+                       return ret;
+       }
+
+       *val = info->value;
+
+       mutex_unlock(&info->lock);
+
+       return 0;
+}
+
+static int stmpe_read_temp(struct stmpe_adc *info,
+               struct iio_chan_spec const *chan, int *val)
+{
+       long ret;
+
+       mutex_lock(&info->lock);
+
+       info->channel = (u8)chan->channel;
+
+       if (info->channel != STMPE_TEMP_CHANNEL) {
+               mutex_unlock(&info->lock);
+               return -EINVAL;
+       }
+
+       stmpe_reg_write(info->stmpe, STMPE_REG_TEMP_CTRL,
+                       STMPE_START_ONE_TEMP_CONV);
+
+       ret = wait_for_completion_interruptible_timeout
+               (&info->completion, STMPE_ADC_TIMEOUT);
+
+       if (ret <= 0) {
+               mutex_unlock(&info->lock);
+               if (ret == 0)
+                       return -ETIMEDOUT;
+               else
+                       return ret;
+       }
+
+       /*
+        * absolute temp = +V3.3 * value /7.51 [K]
+        * scale to [milli Â°C]
+        */
+       *val = ((449960l * info->value) / 1024l) - 273150;
+
+       mutex_unlock(&info->lock);
+
+       return 0;
+}
+
+static int stmpe_read_raw(struct iio_dev *indio_dev,
+                         struct iio_chan_spec const *chan,
+                         int *val,
+                         int *val2,
+                         long mask)
+{
+       struct stmpe_adc *info = iio_priv(indio_dev);
+       long ret;
+
+       switch (mask) {
+       case IIO_CHAN_INFO_RAW:
+       case IIO_CHAN_INFO_PROCESSED:
+
+               switch (chan->type) {
+               case IIO_VOLTAGE:
+                       ret = stmpe_read_voltage(info, chan, val);
+                       break;
+
+               case IIO_TEMP:
+                       ret = stmpe_read_temp(info, chan, val);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+
+               if (ret < 0)
+                       return ret;
+
+               return IIO_VAL_INT;
+
+       case IIO_CHAN_INFO_SCALE:
+               *val = 3300;
+               *val2 = info->stmpe->mod_12b ? 12 : 10;
+               return IIO_VAL_FRACTIONAL_LOG2;
+
+       default:
+               break;
+       }
+
+       return -EINVAL;
+}
+
+static irqreturn_t stmpe_adc_isr(int irq, void *dev_id)
+{
+       struct stmpe_adc *info = (struct stmpe_adc *)dev_id;
+       u16 data;
+
+       if (info->channel > STMPE_TEMP_CHANNEL)
+               return IRQ_NONE;
+
+       if (info->channel <= STMPE_ADC_LAST_NR) {
+               int int_sta;
+
+               int_sta = stmpe_reg_read(info->stmpe, STMPE_REG_ADC_INT_STA);
+
+               /* Is the interrupt relevant */
+               if (!(int_sta & STMPE_ADC_CH(info->channel)))
+                       return IRQ_NONE;
+
+               /* Read value */
+               stmpe_block_read(info->stmpe,
+                       STMPE_REG_ADC_DATA_CH(info->channel), 2, (u8 *) &data);
+
+               stmpe_reg_write(info->stmpe, STMPE_REG_ADC_INT_STA, int_sta);
+       } else if (info->channel == STMPE_TEMP_CHANNEL) {
+               /* Read value */
+               stmpe_block_read(info->stmpe, STMPE_REG_TEMP_DATA, 2,
+                               (u8 *) &data);
+       }
+
+       info->value = (u32) be16_to_cpu(data);
+       complete(&info->completion);
+
+       return IRQ_HANDLED;
+}
+
+static const struct iio_info stmpe_adc_iio_info = {
+       .read_raw = &stmpe_read_raw,
+};
+
+static void stmpe_adc_voltage_chan(struct iio_chan_spec *ics, int chan)
+{
+       ics->type = IIO_VOLTAGE;
+       ics->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+       ics->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
+       ics->indexed = 1;
+       ics->channel = chan;
+}
+
+static void stmpe_adc_temp_chan(struct iio_chan_spec *ics, int chan)
+{
+       ics->type = IIO_TEMP;
+       ics->info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED);
+       ics->indexed = 1;
+       ics->channel = chan;
+}
+
+static int stmpe_adc_init_hw(struct stmpe_adc *adc)
+{
+       int ret;
+       struct stmpe *stmpe = adc->stmpe;
+
+       ret = stmpe_enable(stmpe, STMPE_BLOCK_ADC);
+       if (ret) {
+               dev_err(stmpe->dev, "Could not enable clock for ADC\n");
+               return ret;
+       }
+
+       ret = stmpe811_adc_common_init(stmpe);
+       if (ret) {
+               stmpe_disable(stmpe, STMPE_BLOCK_ADC);
+               return ret;
+       }
+
+       /* use temp irq for each conversion completion */
+       stmpe_reg_write(stmpe, STMPE_REG_TEMP_TH, 0);
+       stmpe_reg_write(stmpe, STMPE_REG_TEMP_TH + 1, 0);
+
+       return 0;
+}
+
+static int stmpe_adc_probe(struct platform_device *pdev)
+{
+       struct iio_dev *indio_dev;
+       struct stmpe_adc *info;
+       struct device_node *np;
+       u32 norequest_mask = 0;
+       int irq_temp, irq_adc;
+       int num_chan = 0;
+       int i = 0;
+       int ret;
+
+       irq_adc = platform_get_irq_byname(pdev, "STMPE_ADC");
+       if (irq_adc < 0)
+               return irq_adc;
+
+       indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(struct stmpe_adc));
+       if (!indio_dev) {
+               dev_err(&pdev->dev, "failed allocating iio device\n");
+               return -ENOMEM;
+       }
+
+       info = iio_priv(indio_dev);
+       mutex_init(&info->lock);
+
+       init_completion(&info->completion);
+       ret = devm_request_threaded_irq(&pdev->dev, irq_adc, NULL,
+                                       stmpe_adc_isr, IRQF_ONESHOT,
+                                       "stmpe-adc", info);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed requesting irq, irq = %d\n",
+                               irq_adc);
+               return ret;
+       }
+
+       irq_temp = platform_get_irq_byname(pdev, "STMPE_TEMP_SENS");
+       if (irq_temp >= 0) {
+               ret = devm_request_threaded_irq(&pdev->dev, irq_temp, NULL,
+                                               stmpe_adc_isr, IRQF_ONESHOT,
+                                               "stmpe-adc", info);
+               if (ret < 0)
+                       dev_warn(&pdev->dev, "failed requesting irq for"
+                                " temp sensor, irq = %d\n", irq_temp);
+       }
+
+       platform_set_drvdata(pdev, indio_dev);
+
+       indio_dev->name         = dev_name(&pdev->dev);
+       indio_dev->dev.parent   = &pdev->dev;
+       indio_dev->info         = &stmpe_adc_iio_info;
+       indio_dev->modes        = INDIO_DIRECT_MODE;
+
+       info->stmpe = dev_get_drvdata(pdev->dev.parent);
+
+       np = pdev->dev.of_node;
+
+       if (!np)
+               dev_err(&pdev->dev, "no device tree node found\n");
+
+       of_property_read_u32(np, "st,norequest-mask", &norequest_mask);
+
+       for_each_clear_bit(i, (unsigned long *) &norequest_mask,
+                          (STMPE_ADC_LAST_NR + 1)) {
+               stmpe_adc_voltage_chan(&info->stmpe_adc_iio_channels[num_chan], i);
+               num_chan++;
+       }
+       stmpe_adc_temp_chan(&info->stmpe_adc_iio_channels[num_chan], i);
+       num_chan++;
+       indio_dev->channels = info->stmpe_adc_iio_channels;
+       indio_dev->num_channels = num_chan;
+
+       ret = stmpe_adc_init_hw(info);
+       if (ret)
+               return ret;
+
+       return devm_iio_device_register(&pdev->dev, indio_dev);
+}
+
+static int __maybe_unused stmpe_adc_resume(struct device *dev)
+{
+       struct iio_dev *indio_dev = dev_get_drvdata(dev);
+       struct stmpe_adc *info = iio_priv(indio_dev);
+
+       stmpe_adc_init_hw(info);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(stmpe_adc_pm_ops, NULL, stmpe_adc_resume);
+
+static struct platform_driver stmpe_adc_driver = {
+       .probe          = stmpe_adc_probe,
+       .driver         = {
+               .name   = "stmpe-adc",
+               .pm     = &stmpe_adc_pm_ops,
+       },
+};
+
+module_platform_driver(stmpe_adc_driver);
+
+MODULE_AUTHOR("Stefan Agner <stefan.agner@toradex.com>");
+MODULE_DESCRIPTION("STMPEXXX ADC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:stmpe-adc");
index ca59a2b..279fb02 100644 (file)
@@ -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
index 9d0f9d1..1b44202 100644 (file)
@@ -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 (file)
index 0000000..7b49c99
--- /dev/null
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) STMicroelectronics 2018
+// Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
+
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/stpmic1.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+/**
+ * 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 <p.paillet@st.com>");
+MODULE_LICENSE("GPL v2");
index 2a78e27..cf9c9aa 100644 (file)
@@ -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
 
 #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
 
  * @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
@@ -99,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;
@@ -203,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;
 
@@ -213,27 +187,17 @@ 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);
-
-       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,
-                       ADC_FREQ(0xff), 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;
        }
 
-       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 +206,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 +227,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;
@@ -303,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))
index 2acc105..211da11 100644 (file)
@@ -1204,7 +1204,7 @@ config MFD_STMPE
 
          Currently supported devices are:
 
-               STMPE811: GPIO, Touchscreen
+               STMPE811: GPIO, Touchscreen, ADC
                STMPE1601: GPIO, Keypad
                STMPE1801: GPIO, Keypad
                STMPE2401: GPIO, Keypad
@@ -1217,6 +1217,7 @@ config MFD_STMPE
                GPIO: stmpe-gpio
                Keypad: stmpe-keypad
                Touchscreen: stmpe-ts
+               ADC: stmpe-adc
 
 menu "STMicroelectronics STMPE Interface Drivers"
 depends on MFD_STMPE
@@ -1871,6 +1872,22 @@ config MFD_STM32_TIMERS
          for PWM and IIO Timer. This driver allow to share the
          registers between the others drivers.
 
+config MFD_STPMIC1
+       tristate "Support for STPMIC1 PMIC"
+       depends on (I2C=y && OF)
+       select REGMAP_I2C
+       select REGMAP_IRQ
+       select MFD_CORE
+       help
+         Support for ST Microelectronics STPMIC1 PMIC. STPMIC1 has power on
+         key, watchdog and regulator functionalities which are supported via
+         the relevant subsystems. This driver provides core support for the
+         STPMIC1. In order to use the actual functionaltiy of the device other
+         drivers must be enabled.
+
+         To compile this driver as a module, choose M here: the
+         module will be called stpmic1.
+
 menu "Multimedia Capabilities Port drivers"
        depends on ARCH_SA1100
 
index 12980a4..a62fb01 100644 (file)
@@ -233,6 +233,7 @@ obj-$(CONFIG_INTEL_SOC_PMIC_CHTDC_TI)       += intel_soc_pmic_chtdc_ti.o
 obj-$(CONFIG_MFD_MT6397)       += mt6397-core.o
 
 obj-$(CONFIG_MFD_ALTERA_A10SR) += altera-a10sr.o
+obj-$(CONFIG_MFD_STPMIC1)      += stpmic1.o
 obj-$(CONFIG_MFD_SUN4I_GPADC)  += sun4i-gpadc.o
 
 obj-$(CONFIG_MFD_STM32_LPTIMER)        += stm32-lptimer.o
index 7569a4b..f2acb1f 100644 (file)
@@ -463,6 +463,28 @@ static const struct mfd_cell stmpe_ts_cell = {
        .num_resources  = ARRAY_SIZE(stmpe_ts_resources),
 };
 
+/*
+ * ADC (STMPE811)
+ */
+
+static struct resource stmpe_adc_resources[] = {
+       {
+               .name   = "STMPE_TEMP_SENS",
+               .flags  = IORESOURCE_IRQ,
+       },
+       {
+               .name   = "STMPE_ADC",
+               .flags  = IORESOURCE_IRQ,
+       },
+};
+
+static const struct mfd_cell stmpe_adc_cell = {
+       .name           = "stmpe-adc",
+       .of_compatible  = "st,stmpe-adc",
+       .resources      = stmpe_adc_resources,
+       .num_resources  = ARRAY_SIZE(stmpe_adc_resources),
+};
+
 /*
  * STMPE811 or STMPE610
  */
@@ -497,6 +519,11 @@ static struct stmpe_variant_block stmpe811_blocks[] = {
                .irq    = STMPE811_IRQ_TOUCH_DET,
                .block  = STMPE_BLOCK_TOUCHSCREEN,
        },
+       {
+               .cell   = &stmpe_adc_cell,
+               .irq    = STMPE811_IRQ_TEMP_SENS,
+               .block  = STMPE_BLOCK_ADC,
+       },
 };
 
 static int stmpe811_enable(struct stmpe *stmpe, unsigned int blocks,
@@ -517,6 +544,35 @@ static int stmpe811_enable(struct stmpe *stmpe, unsigned int blocks,
                                enable ? 0 : mask);
 }
 
+int stmpe811_adc_common_init(struct stmpe *stmpe)
+{
+       int ret;
+       u8 adc_ctrl1, adc_ctrl1_mask;
+
+       adc_ctrl1 = STMPE_SAMPLE_TIME(stmpe->sample_time) |
+                   STMPE_MOD_12B(stmpe->mod_12b) |
+                   STMPE_REF_SEL(stmpe->ref_sel);
+       adc_ctrl1_mask = STMPE_SAMPLE_TIME(0xff) | STMPE_MOD_12B(0xff) |
+                        STMPE_REF_SEL(0xff);
+
+       ret = stmpe_set_bits(stmpe, STMPE811_REG_ADC_CTRL1,
+                       adc_ctrl1_mask, adc_ctrl1);
+       if (ret) {
+               dev_err(stmpe->dev, "Could not setup ADC\n");
+               return ret;
+       }
+
+       ret = stmpe_set_bits(stmpe, STMPE811_REG_ADC_CTRL2,
+                       STMPE_ADC_FREQ(0xff), STMPE_ADC_FREQ(stmpe->adc_freq));
+       if (ret) {
+               dev_err(stmpe->dev, "Could not setup ADC\n");
+               return ret;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(stmpe811_adc_common_init);
+
 static int stmpe811_get_altfunc(struct stmpe *stmpe, enum stmpe_block block)
 {
        /* 0 for touchscreen, 1 for GPIO */
@@ -1325,6 +1381,7 @@ int stmpe_probe(struct stmpe_client_info *ci, enum stmpe_partnum partnum)
        struct device_node *np = ci->dev->of_node;
        struct stmpe *stmpe;
        int ret;
+       u32 val;
 
        pdata = devm_kzalloc(ci->dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
@@ -1342,6 +1399,15 @@ int stmpe_probe(struct stmpe_client_info *ci, enum stmpe_partnum partnum)
        mutex_init(&stmpe->irq_lock);
        mutex_init(&stmpe->lock);
 
+       if (!of_property_read_u32(np, "st,sample-time", &val))
+               stmpe->sample_time = val;
+       if (!of_property_read_u32(np, "st,mod-12b", &val))
+               stmpe->mod_12b = val;
+       if (!of_property_read_u32(np, "st,ref-sel", &val))
+               stmpe->ref_sel = val;
+       if (!of_property_read_u32(np, "st,adc-freq", &val))
+               stmpe->adc_freq = val;
+
        stmpe->dev = ci->dev;
        stmpe->client = ci->client;
        stmpe->pdata = pdata;
@@ -1433,6 +1499,8 @@ int stmpe_remove(struct stmpe *stmpe)
        if (!IS_ERR(stmpe->vcc))
                regulator_disable(stmpe->vcc);
 
+       __stmpe_disable(stmpe, STMPE_BLOCK_ADC);
+
        mfd_remove_devices(stmpe->dev);
 
        return 0;
diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c
new file mode 100644 (file)
index 0000000..7dfbe89
--- /dev/null
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) STMicroelectronics 2018
+// Author: Pascal Paillet <p.paillet@st.com>
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/stpmic1.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/pm_wakeirq.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/mfd/st,stpmic1.h>
+
+#define STPMIC1_MAIN_IRQ 0
+
+static const struct regmap_range stpmic1_readable_ranges[] = {
+       regmap_reg_range(TURN_ON_SR, VERSION_SR),
+       regmap_reg_range(SWOFF_PWRCTRL_CR, LDO6_STDBY_CR),
+       regmap_reg_range(BST_SW_CR, BST_SW_CR),
+       regmap_reg_range(INT_PENDING_R1, INT_PENDING_R4),
+       regmap_reg_range(INT_CLEAR_R1, INT_CLEAR_R4),
+       regmap_reg_range(INT_MASK_R1, INT_MASK_R4),
+       regmap_reg_range(INT_SET_MASK_R1, INT_SET_MASK_R4),
+       regmap_reg_range(INT_CLEAR_MASK_R1, INT_CLEAR_MASK_R4),
+       regmap_reg_range(INT_SRC_R1, INT_SRC_R1),
+};
+
+static const struct regmap_range stpmic1_writeable_ranges[] = {
+       regmap_reg_range(SWOFF_PWRCTRL_CR, LDO6_STDBY_CR),
+       regmap_reg_range(BST_SW_CR, BST_SW_CR),
+       regmap_reg_range(INT_CLEAR_R1, INT_CLEAR_R4),
+       regmap_reg_range(INT_SET_MASK_R1, INT_SET_MASK_R4),
+       regmap_reg_range(INT_CLEAR_MASK_R1, INT_CLEAR_MASK_R4),
+};
+
+static const struct regmap_range stpmic1_volatile_ranges[] = {
+       regmap_reg_range(TURN_ON_SR, VERSION_SR),
+       regmap_reg_range(WCHDG_CR, WCHDG_CR),
+       regmap_reg_range(INT_PENDING_R1, INT_PENDING_R4),
+       regmap_reg_range(INT_SRC_R1, INT_SRC_R4),
+};
+
+static const struct regmap_access_table stpmic1_readable_table = {
+       .yes_ranges = stpmic1_readable_ranges,
+       .n_yes_ranges = ARRAY_SIZE(stpmic1_readable_ranges),
+};
+
+static const struct regmap_access_table stpmic1_writeable_table = {
+       .yes_ranges = stpmic1_writeable_ranges,
+       .n_yes_ranges = ARRAY_SIZE(stpmic1_writeable_ranges),
+};
+
+static const struct regmap_access_table stpmic1_volatile_table = {
+       .yes_ranges = stpmic1_volatile_ranges,
+       .n_yes_ranges = ARRAY_SIZE(stpmic1_volatile_ranges),
+};
+
+const struct regmap_config stpmic1_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .cache_type = REGCACHE_RBTREE,
+       .max_register = PMIC_MAX_REGISTER_ADDRESS,
+       .rd_table = &stpmic1_readable_table,
+       .wr_table = &stpmic1_writeable_table,
+       .volatile_table = &stpmic1_volatile_table,
+};
+
+static const struct regmap_irq stpmic1_irqs[] = {
+       REGMAP_IRQ_REG(IT_PONKEY_F, 0, 0x01),
+       REGMAP_IRQ_REG(IT_PONKEY_R, 0, 0x02),
+       REGMAP_IRQ_REG(IT_WAKEUP_F, 0, 0x04),
+       REGMAP_IRQ_REG(IT_WAKEUP_R, 0, 0x08),
+       REGMAP_IRQ_REG(IT_VBUS_OTG_F, 0, 0x10),
+       REGMAP_IRQ_REG(IT_VBUS_OTG_R, 0, 0x20),
+       REGMAP_IRQ_REG(IT_SWOUT_F, 0, 0x40),
+       REGMAP_IRQ_REG(IT_SWOUT_R, 0, 0x80),
+
+       REGMAP_IRQ_REG(IT_CURLIM_BUCK1, 1, 0x01),
+       REGMAP_IRQ_REG(IT_CURLIM_BUCK2, 1, 0x02),
+       REGMAP_IRQ_REG(IT_CURLIM_BUCK3, 1, 0x04),
+       REGMAP_IRQ_REG(IT_CURLIM_BUCK4, 1, 0x08),
+       REGMAP_IRQ_REG(IT_OCP_OTG, 1, 0x10),
+       REGMAP_IRQ_REG(IT_OCP_SWOUT, 1, 0x20),
+       REGMAP_IRQ_REG(IT_OCP_BOOST, 1, 0x40),
+       REGMAP_IRQ_REG(IT_OVP_BOOST, 1, 0x80),
+
+       REGMAP_IRQ_REG(IT_CURLIM_LDO1, 2, 0x01),
+       REGMAP_IRQ_REG(IT_CURLIM_LDO2, 2, 0x02),
+       REGMAP_IRQ_REG(IT_CURLIM_LDO3, 2, 0x04),
+       REGMAP_IRQ_REG(IT_CURLIM_LDO4, 2, 0x08),
+       REGMAP_IRQ_REG(IT_CURLIM_LDO5, 2, 0x10),
+       REGMAP_IRQ_REG(IT_CURLIM_LDO6, 2, 0x20),
+       REGMAP_IRQ_REG(IT_SHORT_SWOTG, 2, 0x40),
+       REGMAP_IRQ_REG(IT_SHORT_SWOUT, 2, 0x80),
+
+       REGMAP_IRQ_REG(IT_TWARN_F, 3, 0x01),
+       REGMAP_IRQ_REG(IT_TWARN_R, 3, 0x02),
+       REGMAP_IRQ_REG(IT_VINLOW_F, 3, 0x04),
+       REGMAP_IRQ_REG(IT_VINLOW_R, 3, 0x08),
+       REGMAP_IRQ_REG(IT_SWIN_F, 3, 0x40),
+       REGMAP_IRQ_REG(IT_SWIN_R, 3, 0x80),
+};
+
+static const struct regmap_irq_chip stpmic1_regmap_irq_chip = {
+       .name = "pmic_irq",
+       .status_base = INT_PENDING_R1,
+       .mask_base = INT_CLEAR_MASK_R1,
+       .unmask_base = INT_SET_MASK_R1,
+       .ack_base = INT_CLEAR_R1,
+       .num_regs = STPMIC1_PMIC_NUM_IRQ_REGS,
+       .irqs = stpmic1_irqs,
+       .num_irqs = ARRAY_SIZE(stpmic1_irqs),
+};
+
+static int stpmic1_probe(struct i2c_client *i2c,
+                        const struct i2c_device_id *id)
+{
+       struct stpmic1 *ddata;
+       struct device *dev = &i2c->dev;
+       int ret;
+       struct device_node *np = dev->of_node;
+       u32 reg;
+
+       ddata = devm_kzalloc(dev, sizeof(struct stpmic1), GFP_KERNEL);
+       if (!ddata)
+               return -ENOMEM;
+
+       i2c_set_clientdata(i2c, ddata);
+       ddata->dev = dev;
+
+       ddata->regmap = devm_regmap_init_i2c(i2c, &stpmic1_regmap_config);
+       if (IS_ERR(ddata->regmap))
+               return PTR_ERR(ddata->regmap);
+
+       ddata->irq = of_irq_get(np, STPMIC1_MAIN_IRQ);
+       if (ddata->irq < 0) {
+               dev_err(dev, "Failed to get main IRQ: %d\n", ddata->irq);
+               return ddata->irq;
+       }
+
+       ret = regmap_read(ddata->regmap, VERSION_SR, &reg);
+       if (ret) {
+               dev_err(dev, "Unable to read PMIC version\n");
+               return ret;
+       }
+       dev_info(dev, "PMIC Chip Version: 0x%x\n", reg);
+
+       /* Initialize PMIC IRQ Chip & associated IRQ domains */
+       ret = devm_regmap_add_irq_chip(dev, ddata->regmap, ddata->irq,
+                                      IRQF_ONESHOT | IRQF_SHARED,
+                                      0, &stpmic1_regmap_irq_chip,
+                                      &ddata->irq_data);
+       if (ret) {
+               dev_err(dev, "IRQ Chip registration failed: %d\n", ret);
+               return ret;
+       }
+
+       return devm_of_platform_populate(dev);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stpmic1_suspend(struct device *dev)
+{
+       struct i2c_client *i2c = to_i2c_client(dev);
+       struct stpmic1 *pmic_dev = i2c_get_clientdata(i2c);
+
+       disable_irq(pmic_dev->irq);
+
+       return 0;
+}
+
+static int stpmic1_resume(struct device *dev)
+{
+       struct i2c_client *i2c = to_i2c_client(dev);
+       struct stpmic1 *pmic_dev = i2c_get_clientdata(i2c);
+       int ret;
+
+       ret = regcache_sync(pmic_dev->regmap);
+       if (ret)
+               return ret;
+
+       enable_irq(pmic_dev->irq);
+
+       return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(stpmic1_pm, stpmic1_suspend, stpmic1_resume);
+
+static const struct of_device_id stpmic1_of_match[] = {
+       { .compatible = "st,stpmic1", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, stpmic1_of_match);
+
+static struct i2c_driver stpmic1_driver = {
+       .driver = {
+               .name = "stpmic1",
+               .of_match_table = of_match_ptr(stpmic1_of_match),
+               .pm = &stpmic1_pm,
+       },
+       .probe = stpmic1_probe,
+};
+
+module_i2c_driver(stpmic1_driver);
+
+MODULE_DESCRIPTION("STPMIC1 PMIC Driver");
+MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>");
+MODULE_LICENSE("GPL v2");
index 57f017d..65c3c42 100644 (file)
@@ -817,6 +817,18 @@ config STM32_WATCHDOG
          To compile this driver as a module, choose M here: the
          module will be called stm32_iwdg.
 
+config STPMIC1_WATCHDOG
+       tristate "STPMIC1 PMIC watchdog support"
+       depends on MFD_STPMIC1
+       select WATCHDOG_CORE
+       help
+         Say Y here to include watchdog support embedded into STPMIC1 PMIC.
+         If the watchdog timer expires, stpmic1 will shut down all its power
+         supplies.
+
+         To compile this driver as a module, choose M here: the
+         module will be called spmic1_wdt.
+
 config UNIPHIER_WATCHDOG
        tristate "UniPhier watchdog support"
        depends on ARCH_UNIPHIER || COMPILE_TEST
index a0917ef..4e78a8c 100644 (file)
@@ -220,3 +220,4 @@ obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o
 obj-$(CONFIG_MENF21BMC_WATCHDOG) += menf21bmc_wdt.o
 obj-$(CONFIG_MENZ069_WATCHDOG) += menz69_wdt.o
 obj-$(CONFIG_RAVE_SP_WATCHDOG) += rave-sp-wdt.o
+obj-$(CONFIG_STPMIC1_WATCHDOG) += stpmic1_wdt.o
diff --git a/drivers/watchdog/stpmic1_wdt.c b/drivers/watchdog/stpmic1_wdt.c
new file mode 100644 (file)
index 0000000..ad431d8
--- /dev/null
@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) STMicroelectronics 2018
+// Author: Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
+
+#include <linux/kernel.h>
+#include <linux/mfd/stpmic1.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/watchdog.h>
+
+/* WATCHDOG CONTROL REGISTER bit */
+#define WDT_START              BIT(0)
+#define WDT_PING               BIT(1)
+#define WDT_START_MASK         BIT(0)
+#define WDT_PING_MASK          BIT(1)
+#define WDT_STOP               0
+
+#define PMIC_WDT_MIN_TIMEOUT 1
+#define PMIC_WDT_MAX_TIMEOUT 256
+#define PMIC_WDT_DEFAULT_TIMEOUT 30
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+struct stpmic1_wdt {
+       struct stpmic1 *pmic;
+       struct watchdog_device wdtdev;
+};
+
+static int pmic_wdt_start(struct watchdog_device *wdd)
+{
+       struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd);
+
+       return regmap_update_bits(wdt->pmic->regmap,
+                                 WCHDG_CR, WDT_START_MASK, WDT_START);
+}
+
+static int pmic_wdt_stop(struct watchdog_device *wdd)
+{
+       struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd);
+
+       return regmap_update_bits(wdt->pmic->regmap,
+                                 WCHDG_CR, WDT_START_MASK, WDT_STOP);
+}
+
+static int pmic_wdt_ping(struct watchdog_device *wdd)
+{
+       struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd);
+
+       return regmap_update_bits(wdt->pmic->regmap,
+                                 WCHDG_CR, WDT_PING_MASK, WDT_PING);
+}
+
+static int pmic_wdt_set_timeout(struct watchdog_device *wdd,
+                               unsigned int timeout)
+{
+       struct stpmic1_wdt *wdt = watchdog_get_drvdata(wdd);
+
+       wdd->timeout = timeout;
+       /* timeout is equal to register value + 1 */
+       return regmap_write(wdt->pmic->regmap, WCHDG_TIMER_CR, timeout - 1);
+}
+
+static const struct watchdog_info pmic_watchdog_info = {
+       .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
+       .identity = "STPMIC1 PMIC Watchdog",
+};
+
+static const struct watchdog_ops pmic_watchdog_ops = {
+       .owner = THIS_MODULE,
+       .start = pmic_wdt_start,
+       .stop = pmic_wdt_stop,
+       .ping = pmic_wdt_ping,
+       .set_timeout = pmic_wdt_set_timeout,
+};
+
+static int pmic_wdt_probe(struct platform_device *pdev)
+{
+       int ret;
+       struct stpmic1 *pmic;
+       struct stpmic1_wdt *wdt;
+
+       if (!pdev->dev.parent)
+               return -EINVAL;
+
+       pmic = dev_get_drvdata(pdev->dev.parent);
+       if (!pmic)
+               return -EINVAL;
+
+       wdt = devm_kzalloc(&pdev->dev, sizeof(struct stpmic1_wdt), GFP_KERNEL);
+       if (!wdt)
+               return -ENOMEM;
+
+       wdt->pmic = pmic;
+
+       wdt->wdtdev.info = &pmic_watchdog_info;
+       wdt->wdtdev.ops = &pmic_watchdog_ops;
+       wdt->wdtdev.min_timeout = PMIC_WDT_MIN_TIMEOUT;
+       wdt->wdtdev.max_timeout = PMIC_WDT_MAX_TIMEOUT;
+       wdt->wdtdev.parent = &pdev->dev;
+
+       wdt->wdtdev.timeout = PMIC_WDT_DEFAULT_TIMEOUT;
+       watchdog_init_timeout(&wdt->wdtdev, 0, &pdev->dev);
+
+       watchdog_set_nowayout(&wdt->wdtdev, nowayout);
+       watchdog_set_drvdata(&wdt->wdtdev, wdt);
+
+       ret = devm_watchdog_register_device(&pdev->dev, &wdt->wdtdev);
+       if (ret)
+               return ret;
+
+       dev_dbg(wdt->pmic->dev, "PMIC Watchdog driver probed\n");
+       return 0;
+}
+
+static const struct of_device_id of_pmic_wdt_match[] = {
+       { .compatible = "st,stpmic1-wdt" },
+       { },
+};
+
+MODULE_DEVICE_TABLE(of, of_pmic_wdt_match);
+
+static struct platform_driver stpmic1_wdt_driver = {
+       .probe = pmic_wdt_probe,
+       .driver = {
+               .name = "stpmic1-wdt",
+               .of_match_table = of_pmic_wdt_match,
+       },
+};
+module_platform_driver(stpmic1_wdt_driver);
+
+MODULE_DESCRIPTION("Watchdog driver for STPMIC1 device");
+MODULE_AUTHOR("Pascal Paillet <p.paillet@st.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/dt-bindings/mfd/st,stpmic1.h b/include/dt-bindings/mfd/st,stpmic1.h
new file mode 100644 (file)
index 0000000..321cd08
--- /dev/null
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Philippe Peurichard <philippe.peurichard@st.com>,
+ * Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
+ */
+
+#ifndef __DT_BINDINGS_STPMIC1_H__
+#define __DT_BINDINGS_STPMIC1_H__
+
+/* IRQ definitions */
+#define IT_PONKEY_F    0
+#define IT_PONKEY_R    1
+#define IT_WAKEUP_F    2
+#define IT_WAKEUP_R    3
+#define IT_VBUS_OTG_F  4
+#define IT_VBUS_OTG_R  5
+#define IT_SWOUT_F     6
+#define IT_SWOUT_R     7
+
+#define IT_CURLIM_BUCK1        8
+#define IT_CURLIM_BUCK2        9
+#define IT_CURLIM_BUCK3        10
+#define IT_CURLIM_BUCK4        11
+#define IT_OCP_OTG     12
+#define IT_OCP_SWOUT   13
+#define IT_OCP_BOOST   14
+#define IT_OVP_BOOST   15
+
+#define IT_CURLIM_LDO1 16
+#define IT_CURLIM_LDO2 17
+#define IT_CURLIM_LDO3 18
+#define IT_CURLIM_LDO4 19
+#define IT_CURLIM_LDO5 20
+#define IT_CURLIM_LDO6 21
+#define IT_SHORT_SWOTG 22
+#define IT_SHORT_SWOUT 23
+
+#define IT_TWARN_F     24
+#define IT_TWARN_R     25
+#define IT_VINLOW_F    26
+#define IT_VINLOW_R    27
+#define IT_SWIN_F      30
+#define IT_SWIN_R      31
+
+/* BUCK MODES definitions */
+#define STPMIC1_BUCK_MODE_NORMAL 0
+#define STPMIC1_BUCK_MODE_LP 2
+
+#endif /* __DT_BINDINGS_STPMIC1_H__ */
index 4a827af..07f55aa 100644 (file)
 
 #include <linux/mutex.h>
 
+#define STMPE_SAMPLE_TIME(x)   ((x & 0xf) << 4)
+#define STMPE_MOD_12B(x)       ((x & 0x1) << 3)
+#define STMPE_REF_SEL(x)       ((x & 0x1) << 1)
+#define STMPE_ADC_FREQ(x)      (x & 0x3)
+#define STMPE_AVE_CTRL(x)      ((x & 0x3) << 6)
+#define STMPE_DET_DELAY(x)     ((x & 0x7) << 3)
+#define STMPE_SETTLING(x)      (x & 0x7)
+#define STMPE_FRACTION_Z(x)    (x & 0x7)
+#define STMPE_I_DRIVE(x)       (x & 0x1)
+#define STMPE_OP_MODE(x)       ((x & 0x7) << 1)
+
+#define STMPE811_REG_ADC_CTRL1 0x20
+#define STMPE811_REG_ADC_CTRL2 0x21
+
 struct device;
 struct regulator;
 
@@ -123,6 +137,12 @@ struct stmpe {
        u8 ier[2];
        u8 oldier[2];
        struct stmpe_platform_data *pdata;
+
+       /* For devices that use an ADC */
+       u8 sample_time;
+       u8 mod_12b;
+       u8 ref_sel;
+       u8 adc_freq;
 };
 
 extern int stmpe_reg_write(struct stmpe *stmpe, u8 reg, u8 data);
@@ -136,6 +156,7 @@ extern int stmpe_set_altfunc(struct stmpe *stmpe, u32 pins,
                             enum stmpe_block block);
 extern int stmpe_enable(struct stmpe *stmpe, unsigned int blocks);
 extern int stmpe_disable(struct stmpe *stmpe, unsigned int blocks);
+extern int stmpe811_adc_common_init(struct stmpe *stmpe);
 
 #define STMPE_GPIO_NOREQ_811_TOUCH     (0xf0)
 
diff --git a/include/linux/mfd/stpmic1.h b/include/linux/mfd/stpmic1.h
new file mode 100644 (file)
index 0000000..fa3f99f
--- /dev/null
@@ -0,0 +1,212 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) STMicroelectronics 2018 - All Rights Reserved
+ * Author: Philippe Peurichard <philippe.peurichard@st.com>,
+ * Pascal Paillet <p.paillet@st.com> for STMicroelectronics.
+ */
+
+#ifndef __LINUX_MFD_STPMIC1_H
+#define __LINUX_MFD_STPMIC1_H
+
+#define TURN_ON_SR             0x1
+#define TURN_OFF_SR            0x2
+#define ICC_LDO_TURN_OFF_SR    0x3
+#define ICC_BUCK_TURN_OFF_SR   0x4
+#define RREQ_STATE_SR          0x5
+#define VERSION_SR             0x6
+
+#define SWOFF_PWRCTRL_CR       0x10
+#define PADS_PULL_CR           0x11
+#define BUCKS_PD_CR            0x12
+#define LDO14_PD_CR            0x13
+#define LDO56_VREF_PD_CR       0x14
+#define VBUS_DET_VIN_CR                0x15
+#define PKEY_TURNOFF_CR                0x16
+#define BUCKS_MASK_RANK_CR     0x17
+#define BUCKS_MASK_RESET_CR    0x18
+#define LDOS_MASK_RANK_CR      0x19
+#define LDOS_MASK_RESET_CR     0x1A
+#define WCHDG_CR               0x1B
+#define WCHDG_TIMER_CR         0x1C
+#define BUCKS_ICCTO_CR         0x1D
+#define LDOS_ICCTO_CR          0x1E
+
+#define BUCK1_ACTIVE_CR                0x20
+#define BUCK2_ACTIVE_CR                0x21
+#define BUCK3_ACTIVE_CR                0x22
+#define BUCK4_ACTIVE_CR                0x23
+#define VREF_DDR_ACTIVE_CR     0x24
+#define LDO1_ACTIVE_CR         0x25
+#define LDO2_ACTIVE_CR         0x26
+#define LDO3_ACTIVE_CR         0x27
+#define LDO4_ACTIVE_CR         0x28
+#define LDO5_ACTIVE_CR         0x29
+#define LDO6_ACTIVE_CR         0x2A
+
+#define BUCK1_STDBY_CR         0x30
+#define BUCK2_STDBY_CR         0x31
+#define BUCK3_STDBY_CR         0x32
+#define BUCK4_STDBY_CR         0x33
+#define VREF_DDR_STDBY_CR      0x34
+#define LDO1_STDBY_CR          0x35
+#define LDO2_STDBY_CR          0x36
+#define LDO3_STDBY_CR          0x37
+#define LDO4_STDBY_CR          0x38
+#define LDO5_STDBY_CR          0x39
+#define LDO6_STDBY_CR          0x3A
+
+#define BST_SW_CR              0x40
+
+#define INT_PENDING_R1         0x50
+#define INT_PENDING_R2         0x51
+#define INT_PENDING_R3         0x52
+#define INT_PENDING_R4         0x53
+
+#define INT_DBG_LATCH_R1       0x60
+#define INT_DBG_LATCH_R2       0x61
+#define INT_DBG_LATCH_R3       0x62
+#define INT_DBG_LATCH_R4       0x63
+
+#define INT_CLEAR_R1           0x70
+#define INT_CLEAR_R2           0x71
+#define INT_CLEAR_R3           0x72
+#define INT_CLEAR_R4           0x73
+
+#define INT_MASK_R1            0x80
+#define INT_MASK_R2            0x81
+#define INT_MASK_R3            0x82
+#define INT_MASK_R4            0x83
+
+#define INT_SET_MASK_R1                0x90
+#define INT_SET_MASK_R2                0x91
+#define INT_SET_MASK_R3                0x92
+#define INT_SET_MASK_R4                0x93
+
+#define INT_CLEAR_MASK_R1      0xA0
+#define INT_CLEAR_MASK_R2      0xA1
+#define INT_CLEAR_MASK_R3      0xA2
+#define INT_CLEAR_MASK_R4      0xA3
+
+#define INT_SRC_R1             0xB0
+#define INT_SRC_R2             0xB1
+#define INT_SRC_R3             0xB2
+#define INT_SRC_R4             0xB3
+
+#define PMIC_MAX_REGISTER_ADDRESS INT_SRC_R4
+
+#define STPMIC1_PMIC_NUM_IRQ_REGS 4
+
+#define TURN_OFF_SR_ICC_EVENT  0x08
+
+#define LDO_VOLTAGE_MASK               GENMASK(6, 2)
+#define BUCK_VOLTAGE_MASK              GENMASK(7, 2)
+#define LDO_BUCK_VOLTAGE_SHIFT         2
+
+#define LDO_ENABLE_MASK                        BIT(0)
+#define BUCK_ENABLE_MASK               BIT(0)
+
+#define BUCK_HPLP_ENABLE_MASK          BIT(1)
+#define BUCK_HPLP_SHIFT                        1
+
+#define STDBY_ENABLE_MASK  BIT(0)
+
+#define BUCKS_PD_CR_REG_MASK   GENMASK(7, 0)
+#define BUCK_MASK_RANK_REGISTER_MASK   GENMASK(3, 0)
+#define BUCK_MASK_RESET_REGISTER_MASK  GENMASK(3, 0)
+#define LDO1234_PULL_DOWN_REGISTER_MASK        GENMASK(7, 0)
+#define LDO56_VREF_PD_CR_REG_MASK      GENMASK(5, 0)
+#define LDO_MASK_RANK_REGISTER_MASK    GENMASK(5, 0)
+#define LDO_MASK_RESET_REGISTER_MASK   GENMASK(5, 0)
+
+#define BUCK1_PULL_DOWN_REG            BUCKS_PD_CR
+#define BUCK1_PULL_DOWN_MASK           BIT(0)
+#define BUCK2_PULL_DOWN_REG            BUCKS_PD_CR
+#define BUCK2_PULL_DOWN_MASK           BIT(2)
+#define BUCK3_PULL_DOWN_REG            BUCKS_PD_CR
+#define BUCK3_PULL_DOWN_MASK           BIT(4)
+#define BUCK4_PULL_DOWN_REG            BUCKS_PD_CR
+#define BUCK4_PULL_DOWN_MASK           BIT(6)
+
+#define LDO1_PULL_DOWN_REG             LDO14_PD_CR
+#define LDO1_PULL_DOWN_MASK            BIT(0)
+#define LDO2_PULL_DOWN_REG             LDO14_PD_CR
+#define LDO2_PULL_DOWN_MASK            BIT(2)
+#define LDO3_PULL_DOWN_REG             LDO14_PD_CR
+#define LDO3_PULL_DOWN_MASK            BIT(4)
+#define LDO4_PULL_DOWN_REG             LDO14_PD_CR
+#define LDO4_PULL_DOWN_MASK            BIT(6)
+#define LDO5_PULL_DOWN_REG             LDO56_VREF_PD_CR
+#define LDO5_PULL_DOWN_MASK            BIT(0)
+#define LDO6_PULL_DOWN_REG             LDO56_VREF_PD_CR
+#define LDO6_PULL_DOWN_MASK            BIT(2)
+#define VREF_DDR_PULL_DOWN_REG         LDO56_VREF_PD_CR
+#define VREF_DDR_PULL_DOWN_MASK                BIT(4)
+
+#define BUCKS_ICCTO_CR_REG_MASK        GENMASK(6, 0)
+#define LDOS_ICCTO_CR_REG_MASK GENMASK(5, 0)
+
+#define LDO_BYPASS_MASK                        BIT(7)
+
+/* Main PMIC Control Register
+ * SWOFF_PWRCTRL_CR
+ * Address : 0x10
+ */
+#define ICC_EVENT_ENABLED              BIT(4)
+#define PWRCTRL_POLARITY_HIGH          BIT(3)
+#define PWRCTRL_PIN_VALID              BIT(2)
+#define RESTART_REQUEST_ENABLED                BIT(1)
+#define SOFTWARE_SWITCH_OFF_ENABLED    BIT(0)
+
+/* Main PMIC PADS Control Register
+ * PADS_PULL_CR
+ * Address : 0x11
+ */
+#define WAKEUP_DETECTOR_DISABLED       BIT(4)
+#define PWRCTRL_PD_ACTIVE              BIT(3)
+#define PWRCTRL_PU_ACTIVE              BIT(2)
+#define WAKEUP_PD_ACTIVE               BIT(1)
+#define PONKEY_PU_INACTIVE             BIT(0)
+
+/* Main PMIC VINLOW Control Register
+ * VBUS_DET_VIN_CRC DMSC
+ * Address : 0x15
+ */
+#define SWIN_DETECTOR_ENABLED          BIT(7)
+#define SWOUT_DETECTOR_ENABLED         BIT(6)
+#define VINLOW_ENABLED                 BIT(0)
+#define VINLOW_CTRL_REG_MASK           GENMASK(7, 0)
+
+/* USB Control Register
+ * Address : 0x40
+ */
+#define BOOST_OVP_DISABLED             BIT(7)
+#define VBUS_OTG_DETECTION_DISABLED    BIT(6)
+#define SW_OUT_DISCHARGE               BIT(5)
+#define VBUS_OTG_DISCHARGE             BIT(4)
+#define OCP_LIMIT_HIGH                 BIT(3)
+#define SWIN_SWOUT_ENABLED             BIT(2)
+#define USBSW_OTG_SWITCH_ENABLED       BIT(1)
+#define BOOST_ENABLED                  BIT(0)
+
+/* PKEY_TURNOFF_CR
+ * Address : 0x16
+ */
+#define PONKEY_PWR_OFF                 BIT(7)
+#define PONKEY_CC_FLAG_CLEAR           BIT(6)
+#define PONKEY_TURNOFF_TIMER_MASK      GENMASK(3, 0)
+#define PONKEY_TURNOFF_MASK            GENMASK(7, 0)
+
+/*
+ * struct stpmic1 - stpmic1 master device for sub-drivers
+ * @dev: master device of the chip (can be used to access platform data)
+ * @irq: main IRQ number
+ * @regmap_irq_chip_data: irq chip data
+ */
+struct stpmic1 {
+       struct device *dev;
+       struct regmap *regmap;
+       int irq;
+       struct regmap_irq_chip_data *irq_data;
+};
+
+#endif /*  __LINUX_MFD_STPMIC1_H */