From 30e7250dfd9593fd6e95103f3471b4c4642c44a1 Mon Sep 17 00:00:00 2001 From: Xingyu Chen Date: Tue, 14 Mar 2017 11:06:43 +0800 Subject: [PATCH] saradc: refactor the driver based on the iio sub-system PD#146222: saradc: refactor the driver based on the iio sub-system the sar adc driver has been moved from directory input/saradc into directory iio/adc, and is refactored base on the standard iio sub-system. the iio sub-system provide two ways to access sar adc resources: 1. standard api for consumer driver it can be found at the file "include/linux/iio/consumer.h". 2. sysfs interface for user space(X: 0-7) - obtain 10-bit sample value: cat sys/bus/iio/devices/iio:device0/in_voltage[X]_input - obtain raw sample value(10-bit or 12-bit): cat sys/bus/iio/devices/iio:device0/in_voltage[X]_raw - obtain mean raw sample value: cat sys/bus/iio/devices/iio:device0/in_voltage[X]_mean_raw test pass on the gxl skt, axg skt, m200. Change-Id: I6c8877c782c51a01993557cabc0d43f212a8e524 Signed-off-by: xingyu.chen --- .../bindings/amlogic/input/amlogic-saradc.txt | 24 - .../bindings/iio/adc/amlogic,meson-saradc.txt | 38 + MAINTAINERS | 4 +- arch/arm/boot/dts/amlogic/meson8b.dtsi | 9 +- arch/arm/boot/dts/amlogic/meson8b_m200.dts | 2 + arch/arm/boot/dts/amlogic/meson8b_m400.dts | 2 + arch/arm/boot/dts/amlogic/meson8b_skt.dts | 2 + arch/arm/configs/meson32_defconfig | 4 +- arch/arm64/boot/dts/amlogic/mesonaxg.dtsi | 11 + arch/arm64/boot/dts/amlogic/mesongxl.dtsi | 13 +- arch/arm64/boot/dts/amlogic/mesongxm.dtsi | 13 +- arch/arm64/configs/meson64_defconfig | 5 +- drivers/amlogic/Kconfig | 2 + drivers/amlogic/Makefile | 2 + drivers/amlogic/iio/Kconfig | 16 + drivers/amlogic/iio/Makefile | 5 + drivers/amlogic/iio/adc/Kconfig | 16 + drivers/amlogic/iio/adc/Makefile | 7 + drivers/amlogic/iio/adc/meson_saradc.c | 1214 ++++++++++++++++++++ drivers/amlogic/input/Kconfig | 2 - drivers/amlogic/input/Makefile | 2 - drivers/amlogic/input/saradc/Kconfig | 8 - drivers/amlogic/input/saradc/Makefile | 9 - drivers/amlogic/input/saradc/saradc.c | 650 ----------- drivers/amlogic/input/saradc/saradc_reg.h | 69 -- drivers/amlogic/spicc/spicc.c | 32 +- drivers/amlogic/spicc/spicc.h | 8 +- drivers/amlogic/thermal/aml_thermal_hw_m8b.c | 23 +- include/dt-bindings/iio/adc/amlogic-saradc.h | 19 + include/linux/amlogic/saradc.h | 54 - 30 files changed, 1419 insertions(+), 846 deletions(-) delete mode 100644 Documentation/devicetree/bindings/amlogic/input/amlogic-saradc.txt create mode 100644 Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt create mode 100644 drivers/amlogic/iio/Kconfig create mode 100644 drivers/amlogic/iio/Makefile create mode 100644 drivers/amlogic/iio/adc/Kconfig create mode 100644 drivers/amlogic/iio/adc/Makefile create mode 100644 drivers/amlogic/iio/adc/meson_saradc.c delete mode 100644 drivers/amlogic/input/saradc/Kconfig delete mode 100644 drivers/amlogic/input/saradc/Makefile delete mode 100644 drivers/amlogic/input/saradc/saradc.c delete mode 100644 drivers/amlogic/input/saradc/saradc_reg.h create mode 100644 include/dt-bindings/iio/adc/amlogic-saradc.h delete mode 100644 include/linux/amlogic/saradc.h diff --git a/Documentation/devicetree/bindings/amlogic/input/amlogic-saradc.txt b/Documentation/devicetree/bindings/amlogic/input/amlogic-saradc.txt deleted file mode 100644 index 75d3e88..0000000 --- a/Documentation/devicetree/bindings/amlogic/input/amlogic-saradc.txt +++ /dev/null @@ -1,24 +0,0 @@ -Amlogic Successive Approximation Register (SAR) A/D Converter bindings - -Required properties: -- compatible: Must be "amlogic, saradc". -- clocks: The clock provided by the SoC to the device. -- clock-names: Shall be "saradc_clk" for the device. -- resets: Shall be "GCLK_IDX_SARADC" for the device. -- reg: Physical base address of the controller and length of memory mapped - region. - -Optional properties: -- status: Shall be "ok" or "okay" if enabled or "disabled" if disabled. - Default is "ok". - -Example: - saradc: saradc { - compatible = "amlogic, saradc"; - status = "okay"; - clocks = <&clock CLK_XTAL>; - clock-names = "saradc_clk"; - resets = <&clock GCLK_IDX_SARADC>; - reg = <0x0 0xc1108680 0x0 0x30 - 0x0 0xc883c3d8 0x0 0x08>; - }; diff --git a/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt new file mode 100644 index 0000000..855c09b --- /dev/null +++ b/Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt @@ -0,0 +1,38 @@ +* Amlogic Meson SAR (Successive Approximation Register) A/D converter + +Required properties: +- compatible: depending on the SoC this should be one of: + - "amlogic,meson-axg-saradc" for AXG + - "amlogic,meson-gxl-saradc" for GXL + - "amlogic,meson-gxm-saradc" for GXM + - "amlogic,meson-m8b-saradc" for M8B +along with the generic "amlogic,meson-saradc" + +- reg: the physical base address and length of the registers + +- interrupts: the interrupt indicating end of sampling + +- clocks: phandle and clock identifier (see clock-names) + +- clock-names: mandatory clocks: + - "xtal" for the reference clock (typically XTAL) + - "saradc_clk" for the SAR ADC (sampling) clock + optional clocks: + - "clk81_gate" for the clk81 clock gate + +- #io-channel-cells: must be 1, see ../iio-bindings.txt + +Optional properties: +- status: Shall be "ok" or "okay" if enabled or "disabled" if disabled. + Default is "ok". + +Example: +saradc:saradc { + compatible = "amlogic,meson-axg-saradc"; + status = "okay"; + #io-channel-cells = <1>; + clocks = <&xtal>, <&clkc CLKID_SARADC_GATE>; + clock-names = "xtal", "saradc_clk"; + interrupts = ; + reg = <0x0 0xff809000 0x0 0x38>; +} diff --git a/MAINTAINERS b/MAINTAINERS index caa3ae9..92ce515 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13450,7 +13450,9 @@ F: drivers/amlogic/crypto/* AMLOGIC saradc M: Xingyu Chen -F: drivers/amlogic/input/saradc/* +F: drivers/amlogic/iio/adc/* +F: include/dt-bindings/iio/adc/amlogic-saradc.h +F: Documentation/devicetree/bindings/iio/adc/amlogic,meson-saradc.txt AMLOGIC adc_keypad M: Xingyu Chen diff --git a/arch/arm/boot/dts/amlogic/meson8b.dtsi b/arch/arm/boot/dts/amlogic/meson8b.dtsi index 00731b1..523bf31 100644 --- a/arch/arm/boot/dts/amlogic/meson8b.dtsi +++ b/arch/arm/boot/dts/amlogic/meson8b.dtsi @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -802,10 +803,12 @@ dwc2_b { }; saradc: saradc { - compatible = "amlogic, saradc"; + compatible = "amlogic,meson-m8b-saradc"; status = "okay"; - clocks = <&clkc CLKID_SAR_ADC>; - clock-names = "saradc_clk"; + #io-channel-cells = <1>; + clocks = <&clkc CLKID_XTAL>, <&clkc CLKID_SAR_ADC>; + clock-names = "xtal", "clk81_gate"; + interrupts = <0 73 1>; reg = <0xc1108680 0x30>; }; diff --git a/arch/arm/boot/dts/amlogic/meson8b_m200.dts b/arch/arm/boot/dts/amlogic/meson8b_m200.dts index 329b4cb..0a9ad1c2 100644 --- a/arch/arm/boot/dts/amlogic/meson8b_m200.dts +++ b/arch/arm/boot/dts/amlogic/meson8b_m200.dts @@ -380,6 +380,8 @@ compatible = "amlogic, aml-thermal"; device_name = "thermal"; #thermal-sensor-cells = <1>; + io-channels = <&saradc SARADC_CH6>; + io-channel-names = "TEMP_CHAN"; cooling_devices { cpufreq_cool_cluster0 { min_state = <768000>; diff --git a/arch/arm/boot/dts/amlogic/meson8b_m400.dts b/arch/arm/boot/dts/amlogic/meson8b_m400.dts index b8b185a..56e1b03 100644 --- a/arch/arm/boot/dts/amlogic/meson8b_m400.dts +++ b/arch/arm/boot/dts/amlogic/meson8b_m400.dts @@ -307,6 +307,8 @@ compatible = "amlogic, aml-thermal"; device_name = "thermal"; #thermal-sensor-cells = <1>; + io-channels = <&saradc SARADC_CH6>; + io-channel-names = "TEMP_CHAN"; cooling_devices { cpufreq_cool_cluster0 { min_state = <768000>; diff --git a/arch/arm/boot/dts/amlogic/meson8b_skt.dts b/arch/arm/boot/dts/amlogic/meson8b_skt.dts index 7c1c019..aca3210 100644 --- a/arch/arm/boot/dts/amlogic/meson8b_skt.dts +++ b/arch/arm/boot/dts/amlogic/meson8b_skt.dts @@ -225,6 +225,8 @@ compatible = "amlogic, aml-thermal"; device_name = "thermal"; #thermal-sensor-cells = <1>; + io-channels = <&saradc SARADC_CH6>; + io-channel-names = "TEMP_CHAN"; cooling_devices { cpufreq_cool_cluster0 { min_state = <768000>; diff --git a/arch/arm/configs/meson32_defconfig b/arch/arm/configs/meson32_defconfig index 09f7301..58e45e4 100644 --- a/arch/arm/configs/meson32_defconfig +++ b/arch/arm/configs/meson32_defconfig @@ -177,7 +177,6 @@ CONFIG_AMLOGIC_M8B_CLK=y CONFIG_AMLOGIC_CRYPTO=y CONFIG_AMLOGIC_CRYPTO_BLKMV=y CONFIG_AMLOGIC_INPUT=y -CONFIG_AMLOGIC_SARADC=y CONFIG_AMLOGIC_REMOTE=y CONFIG_AMLOGIC_MESON_REMOTE=y CONFIG_AMLOGIC_EFUSE=y @@ -211,6 +210,8 @@ CONFIG_AMLOGIC_PMU_OF=y CONFIG_AMLOGIC_PMU=y CONFIG_AMLOGIC_1218=y CONFIG_AMLOGIC_M8B_DVFS=y +CONFIG_AMLOGIC_IIO=y +CONFIG_AMLOGIC_SARADC=y CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y CONFIG_DMA_CMA=y @@ -300,6 +301,7 @@ CONFIG_CHROME_PLATFORMS=y CONFIG_PM_DEVFREQ=y CONFIG_EXTCON=y CONFIG_MEMORY=y +CONFIG_IIO=y CONFIG_PWM=y CONFIG_RESET_CONTROLLER=y CONFIG_GENERIC_PHY=y diff --git a/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi b/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi index e18f2f3..5a1cbf2 100644 --- a/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesonaxg.dtsi @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -686,6 +687,16 @@ interrupts = <0 180 1 0 181 1>; reg = <0x0 0xff63e000 0x0 0x48>; }; + + saradc:saradc { + compatible = "amlogic,meson-axg-saradc"; + status = "okay"; + #io-channel-cells = <1>; + clocks = <&xtal>, <&clkc CLKID_SARADC_GATE>; + clock-names = "xtal", "saradc_clk"; + interrupts = ; + reg = <0x0 0xff809000 0x0 0x38>; + }; };/* end of / */ &pinctrl_aobus { diff --git a/arch/arm64/boot/dts/amlogic/mesongxl.dtsi b/arch/arm64/boot/dts/amlogic/mesongxl.dtsi index 29b7ce1..58e3214 100644 --- a/arch/arm64/boot/dts/amlogic/mesongxl.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesongxl.dtsi @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1010,12 +1011,14 @@ i2c_ao: i2c@c8100500{ /*I2C-AO*/ }; saradc: saradc { - compatible = "amlogic, saradc"; + compatible = "amlogic,meson-gxl-saradc"; status = "okay"; - clocks = <&clkc CLKID_SARADC>; - clock-names = "saradc_clk"; - reg = <0x0 0xc1108680 0x0 0x30 - 0x0 0xc883c3d8 0x0 0x08>; + #io-channel-cells = <1>; + clocks = <&xtal>, <&clkc CLKID_SARADC>, + <&clkc CLKID_SARADC_COMP>; + clock-names = "xtal", "clk81_gate", "saradc_clk"; + interrupts = ; + reg = <0x0 0xc1108680 0x0 0x38>; }; efuse: efuse{ diff --git a/arch/arm64/boot/dts/amlogic/mesongxm.dtsi b/arch/arm64/boot/dts/amlogic/mesongxm.dtsi index abf72ba..997ca6b 100644 --- a/arch/arm64/boot/dts/amlogic/mesongxm.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesongxm.dtsi @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -1138,12 +1139,14 @@ }; saradc: saradc { - compatible = "amlogic, saradc"; + compatible = "amlogic,meson-gxl-saradc"; status = "okay"; - clocks = <&clkc CLKID_SARADC>; - clock-names = "saradc_clk"; - reg = <0x0 0xc1108680 0x0 0x30 - 0x0 0xc883c3d8 0x0 0x08>; + #io-channel-cells = <1>; + clocks = <&xtal>, <&clkc CLKID_SARADC>, + <&clkc CLKID_SARADC_COMP>; + clock-names = "xtal", "clk81_gate", "saradc_clk"; + interrupts = ; + reg = <0x0 0xc1108680 0x0 0x38>; }; efuse: efuse{ diff --git a/arch/arm64/configs/meson64_defconfig b/arch/arm64/configs/meson64_defconfig index 3a85ed5..c622932 100644 --- a/arch/arm64/configs/meson64_defconfig +++ b/arch/arm64/configs/meson64_defconfig @@ -222,8 +222,6 @@ CONFIG_AMLOGIC_CRYPTO=y CONFIG_AMLOGIC_CRYPTO_DMA=y CONFIG_AMLOGIC_INPUT=y CONFIG_AMLOGIC_INPUT_KEYBOARD=y -CONFIG_AMLOGIC_ADC_KEYPADS=y -CONFIG_AMLOGIC_SARADC=y CONFIG_AMLOGIC_REMOTE=y CONFIG_AMLOGIC_MESON_REMOTE=y CONFIG_AMLOGIC_IRBLASTER=y @@ -301,6 +299,8 @@ CONFIG_AMLOGIC_WIFI=y CONFIG_AMLOGIC_BT_DEVICE=y CONFIG_AMLOGIC_DVB_COMPAT=y CONFIG_AMLOGIC_PCIE=y +CONFIG_AMLOGIC_IIO=y +CONFIG_AMLOGIC_SARADC=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y @@ -436,6 +436,7 @@ CONFIG_DEVFREQ_GOV_PERFORMANCE=y CONFIG_DEVFREQ_GOV_POWERSAVE=y CONFIG_DEVFREQ_GOV_USERSPACE=y CONFIG_EXTCON=y +CONFIG_IIO=y CONFIG_PWM=y CONFIG_ANDROID=y CONFIG_ANDROID_BINDER_IPC=y diff --git a/drivers/amlogic/Kconfig b/drivers/amlogic/Kconfig index 8315bc6..f1bb3c6 100644 --- a/drivers/amlogic/Kconfig +++ b/drivers/amlogic/Kconfig @@ -102,5 +102,7 @@ source "drivers/amlogic/pci/Kconfig" source "drivers/amlogic/irblaster/Kconfig" +source "drivers/amlogic/iio/Kconfig" + endmenu endif diff --git a/drivers/amlogic/Makefile b/drivers/amlogic/Makefile index 0a05beb..4eafb41 100644 --- a/drivers/amlogic/Makefile +++ b/drivers/amlogic/Makefile @@ -85,3 +85,5 @@ obj-$(CONFIG_AMLOGIC_POWER) += power/ obj-$(CONFIG_AMLOGIC_PCIE) += pci/ obj-$(CONFIG_AMLOGIC_IRBLASTER) += irblaster/ + +obj-$(CONFIG_AMLOGIC_IIO) += iio/ diff --git a/drivers/amlogic/iio/Kconfig b/drivers/amlogic/iio/Kconfig new file mode 100644 index 0000000..c279962 --- /dev/null +++ b/drivers/amlogic/iio/Kconfig @@ -0,0 +1,16 @@ +# +# Industrial I/O subsystem configuration +# + +menuconfig AMLOGIC_IIO + tristate "Industrial I/O support" + help + The industrial I/O subsystem provides a unified framework for + drivers for many different types of embedded sensors using a + number of different physical interfaces (i2c, spi, etc). + +if AMLOGIC_IIO + +source "drivers/amlogic/iio/adc/Kconfig" + +endif #IIO diff --git a/drivers/amlogic/iio/Makefile b/drivers/amlogic/iio/Makefile new file mode 100644 index 0000000..5388d0c --- /dev/null +++ b/drivers/amlogic/iio/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the industrial I/O core. +# + +obj-$(CONFIG_AMLOGIC_IIO) += adc/ diff --git a/drivers/amlogic/iio/adc/Kconfig b/drivers/amlogic/iio/adc/Kconfig new file mode 100644 index 0000000..462f825 --- /dev/null +++ b/drivers/amlogic/iio/adc/Kconfig @@ -0,0 +1,16 @@ +# +# ADC drivers +# +# When adding new entries keep the list in alphabetical order + +menu "Analog to digital converters" + +config AMLOGIC_SARADC + bool "Meson SAR ADC support" + depends on REGMAP_MMIO + depends on IIO + default n + help + Say Y here if you want to use the Meson SAR ADC. + +endmenu diff --git a/drivers/amlogic/iio/adc/Makefile b/drivers/amlogic/iio/adc/Makefile new file mode 100644 index 0000000..d6dfd43 --- /dev/null +++ b/drivers/amlogic/iio/adc/Makefile @@ -0,0 +1,7 @@ +# +#Makefile for IIO ADC drivers +# + +obj-$(CONFIG_AMLOGIC_SARADC) += meson_saradc.o + + diff --git a/drivers/amlogic/iio/adc/meson_saradc.c b/drivers/amlogic/iio/adc/meson_saradc.c new file mode 100644 index 0000000..fa268ed --- /dev/null +++ b/drivers/amlogic/iio/adc/meson_saradc.c @@ -0,0 +1,1214 @@ +/* + * drivers/amlogic/iio/adc/meson_saradc.c + * + * Copyright (C) 2017 Amlogic, Inc. All rights reserved. + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MESON_SAR_ADC_REG0 0x00 + #define MESON_SAR_ADC_REG0_PANEL_DETECT BIT(31) + #define MESON_SAR_ADC_REG0_BUSY_MASK GENMASK(30, 28) + #define MESON_SAR_ADC_REG0_DELTA_BUSY BIT(30) + #define MESON_SAR_ADC_REG0_AVG_BUSY BIT(29) + #define MESON_SAR_ADC_REG0_SAMPLE_BUSY BIT(28) + #define MESON_SAR_ADC_REG0_FIFO_FULL BIT(27) + #define MESON_SAR_ADC_REG0_FIFO_EMPTY BIT(26) + #define MESON_SAR_ADC_REG0_FIFO_COUNT_MASK GENMASK(25, 21) + #define MESON_SAR_ADC_REG0_ADC_BIAS_CTRL_MASK GENMASK(20, 19) + #define MESON_SAR_ADC_REG0_CURR_CHAN_ID_MASK GENMASK(18, 16) + #define MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL BIT(15) + #define MESON_SAR_ADC_REG0_SAMPLING_STOP BIT(14) + #define MESON_SAR_ADC_REG0_CHAN_DELTA_EN_MASK GENMASK(13, 12) + #define MESON_SAR_ADC_REG0_DETECT_IRQ_POL BIT(10) + #define MESON_SAR_ADC_REG0_DETECT_IRQ_EN BIT(9) + #define MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK GENMASK(8, 4) + #define MESON_SAR_ADC_REG0_FIFO_IRQ_EN BIT(3) + #define MESON_SAR_ADC_REG0_SAMPLING_START BIT(2) + #define MESON_SAR_ADC_REG0_CONTINUOUS_EN BIT(1) + #define MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE BIT(0) + +#define MESON_SAR_ADC_CHAN_LIST 0x04 + #define MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK GENMASK(26, 24) + #define MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(_chan) \ + (GENMASK(2, 0) << ((_chan) * 3)) + +#define MESON_SAR_ADC_AVG_CNTL 0x08 + #define MESON_SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(_chan) \ + (16 + ((_chan) * 2)) + #define MESON_SAR_ADC_AVG_CNTL_AVG_MODE_MASK(_chan) \ + (GENMASK(17, 16) << ((_chan) * 2)) + #define MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(_chan) \ + (0 + ((_chan) * 2)) + #define MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(_chan) \ + (GENMASK(1, 0) << ((_chan) * 2)) + +#define MESON_SAR_ADC_REG3 0x0c + #define MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY BIT(31) + #define MESON_SAR_ADC_REG3_CLK_EN BIT(30) + #define MESON_SAR_ADC_REG3_BL30_INITIALIZED BIT(28) + #define MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN BIT(27) + #define MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE BIT(26) + #define MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK GENMASK(25, 23) + #define MESON_SAR_ADC_REG3_DETECT_EN BIT(22) + #define MESON_SAR_ADC_REG3_ADC_EN BIT(21) + #define MESON_SAR_ADC_REG3_PANEL_DETECT_COUNT_MASK GENMASK(20, 18) + #define MESON_SAR_ADC_REG3_PANEL_DETECT_FILTER_TB_MASK GENMASK(17, 16) + #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_SHIFT 10 + #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH 6 + #define MESON_SAR_ADC_REG3_BLOCK_DLY_SEL_MASK GENMASK(9, 8) + #define MESON_SAR_ADC_REG3_BLOCK_DLY_MASK GENMASK(7, 0) + +#define MESON_SAR_ADC_DELAY 0x10 + #define MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK GENMASK(25, 24) + #define MESON_SAR_ADC_DELAY_BL30_BUSY BIT(15) + #define MESON_SAR_ADC_DELAY_KERNEL_BUSY BIT(14) + #define MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK GENMASK(23, 16) + #define MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK GENMASK(9, 8) + #define MESON_SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK GENMASK(7, 0) + +#define MESON_SAR_ADC_LAST_RD 0x14 + #define MESON_SAR_ADC_LAST_RD_LAST_CHANNEL1_MASK GENMASK(23, 16) + #define MESON_SAR_ADC_LAST_RD_LAST_CHANNEL0_MASK GENMASK(9, 0) + +#define MESON_SAR_ADC_FIFO_RD 0x18 + #define MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK GENMASK(14, 12) + #define MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK GENMASK(11, 0) + +#define MESON_SAR_ADC_AUX_SW 0x1c + #define MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_MASK(_chan) \ + (GENMASK(10, 8) << (((_chan) - 2) * 2)) + #define MESON_SAR_ADC_AUX_SW_VREF_P_MUX BIT(6) + #define MESON_SAR_ADC_AUX_SW_VREF_N_MUX BIT(5) + #define MESON_SAR_ADC_AUX_SW_MODE_SEL BIT(4) + #define MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW BIT(3) + #define MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW BIT(2) + #define MESON_SAR_ADC_AUX_SW_YM_DRIVE_SW BIT(1) + #define MESON_SAR_ADC_AUX_SW_XM_DRIVE_SW BIT(0) + +#define MESON_SAR_ADC_CHAN_10_SW 0x20 + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK GENMASK(25, 23) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_VREF_P_MUX BIT(22) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_VREF_N_MUX BIT(21) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_MODE_SEL BIT(20) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW BIT(19) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW BIT(18) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_YM_DRIVE_SW BIT(17) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_XM_DRIVE_SW BIT(16) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK GENMASK(9, 7) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_VREF_P_MUX BIT(6) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_VREF_N_MUX BIT(5) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_MODE_SEL BIT(4) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW BIT(3) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW BIT(2) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_YM_DRIVE_SW BIT(1) + #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_XM_DRIVE_SW BIT(0) + +#define MESON_SAR_ADC_DETECT_IDLE_SW 0x24 + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_SW_EN BIT(26) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK GENMASK(25, 23) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_VREF_P_MUX BIT(22) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_VREF_N_MUX BIT(21) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_SEL BIT(20) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_YP_DRIVE_SW BIT(19) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_XP_DRIVE_SW BIT(18) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_YM_DRIVE_SW BIT(17) + #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_XM_DRIVE_SW BIT(16) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK GENMASK(9, 7) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_VREF_P_MUX BIT(6) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_VREF_N_MUX BIT(5) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_SEL BIT(4) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_YP_DRIVE_SW BIT(3) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_XP_DRIVE_SW BIT(2) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_YM_DRIVE_SW BIT(1) + #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_XM_DRIVE_SW BIT(0) + +#define MESON_SAR_ADC_DELTA_10 0x28 + #define MESON_SAR_ADC_DELTA_10_TEMP_SEL BIT(27) + #define MESON_SAR_ADC_DELTA_10_TS_REVE1 BIT(26) + #define MESON_SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_MASK GENMASK(25, 16) + #define MESON_SAR_ADC_DELTA_10_TS_REVE0 BIT(15) + #define MESON_SAR_ADC_DELTA_10_TS_C_SHIFT 11 + #define MESON_SAR_ADC_DELTA_10_TS_C_MASK GENMASK(14, 11) + #define MESON_SAR_ADC_DELTA_10_TS_VBG_EN BIT(10) + #define MESON_SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_MASK GENMASK(9, 0) + +/* + * NOTE: registers from here are undocumented (the vendor Linux kernel driver + * and u-boot source served as reference). These only seem to be relevant on + * GXBB and newer. + */ +#define MESON_SAR_ADC_REG11 0x2c + #define MESON_SAR_ADC_REG11_VREF_SEL BIT(0) + #define MESON_SAR_ADC_REG11_BANDGAP_EN BIT(13) + +#define MESON_SAR_ADC_REG13 0x34 + #define MESON_SAR_ADC_REG13_12BIT_CALIBRATION_MASK GENMASK(13, 8) + +#define MESON_SAR_ADC_MAX_FIFO_SIZE 16 +#define MESON_SAR_ADC_TIMEOUT 100 /* ms */ + +#define P_HHI_DPLL_TOP_0 0x10c6 + +/* for use with IIO_VAL_INT_PLUS_MICRO */ +#define MILLION 1000000 + +#define MESON_SAR_ADC_CHAN(_chan) { \ + .type = IIO_VOLTAGE, \ + .indexed = 1, \ + .channel = _chan, \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ + BIT(IIO_CHAN_INFO_AVERAGE_RAW) | \ + BIT(IIO_CHAN_INFO_PROCESSED), \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ + BIT(IIO_CHAN_INFO_CALIBBIAS) | \ + BIT(IIO_CHAN_INFO_CALIBSCALE), \ + .datasheet_name = "SAR_ADC_CH"#_chan, \ +} + +#define IS_CHAN6(_chan) (_chan == 6) + +/*unit: v*/ +#define SAR_ADC_VREF 1.8 + +/*default clock for sar adc*/ +#define SAR_ADC_CLOCK 1200000 + +static const char * const chan7_vol[] = { + "gnd", + "vdd/4", + "vdd/2", + "vdd*3/4", + "vdd", + "unused", + "unused", + "unused" +}; + +/* + * TODO: the hardware supports IIO_TEMP for channel 6 as well which is + * currently not supported by this driver. + */ +static const struct iio_chan_spec meson_sar_adc_iio_channels[] = { + MESON_SAR_ADC_CHAN(SARADC_CH0), + MESON_SAR_ADC_CHAN(SARADC_CH1), + MESON_SAR_ADC_CHAN(SARADC_CH2), + MESON_SAR_ADC_CHAN(SARADC_CH3), + MESON_SAR_ADC_CHAN(SARADC_CH4), + MESON_SAR_ADC_CHAN(SARADC_CH5), + MESON_SAR_ADC_CHAN(SARADC_CH6), + MESON_SAR_ADC_CHAN(SARADC_CH7), + IIO_CHAN_SOFT_TIMESTAMP(8), +}; + +enum meson_sar_adc_avg_mode { + NO_AVERAGING = 0x0, + MEAN_AVERAGING = 0x1, + MEDIAN_AVERAGING = 0x2, +}; + +enum meson_sar_adc_num_samples { + ONE_SAMPLE = 0x0, + TWO_SAMPLES = 0x1, + FOUR_SAMPLES = 0x2, + EIGHT_SAMPLES = 0x3, +}; + +enum meson_sar_adc_chan7_mux_sel { + CHAN7_MUX_VSS = 0x0, + CHAN7_MUX_VDD_DIV4 = 0x1, + CHAN7_MUX_VDD_DIV2 = 0x2, + CHAN7_MUX_VDD_MUL3_DIV4 = 0x3, + CHAN7_MUX_VDD = 0x4, + CHAN7_MUX_CH7_INPUT = 0x7, +}; + +enum meson_sar_adc_resolution { + SAR_ADC_10BIT = 10, + SAR_ADC_12BIT = 12, +}; + +enum register_bit_state { + BIT_LOW = 0, + BIT_HIGH = 1, +}; + +enum vref_select { + CALIB_VOL_AS_VREF = 0, + VDDA_AS_VREF = 1, +}; + +/* + * struct meson_sar_adc_reg_diff - various information relative to registers + * + * @reg3_ring_counter_disable: to disable continuous ring counter. + * gxl and later: 1; others(gxtvbb etc): 0 + */ +struct meson_sar_adc_reg_diff { + bool reg3_ring_counter_disable; +}; + +/* + * struct meson_sar_adc_data - describe the differences of different platform. + * + * @obt_temp_chan6: whether to read data of temp sensor by channel 6 + * @has_bl30_integration: + * @vref_sel: txlx and later: VDDA; others(txl etc): calibration voltage + * @resolution: gxl and later: 12bit; others(gxtvbb etc): 10bit + * @name: + * @regs_diff: to describe the differences of the registers + */ +struct meson_sar_adc_data { + bool obt_temp_chan6; + bool has_bl30_integration; + bool vref_sel; + unsigned int resolution; + const char *name; + struct meson_sar_adc_reg_diff regs_diff; +}; + +struct meson_sar_adc_priv { + struct regmap *regmap; + const struct meson_sar_adc_data *data; + struct clk *clkin; + struct clk *clk81_gate; + struct clk *adc_clk; + struct clk_gate clk_gate; + struct clk *adc_div_clk; + struct clk_divider clk_div; + struct completion done; + int calibbias; + int calibscale; + int chan7_mux_sel; +}; + +static const struct regmap_config meson_sar_adc_regmap_config = { + .reg_bits = 8, + .val_bits = 32, + .reg_stride = 4, + .max_register = MESON_SAR_ADC_REG13, +}; + +static unsigned int meson_sar_adc_get_fifo_count(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + u32 regval; + + regmap_read(priv->regmap, MESON_SAR_ADC_REG0, ®val); + + return FIELD_GET(MESON_SAR_ADC_REG0_FIFO_COUNT_MASK, regval); +} + +static int meson_sar_adc_calib_val(struct iio_dev *indio_dev, int val) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int tmp; + + /* use val_calib = scale * val_raw + offset calibration function */ + tmp = div_s64((s64)val * priv->calibscale, MILLION) + priv->calibbias; + + return clamp(tmp, 0, (1 << priv->data->resolution) - 1); +} + +static int meson_sar_adc_wait_busy_clear(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int regval, timeout = 10000; + + /* + * NOTE: we need a small delay before reading the status, otherwise + * the sample engine may not have started internally (which would + * seem to us that sampling is already finished). + */ + do { + udelay(1); + regmap_read(priv->regmap, MESON_SAR_ADC_REG0, ®val); + } while (FIELD_GET(MESON_SAR_ADC_REG0_BUSY_MASK, regval) && timeout--); + + if (timeout < 0) + return -ETIMEDOUT; + + return 0; +} + +static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int regval, fifo_chan, fifo_val, count; + + if (!wait_for_completion_timeout(&priv->done, + msecs_to_jiffies(MESON_SAR_ADC_TIMEOUT))) + return -ETIMEDOUT; + + count = meson_sar_adc_get_fifo_count(indio_dev); + if (count != 1) { + dev_err(&indio_dev->dev, + "ADC FIFO has %d element(s) instead of one\n", count); + return -EINVAL; + } + + regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, ®val); + fifo_chan = FIELD_GET(MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK, regval); + if (fifo_chan != chan->channel) { + dev_err(&indio_dev->dev, + "ADC FIFO entry belongs to channel %d instead of %d\n", + fifo_chan, chan->channel); + return -EINVAL; + } + + fifo_val = FIELD_GET(MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK, regval); + fifo_val &= GENMASK(priv->data->resolution - 1, 0); + + /* to fix the sample value by software */ + *val = meson_sar_adc_calib_val(indio_dev, fifo_val); + + return 0; +} + +static void meson_sar_adc_set_averaging(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum meson_sar_adc_avg_mode mode, + enum meson_sar_adc_num_samples samples) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int val, channel = chan->channel; + + val = samples << MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(channel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_AVG_CNTL, + MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(channel), + val); + + val = mode << MESON_SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(channel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_AVG_CNTL, + MESON_SAR_ADC_AVG_CNTL_AVG_MODE_MASK(channel), val); +} + +static int meson_sar_adc_temp_sensor_init(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, + MESON_SAR_ADC_DELTA_10_TEMP_SEL, + FIELD_PREP(MESON_SAR_ADC_DELTA_10_TEMP_SEL, 1)); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, + MESON_SAR_ADC_DELTA_10_TS_REVE0, + FIELD_PREP(MESON_SAR_ADC_DELTA_10_TS_REVE0, 1)); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, + MESON_SAR_ADC_DELTA_10_TS_REVE1, + FIELD_PREP(MESON_SAR_ADC_DELTA_10_TS_REVE1, 1)); + return 0; +} + +static void meson_sar_adc_enable_channel(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + u32 regval; + + /* + * the SAR ADC engine allows sampling multiple channels at the same + * time. to keep it simple we're only working with one *internal* + * channel, which starts counting at index 0 (which means: count = 1). + */ + regval = FIELD_PREP(MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, 0); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_LIST, + MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, regval); + + /* map channel index 0 to the channel which we want to read */ + regval = FIELD_PREP(MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(0), + chan->channel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_LIST, + MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(0), regval); + + regval = FIELD_PREP(MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK, + chan->channel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DETECT_IDLE_SW, + MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK, + regval); + + regval = FIELD_PREP(MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK, + chan->channel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DETECT_IDLE_SW, + MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK, + regval); + + if (IS_CHAN6(chan->channel)) { + if (priv->data->obt_temp_chan6) + meson_sar_adc_temp_sensor_init(indio_dev); + else + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, + MESON_SAR_ADC_DELTA_10_TEMP_SEL, 0); + } +} + +static void meson_sar_adc_set_chan7_mux(struct iio_dev *indio_dev, int sel) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + u32 regval; + + regval = FIELD_PREP(MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, sel); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, regval); + + priv->chan7_mux_sel = sel; + + usleep_range(10, 20); +} + +static void meson_sar_adc_start_sample_engine(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + + reinit_completion(&priv->done); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_FIFO_IRQ_EN, + MESON_SAR_ADC_REG0_FIFO_IRQ_EN); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, + MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLING_START, + MESON_SAR_ADC_REG0_SAMPLING_START); +} + +static void meson_sar_adc_stop_sample_engine(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_FIFO_IRQ_EN, 0); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLING_STOP, + MESON_SAR_ADC_REG0_SAMPLING_STOP); + + /* wait until all modules are stopped */ + meson_sar_adc_wait_busy_clear(indio_dev); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0); +} + +static int meson_sar_adc_lock(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int val, timeout = 10000; + + mutex_lock(&indio_dev->mlock); + + if (priv->data->has_bl30_integration) { + /* prevent BL30 from using the SAR ADC while we are using it */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY); + + /* wait until BL30 releases it's lock (so we can use + * the SAR ADC) + */ + do { + udelay(1); + regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val); + } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--); + + if (timeout < 0) + return -ETIMEDOUT; + } + + return 0; +} + +static void meson_sar_adc_unlock(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + + if (priv->data->has_bl30_integration) + /* allow BL30 to use the SAR ADC again */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0); + + mutex_unlock(&indio_dev->mlock); +} + +static void meson_sar_adc_clear_fifo(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + unsigned int tmp; + + while (meson_sar_adc_get_fifo_count(indio_dev)) + regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, &tmp); +} + +static int meson_sar_adc_get_sample(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + enum meson_sar_adc_avg_mode avg_mode, + enum meson_sar_adc_num_samples avg_samples, + int *val) +{ + int ret; + + ret = meson_sar_adc_lock(indio_dev); + if (ret) + return ret; + + /* clear the FIFO to make sure we're not reading old values */ + meson_sar_adc_clear_fifo(indio_dev); + + meson_sar_adc_set_averaging(indio_dev, chan, avg_mode, avg_samples); + + meson_sar_adc_enable_channel(indio_dev, chan); + + meson_sar_adc_start_sample_engine(indio_dev); + ret = meson_sar_adc_read_raw_sample(indio_dev, chan, val); + meson_sar_adc_stop_sample_engine(indio_dev); + + meson_sar_adc_unlock(indio_dev); + + if (ret) { + dev_warn(indio_dev->dev.parent, + "failed to read sample for channel %d: %d\n", + chan->channel, ret); + return ret; + } + + return IIO_VAL_INT; +} + +static int meson_sar_adc_temp_sensor_calib(struct iio_dev *indio_dev, + int factor) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int tmp; + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, + MESON_SAR_ADC_DELTA_10_TS_C_MASK, + FIELD_PREP(MESON_SAR_ADC_DELTA_10_TS_C_MASK, + (factor & 0xf))); + + tmp = aml_read_cbus(P_HHI_DPLL_TOP_0); + tmp = (tmp & (~(1 << 9))) | (((factor >> 4) & 0x1) << 9); + aml_write_cbus(P_HHI_DPLL_TOP_0, tmp); + + return 0; +} +static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long mask) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int ret; + + switch (mask) { + case IIO_CHAN_INFO_RAW: + return meson_sar_adc_get_sample(indio_dev, chan, NO_AVERAGING, + ONE_SAMPLE, val); + + case IIO_CHAN_INFO_AVERAGE_RAW: + return meson_sar_adc_get_sample(indio_dev, chan, + MEAN_AVERAGING, EIGHT_SAMPLES, + val); + + case IIO_CHAN_INFO_PROCESSED: /* return the 10bit sample value */ + ret = meson_sar_adc_get_sample(indio_dev, chan, NO_AVERAGING, + ONE_SAMPLE, val); + if (priv->data->resolution == SAR_ADC_12BIT) + *val = *val >> 2; + + return ret; + + case IIO_CHAN_INFO_SCALE: + *val = SAR_ADC_VREF * MILLION; + *val2 = priv->data->resolution; + return IIO_VAL_FRACTIONAL_LOG2; + + case IIO_CHAN_INFO_CALIBBIAS: + *val = priv->calibbias; + return IIO_VAL_INT; + + case IIO_CHAN_INFO_CALIBSCALE: + *val = priv->calibscale / MILLION; + *val2 = priv->calibscale % MILLION; + return IIO_VAL_INT_PLUS_MICRO; + + default: + return -EINVAL; + } +} + +static int meson_sar_adc_iio_info_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, int val, int val2, long mask) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + + switch (mask) { + /* to set temperature calibration factor */ + /* TODO: there is no better way to set the temperature calibration + * factor currently by the consumer API of IIO. use the + * mask "IIO_CHAN_INFO_RAW" to pass the parameter temporarily. + */ + case IIO_CHAN_INFO_RAW: + if (priv->data->obt_temp_chan6 && IS_CHAN6(chan->channel)) { + meson_sar_adc_temp_sensor_calib(indio_dev, val); + return 0; + } else + return -EINVAL; + default: + return -EINVAL; + } +} + +static int meson_sar_adc_clk_init(struct iio_dev *indio_dev, + + void __iomem *base) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + struct clk_init_data init; + const char *clk_parents[1]; + + init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_div", + of_node_full_name(indio_dev->dev.of_node)); + init.flags = 0; + init.ops = &clk_divider_ops; + clk_parents[0] = __clk_get_name(priv->clkin); + init.parent_names = clk_parents; + init.num_parents = 1; + + priv->clk_div.reg = base + MESON_SAR_ADC_REG3; + priv->clk_div.shift = MESON_SAR_ADC_REG3_ADC_CLK_DIV_SHIFT; + priv->clk_div.width = MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH; + priv->clk_div.hw.init = &init; + priv->clk_div.flags = 0; + + priv->adc_div_clk = devm_clk_register(&indio_dev->dev, + &priv->clk_div.hw); + if (WARN_ON(IS_ERR(priv->adc_div_clk))) + return PTR_ERR(priv->adc_div_clk); + + init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%s#adc_en", + of_node_full_name(indio_dev->dev.of_node)); + init.flags = CLK_SET_RATE_PARENT; + init.ops = &clk_gate_ops; + clk_parents[0] = __clk_get_name(priv->adc_div_clk); + init.parent_names = clk_parents; + init.num_parents = 1; + + priv->clk_gate.reg = base + MESON_SAR_ADC_REG3; + priv->clk_gate.bit_idx = fls(MESON_SAR_ADC_REG3_CLK_EN); + priv->clk_gate.hw.init = &init; + + priv->adc_clk = devm_clk_register(&indio_dev->dev, &priv->clk_gate.hw); + if (WARN_ON(IS_ERR(priv->adc_clk))) + return PTR_ERR(priv->adc_clk); + + return 0; +} + +static int meson_sar_adc_init(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int regval, ret; + + /* + * make sure we start at CH7 input since the other muxes are only used + * for internal calibration. + */ + meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_CH7_INPUT); + + if (priv->data->has_bl30_integration) { + /* + * leave sampling delay and the input clocks as configured by + * BL30 to make sure BL30 gets the values it expects when + * reading the temperature sensor. + */ + regmap_read(priv->regmap, MESON_SAR_ADC_REG3, ®val); + if (regval & MESON_SAR_ADC_REG3_BL30_INITIALIZED) + return 0; + } + + meson_sar_adc_stop_sample_engine(indio_dev); + + /* update the channel 6 MUX to select the temperature sensor */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, + MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL); + + /* disable all channels by default */ + regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY, + MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY); + + /* delay between two samples = (10+1) * 1uS */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, + FIELD_PREP(MESON_SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK, + 10)); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK, + FIELD_PREP(MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK, + 0)); + + /* delay between two samples = (10+1) * 1uS */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, + FIELD_PREP(MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, + 10)); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, + MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK, + FIELD_PREP(MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK, + 1)); + /* disable internal ring counter */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN, + FIELD_PREP(MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN, + priv->data->regs_diff.reg3_ring_counter_disable)); + /* select the vref */ + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, + MESON_SAR_ADC_REG11_VREF_SEL, + FIELD_PREP(MESON_SAR_ADC_REG11_VREF_SEL, + priv->data->vref_sel)); + + ret = clk_set_rate(priv->adc_clk, SAR_ADC_CLOCK); + if (ret) { + dev_err(indio_dev->dev.parent, + "failed to set adc clock rate\n"); + return ret; + } + + return 0; +} + +static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int ret; + u32 regval; + + ret = meson_sar_adc_lock(indio_dev); + if (ret) + goto err_lock; + + regval = FIELD_PREP(MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, 1); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, + MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, regval); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, + MESON_SAR_ADC_REG11_BANDGAP_EN, + MESON_SAR_ADC_REG11_BANDGAP_EN); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_ADC_EN, + MESON_SAR_ADC_REG3_ADC_EN); + + udelay(5); + + if (priv->clk81_gate) { + ret = clk_prepare_enable(priv->clk81_gate); + if (ret) { + dev_err(indio_dev->dev.parent, "failed to enable clk81 gate\n"); + goto err_adc_clk; + } + } + + ret = clk_prepare_enable(priv->adc_clk); + if (ret) { + dev_err(indio_dev->dev.parent, "failed to enable adc clk\n"); + goto err_adc_clk; + } + + meson_sar_adc_unlock(indio_dev); + + return 0; + +err_adc_clk: + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_ADC_EN, 0); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, + MESON_SAR_ADC_REG11_BANDGAP_EN, 0); + meson_sar_adc_unlock(indio_dev); +err_lock: + return ret; +} + +static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int ret; + + ret = meson_sar_adc_lock(indio_dev); + if (ret) + return ret; + + clk_disable_unprepare(priv->adc_clk); + + if (priv->clk81_gate) + clk_disable_unprepare(priv->clk81_gate); + + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, + MESON_SAR_ADC_REG3_ADC_EN, 0); + regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG11, + MESON_SAR_ADC_REG11_BANDGAP_EN, 0); + + meson_sar_adc_unlock(indio_dev); + + return 0; +} + +static irqreturn_t meson_sar_adc_irq(int irq, void *data) +{ + struct iio_dev *indio_dev = data; + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + unsigned int cnt, threshold; + u32 regval; + + regmap_read(priv->regmap, MESON_SAR_ADC_REG0, ®val); + cnt = FIELD_GET(MESON_SAR_ADC_REG0_FIFO_COUNT_MASK, regval); + threshold = FIELD_GET(MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, regval); + + if (cnt < threshold) + return IRQ_NONE; + + complete(&priv->done); + + return IRQ_HANDLED; +} + +static int meson_sar_adc_calib(struct iio_dev *indio_dev) +{ + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int ret, nominal0, nominal1, value0, value1; + + /* use points 25% and 75% for calibration */ + nominal0 = (1 << priv->data->resolution) >> 2; + nominal1 = ((1 << priv->data->resolution) * 3) >> 2; + + meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_VDD_DIV4); + usleep_range(10, 20); + ret = meson_sar_adc_get_sample(indio_dev, + &meson_sar_adc_iio_channels[7], + MEAN_AVERAGING, EIGHT_SAMPLES, &value0); + if (ret < 0) + goto out; + + meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_VDD_MUL3_DIV4); + usleep_range(10, 20); + ret = meson_sar_adc_get_sample(indio_dev, + &meson_sar_adc_iio_channels[7], + MEAN_AVERAGING, EIGHT_SAMPLES, &value1); + if (ret < 0) + goto out; + + if (value1 <= value0) { + ret = -EINVAL; + goto out; + } + + priv->calibscale = div_s64((nominal1 - nominal0) * (s64)MILLION, + value1 - value0); + priv->calibbias = nominal0 - div_s64((s64)value0 * priv->calibscale, + MILLION); + ret = 0; +out: + meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_CH7_INPUT); + + return ret; +} + +static ssize_t chan7_mux_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct meson_sar_adc_priv *priv = iio_priv(indio_dev); + int len = 0; + int i; + + len = sprintf(buf, "current: [%d]%s\n\n", + priv->chan7_mux_sel, chan7_vol[priv->chan7_mux_sel]); + for (i = 0; i < ARRAY_SIZE(chan7_vol); i++) + len += sprintf(buf+len, "%d: %s\n", i, chan7_vol[i]); + + return len; +} + +static ssize_t chan7_mux_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + int val; + + if (kstrtoint(buf, 0, &val) != 0) + return -EINVAL; + if (val >= ARRAY_SIZE(chan7_vol)) + return -EINVAL; + meson_sar_adc_set_chan7_mux(indio_dev, val); + + return count; +} + +static IIO_DEVICE_ATTR(chan7_mux, 0644, + chan7_mux_show, chan7_mux_store, -1); + +static struct attribute *attrs[] = { + &iio_dev_attr_chan7_mux.dev_attr.attr, + NULL, /*need to terminate the list of attributes by NULL*/ +}; + +static const struct attribute_group meson_sar_adc_attr_group = { + .attrs = attrs, +}; + +static const struct iio_info meson_sar_adc_iio_info = { + .read_raw = meson_sar_adc_iio_info_read_raw, + .write_raw = meson_sar_adc_iio_info_write_raw, + .attrs = &meson_sar_adc_attr_group, + .driver_module = THIS_MODULE, +}; + +struct meson_sar_adc_data meson_sar_adc_axg_data = { + .obt_temp_chan6 = false, + .has_bl30_integration = true, + .vref_sel = VDDA_AS_VREF, + .resolution = SAR_ADC_12BIT, + .name = "meson-axg-saradc", + .regs_diff = { + .reg3_ring_counter_disable = BIT_HIGH, + }, +}; + +struct meson_sar_adc_data meson_sar_adc_gxl_data = { + .obt_temp_chan6 = false, + .has_bl30_integration = true, + .vref_sel = CALIB_VOL_AS_VREF, + .resolution = SAR_ADC_12BIT, + .name = "meson-gxl-saradc", + .regs_diff = { + .reg3_ring_counter_disable = BIT_HIGH, + }, +}; + +struct meson_sar_adc_data meson_sar_adc_gxm_data = { + .obt_temp_chan6 = false, + .has_bl30_integration = true, + .vref_sel = CALIB_VOL_AS_VREF, + .resolution = SAR_ADC_12BIT, + .name = "meson-gxm-saradc", + .regs_diff = { + .reg3_ring_counter_disable = BIT_HIGH, + }, +}; + +struct meson_sar_adc_data meson_sar_adc_m8b_data = { + .obt_temp_chan6 = true, + .has_bl30_integration = true, + .vref_sel = CALIB_VOL_AS_VREF, + .resolution = SAR_ADC_10BIT, + .name = "meson-m8b-saradc", + .regs_diff = { + .reg3_ring_counter_disable = BIT_LOW, + }, +}; + +static const struct of_device_id meson_sar_adc_of_match[] = { + { + .compatible = "amlogic,meson-axg-saradc", + .data = &meson_sar_adc_axg_data, + }, { + .compatible = "amlogic,meson-gxl-saradc", + .data = &meson_sar_adc_gxl_data, + }, { + .compatible = "amlogic,meson-gxm-saradc", + .data = &meson_sar_adc_gxm_data, + }, { + .compatible = "amlogic,meson-m8b-saradc", + .data = &meson_sar_adc_m8b_data, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, meson_sar_adc_of_match); + +static int meson_sar_adc_probe(struct platform_device *pdev) +{ + struct meson_sar_adc_priv *priv; + struct iio_dev *indio_dev; + struct resource *res; + void __iomem *base; + const struct of_device_id *match; + int irq, ret; + + indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); + if (!indio_dev) { + dev_err(&pdev->dev, "failed allocating iio device\n"); + return -ENOMEM; + } + + priv = iio_priv(indio_dev); + init_completion(&priv->done); + + match = of_match_device(meson_sar_adc_of_match, &pdev->dev); + priv->data = match->data; + + indio_dev->name = priv->data->name; + indio_dev->dev.parent = &pdev->dev; + indio_dev->dev.of_node = pdev->dev.of_node; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &meson_sar_adc_iio_info; + + indio_dev->channels = meson_sar_adc_iio_channels; + indio_dev->num_channels = ARRAY_SIZE(meson_sar_adc_iio_channels); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + irq = irq_of_parse_and_map(pdev->dev.of_node, 0); + if (!irq) + return -EINVAL; + + ret = devm_request_irq(&pdev->dev, irq, meson_sar_adc_irq, IRQF_SHARED, + dev_name(&pdev->dev), indio_dev); + if (ret) + return ret; + + priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, + &meson_sar_adc_regmap_config); + if (IS_ERR(priv->regmap)) + return PTR_ERR(priv->regmap); + + priv->clkin = devm_clk_get(&pdev->dev, "xtal"); + if (IS_ERR(priv->clkin)) { + dev_err(&pdev->dev, "failed to get xtal\n"); + return PTR_ERR(priv->clkin); + } + + priv->clk81_gate = devm_clk_get(&pdev->dev, "clk81_gate"); + if (IS_ERR(priv->clk81_gate)) { + if (PTR_ERR(priv->clk81_gate) == -ENOENT) { + priv->clk81_gate = NULL; + } else { + dev_err(&pdev->dev, "failed to get clk81 gate\n"); + return PTR_ERR(priv->clk81_gate); + } + } + + priv->adc_clk = devm_clk_get(&pdev->dev, "saradc_clk"); + if (IS_ERR(priv->adc_clk)) { + if (PTR_ERR(priv->adc_clk) == -ENOENT) { + priv->adc_clk = NULL; + } else { + dev_err(&pdev->dev, "failed to get adc clk\n"); + return PTR_ERR(priv->adc_clk); + } + } + + /* on pre-GXBB SoCs the SAR ADC itself provides the ADC clock: */ + if (!priv->adc_clk) { + ret = meson_sar_adc_clk_init(indio_dev, base); + if (ret) + return ret; + } + + priv->calibscale = MILLION; + + ret = meson_sar_adc_init(indio_dev); + if (ret) + goto err; + + ret = meson_sar_adc_hw_enable(indio_dev); + if (ret) + goto err; + + ret = meson_sar_adc_calib(indio_dev); + if (ret) + dev_warn(&pdev->dev, "calibration failed\n"); + + platform_set_drvdata(pdev, indio_dev); + + ret = iio_device_register(indio_dev); + if (ret) + goto err_hw; + + return 0; + +err_hw: + meson_sar_adc_hw_disable(indio_dev); +err: + return ret; +} + +static int meson_sar_adc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + + iio_device_unregister(indio_dev); + + return meson_sar_adc_hw_disable(indio_dev); +} + +static int __maybe_unused meson_sar_adc_suspend(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + + return meson_sar_adc_hw_disable(indio_dev); +} + +static int __maybe_unused meson_sar_adc_resume(struct device *dev) +{ + struct iio_dev *indio_dev = dev_get_drvdata(dev); + + return meson_sar_adc_hw_enable(indio_dev); +} + +static SIMPLE_DEV_PM_OPS(meson_sar_adc_pm_ops, + meson_sar_adc_suspend, meson_sar_adc_resume); + +static struct platform_driver meson_sar_adc_driver = { + .probe = meson_sar_adc_probe, + .remove = meson_sar_adc_remove, + .driver = { + .name = "meson-saradc", + .of_match_table = meson_sar_adc_of_match, + .pm = &meson_sar_adc_pm_ops, + }, +}; + +module_platform_driver(meson_sar_adc_driver); + +MODULE_AUTHOR("Martin Blumenstingl and Amlogic"); +MODULE_DESCRIPTION("Amlogic Meson SAR ADC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/amlogic/input/Kconfig b/drivers/amlogic/input/Kconfig index e71c61c..a155d4a 100644 --- a/drivers/amlogic/input/Kconfig +++ b/drivers/amlogic/input/Kconfig @@ -12,8 +12,6 @@ if AMLOGIC_INPUT source "drivers/amlogic/input/keyboard/Kconfig" -source "drivers/amlogic/input/saradc/Kconfig" - source "drivers/amlogic/input/remote/Kconfig" endif diff --git a/drivers/amlogic/input/Makefile b/drivers/amlogic/input/Makefile index 5e8f565..87fc1ae 100644 --- a/drivers/amlogic/input/Makefile +++ b/drivers/amlogic/input/Makefile @@ -6,6 +6,4 @@ obj-$(CONFIG_AMLOGIC_INPUT_KEYBOARD) += keyboard/ -obj-$(CONFIG_AMLOGIC_SARADC) += saradc/ - obj-$(CONFIG_AMLOGIC_REMOTE) += remote/ diff --git a/drivers/amlogic/input/saradc/Kconfig b/drivers/amlogic/input/saradc/Kconfig deleted file mode 100644 index c0e8f6a..0000000 --- a/drivers/amlogic/input/saradc/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -# -# Input core configuration -# -config AMLOGIC_SARADC - bool "Meson SAR ADC support" - default n - help - Say Y here if you want to use the Meson SAR ADC. diff --git a/drivers/amlogic/input/saradc/Makefile b/drivers/amlogic/input/saradc/Makefile deleted file mode 100644 index 8c7dce8..0000000 --- a/drivers/amlogic/input/saradc/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for the input core drivers. -# - -# Each configuration option enables a list of files. - -obj-$(CONFIG_AMLOGIC_SARADC) += saradc.o - - diff --git a/drivers/amlogic/input/saradc/saradc.c b/drivers/amlogic/input/saradc/saradc.c deleted file mode 100644 index 7a8de9c..0000000 --- a/drivers/amlogic/input/saradc/saradc.c +++ /dev/null @@ -1,650 +0,0 @@ -/* - * drivers/amlogic/input/saradc/saradc.c - * - * Copyright (C) 2017 Amlogic, Inc. All rights reserved. - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "saradc_reg.h" - -/* #define ENABLE_DYNAMIC_POWER */ -#define CLEAN_BUFF_BEFORE_SARADC 1 - -/* flag_12bit = 0 : 10 bit */ -/* flag_12bit = 1 : 12 bit */ -static char flag_12bit; - -#define saradc_info(x...) dev_info(adc->dev, x) -#define saradc_dbg(x...) /* dev_info(adc->dev, x) */ -#define saradc_err(x...) dev_err(adc->dev, x) - -#define SARADC_STATE_IDLE 0 -#define SARADC_STATE_BUSY 1 -#define SARADC_STATE_SUSPEND 2 - -const char *ch7_vol[] = { - "gnd", - "vdd/4", - "vdd/2", - "vdd*3/4", - "vdd", - "unused", - "unused", - "unused" -}; - -struct saradc { - struct device *dev; - void __iomem *mem_base; - void __iomem *clk_mem_base; - struct clk *clk; - spinlock_t lock; - int ref_val; - int ref_nominal; - int coef; - int state; - int ch7_sel; -}; - -static struct saradc *gp_saradc; - -void setb( - void __iomem *mem_base, - unsigned int bits_desc, - unsigned int bits_val) -{ - unsigned int mem_offset, val; - unsigned int bits_offset, bits_mask; - - if (IS_ERR(mem_base)) - return; - mem_offset = of_mem_offset(bits_desc); - bits_offset = of_bits_offset(bits_desc); - bits_mask = (1L<> bits_offset) & bits_mask; -} -EXPORT_SYMBOL(getb); - -#ifdef CONFIG_AMLOGIC_M8B_TEMP_SENSOR -#ifndef CONFIG_MACH_MESON8 -void temp_set_trim(unsigned char val) -{ - int tmp; - - tmp = aml_read_cbus(P_HHI_DPLL_TOP_0); - tmp = (tmp & (~(1 << 9))) | ((val & 0x1) << 9); - aml_write_cbus(P_HHI_DPLL_TOP_0, tmp); -} -#endif -void temp_sensor_adc_init(int triming) -{ - struct saradc *adc = gp_saradc; - void __iomem *mem_base; - - mem_base = adc->mem_base; - setb(mem_base, TEMP_SELECT, 1); - setb(mem_base, TEMP_TRIM, triming & 0xf); -#ifndef CONFIG_MACH_MESON8 - temp_set_trim(triming >> 4); -#endif - setb(mem_base, TEMP_EN0, 1); - setb(mem_base, TEMP_EN1, 1); -} -EXPORT_SYMBOL(temp_sensor_adc_init); -#endif - -static void saradc_power_control(struct saradc *adc, int on) -{ - void __iomem *mem_base = adc->mem_base; - - if (on) { - setb(mem_base, BANDGAP_EN, 1); - setb(mem_base, ADC_EN, 1); - udelay(5); - if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXBB)) - setb(adc->clk_mem_base, REGC_CLK_EN, 1); - else - setb(mem_base, CLK_EN, 1); - } else { - if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXBB)) - setb(adc->clk_mem_base, REGC_CLK_EN, 0); - else - setb(mem_base, CLK_EN, 0); - setb(mem_base, ADC_EN, 0); - setb(mem_base, BANDGAP_EN, 0); - } -} - -static void saradc_reset(struct saradc *adc) -{ - void __iomem *mem_base = adc->mem_base; - int clk_div; - - - if (getb(mem_base, FLAG_INITIALIZED)) { - saradc_info("initialized by BL30\n"); -#ifndef ENABLE_DYNAMIC_POWER - saradc_power_control(adc, 1); -#endif - return; - } - writel(0x84004040, mem_base+SARADC_REG0); - writel(0, mem_base+SARADC_CH_LIST); - writel(0xaaaa, mem_base+SARADC_AVG_CNTL); - if (flag_12bit) - writel(0x9b88000a, mem_base+SARADC_REG3); - else - writel(0x9388000a, mem_base+SARADC_REG3); - /* set SARADC_DELAY with 0x190a380a when 32k */ - writel(0x10a000a, mem_base+SARADC_DELAY); - writel(0x3eb1a0c, mem_base+SARADC_AUX_SW); - writel(0x3eb1a0c, mem_base+SARADC_AUX_SW); - writel(0x8c000c, mem_base+SARADC_CH10_SW); - writel(0xc000c, mem_base+SARADC_DETECT_IDLE_SW); - - clk_prepare_enable(adc->clk); - clk_div = clk_get_rate(adc->clk) / 1200000; - if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXBB)) { - setb(adc->clk_mem_base, REGC_CLK_DIV, clk_div); - setb(adc->clk_mem_base, REGC_CLK_SRC, 0); - } else { - setb(mem_base, CLK_DIV, clk_div); - } - saradc_info("initialized by kernel, clk_div=%d\n", clk_div); -#ifndef ENABLE_DYNAMIC_POWER - saradc_power_control(adc, 1); -#endif -} - -static int saradc_internal_cal(struct saradc *adc) -{ - int val[5], nominal[5] = {0, 256, 512, 768, 1023}; - int i; - - saradc_info("calibration start:\n"); - adc->coef = 0; - for (i = 0; i < 5; i++) { - setb(adc->mem_base, CAL_CNTL, i); - udelay(10); - val[i] = get_adc_sample(0, CHAN_7); - saradc_info("nominal=%d, value=%d\n", nominal[i], val[i]); - if (val[i] < 0) - goto cal_end; - } - adc->ref_val = val[2]; - adc->ref_nominal = nominal[2]; - if (val[3] > val[1]) { - adc->coef = (nominal[3] - nominal[1]) << 12; - adc->coef /= val[3] - val[1]; - } -cal_end: - saradc_info("calibration end: coef=%d\n", adc->coef); - setb(adc->mem_base, CAL_CNTL, 7); - adc->ch7_sel = 7; - return 0; -} - -static int saradc_get_cal_value(struct saradc *adc, int val) -{ - int nominal; - - /*((nominal - ref_nominal) << 10) / (val - ref_val) = coef*/ - /*==> nominal = ((val - ref_val) * coef >> 10) + ref_nominal*/ - - nominal = val; - if ((adc->coef > 0) && (val > 0)) { - nominal = (val - adc->ref_val) * adc->coef; - nominal >>= 12; - nominal += adc->ref_nominal; - } - if (nominal < 0) - nominal = 0; - if (nominal > 1023) - nominal = 1023; - return nominal; -} - -static int saradc_get_cal_value_12bit(struct saradc *adc, int val) -{ - int nominal; - - /*((nominal - ref_nominal) << 10) / (val - ref_val) = coef*/ - /*==> nominal = ((val - ref_val) * coef >> 10) + ref_nominal*/ - - nominal = val; - if ((adc->coef > 0) && (val > 0)) { - nominal = (val - adc->ref_val) * adc->coef; - nominal >>= 12; - nominal += adc->ref_nominal; - } - if (nominal < 0) - nominal = 0; - if (nominal > 4095) - nominal = 4095; - return nominal; -} - -/*if_10bit=1:10bit*/ -/*if_10bit=0:12bit*/ -int get_adc_sample_early(int dev_id, int ch, char if_10bit) -{ - struct saradc *adc; - void __iomem *mem_base; - int value, count, sum; - int max = 0; - int min = 0x3ff; - int min_12bit = 0xfff; - unsigned long flags; - - if (!if_10bit) - min = min_12bit; - - adc = gp_saradc; - mem_base = adc->mem_base; - if (!adc || getb(mem_base, FLAG_BUSY_BL30) - || (adc->state != SARADC_STATE_IDLE)) - return -1; - - spin_lock_irqsave(&adc->lock, flags); - adc->state = SARADC_STATE_BUSY; - setb(mem_base, FLAG_BUSY_KERNEL, 1); - isb(); - dsb(sy); - udelay(1); - if (getb(mem_base, FLAG_BUSY_BL30)) { - value = -1; - goto end; - } - -#ifdef ENABLE_DYNAMIC_POWER - saradc_power_control(adc, 1); -#endif -#if CLEAN_BUFF_BEFORE_SARADC - count = 0; - while (getb(mem_base, FIFO_COUNT) && (count < FIFO_MAX)) { - value = readl(mem_base+SARADC_FIFO_RD); - count++; - } -#endif - writel(ch, mem_base+SARADC_CH_LIST); - setb(mem_base, DETECT_MUX, ch); - setb(mem_base, IDLE_MUX, ch); - setb(mem_base, SAMPLE_ENGINE_EN, 1); - setb(mem_base, START_SAMPLE, 1); - - count = 0; - do { - udelay(1); - if (++count > 1000) { - saradc_err("busy, %x\n", readl(mem_base+SARADC_REG0)); - value = -1; - goto end1; - } - } while (getb(mem_base, ALL_BUSY)); - - count = 0; - sum = 0; - while (getb(mem_base, FIFO_COUNT) && (count < FIFO_MAX)) { - value = readl(mem_base+SARADC_FIFO_RD); - if (((value>>12) & 0x07) == ch) { - if (if_10bit) { - if (flag_12bit) { - value &= 0xffc; - value >>= 2; - } else - value &= 0x3ff; - } else - value &= 0xfff; - - if (value > max) - max = value; - if (value < min) - min = value; - sum += value; - count++; - } - } - - if (!count) { - value = -1; - goto end1; - } - if (count > 2) { - sum -= (max + min); - count -= 2; - } - value = sum / count; - saradc_dbg("before cal: %d, count=%d\n", value, count); - if (adc->coef) { - if (if_10bit) - value = saradc_get_cal_value(adc, value); - else - value = saradc_get_cal_value_12bit(adc, value); - saradc_dbg("after cal: %d\n", value); - } -end1: - setb(mem_base, STOP_SAMPLE, 1); - setb(mem_base, SAMPLE_ENGINE_EN, 0); -#ifdef ENABLE_DYNAMIC_POWER - saradc_power_control(0); -#endif -end: - setb(mem_base, FLAG_BUSY_KERNEL, 0); - isb(); - dsb(sy); - udelay(1); - adc->state = SARADC_STATE_IDLE; - spin_unlock_irqrestore(&adc->lock, flags); - return value; -} - - -int get_adc_sample(int dev_id, int ch) -{ - int val; - - val = get_adc_sample_early(dev_id, ch, 1); - return val; -} -EXPORT_SYMBOL(get_adc_sample); - -int get_adc_sample_12bit(int dev_id, int ch) -{ - int val; - - val = get_adc_sample_early(dev_id, ch, 0); - return val; -} -EXPORT_SYMBOL(get_adc_sample_12bit); - -static void __iomem * -saradc_get_reg_addr(struct platform_device *pdev, int index) -{ - struct resource *res; - void __iomem *reg_addr; - - res = platform_get_resource(pdev, IORESOURCE_MEM, index); - if (!res) { - dev_err(&pdev->dev, "reg: cannot obtain I/O memory region"); - return 0; - } - if (!devm_request_mem_region(&pdev->dev, res->start, - resource_size(res), dev_name(&pdev->dev))) { - dev_err(&pdev->dev, "Memory region busy\n"); - return 0; - } - reg_addr = devm_ioremap_nocache(&pdev->dev, res->start, - resource_size(res)); - return reg_addr; -} - -static ssize_t ch0_show(struct class *cla, - struct class_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", get_adc_sample(0, 0)); -} -static ssize_t ch1_show(struct class *cla, - struct class_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", get_adc_sample(0, 1)); -} -static ssize_t ch2_show(struct class *cla, - struct class_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", get_adc_sample(0, 2)); -} -static ssize_t ch3_show(struct class *cla, - struct class_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", get_adc_sample(0, 3)); -} -static ssize_t ch4_show(struct class *cla, - struct class_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", get_adc_sample(0, 4)); -} -static ssize_t ch5_show(struct class *cla, - struct class_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", get_adc_sample(0, 5)); -} -static ssize_t ch6_show(struct class *cla, - struct class_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", get_adc_sample(0, 6)); -} -static ssize_t ch7_show(struct class *cla, - struct class_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", get_adc_sample(0, 7)); -} - -static ssize_t ch7_mux_show(struct class *cla, - struct class_attribute *attr, char *buf) -{ - int i; - int len = 0; - struct saradc *adc = gp_saradc; - - len = sprintf(buf, "current: [%d]%s\n\n", - adc->ch7_sel, ch7_vol[adc->ch7_sel]); - for (i = 0; i < ARRAY_SIZE(ch7_vol); i++) - len += sprintf(buf + len, "%d: %s\n", i, ch7_vol[i]); - - return len; -} - -static ssize_t ch7_mux_store(struct class *cla, - struct class_attribute *attr, const char *buf, size_t count) -{ - int val; - struct saradc *adc = gp_saradc; - - if (kstrtoint(buf, 0, &val) != 0) - return -EINVAL; - - if (val >= ARRAY_SIZE(ch7_vol)) - return -EINVAL; - - setb(adc->mem_base, CAL_CNTL, val); - adc->ch7_sel = val; - - return count; -} -static struct class_attribute saradc_class_attrs[] = { - __ATTR_RO(ch0), - __ATTR_RO(ch1), - __ATTR_RO(ch2), - __ATTR_RO(ch3), - __ATTR_RO(ch4), - __ATTR_RO(ch5), - __ATTR_RO(ch6), - __ATTR_RO(ch7), - __ATTR_RW(ch7_mux), - __ATTR_NULL -}; - -static struct class saradc_class = { - .name = "saradc", - .class_attrs = saradc_class_attrs, -}; - -static int saradc_probe(struct platform_device *pdev) -{ - int err; - struct saradc *adc; - - if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXL)) - flag_12bit = 1; - else - flag_12bit = 0; - - adc = kzalloc(sizeof(struct saradc), GFP_KERNEL); - if (!adc) { - err = -ENOMEM; - goto end_err; - } - adc->dev = &pdev->dev; - - if (!pdev->dev.of_node) { - err = -EINVAL; - goto end_free; - } - adc->mem_base = saradc_get_reg_addr(pdev, 0); - if (!adc->mem_base) { - err = -ENODEV; - goto end_free; - } - if (cpu_after_eq(MESON_CPU_MAJOR_ID_GXBB)) - adc->clk_mem_base = saradc_get_reg_addr(pdev, 1); - - adc->clk = devm_clk_get(&pdev->dev, "saradc_clk"); - if (IS_ERR(adc->clk)) { - err = -ENOENT; - goto end_free; - } - - saradc_reset(adc); - gp_saradc = adc; - dev_set_drvdata(&pdev->dev, adc); - spin_lock_init(&adc->lock); - adc->state = SARADC_STATE_IDLE; - saradc_internal_cal(adc); - - class_register(&saradc_class); - - return 0; -end_free: - kfree(adc); -end_err: - dev_err(&pdev->dev, "error=%d\n", err); - return err; -} - -static int saradc_suspend(struct platform_device *pdev, pm_message_t state) -{ - struct saradc *adc = (struct saradc *)dev_get_drvdata(&pdev->dev); - unsigned long flags; - - spin_lock_irqsave(&adc->lock, flags); - saradc_power_control(adc, 0); - adc->state = SARADC_STATE_SUSPEND; - spin_unlock_irqrestore(&adc->lock, flags); - return 0; -} - -static int saradc_resume(struct platform_device *pdev) -{ - struct saradc *adc = (struct saradc *)dev_get_drvdata(&pdev->dev); - unsigned long flags; - - spin_lock_irqsave(&adc->lock, flags); - saradc_power_control(adc, 1); - adc->state = SARADC_STATE_IDLE; - spin_unlock_irqrestore(&adc->lock, flags); - return 0; -} - -static int saradc_remove(struct platform_device *pdev) -{ - struct saradc *adc = (struct saradc *)dev_get_drvdata(&pdev->dev); - unsigned long flags; - - class_unregister(&saradc_class); - spin_lock_irqsave(&adc->lock, flags); - saradc_power_control(adc, 0); - spin_unlock_irqrestore(&adc->lock, flags); - kfree(adc); - return 0; -} - -static void saradc_shutdown(struct platform_device *pdev) -{ - struct saradc *adc = (struct saradc *)dev_get_drvdata(&pdev->dev); - unsigned long flags; - - spin_lock_irqsave(&adc->lock, flags); - saradc_power_control(adc, 0); - spin_unlock_irqrestore(&adc->lock, flags); -} - -#ifdef CONFIG_OF -static const struct of_device_id saradc_dt_match[] = { - { .compatible = "amlogic, saradc"}, - {}, -}; -#else -#define saradc_dt_match NULL -#endif - -static struct platform_driver saradc_driver = { - .probe = saradc_probe, - .remove = saradc_remove, - .suspend = saradc_suspend, - .resume = saradc_resume, - .shutdown = saradc_shutdown, - .driver = { - .name = "saradc", - .of_match_table = saradc_dt_match, - }, -}; - -static int __init saradc_init(void) -{ - /* printk(KERN_INFO "SARADC Driver init.\n"); */ - return platform_driver_register(&saradc_driver); -} - -static void __exit saradc_exit(void) -{ - /* printk(KERN_INFO "SARADC Driver exit.\n"); */ - platform_driver_unregister(&saradc_driver); -} - -module_init(saradc_init); -module_exit(saradc_exit); - -MODULE_AUTHOR("aml"); -MODULE_DESCRIPTION("SARADC Driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/amlogic/input/saradc/saradc_reg.h b/drivers/amlogic/input/saradc/saradc_reg.h deleted file mode 100644 index 458e2a8..0000000 --- a/drivers/amlogic/input/saradc/saradc_reg.h +++ /dev/null @@ -1,69 +0,0 @@ -/* - * drivers/amlogic/input/saradc/saradc_reg.h - * - * Copyright (C) 2017 Amlogic, Inc. All rights reserved. - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - */ - -#ifndef __SARADC_REG_H__ -#define __SARADC_REG_H__ - -#define SARADC_REG0 (0<<2) -#define SARADC_CH_LIST (1<<2) -#define SARADC_AVG_CNTL (2<<2) -#define SARADC_REG3 (3<<2) -#define SARADC_DELAY (4<<2) -#define SARADC_LAST_RD (5<<2) -#define SARADC_FIFO_RD (6<<2) -#define SARADC_AUX_SW (7<<2) -#define SARADC_CH10_SW (8<<2) -#define SARADC_DETECT_IDLE_SW (9<<2) -#define SARADC_DELTA_10 (10<<2) -#define SARADC_REG11 (11<<2) -#define P_HHI_DPLL_TOP_0 0x10c6 - -#define SAMPLE_ENGINE_EN bits_desc(SARADC_REG0, 0, 1) -#define START_SAMPLE bits_desc(SARADC_REG0, 2, 1) -#define STOP_SAMPLE bits_desc(SARADC_REG0, 14, 1) -#define FIFO_COUNT bits_desc(SARADC_REG0, 21, 5) -#define SAMPLE_BUSY bits_desc(SARADC_REG0, 28, 1) -#define AVG_BUSY bits_desc(SARADC_REG0, 29, 1) -#define DELTA_BUSY bits_desc(SARADC_REG0, 30, 1) -#define ALL_BUSY bits_desc(SARADC_REG0, 28, 3) -#define CLK_DIV bits_desc(SARADC_REG3, 10, 6) -#define ADC_EN bits_desc(SARADC_REG3, 21, 1) -#define CAL_CNTL bits_desc(SARADC_REG3, 23, 3) -#define FLAG_INITIALIZED bits_desc(SARADC_REG3, 28, 1) /* for bl30 */ -#define CLK_EN bits_desc(SARADC_REG3, 30, 1) -#define FLAG_BUSY_KERNEL bits_desc(SARADC_DELAY, 14, 1) /* for bl30 */ -#define FLAG_BUSY_BL30 bits_desc(SARADC_DELAY, 15, 1) /* for bl30 */ -#define IDLE_MUX bits_desc(SARADC_DETECT_IDLE_SW, 7, 3) -#define DETECT_MUX bits_desc(SARADC_DETECT_IDLE_SW, 23, 3) -#ifdef CONFIG_MACH_MESON8B -#define BANDGAP_EN bits_desc(SARADC_DELTA_10, 10, 1) -#define TEMP_TRIM bits_desc(SARADC_DELTA_10, 11, 4) -#define TEMP_EN0 bits_desc(SARADC_DELTA_10, 15, 1) -#define TEMP_EN1 bits_desc(SARADC_DELTA_10, 26, 1) -#define TEMP_SELECT bits_desc(SARADC_DELTA_10, 27, 1) -#else -#define BANDGAP_EN bits_desc(SARADC_REG11, 13, 1) -#endif - -/* saradc clock register */ -#define REGC_CLK_DIV bits_desc(0, 0, 8) -#define REGC_CLK_EN bits_desc(0, 8, 1) -#define REGC_CLK_SRC bits_desc(0, 9, 3) - -#define FIFO_MAX 32 - -#endif diff --git a/drivers/amlogic/spicc/spicc.c b/drivers/amlogic/spicc/spicc.c index be37dc5..9f62357 100644 --- a/drivers/amlogic/spicc/spicc.c +++ b/drivers/amlogic/spicc/spicc.c @@ -132,7 +132,6 @@ static const char * const log_comment[] = { "pio begin", "pio end" }; - static void spicc_log_init(struct spicc *spicc) { spicc->log = 0; @@ -212,6 +211,37 @@ static void spicc_log_print(struct spicc *spicc) #define spicc_log_print(spicc) #endif +static void setb(void __iomem *mem_base, + unsigned int bits_desc, + unsigned int bits_val) { + unsigned int mem_offset, val; + unsigned int bits_offset, bits_mask; + + if (IS_ERR(mem_base)) + return; + mem_offset = of_mem_offset(bits_desc); + bits_offset = of_bits_offset(bits_desc); + bits_mask = (1L<> bits_offset) & bits_mask; +} + /* Note this is chip_select enable or disable */ void spicc_chip_select(struct spi_device *spi, bool select) { diff --git a/drivers/amlogic/spicc/spicc.h b/drivers/amlogic/spicc/spicc.h index 0080675..bdb35da 100644 --- a/drivers/amlogic/spicc/spicc.h +++ b/drivers/amlogic/spicc/spicc.h @@ -18,8 +18,6 @@ #ifndef __SPICC_H__ #define __SPICC_H__ -#include - #define SPICC_FIFO_SIZE 16 #define SPICC_DEFAULT_BIT_WIDTH 8 #define SPICC_DEFAULT_SPEED_HZ 3000000 @@ -41,6 +39,12 @@ #define SPICC_REG_ENHANCE_CNTL (14<<2) #define SPICC_REG_ENHANCE_CNTL1 (15<<2) +#define bits_desc(reg_offset, bits_offset, bits_len) \ + (((bits_len)<<24)|((bits_offset)<<16)|(reg_offset)) +#define of_mem_offset(bd) ((bd)&0xffff) +#define of_bits_offset(bd) (((bd)>>16)&0xff) +#define of_bits_len(bd) (((bd)>>24)&0xff) + #define CON_ENABLE bits_desc(SPICC_REG_CON, 0, 1) #define CON_MODE bits_desc(SPICC_REG_CON, 1, 1) #define CON_XCH bits_desc(SPICC_REG_CON, 2, 1) diff --git a/drivers/amlogic/thermal/aml_thermal_hw_m8b.c b/drivers/amlogic/thermal/aml_thermal_hw_m8b.c index cb2cced..febb172 100644 --- a/drivers/amlogic/thermal/aml_thermal_hw_m8b.c +++ b/drivers/amlogic/thermal/aml_thermal_hw_m8b.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -72,6 +72,7 @@ struct aml_thermal_sensor { unsigned int cool_dev_num : 9; struct cpumask mask[NUM_CLUSTERS]; struct cool_dev *cool_devs; + struct iio_channel *temp_chan; struct thermal_zone_device *tzd; }; @@ -103,7 +104,7 @@ int thermal_firmware_init(void) soc_sensor.chip_trimmed = 0; } if (soc_sensor.chip_trimmed) { - temp_sensor_adc_init(soc_sensor.ts_c); + iio_write_channel_raw(soc_sensor.temp_chan, soc_sensor.ts_c); return 0; } else return -1; @@ -113,17 +114,19 @@ EXPORT_SYMBOL(thermal_firmware_init); int get_cpu_temp(void) { - int ret = TEMP_NOT_TRIMMED, tempa; + int ret; + int tempa; + int tval = TEMP_NOT_TRIMMED; if (soc_sensor.chip_trimmed) { - ret = get_adc_sample(0, TEMP_ADC_CHANNEL); + ret = iio_read_channel_processed(soc_sensor.temp_chan, &tval); if (ret >= 0) { - tempa = (10 * (ret - soc_sensor.fix_value)) / 32 + 27; - ret = tempa; + tempa = (10 * (tval - soc_sensor.fix_value)) / 32 + 27; + tval = tempa; } else - ret = TEMP_ADC_ERROR; + tval = TEMP_ADC_ERROR; } - return ret; + return tval; } EXPORT_SYMBOL(get_cpu_temp); @@ -357,6 +360,10 @@ static int aml_thermal_probe(struct platform_device *pdev) return -EPROBE_DEFER; } + soc_sensor.temp_chan = devm_iio_channel_get(&pdev->dev, "TEMP_CHAN"); + if (IS_ERR(soc_sensor.temp_chan)) + return PTR_ERR(soc_sensor.temp_chan); + if (thermal_firmware_init() < 0) { dev_err(&pdev->dev, "chip is not trimmed, disable thermal\n"); return -EINVAL; diff --git a/include/dt-bindings/iio/adc/amlogic-saradc.h b/include/dt-bindings/iio/adc/amlogic-saradc.h new file mode 100644 index 0000000..7611426 --- /dev/null +++ b/include/dt-bindings/iio/adc/amlogic-saradc.h @@ -0,0 +1,19 @@ +/* + * This header provides constants for configuring the AMLOGIC SAR ADC + */ + +#ifndef _DT_BINDINGS_IIO_ADC_AMLOGIC_H +#define _DT_BINDINGS_IIO_ADC_AMLOGIC_H + +#define SARADC_CH0 0 +#define SARADC_CH1 1 +#define SARADC_CH2 2 +#define SARADC_CH3 3 +#define SARADC_CH4 4 +#define SARADC_CH5 5 +#define SARADC_CH6 6 +#define SARADC_CH7 7 + +#define SARADC_CH_NUM 8 + +#endif diff --git a/include/linux/amlogic/saradc.h b/include/linux/amlogic/saradc.h deleted file mode 100644 index a294c8a..0000000 --- a/include/linux/amlogic/saradc.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * include/linux/amlogic/saradc.h - * - * Copyright (C) 2017 Amlogic, Inc. All rights reserved. - * - * 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; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - */ - -#ifndef __AML_SARADC_H__ -#define __AML_SARADC_H__ - -#include - -#define SARADC_DEV_NUM 1 - -enum { - CHAN_0 = 0, - CHAN_1, - CHAN_2, - CHAN_3, - CHAN_4, - CHAN_5, - CHAN_6, - CHAN_7, - SARADC_CHAN_NUM, -}; - -extern int get_adc_sample(int dev_id, int ch); -extern int get_adc_sample_12bit(int dev_id, int ch); - -#ifdef CONFIG_AMLOGIC_M8B_TEMP_SENSOR -extern void temp_sensor_adc_init(int triming); -#endif - -#define bits_desc(reg_offset, bits_offset, bits_len) \ - (((bits_len)<<24)|((bits_offset)<<16)|(reg_offset)) -#define of_mem_offset(bd) ((bd)&0xffff) -#define of_bits_offset(bd) (((bd)>>16)&0xff) -#define of_bits_len(bd) (((bd)>>24)&0xff) - -extern void setb(void __iomem *mem_base, unsigned int bits_desc, - unsigned int bits_val); -extern unsigned int getb(void __iomem *mem_base, unsigned int bits_desc); - -#endif -- 2.7.4