diff options
-rw-r--r-- | Documentation/devicetree/bindings/iio/adc/ti,am3359-adc.yaml | 70 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/input/touchscreen/ti,am3359-tsc.yaml | 76 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt | 91 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml | 84 | ||||
-rw-r--r-- | drivers/clk/ti/clk-43xx.c | 1 | ||||
-rw-r--r-- | drivers/iio/adc/ti_am335x_adc.c | 220 | ||||
-rw-r--r-- | drivers/mfd/hi6421-spmi-pmic.c | 16 | ||||
-rw-r--r-- | drivers/mfd/ti_am335x_tscadc.c | 235 | ||||
-rw-r--r-- | drivers/misc/hi6421v600-irq.c | 9 | ||||
-rw-r--r-- | drivers/regulator/hi6421v600-regulator.c | 10 | ||||
-rw-r--r-- | include/dt-bindings/clock/am4.h | 1 | ||||
-rw-r--r-- | include/linux/mfd/hi6421-spmi-pmic.h | 25 | ||||
-rw-r--r-- | include/linux/mfd/ti_am335x_tscadc.h | 119 |
13 files changed, 563 insertions, 394 deletions
diff --git a/Documentation/devicetree/bindings/iio/adc/ti,am3359-adc.yaml b/Documentation/devicetree/bindings/iio/adc/ti,am3359-adc.yaml new file mode 100644 index 000000000000..d6f21d5cccd7 --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/ti,am3359-adc.yaml @@ -0,0 +1,70 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/iio/adc/ti,am3359-adc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI AM3359 ADC + +maintainers: + - Miquel Raynal <miquel.raynal@bootlin.com> + +properties: + compatible: + enum: + - ti,am3359-adc + - ti,am4372-adc + + '#io-channel-cells': + const: 1 + + ti,adc-channels: + description: List of analog inputs available for ADC. AIN0 = 0, AIN1 = 1 and + so on until AIN7 = 7. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 8 + + ti,chan-step-opendelay: + description: List of open delays for each channel of ADC in the order of + ti,adc-channels. The value corresponds to the number of ADC clock cycles + to wait after applying the step configuration registers and before sending + the start of ADC conversion. Maximum value is 0x3FFFF. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 8 + + ti,chan-step-sampledelay: + description: List of sample delays for each channel of ADC in the order of + ti,adc-channels. The value corresponds to the number of ADC clock cycles + to sample (to hold start of conversion high). Maximum value is 0xFF. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 8 + + ti,chan-step-avg: + description: Number of averages to be performed for each channel of ADC. If + average is 16 (this is also the maximum) then input is sampled 16 times + and averaged to get more accurate value. This increases the time taken by + ADC to generate a sample. Maximum value is 16. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 1 + maxItems: 8 + +required: + - compatible + - '#io-channel-cells' + - ti,adc-channels + +additionalProperties: false + +examples: + - | + adc { + compatible = "ti,am3359-adc"; + #io-channel-cells = <1>; + ti,adc-channels = <4 5 6 7>; + ti,chan-step-opendelay = <0x098 0x3ffff 0x098 0x0>; + ti,chan-step-sampledelay = <0xff 0x0 0xf 0x0>; + ti,chan-step-avg = <16 2 4 8>; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/ti,am3359-tsc.yaml b/Documentation/devicetree/bindings/input/touchscreen/ti,am3359-tsc.yaml new file mode 100644 index 000000000000..e44cc65abc8c --- /dev/null +++ b/Documentation/devicetree/bindings/input/touchscreen/ti,am3359-tsc.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/input/touchscreen/ti,am3359-tsc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI AM3359 Touchscreen controller + +maintainers: + - Miquel Raynal <miquel.raynal@bootlin.com> + +properties: + compatible: + const: ti,am3359-tsc + + ti,wires: + description: Wires refer to application modes i.e. 4/5/8 wire touchscreen + support on the platform. + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [4, 5, 8] + + ti,x-plate-resistance: + description: X plate resistance + $ref: /schemas/types.yaml#/definitions/uint32 + + ti,coordinate-readouts: + description: The sequencer supports a total of 16 programmable steps. Each + step is used to read a single coordinate. A single readout is enough but + multiple reads can increase the quality. A value of 5 means, 5 reads for + X, 5 for Y and 2 for Z (always). This utilises 12 of the 16 software steps + available. The remaining 4 can be used by the ADC. + $ref: /schemas/types.yaml#/definitions/uint32 + minimum: 1 + maximum: 6 + + ti,wire-config: + description: Different boards could have a different order for connecting + wires on touchscreen. We need to provide an 8-bit number where the + first four bits represent the analog lines and the next 4 bits represent + positive/negative terminal on that input line. Notations to represent the + input lines and terminals respectively are as follows, AIN0 = 0, AIN1 = 1 + and so on until AIN7 = 7. XP = 0, XN = 1, YP = 2, YN = 3. + $ref: /schemas/types.yaml#/definitions/uint32-array + minItems: 4 + maxItems: 8 + + ti,charge-delay: + description: Length of touch screen charge delay step in terms of ADC clock + cycles. Charge delay value should be large in order to avoid false pen-up + events. This value effects the overall sampling speed, hence need to be + kept as low as possible, while avoiding false pen-up event. Start from a + lower value, say 0x400, and increase value until false pen-up events are + avoided. The pen-up detection happens immediately after the charge step, + so this does in fact function as a hardware knob for adjusting the amount + of "settling time". + $ref: /schemas/types.yaml#/definitions/uint32 + +required: + - compatible + - ti,wires + - ti,x-plate-resistance + - ti,coordinate-readouts + - ti,wire-config + +additionalProperties: false + +examples: + - | + tsc { + compatible = "ti,am3359-tsc"; + ti,wires = <4>; + ti,x-plate-resistance = <200>; + ti,coordinate-readouts = <5>; + ti,wire-config = <0x00 0x11 0x22 0x33>; + ti,charge-delay = <0x400>; + }; diff --git a/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt b/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt deleted file mode 100644 index aad5e34965eb..000000000000 --- a/Documentation/devicetree/bindings/input/touchscreen/ti-tsc-adc.txt +++ /dev/null @@ -1,91 +0,0 @@ -* TI - TSC ADC (Touschscreen and analog digital converter) -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Required properties: -- mfd - compatible: Should be - "ti,am3359-tscadc" for AM335x/AM437x SoCs - "ti,am654-tscadc", "ti,am3359-tscadc" for AM654 SoCs -- child "tsc" - compatible: Should be "ti,am3359-tsc". - ti,wires: Wires refer to application modes i.e. 4/5/8 wire touchscreen - support on the platform. - ti,x-plate-resistance: X plate resistance - ti,coordinate-readouts: The sequencer supports a total of 16 - programmable steps each step is used to - read a single coordinate. A single - readout is enough but multiple reads can - increase the quality. - A value of 5 means, 5 reads for X, 5 for - Y and 2 for Z (always). This utilises 12 - of the 16 software steps available. The - remaining 4 can be used by the ADC. - ti,wire-config: Different boards could have a different order for - connecting wires on touchscreen. We need to provide an - 8 bit number where in the 1st four bits represent the - analog lines and the next 4 bits represent positive/ - negative terminal on that input line. Notations to - represent the input lines and terminals resoectively - is as follows: - AIN0 = 0, AIN1 = 1 and so on till AIN7 = 7. - XP = 0, XN = 1, YP = 2, YN = 3. -- child "adc" - compatible: Should be - "ti,am3359-adc" for AM335x/AM437x SoCs - "ti,am654-adc", "ti,am3359-adc" for AM654 SoCs - ti,adc-channels: List of analog inputs available for ADC. - AIN0 = 0, AIN1 = 1 and so on till AIN7 = 7. - -Optional properties: -- child "tsc" - ti,charge-delay: Length of touch screen charge delay step in terms of - ADC clock cycles. Charge delay value should be large - in order to avoid false pen-up events. This value - effects the overall sampling speed, hence need to be - kept as low as possible, while avoiding false pen-up - event. Start from a lower value, say 0x400, and - increase value until false pen-up events are avoided. - The pen-up detection happens immediately after the - charge step, so this does in fact function as a - hardware knob for adjusting the amount of "settling - time". - -- child "adc" - ti,chan-step-opendelay: List of open delays for each channel of - ADC in the order of ti,adc-channels. The - value corresponds to the number of ADC - clock cycles to wait after applying the - step configuration registers and before - sending the start of ADC conversion. - Maximum value is 0x3FFFF. - ti,chan-step-sampledelay: List of sample delays for each channel - of ADC in the order of ti,adc-channels. - The value corresponds to the number of - ADC clock cycles to sample (to hold - start of conversion high). - Maximum value is 0xFF. - ti,chan-step-avg: Number of averages to be performed for each - channel of ADC. If average is 16 then input - is sampled 16 times and averaged to get more - accurate value. This increases the time taken - by ADC to generate a sample. Valid range is 0 - average to 16 averages. Maximum value is 16. - -Example: - tscadc: tscadc@44e0d000 { - compatible = "ti,am3359-tscadc"; - tsc { - ti,wires = <4>; - ti,x-plate-resistance = <200>; - ti,coordiante-readouts = <5>; - ti,wire-config = <0x00 0x11 0x22 0x33>; - ti,charge-delay = <0x400>; - }; - - adc { - ti,adc-channels = <4 5 6 7>; - ti,chan-step-opendelay = <0x098 0x3ffff 0x098 0x0>; - ti,chan-step-sampledelay = <0xff 0x0 0xf 0x0>; - ti,chan-step-avg = <16 2 4 8>; - }; - } diff --git a/Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml b/Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml new file mode 100644 index 000000000000..34bf6a01436f --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/ti,am3359-tscadc.yaml @@ -0,0 +1,84 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/mfd/ti,am3359-tscadc.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI AM3359 Touchscreen controller/ADC + +maintainers: + - Miquel Raynal <miquel.raynal@bootlin.com> + +properties: + compatible: + oneOf: + - const: ti,am3359-tscadc + - items: + - const: ti,am654-tscadc + - const: ti,am3359-tscadc + - const: ti,am4372-magadc + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + clock-names: + const: fck + + dmas: + items: + - description: DMA controller phandle and request line for FIFO0 + - description: DMA controller phandle and request line for FIFO1 + + dma-names: + items: + - const: fifo0 + - const: fifo1 + + adc: + type: object + description: ADC child + + tsc: + type: object + description: Touchscreen controller child + + mag: + type: object + description: Magnetic reader + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - dmas + - dma-names + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/arm-gic.h> + + tscadc@0 { + compatible = "ti,am3359-tscadc"; + reg = <0x0 0x1000>; + interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&adc_tsc_fck>; + clock-names = "fck"; + dmas = <&edma 53 0>, <&edma 57 0>; + dma-names = "fifo0", "fifo1"; + + tsc { + }; + + adc { + }; + }; diff --git a/drivers/clk/ti/clk-43xx.c b/drivers/clk/ti/clk-43xx.c index 46c0add99570..6e97a541cfd3 100644 --- a/drivers/clk/ti/clk-43xx.c +++ b/drivers/clk/ti/clk-43xx.c @@ -116,6 +116,7 @@ static const struct omap_clkctrl_reg_data am4_l3s_clkctrl_regs[] __initconst = { { AM4_L3S_VPFE0_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" }, { AM4_L3S_VPFE1_CLKCTRL, NULL, CLKF_SW_SUP, "l3_gclk" }, { AM4_L3S_GPMC_CLKCTRL, NULL, CLKF_SW_SUP, "l3s_gclk" }, + { AM4_L3S_ADC1_CLKCTRL, NULL, CLKF_SW_SUP, "l3s_gclk" }, { AM4_L3S_MCASP0_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp0_fck" }, { AM4_L3S_MCASP1_CLKCTRL, NULL, CLKF_SW_SUP, "mcasp1_fck" }, { AM4_L3S_MMC3_CLKCTRL, NULL, CLKF_SW_SUP, "mmc_clk" }, diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c index 855cc2d64ac8..dbdc1ef48566 100644 --- a/drivers/iio/adc/ti_am335x_adc.c +++ b/drivers/iio/adc/ti_am335x_adc.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI ADC MFD driver * * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/kernel.h> @@ -25,6 +17,7 @@ #include <linux/of_device.h> #include <linux/iio/machine.h> #include <linux/iio/driver.h> +#include <linux/iopoll.h> #include <linux/mfd/ti_am335x_tscadc.h> #include <linux/iio/buffer.h> @@ -65,7 +58,7 @@ static unsigned int tiadc_readl(struct tiadc_device *adc, unsigned int reg) } static void tiadc_writel(struct tiadc_device *adc, unsigned int reg, - unsigned int val) + unsigned int val) { writel(val, adc->mfd_tscadc->tscadc_base + reg); } @@ -80,7 +73,7 @@ static u32 get_adc_step_mask(struct tiadc_device *adc_dev) } static u32 get_adc_chan_step_mask(struct tiadc_device *adc_dev, - struct iio_chan_spec const *chan) + struct iio_chan_spec const *chan) { int i; @@ -102,10 +95,18 @@ static u32 get_adc_step_bit(struct tiadc_device *adc_dev, int chan) return 1 << adc_dev->channel_step[chan]; } +static int tiadc_wait_idle(struct tiadc_device *adc_dev) +{ + u32 val; + + return readl_poll_timeout(adc_dev->mfd_tscadc->tscadc_base + REG_ADCFSM, + val, !(val & SEQ_STATUS), 10, + IDLE_TIMEOUT_MS * 1000 * adc_dev->channels); +} + static void tiadc_step_config(struct iio_dev *indio_dev) { struct tiadc_device *adc_dev = iio_priv(indio_dev); - struct device *dev = adc_dev->mfd_tscadc->dev; unsigned int stepconfig; int i, steps = 0; @@ -118,23 +119,14 @@ static void tiadc_step_config(struct iio_dev *indio_dev) * Channel would represent which analog input * needs to be given to ADC to digitalize data. */ - - for (i = 0; i < adc_dev->channels; i++) { int chan; chan = adc_dev->channel_line[i]; - if (adc_dev->step_avg[i] > STEPCONFIG_AVG_16) { - dev_warn(dev, "chan %d step_avg truncating to %d\n", - chan, STEPCONFIG_AVG_16); - adc_dev->step_avg[i] = STEPCONFIG_AVG_16; - } - if (adc_dev->step_avg[i]) - stepconfig = - STEPCONFIG_AVG(ffs(adc_dev->step_avg[i]) - 1) | - STEPCONFIG_FIFO1; + stepconfig = STEPCONFIG_AVG(ffs(adc_dev->step_avg[i]) - 1) | + STEPCONFIG_FIFO1; else stepconfig = STEPCONFIG_FIFO1; @@ -142,26 +134,13 @@ static void tiadc_step_config(struct iio_dev *indio_dev) stepconfig |= STEPCONFIG_MODE_SWCNT; tiadc_writel(adc_dev, REG_STEPCONFIG(steps), - stepconfig | STEPCONFIG_INP(chan) | - STEPCONFIG_INM_ADCREFM | - STEPCONFIG_RFP_VREFP | - STEPCONFIG_RFM_VREFN); - - if (adc_dev->open_delay[i] > STEPDELAY_OPEN_MASK) { - dev_warn(dev, "chan %d open delay truncating to 0x3FFFF\n", - chan); - adc_dev->open_delay[i] = STEPDELAY_OPEN_MASK; - } - - if (adc_dev->sample_delay[i] > 0xFF) { - dev_warn(dev, "chan %d sample delay truncating to 0xFF\n", - chan); - adc_dev->sample_delay[i] = 0xFF; - } + stepconfig | STEPCONFIG_INP(chan) | + STEPCONFIG_INM_ADCREFM | STEPCONFIG_RFP_VREFP | + STEPCONFIG_RFM_VREFN); tiadc_writel(adc_dev, REG_STEPDELAY(steps), - STEPDELAY_OPEN(adc_dev->open_delay[i]) | - STEPDELAY_SAMPLE(adc_dev->sample_delay[i])); + STEPDELAY_OPEN(adc_dev->open_delay[i]) | + STEPDELAY_SAMPLE(adc_dev->sample_delay[i])); adc_dev->channel_step[i] = steps; steps++; @@ -184,12 +163,14 @@ static irqreturn_t tiadc_irq_h(int irq, void *private) if (status & IRQENB_FIFO1OVRRUN) { /* FIFO Overrun. Clear flag. Disable/Enable ADC to recover */ config = tiadc_readl(adc_dev, REG_CTRL); - config &= ~(CNTRLREG_TSCSSENB); + config &= ~(CNTRLREG_SSENB); tiadc_writel(adc_dev, REG_CTRL, config); - tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1OVRRUN - | IRQENB_FIFO1UNDRFLW | IRQENB_FIFO1THRES); + tiadc_writel(adc_dev, REG_IRQSTATUS, + IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW | + IRQENB_FIFO1THRES); - /* wait for idle state. + /* + * Wait for the idle state. * ADC needs to finish the current conversion * before disabling the module */ @@ -197,7 +178,7 @@ static irqreturn_t tiadc_irq_h(int irq, void *private) adc_fsm = tiadc_readl(adc_dev, REG_ADCFSM); } while (adc_fsm != 0x10 && count++ < 100); - tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_TSCSSENB)); + tiadc_writel(adc_dev, REG_CTRL, (config | CNTRLREG_SSENB)); return IRQ_HANDLED; } else if (status & IRQENB_FIFO1THRES) { /* Disable irq and wake worker thread */ @@ -217,11 +198,11 @@ static irqreturn_t tiadc_worker_h(int irq, void *private) fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); for (k = 0; k < fifo1count; k = k + i) { - for (i = 0; i < (indio_dev->scan_bytes)/2; i++) { + for (i = 0; i < indio_dev->scan_bytes / 2; i++) { read = tiadc_readl(adc_dev, REG_FIFO1); data[i] = read & FIFOREAD_DATA_MASK; } - iio_push_to_buffers(indio_dev, (u8 *) data); + iio_push_to_buffers(indio_dev, (u8 *)data); } tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES); @@ -254,6 +235,7 @@ static int tiadc_start_dma(struct iio_dev *indio_dev) struct dma_async_tx_descriptor *desc; dma->current_period = 0; /* We start to fill period 0 */ + /* * Make the fifo thresh as the multiple of total number of * channels enabled, so make sure that cyclic DMA period @@ -263,9 +245,10 @@ static int tiadc_start_dma(struct iio_dev *indio_dev) */ dma->fifo_thresh = rounddown(FIFO1_THRESHOLD + 1, adc_dev->total_ch_enabled) - 1; + /* Make sure that period length is multiple of fifo thresh level */ dma->period_size = rounddown(DMA_BUFFER_SIZE / 2, - (dma->fifo_thresh + 1) * sizeof(u16)); + (dma->fifo_thresh + 1) * sizeof(u16)); dma->conf.src_maxburst = dma->fifo_thresh + 1; dmaengine_slave_config(dma->chan, &dma->conf); @@ -295,10 +278,15 @@ static int tiadc_buffer_preenable(struct iio_dev *indio_dev) { struct tiadc_device *adc_dev = iio_priv(indio_dev); int i, fifo1count; + int ret; + + ret = tiadc_wait_idle(adc_dev); + if (ret) + return ret; - tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES | - IRQENB_FIFO1OVRRUN | - IRQENB_FIFO1UNDRFLW)); + tiadc_writel(adc_dev, REG_IRQCLR, + IRQENB_FIFO1THRES | IRQENB_FIFO1OVRRUN | + IRQENB_FIFO1UNDRFLW); /* Flush FIFO. Needed in corner cases in simultaneous tsc/adc use */ fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); @@ -328,8 +316,9 @@ static int tiadc_buffer_postenable(struct iio_dev *indio_dev) am335x_tsc_se_set_cache(adc_dev->mfd_tscadc, enb); - tiadc_writel(adc_dev, REG_IRQSTATUS, IRQENB_FIFO1THRES - | IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW); + tiadc_writel(adc_dev, REG_IRQSTATUS, + IRQENB_FIFO1THRES | IRQENB_FIFO1OVRRUN | + IRQENB_FIFO1UNDRFLW); irq_enable = IRQENB_FIFO1OVRRUN; if (!dma->chan) @@ -345,8 +334,9 @@ static int tiadc_buffer_predisable(struct iio_dev *indio_dev) struct tiadc_dma *dma = &adc_dev->dma; int fifo1count, i; - tiadc_writel(adc_dev, REG_IRQCLR, (IRQENB_FIFO1THRES | - IRQENB_FIFO1OVRRUN | IRQENB_FIFO1UNDRFLW)); + tiadc_writel(adc_dev, REG_IRQCLR, + IRQENB_FIFO1THRES | IRQENB_FIFO1OVRRUN | + IRQENB_FIFO1UNDRFLW); am335x_tsc_se_clr(adc_dev->mfd_tscadc, adc_dev->buffer_en_ch_steps); adc_dev->buffer_en_ch_steps = 0; adc_dev->total_ch_enabled = 0; @@ -378,12 +368,11 @@ static const struct iio_buffer_setup_ops tiadc_buffer_setup_ops = { }; static int tiadc_iio_buffered_hardware_setup(struct device *dev, - struct iio_dev *indio_dev, - irqreturn_t (*pollfunc_bh)(int irq, void *p), - irqreturn_t (*pollfunc_th)(int irq, void *p), - int irq, - unsigned long flags, - const struct iio_buffer_setup_ops *setup_ops) + struct iio_dev *indio_dev, + irqreturn_t (*pollfunc_bh)(int irq, void *p), + irqreturn_t (*pollfunc_th)(int irq, void *p), + int irq, unsigned long flags, + const struct iio_buffer_setup_ops *setup_ops) { int ret; @@ -394,7 +383,7 @@ static int tiadc_iio_buffered_hardware_setup(struct device *dev, return ret; return devm_request_threaded_irq(dev, irq, pollfunc_th, pollfunc_bh, - flags, indio_dev->name, indio_dev); + flags, indio_dev->name, indio_dev); } static const char * const chan_name_ain[] = { @@ -419,16 +408,16 @@ static int tiadc_channel_init(struct device *dev, struct iio_dev *indio_dev, indio_dev->num_channels = channels; chan_array = devm_kcalloc(dev, channels, sizeof(*chan_array), GFP_KERNEL); - if (chan_array == NULL) + if (!chan_array) return -ENOMEM; chan = chan_array; for (i = 0; i < channels; i++, chan++) { - chan->type = IIO_VOLTAGE; chan->indexed = 1; chan->channel = adc_dev->channel_line[i]; chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); + chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE); chan->datasheet_name = chan_name_ain[chan->channel]; chan->scan_index = i; chan->scan_type.sign = 'u'; @@ -442,16 +431,33 @@ static int tiadc_channel_init(struct device *dev, struct iio_dev *indio_dev, } static int tiadc_read_raw(struct iio_dev *indio_dev, - struct iio_chan_spec const *chan, - int *val, int *val2, long mask) + struct iio_chan_spec const *chan, int *val, int *val2, + long mask) { struct tiadc_device *adc_dev = iio_priv(indio_dev); - int ret = IIO_VAL_INT; int i, map_val; unsigned int fifo1count, read, stepid; bool found = false; u32 step_en; unsigned long timeout; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + break; + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_VOLTAGE: + *val = 1800; + *val2 = chan->scan_type.realbits; + return IIO_VAL_FRACTIONAL_LOG2; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } if (iio_buffer_enabled(indio_dev)) return -EBUSY; @@ -461,15 +467,19 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, return -EINVAL; mutex_lock(&adc_dev->fifo1_lock); + + ret = tiadc_wait_idle(adc_dev); + if (ret) + goto err_unlock; + fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); while (fifo1count--) tiadc_readl(adc_dev, REG_FIFO1); am335x_tsc_se_set_once(adc_dev->mfd_tscadc, step_en); - timeout = jiffies + msecs_to_jiffies - (IDLE_TIMEOUT * adc_dev->channels); /* Wait for Fifo threshold interrupt */ + timeout = jiffies + msecs_to_jiffies(IDLE_TIMEOUT_MS * adc_dev->channels); while (1) { fifo1count = tiadc_readl(adc_dev, REG_FIFO1CNT); if (fifo1count) @@ -481,6 +491,7 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, goto err_unlock; } } + map_val = adc_dev->channel_step[chan->scan_index]; /* @@ -498,17 +509,18 @@ static int tiadc_read_raw(struct iio_dev *indio_dev, if (stepid == map_val) { read = read & FIFOREAD_DATA_MASK; found = true; - *val = (u16) read; + *val = (u16)read; } } + am335x_tsc_se_adc_done(adc_dev->mfd_tscadc); if (!found) - ret = -EBUSY; + ret = -EBUSY; err_unlock: mutex_unlock(&adc_dev->fifo1_lock); - return ret; + return ret ? ret : IIO_VAL_INT; } static const struct iio_info tiadc_info = { @@ -545,6 +557,7 @@ static int tiadc_request_dma(struct platform_device *pdev, goto err; return 0; + err: dma_release_channel(dma->chan); return -ENOMEM; @@ -558,6 +571,7 @@ static int tiadc_parse_dt(struct platform_device *pdev, const __be32 *cur; int channels = 0; u32 val; + int i; of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) { adc_dev->channel_line[channels] = val; @@ -570,6 +584,8 @@ static int tiadc_parse_dt(struct platform_device *pdev, channels++; } + adc_dev->channels = channels; + of_property_read_u32_array(node, "ti,chan-step-avg", adc_dev->step_avg, channels); of_property_read_u32_array(node, "ti,chan-step-opendelay", @@ -577,7 +593,33 @@ static int tiadc_parse_dt(struct platform_device *pdev, of_property_read_u32_array(node, "ti,chan-step-sampledelay", adc_dev->sample_delay, channels); - adc_dev->channels = channels; + for (i = 0; i < adc_dev->channels; i++) { + int chan; + + chan = adc_dev->channel_line[i]; + + if (adc_dev->step_avg[i] > STEPCONFIG_AVG_16) { + dev_warn(&pdev->dev, + "chan %d: wrong step avg, truncated to %ld\n", + chan, STEPCONFIG_AVG_16); + adc_dev->step_avg[i] = STEPCONFIG_AVG_16; + } + + if (adc_dev->open_delay[i] > STEPCONFIG_MAX_OPENDLY) { + dev_warn(&pdev->dev, + "chan %d: wrong open delay, truncated to 0x%lX\n", + chan, STEPCONFIG_MAX_OPENDLY); + adc_dev->open_delay[i] = STEPCONFIG_MAX_OPENDLY; + } + + if (adc_dev->sample_delay[i] > STEPCONFIG_MAX_SAMPLE) { + dev_warn(&pdev->dev, + "chan %d: wrong sample delay, truncated to 0x%lX\n", + chan, STEPCONFIG_MAX_SAMPLE); + adc_dev->sample_delay[i] = STEPCONFIG_MAX_SAMPLE; + } + } + return 0; } @@ -594,7 +636,7 @@ static int tiadc_probe(struct platform_device *pdev) } indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev)); - if (indio_dev == NULL) { + if (!indio_dev) { dev_err(&pdev->dev, "failed to allocate iio device\n"); return -ENOMEM; } @@ -616,18 +658,17 @@ static int tiadc_probe(struct platform_device *pdev) return err; err = tiadc_iio_buffered_hardware_setup(&pdev->dev, indio_dev, - &tiadc_worker_h, - &tiadc_irq_h, - adc_dev->mfd_tscadc->irq, - IRQF_SHARED, - &tiadc_buffer_setup_ops); - + &tiadc_worker_h, + &tiadc_irq_h, + adc_dev->mfd_tscadc->irq, + IRQF_SHARED, + &tiadc_buffer_setup_ops); if (err) - goto err_free_channels; + return err; err = iio_device_register(indio_dev); if (err) - goto err_buffer_unregister; + return err; platform_set_drvdata(pdev, indio_dev); @@ -639,8 +680,7 @@ static int tiadc_probe(struct platform_device *pdev) err_dma: iio_device_unregister(indio_dev); -err_buffer_unregister: -err_free_channels: + return err; } @@ -671,9 +711,8 @@ static int __maybe_unused tiadc_suspend(struct device *dev) unsigned int idle; idle = tiadc_readl(adc_dev, REG_CTRL); - idle &= ~(CNTRLREG_TSCSSENB); - tiadc_writel(adc_dev, REG_CTRL, (idle | - CNTRLREG_POWERDOWN)); + idle &= ~(CNTRLREG_SSENB); + tiadc_writel(adc_dev, REG_CTRL, idle | CNTRLREG_POWERDOWN); return 0; } @@ -686,12 +725,12 @@ static int __maybe_unused tiadc_resume(struct device *dev) /* Make sure ADC is powered up */ restore = tiadc_readl(adc_dev, REG_CTRL); - restore &= ~(CNTRLREG_POWERDOWN); + restore &= ~CNTRLREG_POWERDOWN; tiadc_writel(adc_dev, REG_CTRL, restore); tiadc_step_config(indio_dev); am335x_tsc_se_set_cache(adc_dev->mfd_tscadc, - adc_dev->buffer_en_ch_steps); + adc_dev->buffer_en_ch_steps); return 0; } @@ -699,6 +738,7 @@ static SIMPLE_DEV_PM_OPS(tiadc_pm_ops, tiadc_suspend, tiadc_resume); static const struct of_device_id ti_adc_dt_ids[] = { { .compatible = "ti,am3359-adc", }, + { .compatible = "ti,am4372-adc", }, { } }; MODULE_DEVICE_TABLE(of, ti_adc_dt_ids); diff --git a/drivers/mfd/hi6421-spmi-pmic.c b/drivers/mfd/hi6421-spmi-pmic.c index 4f136826681b..c9c0c3d7011f 100644 --- a/drivers/mfd/hi6421-spmi-pmic.c +++ b/drivers/mfd/hi6421-spmi-pmic.c @@ -8,7 +8,6 @@ */ #include <linux/mfd/core.h> -#include <linux/mfd/hi6421-spmi-pmic.h> #include <linux/module.h> #include <linux/platform_device.h> #include <linux/regmap.h> @@ -30,19 +29,14 @@ static const struct regmap_config regmap_config = { static int hi6421_spmi_pmic_probe(struct spmi_device *sdev) { struct device *dev = &sdev->dev; + struct regmap *regmap; int ret; - struct hi6421_spmi_pmic *ddata; - ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); - if (!ddata) - return -ENOMEM; - ddata->regmap = devm_regmap_init_spmi_ext(sdev, ®map_config); - if (IS_ERR(ddata->regmap)) - return PTR_ERR(ddata->regmap); + regmap = devm_regmap_init_spmi_ext(sdev, ®map_config); + if (IS_ERR(regmap)) + return PTR_ERR(regmap); - ddata->dev = dev; - - dev_set_drvdata(&sdev->dev, ddata); + dev_set_drvdata(&sdev->dev, regmap); ret = devm_mfd_add_devices(&sdev->dev, PLATFORM_DEVID_NONE, hi6421v600_devs, ARRAY_SIZE(hi6421v600_devs), diff --git a/drivers/mfd/ti_am335x_tscadc.c b/drivers/mfd/ti_am335x_tscadc.c index 55adc379f94b..740cae00dac2 100644 --- a/drivers/mfd/ti_am335x_tscadc.c +++ b/drivers/mfd/ti_am335x_tscadc.c @@ -1,16 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-only /* * TI Touch Screen / ADC MFD driver * * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ #include <linux/module.h> @@ -113,70 +105,99 @@ static void tscadc_idle_config(struct ti_tscadc_dev *tscadc) { unsigned int idleconfig; - idleconfig = STEPCONFIG_YNN | STEPCONFIG_INM_ADCREFM | - STEPCONFIG_INP_ADCREFM | STEPCONFIG_YPN; + idleconfig = STEPCONFIG_INM_ADCREFM | STEPCONFIG_INP_ADCREFM; + if (ti_adc_with_touchscreen(tscadc)) + idleconfig |= STEPCONFIG_YNN | STEPCONFIG_YPN; regmap_write(tscadc->regmap, REG_IDLECONFIG, idleconfig); } static int ti_tscadc_probe(struct platform_device *pdev) { - struct ti_tscadc_dev *tscadc; - struct resource *res; - struct clk *clk; - struct device_node *node; - struct mfd_cell *cell; - struct property *prop; - const __be32 *cur; - u32 val; - int err, ctrl; - int clock_rate; - int tsc_wires = 0, adc_channels = 0, total_channels; - int readouts = 0; + struct ti_tscadc_dev *tscadc; + struct resource *res; + struct clk *clk; + struct device_node *node; + struct mfd_cell *cell; + struct property *prop; + const __be32 *cur; + bool use_tsc = false, use_mag = false; + u32 val; + int err; + int tscmag_wires = 0, adc_channels = 0, cell_idx = 0, total_channels; + int readouts = 0, mag_tracks = 0; + + /* Allocate memory for device */ + tscadc = devm_kzalloc(&pdev->dev, sizeof(*tscadc), GFP_KERNEL); + if (!tscadc) + return -ENOMEM; + + tscadc->dev = &pdev->dev; if (!pdev->dev.of_node) { dev_err(&pdev->dev, "Could not find valid DT data.\n"); return -EINVAL; } - node = of_get_child_by_name(pdev->dev.of_node, "tsc"); - of_property_read_u32(node, "ti,wires", &tsc_wires); - of_property_read_u32(node, "ti,coordiante-readouts", &readouts); + tscadc->data = of_device_get_match_data(&pdev->dev); + + if (ti_adc_with_touchscreen(tscadc)) { + node = of_get_child_by_name(pdev->dev.of_node, "tsc"); + of_property_read_u32(node, "ti,wires", &tscmag_wires); + err = of_property_read_u32(node, "ti,coordinate-readouts", + &readouts); + if (err < 0) + of_property_read_u32(node, "ti,coordiante-readouts", + &readouts); + + of_node_put(node); + + if (tscmag_wires) + use_tsc = true; + } else { + /* + * When adding support for the magnetic stripe reader, here is + * the place to look for the number of tracks used from device + * tree. Let's default to 0 for now. + */ + mag_tracks = 0; + tscmag_wires = mag_tracks * 2; + if (tscmag_wires) + use_mag = true; + } node = of_get_child_by_name(pdev->dev.of_node, "adc"); of_property_for_each_u32(node, "ti,adc-channels", prop, cur, val) { adc_channels++; if (val > 7) { dev_err(&pdev->dev, " PIN numbers are 0..7 (not %d)\n", - val); + val); + of_node_put(node); return -EINVAL; } } - total_channels = tsc_wires + adc_channels; + + of_node_put(node); + + total_channels = tscmag_wires + adc_channels; if (total_channels > 8) { dev_err(&pdev->dev, "Number of i/p channels more than 8\n"); return -EINVAL; } + if (total_channels == 0) { dev_err(&pdev->dev, "Need atleast one channel.\n"); return -EINVAL; } - if (readouts * 2 + 2 + adc_channels > 16) { + if (use_tsc && (readouts * 2 + 2 + adc_channels > 16)) { dev_err(&pdev->dev, "Too many step configurations requested\n"); return -EINVAL; } - /* Allocate memory for device */ - tscadc = devm_kzalloc(&pdev->dev, sizeof(*tscadc), GFP_KERNEL); - if (!tscadc) - return -ENOMEM; - - tscadc->dev = &pdev->dev; - err = platform_get_irq(pdev, 0); if (err < 0) - goto ret; + return err; else tscadc->irq = err; @@ -187,11 +208,11 @@ static int ti_tscadc_probe(struct platform_device *pdev) tscadc->tscadc_phys_base = res->start; tscadc->regmap = devm_regmap_init_mmio(&pdev->dev, - tscadc->tscadc_base, &tscadc_regmap_config); + tscadc->tscadc_base, + &tscadc_regmap_config); if (IS_ERR(tscadc->regmap)) { dev_err(&pdev->dev, "regmap init failed\n"); - err = PTR_ERR(tscadc->regmap); - goto ret; + return PTR_ERR(tscadc->regmap); } spin_lock_init(&tscadc->reg_lock); @@ -201,71 +222,70 @@ static int ti_tscadc_probe(struct platform_device *pdev) pm_runtime_get_sync(&pdev->dev); /* - * The TSC_ADC_Subsystem has 2 clock domains - * OCP_CLK and ADC_CLK. - * The ADC clock is expected to run at target of 3MHz, - * and expected to capture 12-bit data at a rate of 200 KSPS. - * The TSC_ADC_SS controller design assumes the OCP clock is - * at least 6x faster than the ADC clock. + * The TSC_ADC_Subsystem has 2 clock domains: OCP_CLK and ADC_CLK. + * ADCs produce a 12-bit sample every 15 ADC_CLK cycles. + * am33xx ADCs expect to capture 200ksps. + * am47xx ADCs expect to capture 867ksps. + * We need ADC clocks respectively running at 3MHz and 13MHz. + * These frequencies are valid since TSC_ADC_SS controller design + * assumes the OCP clock is at least 6x faster than the ADC clock. */ - clk = devm_clk_get(&pdev->dev, "adc_tsc_fck"); + clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(clk)) { - dev_err(&pdev->dev, "failed to get TSC fck\n"); + dev_err(&pdev->dev, "failed to get fck\n"); err = PTR_ERR(clk); goto err_disable_clk; } - clock_rate = clk_get_rate(clk); - tscadc->clk_div = clock_rate / ADC_CLK; - /* TSCADC_CLKDIV needs to be configured to the value minus 1 */ - tscadc->clk_div--; + tscadc->clk_div = (clk_get_rate(clk) / tscadc->data->target_clk_rate) - 1; regmap_write(tscadc->regmap, REG_CLKDIV, tscadc->clk_div); - /* Set the control register bits */ - ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_STEPID; - regmap_write(tscadc->regmap, REG_CTRL, ctrl); - - /* Set register bits for Idle Config Mode */ - if (tsc_wires > 0) { - tscadc->tsc_wires = tsc_wires; - if (tsc_wires == 5) - ctrl |= CNTRLREG_5WIRE | CNTRLREG_TSCENB; - else - ctrl |= CNTRLREG_4WIRE | CNTRLREG_TSCENB; - tscadc_idle_config(tscadc); + /* + * Set the control register bits. tscadc->ctrl stores the configuration + * of the CTRL register but not the subsystem enable bit which must be + * added manually when timely. + */ + tscadc->ctrl = CNTRLREG_STEPID; + if (ti_adc_with_touchscreen(tscadc)) { + tscadc->ctrl |= CNTRLREG_TSC_STEPCONFIGWRT; + if (use_tsc) { + tscadc->ctrl |= CNTRLREG_TSC_ENB; + if (tscmag_wires == 5) + tscadc->ctrl |= CNTRLREG_TSC_5WIRE; + else + tscadc->ctrl |= CNTRLREG_TSC_4WIRE; + } + } else { + tscadc->ctrl |= CNTRLREG_MAG_PREAMP_PWRDOWN | + CNTRLREG_MAG_PREAMP_BYPASS; } + regmap_write(tscadc->regmap, REG_CTRL, tscadc->ctrl); + + tscadc_idle_config(tscadc); /* Enable the TSC module enable bit */ - ctrl |= CNTRLREG_TSCSSENB; - regmap_write(tscadc->regmap, REG_CTRL, ctrl); - - tscadc->used_cells = 0; - tscadc->tsc_cell = -1; - tscadc->adc_cell = -1; - - /* TSC Cell */ - if (tsc_wires > 0) { - tscadc->tsc_cell = tscadc->used_cells; - cell = &tscadc->cells[tscadc->used_cells++]; - cell->name = "TI-am335x-tsc"; - cell->of_compatible = "ti,am3359-tsc"; + regmap_write(tscadc->regmap, REG_CTRL, tscadc->ctrl | CNTRLREG_SSENB); + + /* TSC or MAG Cell */ + if (use_tsc || use_mag) { + cell = &tscadc->cells[cell_idx++]; + cell->name = tscadc->data->secondary_feature_name; + cell->of_compatible = tscadc->data->secondary_feature_compatible; cell->platform_data = &tscadc; cell->pdata_size = sizeof(tscadc); } /* ADC Cell */ if (adc_channels > 0) { - tscadc->adc_cell = tscadc->used_cells; - cell = &tscadc->cells[tscadc->used_cells++]; - cell->name = "TI-am335x-adc"; - cell->of_compatible = "ti,am3359-adc"; + cell = &tscadc->cells[cell_idx++]; + cell->name = tscadc->data->adc_feature_name; + cell->of_compatible = tscadc->data->adc_feature_compatible; cell->platform_data = &tscadc; cell->pdata_size = sizeof(tscadc); } err = mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO, - tscadc->cells, tscadc->used_cells, NULL, - 0, NULL); + tscadc->cells, cell_idx, NULL, 0, NULL); if (err < 0) goto err_disable_clk; @@ -275,13 +295,13 @@ static int ti_tscadc_probe(struct platform_device *pdev) err_disable_clk: pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); -ret: + return err; } static int ti_tscadc_remove(struct platform_device *pdev) { - struct ti_tscadc_dev *tscadc = platform_get_drvdata(pdev); + struct ti_tscadc_dev *tscadc = platform_get_drvdata(pdev); regmap_write(tscadc->regmap, REG_SE, 0x00); @@ -300,7 +320,7 @@ static int __maybe_unused ti_tscadc_can_wakeup(struct device *dev, void *data) static int __maybe_unused tscadc_suspend(struct device *dev) { - struct ti_tscadc_dev *tscadc = dev_get_drvdata(dev); + struct ti_tscadc_dev *tscadc = dev_get_drvdata(dev); regmap_write(tscadc->regmap, REG_SE, 0x00); if (device_for_each_child(dev, NULL, ti_tscadc_can_wakeup)) { @@ -308,7 +328,7 @@ static int __maybe_unused tscadc_suspend(struct device *dev) regmap_read(tscadc->regmap, REG_CTRL, &ctrl); ctrl &= ~(CNTRLREG_POWERDOWN); - ctrl |= CNTRLREG_TSCSSENB; + ctrl |= CNTRLREG_SSENB; regmap_write(tscadc->regmap, REG_CTRL, ctrl); } pm_runtime_put_sync(dev); @@ -318,34 +338,39 @@ static int __maybe_unused tscadc_suspend(struct device *dev) static int __maybe_unused tscadc_resume(struct device *dev) { - struct ti_tscadc_dev *tscadc = dev_get_drvdata(dev); - u32 ctrl; + struct ti_tscadc_dev *tscadc = dev_get_drvdata(dev); pm_runtime_get_sync(dev); - /* context restore */ - ctrl = CNTRLREG_STEPCONFIGWRT | CNTRLREG_STEPID; - regmap_write(tscadc->regmap, REG_CTRL, ctrl); - - if (tscadc->tsc_cell != -1) { - if (tscadc->tsc_wires == 5) - ctrl |= CNTRLREG_5WIRE | CNTRLREG_TSCENB; - else - ctrl |= CNTRLREG_4WIRE | CNTRLREG_TSCENB; - tscadc_idle_config(tscadc); - } - ctrl |= CNTRLREG_TSCSSENB; - regmap_write(tscadc->regmap, REG_CTRL, ctrl); - regmap_write(tscadc->regmap, REG_CLKDIV, tscadc->clk_div); + regmap_write(tscadc->regmap, REG_CTRL, tscadc->ctrl); + tscadc_idle_config(tscadc); + regmap_write(tscadc->regmap, REG_CTRL, tscadc->ctrl | CNTRLREG_SSENB); return 0; } static SIMPLE_DEV_PM_OPS(tscadc_pm_ops, tscadc_suspend, tscadc_resume); +static const struct ti_tscadc_data tscdata = { + .adc_feature_name = "TI-am335x-adc", + .adc_feature_compatible = "ti,am3359-adc", + .secondary_feature_name = "TI-am335x-tsc", + .secondary_feature_compatible = "ti,am3359-tsc", + .target_clk_rate = TSC_ADC_CLK, +}; + +static const struct ti_tscadc_data magdata = { + .adc_feature_name = "TI-am43xx-adc", + .adc_feature_compatible = "ti,am4372-adc", + .secondary_feature_name = "TI-am43xx-mag", + .secondary_feature_compatible = "ti,am4372-mag", + .target_clk_rate = MAG_ADC_CLK, +}; + static const struct of_device_id ti_tscadc_dt_ids[] = { - { .compatible = "ti,am3359-tscadc", }, + { .compatible = "ti,am3359-tscadc", .data = &tscdata }, + { .compatible = "ti,am4372-magadc", .data = &magdata }, { } }; MODULE_DEVICE_TABLE(of, ti_tscadc_dt_ids); @@ -363,6 +388,6 @@ static struct platform_driver ti_tscadc_driver = { module_platform_driver(ti_tscadc_driver); -MODULE_DESCRIPTION("TI touchscreen / ADC MFD controller driver"); +MODULE_DESCRIPTION("TI touchscreen/magnetic stripe reader/ADC MFD controller driver"); MODULE_AUTHOR("Rachna Patil <rachna@ti.com>"); MODULE_LICENSE("GPL"); diff --git a/drivers/misc/hi6421v600-irq.c b/drivers/misc/hi6421v600-irq.c index 08535e97ff43..1c763796cf1f 100644 --- a/drivers/misc/hi6421v600-irq.c +++ b/drivers/misc/hi6421v600-irq.c @@ -10,7 +10,6 @@ #include <linux/bitops.h> #include <linux/interrupt.h> #include <linux/irq.h> -#include <linux/mfd/hi6421-spmi-pmic.h> #include <linux/module.h> #include <linux/of_gpio.h> #include <linux/platform_device.h> @@ -220,7 +219,7 @@ static int hi6421v600_irq_probe(struct platform_device *pdev) struct platform_device *pmic_pdev; struct device *dev = &pdev->dev; struct hi6421v600_irq *priv; - struct hi6421_spmi_pmic *pmic; + struct regmap *regmap; unsigned int virq; int i, ret; @@ -229,8 +228,8 @@ static int hi6421v600_irq_probe(struct platform_device *pdev) * which should first set drvdata. If this doesn't happen, hit * a warn on and return. */ - pmic = dev_get_drvdata(pmic_dev); - if (WARN_ON(!pmic)) + regmap = dev_get_drvdata(pmic_dev); + if (WARN_ON(!regmap)) return -ENODEV; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -238,7 +237,7 @@ static int hi6421v600_irq_probe(struct platform_device *pdev) return -ENOMEM; priv->dev = dev; - priv->regmap = pmic->regmap; + priv->regmap = regmap; spin_lock_init(&priv->lock); diff --git a/drivers/regulator/hi6421v600-regulator.c b/drivers/regulator/hi6421v600-regulator.c index 662d87ae61cb..4671678f6b19 100644 --- a/drivers/regulator/hi6421v600-regulator.c +++ b/drivers/regulator/hi6421v600-regulator.c @@ -9,8 +9,8 @@ // Guodong Xu <guodong.xu@linaro.org> #include <linux/delay.h> -#include <linux/mfd/hi6421-spmi-pmic.h> #include <linux/module.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/regmap.h> #include <linux/regulator/driver.h> @@ -237,7 +237,7 @@ static int hi6421_spmi_regulator_probe(struct platform_device *pdev) struct hi6421_spmi_reg_priv *priv; struct hi6421_spmi_reg_info *info; struct device *dev = &pdev->dev; - struct hi6421_spmi_pmic *pmic; + struct regmap *regmap; struct regulator_dev *rdev; int i; @@ -246,8 +246,8 @@ static int hi6421_spmi_regulator_probe(struct platform_device *pdev) * which should first set drvdata. If this doesn't happen, hit * a warn on and return. */ - pmic = dev_get_drvdata(pmic_dev); - if (WARN_ON(!pmic)) + regmap = dev_get_drvdata(pmic_dev); + if (WARN_ON(!regmap)) return -ENODEV; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -261,7 +261,7 @@ static int hi6421_spmi_regulator_probe(struct platform_device *pdev) config.dev = pdev->dev.parent; config.driver_data = priv; - config.regmap = pmic->regmap; + config.regmap = regmap; rdev = devm_regulator_register(dev, &info->desc, &config); if (IS_ERR(rdev)) { diff --git a/include/dt-bindings/clock/am4.h b/include/dt-bindings/clock/am4.h index d961e7cb3682..4be6c5961f34 100644 --- a/include/dt-bindings/clock/am4.h +++ b/include/dt-bindings/clock/am4.h @@ -158,6 +158,7 @@ #define AM4_L3S_VPFE0_CLKCTRL AM4_L3S_CLKCTRL_INDEX(0x68) #define AM4_L3S_VPFE1_CLKCTRL AM4_L3S_CLKCTRL_INDEX(0x70) #define AM4_L3S_GPMC_CLKCTRL AM4_L3S_CLKCTRL_INDEX(0x220) +#define AM4_L3S_ADC1_CLKCTRL AM4_L3S_CLKCTRL_INDEX(0x230) #define AM4_L3S_MCASP0_CLKCTRL AM4_L3S_CLKCTRL_INDEX(0x238) #define AM4_L3S_MCASP1_CLKCTRL AM4_L3S_CLKCTRL_INDEX(0x240) #define AM4_L3S_MMC3_CLKCTRL AM4_L3S_CLKCTRL_INDEX(0x248) diff --git a/include/linux/mfd/hi6421-spmi-pmic.h b/include/linux/mfd/hi6421-spmi-pmic.h deleted file mode 100644 index e5b8dbf828b6..000000000000 --- a/include/linux/mfd/hi6421-spmi-pmic.h +++ /dev/null @@ -1,25 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -/* - * Header file for device driver Hi6421 PMIC - * - * Copyright (c) 2013 Linaro Ltd. - * Copyright (C) 2011 Hisilicon. - * Copyright (c) 2020-2021 Huawei Technologies Co., Ltd - * - * Guodong Xu <guodong.xu@linaro.org> - */ - -#ifndef __HISI_PMIC_H -#define __HISI_PMIC_H - -#include <linux/irqdomain.h> -#include <linux/regmap.h> - -struct hi6421_spmi_pmic { - struct resource *res; - struct device *dev; - void __iomem *regs; - struct regmap *regmap; -}; - -#endif /* __HISI_PMIC_H */ diff --git a/include/linux/mfd/ti_am335x_tscadc.h b/include/linux/mfd/ti_am335x_tscadc.h index ffc091b77633..ba13e043d910 100644 --- a/include/linux/mfd/ti_am335x_tscadc.h +++ b/include/linux/mfd/ti_am335x_tscadc.h @@ -1,22 +1,16 @@ -#ifndef __LINUX_TI_AM335X_TSCADC_MFD_H -#define __LINUX_TI_AM335X_TSCADC_MFD_H - +/* SPDX-License-Identifier: GPL-2.0-only */ /* * TI Touch Screen / ADC MFD driver * * Copyright (C) 2012 Texas Instruments Incorporated - https://www.ti.com/ - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation version 2. - * - * This program is distributed "as is" WITHOUT ANY WARRANTY of any - * kind, whether express or implied; without even the implied warranty - * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. */ +#ifndef __LINUX_TI_AM335X_TSCADC_MFD_H +#define __LINUX_TI_AM335X_TSCADC_MFD_H + +#include <linux/bitfield.h> #include <linux/mfd/core.h> +#include <linux/units.h> #define REG_RAWIRQSTATUS 0x024 #define REG_IRQSTATUS 0x028 @@ -46,13 +40,6 @@ /* IRQ wakeup enable */ #define IRQWKUP_ENB BIT(0) -/* Step Enable */ -#define STEPENB_MASK (0x1FFFF << 0) -#define STEPENB(val) ((val) << 0) -#define ENB(val) (1 << (val)) -#define STPENB_STEPENB STEPENB(0x1FFFF) -#define STPENB_STEPENB_TC STEPENB(0x1FFF) - /* IRQ enable */ #define IRQENB_HW_PEN BIT(0) #define IRQENB_EOS BIT(1) @@ -65,12 +52,10 @@ #define IRQENB_PENUP BIT(9) /* Step Configuration */ -#define STEPCONFIG_MODE_MASK (3 << 0) -#define STEPCONFIG_MODE(val) ((val) << 0) +#define STEPCONFIG_MODE(val) FIELD_PREP(GENMASK(1, 0), (val)) #define STEPCONFIG_MODE_SWCNT STEPCONFIG_MODE(1) #define STEPCONFIG_MODE_HWSYNC STEPCONFIG_MODE(2) -#define STEPCONFIG_AVG_MASK (7 << 2) -#define STEPCONFIG_AVG(val) ((val) << 2) +#define STEPCONFIG_AVG(val) FIELD_PREP(GENMASK(4, 2), (val)) #define STEPCONFIG_AVG_16 STEPCONFIG_AVG(4) #define STEPCONFIG_XPP BIT(5) #define STEPCONFIG_XNN BIT(6) @@ -78,70 +63,68 @@ #define STEPCONFIG_YNN BIT(8) #define STEPCONFIG_XNP BIT(9) #define STEPCONFIG_YPN BIT(10) -#define STEPCONFIG_RFP(val) ((val) << 12) -#define STEPCONFIG_RFP_VREFP (0x3 << 12) -#define STEPCONFIG_INM_MASK (0xF << 15) -#define STEPCONFIG_INM(val) ((val) << 15) +#define STEPCONFIG_RFP(val) FIELD_PREP(GENMASK(13, 12), (val)) +#define STEPCONFIG_RFP_VREFP STEPCONFIG_RFP(3) +#define STEPCONFIG_INM(val) FIELD_PREP(GENMASK(18, 15), (val)) #define STEPCONFIG_INM_ADCREFM STEPCONFIG_INM(8) -#define STEPCONFIG_INP_MASK (0xF << 19) -#define STEPCONFIG_INP(val) ((val) << 19) +#define STEPCONFIG_INP(val) FIELD_PREP(GENMASK(22, 19), (val)) #define STEPCONFIG_INP_AN4 STEPCONFIG_INP(4) #define STEPCONFIG_INP_ADCREFM STEPCONFIG_INP(8) #define STEPCONFIG_FIFO1 BIT(26) -#define STEPCONFIG_RFM(val) ((val) << 23) -#define STEPCONFIG_RFM_VREFN (0x3 << 23) +#define STEPCONFIG_RFM(val) FIELD_PREP(GENMASK(24, 23), (val)) +#define STEPCONFIG_RFM_VREFN STEPCONFIG_RFM(3) /* Delay register */ -#define STEPDELAY_OPEN_MASK (0x3FFFF << 0) -#define STEPDELAY_OPEN(val) ((val) << 0) +#define STEPDELAY_OPEN(val) FIELD_PREP(GENMASK(17, 0), (val)) #define STEPCONFIG_OPENDLY STEPDELAY_OPEN(0x098) -#define STEPDELAY_SAMPLE_MASK (0xFF << 24) -#define STEPDELAY_SAMPLE(val) ((val) << 24) +#define STEPCONFIG_MAX_OPENDLY GENMASK(17, 0) +#define STEPDELAY_SAMPLE(val) FIELD_PREP(GENMASK(31, 24), (val)) #define STEPCONFIG_SAMPLEDLY STEPDELAY_SAMPLE(0) +#define STEPCONFIG_MAX_SAMPLE GENMASK(7, 0) /* Charge Config */ -#define STEPCHARGE_RFP_MASK (7 << 12) -#define STEPCHARGE_RFP(val) ((val) << 12) +#define STEPCHARGE_RFP(val) FIELD_PREP(GENMASK(14, 12), (val)) #define STEPCHARGE_RFP_XPUL STEPCHARGE_RFP(1) -#define STEPCHARGE_INM_MASK (0xF << 15) -#define STEPCHARGE_INM(val) ((val) << 15) +#define STEPCHARGE_INM(val) FIELD_PREP(GENMASK(18, 15), (val)) #define STEPCHARGE_INM_AN1 STEPCHARGE_INM(1) -#define STEPCHARGE_INP_MASK (0xF << 19) -#define STEPCHARGE_INP(val) ((val) << 19) -#define STEPCHARGE_RFM_MASK (3 << 23) -#define STEPCHARGE_RFM(val) ((val) << 23) +#define STEPCHARGE_INP(val) FIELD_PREP(GENMASK(22, 19), (val)) +#define STEPCHARGE_RFM(val) FIELD_PREP(GENMASK(24, 23), (val)) #define STEPCHARGE_RFM_XNUR STEPCHARGE_RFM(1) /* Charge delay */ -#define CHARGEDLY_OPEN_MASK (0x3FFFF << 0) -#define CHARGEDLY_OPEN(val) ((val) << 0) +#define CHARGEDLY_OPEN(val) FIELD_PREP(GENMASK(17, 0), (val)) #define CHARGEDLY_OPENDLY CHARGEDLY_OPEN(0x400) /* Control register */ -#define CNTRLREG_TSCSSENB BIT(0) +#define CNTRLREG_SSENB BIT(0) #define CNTRLREG_STEPID BIT(1) -#define CNTRLREG_STEPCONFIGWRT BIT(2) +#define CNTRLREG_TSC_STEPCONFIGWRT BIT(2) #define CNTRLREG_POWERDOWN BIT(4) -#define CNTRLREG_AFE_CTRL_MASK (3 << 5) -#define CNTRLREG_AFE_CTRL(val) ((val) << 5) -#define CNTRLREG_4WIRE CNTRLREG_AFE_CTRL(1) -#define CNTRLREG_5WIRE CNTRLREG_AFE_CTRL(2) -#define CNTRLREG_8WIRE CNTRLREG_AFE_CTRL(3) -#define CNTRLREG_TSCENB BIT(7) +#define CNTRLREG_TSC_AFE_CTRL(val) FIELD_PREP(GENMASK(6, 5), (val)) +#define CNTRLREG_TSC_4WIRE CNTRLREG_TSC_AFE_CTRL(1) +#define CNTRLREG_TSC_5WIRE CNTRLREG_TSC_AFE_CTRL(2) +#define CNTRLREG_TSC_8WIRE CNTRLREG_TSC_AFE_CTRL(3) +#define CNTRLREG_TSC_ENB BIT(7) + +/*Control registers bitfields for MAGADC IP */ +#define CNTRLREG_MAGADCENB BIT(0) +#define CNTRLREG_MAG_PREAMP_PWRDOWN BIT(5) +#define CNTRLREG_MAG_PREAMP_BYPASS BIT(6) /* FIFO READ Register */ -#define FIFOREAD_DATA_MASK (0xfff << 0) -#define FIFOREAD_CHNLID_MASK (0xf << 16) +#define FIFOREAD_DATA_MASK GENMASK(11, 0) +#define FIFOREAD_CHNLID_MASK GENMASK(19, 16) /* DMA ENABLE/CLEAR Register */ #define DMA_FIFO0 BIT(0) #define DMA_FIFO1 BIT(1) /* Sequencer Status */ -#define SEQ_STATUS BIT(5) +#define SEQ_STATUS BIT(5) #define CHARGE_STEP 0x11 -#define ADC_CLK 3000000 +#define TSC_ADC_CLK (3 * HZ_PER_MHZ) +#define MAG_ADC_CLK (13 * HZ_PER_MHZ) #define TOTAL_STEPS 16 #define TOTAL_CHANNELS 8 #define FIFO1_THRESHOLD 19 @@ -158,21 +141,27 @@ * * max processing time: 266431 * 308ns = 83ms(approx) */ -#define IDLE_TIMEOUT 83 /* milliseconds */ +#define IDLE_TIMEOUT_MS 83 /* milliseconds */ #define TSCADC_CELLS 2 +struct ti_tscadc_data { + char *adc_feature_name; + char *adc_feature_compatible; + char *secondary_feature_name; + char *secondary_feature_compatible; + unsigned int target_clk_rate; +}; + struct ti_tscadc_dev { struct device *dev; struct regmap *regmap; void __iomem *tscadc_base; phys_addr_t tscadc_phys_base; + const struct ti_tscadc_data *data; int irq; - int used_cells; /* 1-2 */ - int tsc_wires; - int tsc_cell; /* -1 if not used */ - int adc_cell; /* -1 if not used */ struct mfd_cell cells[TSCADC_CELLS]; + u32 ctrl; u32 reg_se_cache; bool adc_waiting; bool adc_in_use; @@ -194,6 +183,12 @@ static inline struct ti_tscadc_dev *ti_tscadc_dev_get(struct platform_device *p) return *tscadc_dev; } +static inline bool ti_adc_with_touchscreen(struct ti_tscadc_dev *tscadc) +{ + return of_device_is_compatible(tscadc->dev->of_node, + "ti,am3359-tscadc"); +} + void am335x_tsc_se_set_cache(struct ti_tscadc_dev *tsadc, u32 val); void am335x_tsc_se_set_once(struct ti_tscadc_dev *tsadc, u32 val); void am335x_tsc_se_clr(struct ti_tscadc_dev *tsadc, u32 val); |