13adbf342SMartin Blumenstingl /* 23adbf342SMartin Blumenstingl * Amlogic Meson Successive Approximation Register (SAR) A/D Converter 33adbf342SMartin Blumenstingl * 43adbf342SMartin Blumenstingl * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com> 53adbf342SMartin Blumenstingl * 63adbf342SMartin Blumenstingl * This program is free software; you can redistribute it and/or modify 73adbf342SMartin Blumenstingl * it under the terms of the GNU General Public License version 2 as 83adbf342SMartin Blumenstingl * published by the Free Software Foundation. 93adbf342SMartin Blumenstingl * 103adbf342SMartin Blumenstingl * You should have received a copy of the GNU General Public License 113adbf342SMartin Blumenstingl * along with this program. If not, see <http://www.gnu.org/licenses/>. 123adbf342SMartin Blumenstingl */ 133adbf342SMartin Blumenstingl 143adbf342SMartin Blumenstingl #include <linux/bitfield.h> 153adbf342SMartin Blumenstingl #include <linux/clk.h> 163adbf342SMartin Blumenstingl #include <linux/clk-provider.h> 173adbf342SMartin Blumenstingl #include <linux/delay.h> 183adbf342SMartin Blumenstingl #include <linux/io.h> 193adbf342SMartin Blumenstingl #include <linux/iio/iio.h> 203adbf342SMartin Blumenstingl #include <linux/module.h> 213af10913SHeiner Kallweit #include <linux/interrupt.h> 223adbf342SMartin Blumenstingl #include <linux/of.h> 233af10913SHeiner Kallweit #include <linux/of_irq.h> 243adbf342SMartin Blumenstingl #include <linux/of_device.h> 253adbf342SMartin Blumenstingl #include <linux/platform_device.h> 263adbf342SMartin Blumenstingl #include <linux/regmap.h> 273adbf342SMartin Blumenstingl #include <linux/regulator/consumer.h> 283adbf342SMartin Blumenstingl 293adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0 0x00 303adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_PANEL_DETECT BIT(31) 313adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_BUSY_MASK GENMASK(30, 28) 323adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_DELTA_BUSY BIT(30) 333adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_AVG_BUSY BIT(29) 343adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_SAMPLE_BUSY BIT(28) 353adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_FIFO_FULL BIT(27) 363adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_FIFO_EMPTY BIT(26) 373adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_FIFO_COUNT_MASK GENMASK(25, 21) 383adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_ADC_BIAS_CTRL_MASK GENMASK(20, 19) 393adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_CURR_CHAN_ID_MASK GENMASK(18, 16) 403adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL BIT(15) 413adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_SAMPLING_STOP BIT(14) 423adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_CHAN_DELTA_EN_MASK GENMASK(13, 12) 433adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_DETECT_IRQ_POL BIT(10) 443adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_DETECT_IRQ_EN BIT(9) 453adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK GENMASK(8, 4) 463adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_FIFO_IRQ_EN BIT(3) 473adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_SAMPLING_START BIT(2) 483adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_CONTINUOUS_EN BIT(1) 493adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE BIT(0) 503adbf342SMartin Blumenstingl 513adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_LIST 0x04 523adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK GENMASK(26, 24) 533adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(_chan) \ 543adbf342SMartin Blumenstingl (GENMASK(2, 0) << ((_chan) * 3)) 553adbf342SMartin Blumenstingl 563adbf342SMartin Blumenstingl #define MESON_SAR_ADC_AVG_CNTL 0x08 573adbf342SMartin Blumenstingl #define MESON_SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(_chan) \ 583adbf342SMartin Blumenstingl (16 + ((_chan) * 2)) 593adbf342SMartin Blumenstingl #define MESON_SAR_ADC_AVG_CNTL_AVG_MODE_MASK(_chan) \ 603adbf342SMartin Blumenstingl (GENMASK(17, 16) << ((_chan) * 2)) 613adbf342SMartin Blumenstingl #define MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(_chan) \ 623adbf342SMartin Blumenstingl (0 + ((_chan) * 2)) 633adbf342SMartin Blumenstingl #define MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(_chan) \ 643adbf342SMartin Blumenstingl (GENMASK(1, 0) << ((_chan) * 2)) 653adbf342SMartin Blumenstingl 663adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG3 0x0c 673adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY BIT(31) 683adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG3_CLK_EN BIT(30) 693adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG3_BL30_INITIALIZED BIT(28) 703adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG3_CTRL_CONT_RING_COUNTER_EN BIT(27) 713adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE BIT(26) 723adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK GENMASK(25, 23) 733adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG3_DETECT_EN BIT(22) 743adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG3_ADC_EN BIT(21) 753adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG3_PANEL_DETECT_COUNT_MASK GENMASK(20, 18) 763adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG3_PANEL_DETECT_FILTER_TB_MASK GENMASK(17, 16) 773adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_SHIFT 10 783adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH 5 793adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG3_BLOCK_DLY_SEL_MASK GENMASK(9, 8) 803adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG3_BLOCK_DLY_MASK GENMASK(7, 0) 813adbf342SMartin Blumenstingl 823adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELAY 0x10 833adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK GENMASK(25, 24) 843adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELAY_BL30_BUSY BIT(15) 853adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELAY_KERNEL_BUSY BIT(14) 863adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK GENMASK(23, 16) 873adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK GENMASK(9, 8) 883adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK GENMASK(7, 0) 893adbf342SMartin Blumenstingl 903adbf342SMartin Blumenstingl #define MESON_SAR_ADC_LAST_RD 0x14 913adbf342SMartin Blumenstingl #define MESON_SAR_ADC_LAST_RD_LAST_CHANNEL1_MASK GENMASK(23, 16) 923adbf342SMartin Blumenstingl #define MESON_SAR_ADC_LAST_RD_LAST_CHANNEL0_MASK GENMASK(9, 0) 933adbf342SMartin Blumenstingl 943adbf342SMartin Blumenstingl #define MESON_SAR_ADC_FIFO_RD 0x18 953adbf342SMartin Blumenstingl #define MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK GENMASK(14, 12) 963adbf342SMartin Blumenstingl #define MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK GENMASK(11, 0) 973adbf342SMartin Blumenstingl 983adbf342SMartin Blumenstingl #define MESON_SAR_ADC_AUX_SW 0x1c 99ab569a4cSMartin Blumenstingl #define MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_SHIFT(_chan) \ 100ab569a4cSMartin Blumenstingl (8 + (((_chan) - 2) * 3)) 1013adbf342SMartin Blumenstingl #define MESON_SAR_ADC_AUX_SW_VREF_P_MUX BIT(6) 1023adbf342SMartin Blumenstingl #define MESON_SAR_ADC_AUX_SW_VREF_N_MUX BIT(5) 1033adbf342SMartin Blumenstingl #define MESON_SAR_ADC_AUX_SW_MODE_SEL BIT(4) 1043adbf342SMartin Blumenstingl #define MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW BIT(3) 1053adbf342SMartin Blumenstingl #define MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW BIT(2) 1063adbf342SMartin Blumenstingl #define MESON_SAR_ADC_AUX_SW_YM_DRIVE_SW BIT(1) 1073adbf342SMartin Blumenstingl #define MESON_SAR_ADC_AUX_SW_XM_DRIVE_SW BIT(0) 1083adbf342SMartin Blumenstingl 1093adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW 0x20 1103adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK GENMASK(25, 23) 1113adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_VREF_P_MUX BIT(22) 1123adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_VREF_N_MUX BIT(21) 1133adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_MODE_SEL BIT(20) 1143adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_YP_DRIVE_SW BIT(19) 1153adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_XP_DRIVE_SW BIT(18) 1163adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_YM_DRIVE_SW BIT(17) 1173adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN1_XM_DRIVE_SW BIT(16) 1183adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK GENMASK(9, 7) 1193adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_VREF_P_MUX BIT(6) 1203adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_VREF_N_MUX BIT(5) 1213adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_MODE_SEL BIT(4) 1223adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_YP_DRIVE_SW BIT(3) 1233adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_XP_DRIVE_SW BIT(2) 1243adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_YM_DRIVE_SW BIT(1) 1253adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN_10_SW_CHAN0_XM_DRIVE_SW BIT(0) 1263adbf342SMartin Blumenstingl 1273adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW 0x24 1283adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_SW_EN BIT(26) 1293adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK GENMASK(25, 23) 1303adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_VREF_P_MUX BIT(22) 1313adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_VREF_N_MUX BIT(21) 1323adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MODE_SEL BIT(20) 1333adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_YP_DRIVE_SW BIT(19) 1343adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_XP_DRIVE_SW BIT(18) 1353adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_YM_DRIVE_SW BIT(17) 1363adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_XM_DRIVE_SW BIT(16) 1373adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK GENMASK(9, 7) 1383adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_VREF_P_MUX BIT(6) 1393adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_VREF_N_MUX BIT(5) 1403adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MODE_SEL BIT(4) 1413adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_YP_DRIVE_SW BIT(3) 1423adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_XP_DRIVE_SW BIT(2) 1433adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_YM_DRIVE_SW BIT(1) 1443adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_XM_DRIVE_SW BIT(0) 1453adbf342SMartin Blumenstingl 1463adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELTA_10 0x28 1473adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELTA_10_TEMP_SEL BIT(27) 1483adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELTA_10_TS_REVE1 BIT(26) 1493adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELTA_10_CHAN1_DELTA_VALUE_MASK GENMASK(25, 16) 1503adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELTA_10_TS_REVE0 BIT(15) 1513adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELTA_10_TS_C_SHIFT 11 1523adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELTA_10_TS_C_MASK GENMASK(14, 11) 1533adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELTA_10_TS_VBG_EN BIT(10) 1543adbf342SMartin Blumenstingl #define MESON_SAR_ADC_DELTA_10_CHAN0_DELTA_VALUE_MASK GENMASK(9, 0) 1553adbf342SMartin Blumenstingl 1563adbf342SMartin Blumenstingl /* 1573adbf342SMartin Blumenstingl * NOTE: registers from here are undocumented (the vendor Linux kernel driver 1583adbf342SMartin Blumenstingl * and u-boot source served as reference). These only seem to be relevant on 1593adbf342SMartin Blumenstingl * GXBB and newer. 1603adbf342SMartin Blumenstingl */ 1613adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG11 0x2c 1623adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG11_BANDGAP_EN BIT(13) 1633adbf342SMartin Blumenstingl 1643adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG13 0x34 1653adbf342SMartin Blumenstingl #define MESON_SAR_ADC_REG13_12BIT_CALIBRATION_MASK GENMASK(13, 8) 1663adbf342SMartin Blumenstingl 1673adbf342SMartin Blumenstingl #define MESON_SAR_ADC_MAX_FIFO_SIZE 32 1683af10913SHeiner Kallweit #define MESON_SAR_ADC_TIMEOUT 100 /* ms */ 16948ba7c3cSHeiner Kallweit /* for use with IIO_VAL_INT_PLUS_MICRO */ 17048ba7c3cSHeiner Kallweit #define MILLION 1000000 1713adbf342SMartin Blumenstingl 1723adbf342SMartin Blumenstingl #define MESON_SAR_ADC_CHAN(_chan) { \ 1733adbf342SMartin Blumenstingl .type = IIO_VOLTAGE, \ 1743adbf342SMartin Blumenstingl .indexed = 1, \ 1753adbf342SMartin Blumenstingl .channel = _chan, \ 1763adbf342SMartin Blumenstingl .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \ 1773adbf342SMartin Blumenstingl BIT(IIO_CHAN_INFO_AVERAGE_RAW), \ 17848ba7c3cSHeiner Kallweit .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \ 17948ba7c3cSHeiner Kallweit BIT(IIO_CHAN_INFO_CALIBBIAS) | \ 18048ba7c3cSHeiner Kallweit BIT(IIO_CHAN_INFO_CALIBSCALE), \ 1813adbf342SMartin Blumenstingl .datasheet_name = "SAR_ADC_CH"#_chan, \ 1823adbf342SMartin Blumenstingl } 1833adbf342SMartin Blumenstingl 1843adbf342SMartin Blumenstingl /* 1853adbf342SMartin Blumenstingl * TODO: the hardware supports IIO_TEMP for channel 6 as well which is 1863adbf342SMartin Blumenstingl * currently not supported by this driver. 1873adbf342SMartin Blumenstingl */ 1883adbf342SMartin Blumenstingl static const struct iio_chan_spec meson_sar_adc_iio_channels[] = { 1893adbf342SMartin Blumenstingl MESON_SAR_ADC_CHAN(0), 1903adbf342SMartin Blumenstingl MESON_SAR_ADC_CHAN(1), 1913adbf342SMartin Blumenstingl MESON_SAR_ADC_CHAN(2), 1923adbf342SMartin Blumenstingl MESON_SAR_ADC_CHAN(3), 1933adbf342SMartin Blumenstingl MESON_SAR_ADC_CHAN(4), 1943adbf342SMartin Blumenstingl MESON_SAR_ADC_CHAN(5), 1953adbf342SMartin Blumenstingl MESON_SAR_ADC_CHAN(6), 1963adbf342SMartin Blumenstingl MESON_SAR_ADC_CHAN(7), 1973adbf342SMartin Blumenstingl IIO_CHAN_SOFT_TIMESTAMP(8), 1983adbf342SMartin Blumenstingl }; 1993adbf342SMartin Blumenstingl 2003adbf342SMartin Blumenstingl enum meson_sar_adc_avg_mode { 2013adbf342SMartin Blumenstingl NO_AVERAGING = 0x0, 2023adbf342SMartin Blumenstingl MEAN_AVERAGING = 0x1, 2033adbf342SMartin Blumenstingl MEDIAN_AVERAGING = 0x2, 2043adbf342SMartin Blumenstingl }; 2053adbf342SMartin Blumenstingl 2063adbf342SMartin Blumenstingl enum meson_sar_adc_num_samples { 2073adbf342SMartin Blumenstingl ONE_SAMPLE = 0x0, 2083adbf342SMartin Blumenstingl TWO_SAMPLES = 0x1, 2093adbf342SMartin Blumenstingl FOUR_SAMPLES = 0x2, 2103adbf342SMartin Blumenstingl EIGHT_SAMPLES = 0x3, 2113adbf342SMartin Blumenstingl }; 2123adbf342SMartin Blumenstingl 2133adbf342SMartin Blumenstingl enum meson_sar_adc_chan7_mux_sel { 2143adbf342SMartin Blumenstingl CHAN7_MUX_VSS = 0x0, 2153adbf342SMartin Blumenstingl CHAN7_MUX_VDD_DIV4 = 0x1, 2163adbf342SMartin Blumenstingl CHAN7_MUX_VDD_DIV2 = 0x2, 2173adbf342SMartin Blumenstingl CHAN7_MUX_VDD_MUL3_DIV4 = 0x3, 2183adbf342SMartin Blumenstingl CHAN7_MUX_VDD = 0x4, 2193adbf342SMartin Blumenstingl CHAN7_MUX_CH7_INPUT = 0x7, 2203adbf342SMartin Blumenstingl }; 2213adbf342SMartin Blumenstingl 222053ffe3cSYixun Lan struct meson_sar_adc_param { 2236c76ed31SMartin Blumenstingl bool has_bl30_integration; 224fda29dbaSMartin Blumenstingl unsigned long clock_rate; 225d85eed9fSMartin Blumenstingl u32 bandgap_reg; 2263adbf342SMartin Blumenstingl unsigned int resolution; 22796748823SMartin Blumenstingl const struct regmap_config *regmap_config; 2283adbf342SMartin Blumenstingl }; 2293adbf342SMartin Blumenstingl 230053ffe3cSYixun Lan struct meson_sar_adc_data { 231053ffe3cSYixun Lan const struct meson_sar_adc_param *param; 232053ffe3cSYixun Lan const char *name; 233053ffe3cSYixun Lan }; 234053ffe3cSYixun Lan 2353adbf342SMartin Blumenstingl struct meson_sar_adc_priv { 2363adbf342SMartin Blumenstingl struct regmap *regmap; 2373adbf342SMartin Blumenstingl struct regulator *vref; 2383adbf342SMartin Blumenstingl const struct meson_sar_adc_data *data; 2393adbf342SMartin Blumenstingl struct clk *clkin; 2403adbf342SMartin Blumenstingl struct clk *core_clk; 2413adbf342SMartin Blumenstingl struct clk *adc_sel_clk; 2423adbf342SMartin Blumenstingl struct clk *adc_clk; 2433adbf342SMartin Blumenstingl struct clk_gate clk_gate; 2443adbf342SMartin Blumenstingl struct clk *adc_div_clk; 2453adbf342SMartin Blumenstingl struct clk_divider clk_div; 2463af10913SHeiner Kallweit struct completion done; 24748ba7c3cSHeiner Kallweit int calibbias; 24848ba7c3cSHeiner Kallweit int calibscale; 2493adbf342SMartin Blumenstingl }; 2503adbf342SMartin Blumenstingl 25196748823SMartin Blumenstingl static const struct regmap_config meson_sar_adc_regmap_config_gxbb = { 2523adbf342SMartin Blumenstingl .reg_bits = 8, 2533adbf342SMartin Blumenstingl .val_bits = 32, 2543adbf342SMartin Blumenstingl .reg_stride = 4, 2553adbf342SMartin Blumenstingl .max_register = MESON_SAR_ADC_REG13, 2563adbf342SMartin Blumenstingl }; 2573adbf342SMartin Blumenstingl 25896748823SMartin Blumenstingl static const struct regmap_config meson_sar_adc_regmap_config_meson8 = { 25996748823SMartin Blumenstingl .reg_bits = 8, 26096748823SMartin Blumenstingl .val_bits = 32, 26196748823SMartin Blumenstingl .reg_stride = 4, 26296748823SMartin Blumenstingl .max_register = MESON_SAR_ADC_DELTA_10, 26396748823SMartin Blumenstingl }; 26496748823SMartin Blumenstingl 2653adbf342SMartin Blumenstingl static unsigned int meson_sar_adc_get_fifo_count(struct iio_dev *indio_dev) 2663adbf342SMartin Blumenstingl { 2673adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 2683adbf342SMartin Blumenstingl u32 regval; 2693adbf342SMartin Blumenstingl 2703adbf342SMartin Blumenstingl regmap_read(priv->regmap, MESON_SAR_ADC_REG0, ®val); 2713adbf342SMartin Blumenstingl 2723adbf342SMartin Blumenstingl return FIELD_GET(MESON_SAR_ADC_REG0_FIFO_COUNT_MASK, regval); 2733adbf342SMartin Blumenstingl } 2743adbf342SMartin Blumenstingl 27548ba7c3cSHeiner Kallweit static int meson_sar_adc_calib_val(struct iio_dev *indio_dev, int val) 27648ba7c3cSHeiner Kallweit { 27748ba7c3cSHeiner Kallweit struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 27848ba7c3cSHeiner Kallweit int tmp; 27948ba7c3cSHeiner Kallweit 28048ba7c3cSHeiner Kallweit /* use val_calib = scale * val_raw + offset calibration function */ 28148ba7c3cSHeiner Kallweit tmp = div_s64((s64)val * priv->calibscale, MILLION) + priv->calibbias; 28248ba7c3cSHeiner Kallweit 283053ffe3cSYixun Lan return clamp(tmp, 0, (1 << priv->data->param->resolution) - 1); 28448ba7c3cSHeiner Kallweit } 28548ba7c3cSHeiner Kallweit 2863adbf342SMartin Blumenstingl static int meson_sar_adc_wait_busy_clear(struct iio_dev *indio_dev) 2873adbf342SMartin Blumenstingl { 2883adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 2893adbf342SMartin Blumenstingl int regval, timeout = 10000; 2903adbf342SMartin Blumenstingl 2913adbf342SMartin Blumenstingl /* 2923adbf342SMartin Blumenstingl * NOTE: we need a small delay before reading the status, otherwise 2933adbf342SMartin Blumenstingl * the sample engine may not have started internally (which would 2943adbf342SMartin Blumenstingl * seem to us that sampling is already finished). 2953adbf342SMartin Blumenstingl */ 2963adbf342SMartin Blumenstingl do { 2973adbf342SMartin Blumenstingl udelay(1); 2983adbf342SMartin Blumenstingl regmap_read(priv->regmap, MESON_SAR_ADC_REG0, ®val); 2993adbf342SMartin Blumenstingl } while (FIELD_GET(MESON_SAR_ADC_REG0_BUSY_MASK, regval) && timeout--); 3003adbf342SMartin Blumenstingl 3013adbf342SMartin Blumenstingl if (timeout < 0) 3023adbf342SMartin Blumenstingl return -ETIMEDOUT; 3033adbf342SMartin Blumenstingl 3043adbf342SMartin Blumenstingl return 0; 3053adbf342SMartin Blumenstingl } 3063adbf342SMartin Blumenstingl 3073adbf342SMartin Blumenstingl static int meson_sar_adc_read_raw_sample(struct iio_dev *indio_dev, 3083adbf342SMartin Blumenstingl const struct iio_chan_spec *chan, 3093adbf342SMartin Blumenstingl int *val) 3103adbf342SMartin Blumenstingl { 3113adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 3126a882a2cSHeiner Kallweit int regval, fifo_chan, fifo_val, count; 3133adbf342SMartin Blumenstingl 3143af10913SHeiner Kallweit if(!wait_for_completion_timeout(&priv->done, 3153af10913SHeiner Kallweit msecs_to_jiffies(MESON_SAR_ADC_TIMEOUT))) 3163af10913SHeiner Kallweit return -ETIMEDOUT; 3173adbf342SMartin Blumenstingl 3186a882a2cSHeiner Kallweit count = meson_sar_adc_get_fifo_count(indio_dev); 3196a882a2cSHeiner Kallweit if (count != 1) { 3206a882a2cSHeiner Kallweit dev_err(&indio_dev->dev, 3216a882a2cSHeiner Kallweit "ADC FIFO has %d element(s) instead of one\n", count); 3226a882a2cSHeiner Kallweit return -EINVAL; 3233adbf342SMartin Blumenstingl } 3243adbf342SMartin Blumenstingl 3256a882a2cSHeiner Kallweit regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, ®val); 3266a882a2cSHeiner Kallweit fifo_chan = FIELD_GET(MESON_SAR_ADC_FIFO_RD_CHAN_ID_MASK, regval); 3276a882a2cSHeiner Kallweit if (fifo_chan != chan->channel) { 3286a882a2cSHeiner Kallweit dev_err(&indio_dev->dev, 3296a882a2cSHeiner Kallweit "ADC FIFO entry belongs to channel %d instead of %d\n", 3306a882a2cSHeiner Kallweit fifo_chan, chan->channel); 3316a882a2cSHeiner Kallweit return -EINVAL; 3326a882a2cSHeiner Kallweit } 3333adbf342SMartin Blumenstingl 3346a882a2cSHeiner Kallweit fifo_val = FIELD_GET(MESON_SAR_ADC_FIFO_RD_SAMPLE_VALUE_MASK, regval); 335053ffe3cSYixun Lan fifo_val &= GENMASK(priv->data->param->resolution - 1, 0); 33648ba7c3cSHeiner Kallweit *val = meson_sar_adc_calib_val(indio_dev, fifo_val); 3373adbf342SMartin Blumenstingl 3383adbf342SMartin Blumenstingl return 0; 3393adbf342SMartin Blumenstingl } 3403adbf342SMartin Blumenstingl 3413adbf342SMartin Blumenstingl static void meson_sar_adc_set_averaging(struct iio_dev *indio_dev, 3423adbf342SMartin Blumenstingl const struct iio_chan_spec *chan, 3433adbf342SMartin Blumenstingl enum meson_sar_adc_avg_mode mode, 3443adbf342SMartin Blumenstingl enum meson_sar_adc_num_samples samples) 3453adbf342SMartin Blumenstingl { 3463adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 3473adbf342SMartin Blumenstingl int val, channel = chan->channel; 3483adbf342SMartin Blumenstingl 3493adbf342SMartin Blumenstingl val = samples << MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_SHIFT(channel); 3503adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_AVG_CNTL, 3513adbf342SMartin Blumenstingl MESON_SAR_ADC_AVG_CNTL_NUM_SAMPLES_MASK(channel), 3523adbf342SMartin Blumenstingl val); 3533adbf342SMartin Blumenstingl 3543adbf342SMartin Blumenstingl val = mode << MESON_SAR_ADC_AVG_CNTL_AVG_MODE_SHIFT(channel); 3553adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_AVG_CNTL, 3563adbf342SMartin Blumenstingl MESON_SAR_ADC_AVG_CNTL_AVG_MODE_MASK(channel), val); 3573adbf342SMartin Blumenstingl } 3583adbf342SMartin Blumenstingl 3593adbf342SMartin Blumenstingl static void meson_sar_adc_enable_channel(struct iio_dev *indio_dev, 3603adbf342SMartin Blumenstingl const struct iio_chan_spec *chan) 3613adbf342SMartin Blumenstingl { 3623adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 3633adbf342SMartin Blumenstingl u32 regval; 3643adbf342SMartin Blumenstingl 3653adbf342SMartin Blumenstingl /* 3663adbf342SMartin Blumenstingl * the SAR ADC engine allows sampling multiple channels at the same 3673adbf342SMartin Blumenstingl * time. to keep it simple we're only working with one *internal* 3683adbf342SMartin Blumenstingl * channel, which starts counting at index 0 (which means: count = 1). 3693adbf342SMartin Blumenstingl */ 3703adbf342SMartin Blumenstingl regval = FIELD_PREP(MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, 0); 3713adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 3723adbf342SMartin Blumenstingl MESON_SAR_ADC_CHAN_LIST_MAX_INDEX_MASK, regval); 3733adbf342SMartin Blumenstingl 3743adbf342SMartin Blumenstingl /* map channel index 0 to the channel which we want to read */ 3753adbf342SMartin Blumenstingl regval = FIELD_PREP(MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(0), 3763adbf342SMartin Blumenstingl chan->channel); 3773adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 3783adbf342SMartin Blumenstingl MESON_SAR_ADC_CHAN_LIST_ENTRY_MASK(0), regval); 3793adbf342SMartin Blumenstingl 3803adbf342SMartin Blumenstingl regval = FIELD_PREP(MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK, 3813adbf342SMartin Blumenstingl chan->channel); 3823adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_DETECT_IDLE_SW, 3833adbf342SMartin Blumenstingl MESON_SAR_ADC_DETECT_IDLE_SW_DETECT_MUX_MASK, 3843adbf342SMartin Blumenstingl regval); 3853adbf342SMartin Blumenstingl 3863adbf342SMartin Blumenstingl regval = FIELD_PREP(MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK, 3873adbf342SMartin Blumenstingl chan->channel); 3883adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_DETECT_IDLE_SW, 3893adbf342SMartin Blumenstingl MESON_SAR_ADC_DETECT_IDLE_SW_IDLE_MUX_SEL_MASK, 3903adbf342SMartin Blumenstingl regval); 3913adbf342SMartin Blumenstingl 3923adbf342SMartin Blumenstingl if (chan->channel == 6) 3933adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELTA_10, 3943adbf342SMartin Blumenstingl MESON_SAR_ADC_DELTA_10_TEMP_SEL, 0); 3953adbf342SMartin Blumenstingl } 3963adbf342SMartin Blumenstingl 3973adbf342SMartin Blumenstingl static void meson_sar_adc_set_chan7_mux(struct iio_dev *indio_dev, 3983adbf342SMartin Blumenstingl enum meson_sar_adc_chan7_mux_sel sel) 3993adbf342SMartin Blumenstingl { 4003adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 4013adbf342SMartin Blumenstingl u32 regval; 4023adbf342SMartin Blumenstingl 4033adbf342SMartin Blumenstingl regval = FIELD_PREP(MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, sel); 4043adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, 4053adbf342SMartin Blumenstingl MESON_SAR_ADC_REG3_CTRL_CHAN7_MUX_SEL_MASK, regval); 4063adbf342SMartin Blumenstingl 4073adbf342SMartin Blumenstingl usleep_range(10, 20); 4083adbf342SMartin Blumenstingl } 4093adbf342SMartin Blumenstingl 4103adbf342SMartin Blumenstingl static void meson_sar_adc_start_sample_engine(struct iio_dev *indio_dev) 4113adbf342SMartin Blumenstingl { 4123adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 4133adbf342SMartin Blumenstingl 4143af10913SHeiner Kallweit reinit_completion(&priv->done); 4153af10913SHeiner Kallweit 4163af10913SHeiner Kallweit regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, 4173af10913SHeiner Kallweit MESON_SAR_ADC_REG0_FIFO_IRQ_EN, 4183af10913SHeiner Kallweit MESON_SAR_ADC_REG0_FIFO_IRQ_EN); 4193af10913SHeiner Kallweit 4203adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, 4213adbf342SMartin Blumenstingl MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 4223adbf342SMartin Blumenstingl MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE); 4233adbf342SMartin Blumenstingl 4243adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, 4253adbf342SMartin Blumenstingl MESON_SAR_ADC_REG0_SAMPLING_START, 4263adbf342SMartin Blumenstingl MESON_SAR_ADC_REG0_SAMPLING_START); 4273adbf342SMartin Blumenstingl } 4283adbf342SMartin Blumenstingl 4293adbf342SMartin Blumenstingl static void meson_sar_adc_stop_sample_engine(struct iio_dev *indio_dev) 4303adbf342SMartin Blumenstingl { 4313adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 4323adbf342SMartin Blumenstingl 4333adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, 4343af10913SHeiner Kallweit MESON_SAR_ADC_REG0_FIFO_IRQ_EN, 0); 4353af10913SHeiner Kallweit 4363af10913SHeiner Kallweit regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, 4373adbf342SMartin Blumenstingl MESON_SAR_ADC_REG0_SAMPLING_STOP, 4383adbf342SMartin Blumenstingl MESON_SAR_ADC_REG0_SAMPLING_STOP); 4393adbf342SMartin Blumenstingl 4403adbf342SMartin Blumenstingl /* wait until all modules are stopped */ 4413adbf342SMartin Blumenstingl meson_sar_adc_wait_busy_clear(indio_dev); 4423adbf342SMartin Blumenstingl 4433adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, 4443adbf342SMartin Blumenstingl MESON_SAR_ADC_REG0_SAMPLE_ENGINE_ENABLE, 0); 4453adbf342SMartin Blumenstingl } 4463adbf342SMartin Blumenstingl 4473adbf342SMartin Blumenstingl static int meson_sar_adc_lock(struct iio_dev *indio_dev) 4483adbf342SMartin Blumenstingl { 4493adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 4503adbf342SMartin Blumenstingl int val, timeout = 10000; 4513adbf342SMartin Blumenstingl 4523adbf342SMartin Blumenstingl mutex_lock(&indio_dev->mlock); 4533adbf342SMartin Blumenstingl 454053ffe3cSYixun Lan if (priv->data->param->has_bl30_integration) { 4553adbf342SMartin Blumenstingl /* prevent BL30 from using the SAR ADC while we are using it */ 4563adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, 4573adbf342SMartin Blumenstingl MESON_SAR_ADC_DELAY_KERNEL_BUSY, 4583adbf342SMartin Blumenstingl MESON_SAR_ADC_DELAY_KERNEL_BUSY); 4593adbf342SMartin Blumenstingl 4606c76ed31SMartin Blumenstingl /* 4616c76ed31SMartin Blumenstingl * wait until BL30 releases it's lock (so we can use the SAR 4626c76ed31SMartin Blumenstingl * ADC) 4636c76ed31SMartin Blumenstingl */ 4643adbf342SMartin Blumenstingl do { 4653adbf342SMartin Blumenstingl udelay(1); 4663adbf342SMartin Blumenstingl regmap_read(priv->regmap, MESON_SAR_ADC_DELAY, &val); 4673adbf342SMartin Blumenstingl } while (val & MESON_SAR_ADC_DELAY_BL30_BUSY && timeout--); 4683adbf342SMartin Blumenstingl 4693c3e4b3aSDan Carpenter if (timeout < 0) { 4703c3e4b3aSDan Carpenter mutex_unlock(&indio_dev->mlock); 4713adbf342SMartin Blumenstingl return -ETIMEDOUT; 4726c76ed31SMartin Blumenstingl } 4733c3e4b3aSDan Carpenter } 4743adbf342SMartin Blumenstingl 4753adbf342SMartin Blumenstingl return 0; 4763adbf342SMartin Blumenstingl } 4773adbf342SMartin Blumenstingl 4783adbf342SMartin Blumenstingl static void meson_sar_adc_unlock(struct iio_dev *indio_dev) 4793adbf342SMartin Blumenstingl { 4803adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 4813adbf342SMartin Blumenstingl 482053ffe3cSYixun Lan if (priv->data->param->has_bl30_integration) 4833adbf342SMartin Blumenstingl /* allow BL30 to use the SAR ADC again */ 4843adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, 4853adbf342SMartin Blumenstingl MESON_SAR_ADC_DELAY_KERNEL_BUSY, 0); 4863adbf342SMartin Blumenstingl 4873adbf342SMartin Blumenstingl mutex_unlock(&indio_dev->mlock); 4883adbf342SMartin Blumenstingl } 4893adbf342SMartin Blumenstingl 4903adbf342SMartin Blumenstingl static void meson_sar_adc_clear_fifo(struct iio_dev *indio_dev) 4913adbf342SMartin Blumenstingl { 4923adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 493103a07d4SMartin Blumenstingl unsigned int count, tmp; 4943adbf342SMartin Blumenstingl 4953adbf342SMartin Blumenstingl for (count = 0; count < MESON_SAR_ADC_MAX_FIFO_SIZE; count++) { 4963adbf342SMartin Blumenstingl if (!meson_sar_adc_get_fifo_count(indio_dev)) 4973adbf342SMartin Blumenstingl break; 4983adbf342SMartin Blumenstingl 499103a07d4SMartin Blumenstingl regmap_read(priv->regmap, MESON_SAR_ADC_FIFO_RD, &tmp); 5003adbf342SMartin Blumenstingl } 5013adbf342SMartin Blumenstingl } 5023adbf342SMartin Blumenstingl 5033adbf342SMartin Blumenstingl static int meson_sar_adc_get_sample(struct iio_dev *indio_dev, 5043adbf342SMartin Blumenstingl const struct iio_chan_spec *chan, 5053adbf342SMartin Blumenstingl enum meson_sar_adc_avg_mode avg_mode, 5063adbf342SMartin Blumenstingl enum meson_sar_adc_num_samples avg_samples, 5073adbf342SMartin Blumenstingl int *val) 5083adbf342SMartin Blumenstingl { 5093adbf342SMartin Blumenstingl int ret; 5103adbf342SMartin Blumenstingl 5113adbf342SMartin Blumenstingl ret = meson_sar_adc_lock(indio_dev); 5123adbf342SMartin Blumenstingl if (ret) 5133adbf342SMartin Blumenstingl return ret; 5143adbf342SMartin Blumenstingl 5153adbf342SMartin Blumenstingl /* clear the FIFO to make sure we're not reading old values */ 5163adbf342SMartin Blumenstingl meson_sar_adc_clear_fifo(indio_dev); 5173adbf342SMartin Blumenstingl 5183adbf342SMartin Blumenstingl meson_sar_adc_set_averaging(indio_dev, chan, avg_mode, avg_samples); 5193adbf342SMartin Blumenstingl 5203adbf342SMartin Blumenstingl meson_sar_adc_enable_channel(indio_dev, chan); 5213adbf342SMartin Blumenstingl 5223adbf342SMartin Blumenstingl meson_sar_adc_start_sample_engine(indio_dev); 5233adbf342SMartin Blumenstingl ret = meson_sar_adc_read_raw_sample(indio_dev, chan, val); 5243adbf342SMartin Blumenstingl meson_sar_adc_stop_sample_engine(indio_dev); 5253adbf342SMartin Blumenstingl 5263adbf342SMartin Blumenstingl meson_sar_adc_unlock(indio_dev); 5273adbf342SMartin Blumenstingl 5283adbf342SMartin Blumenstingl if (ret) { 5293adbf342SMartin Blumenstingl dev_warn(indio_dev->dev.parent, 5303adbf342SMartin Blumenstingl "failed to read sample for channel %d: %d\n", 5313adbf342SMartin Blumenstingl chan->channel, ret); 5323adbf342SMartin Blumenstingl return ret; 5333adbf342SMartin Blumenstingl } 5343adbf342SMartin Blumenstingl 5353adbf342SMartin Blumenstingl return IIO_VAL_INT; 5363adbf342SMartin Blumenstingl } 5373adbf342SMartin Blumenstingl 5383adbf342SMartin Blumenstingl static int meson_sar_adc_iio_info_read_raw(struct iio_dev *indio_dev, 5393adbf342SMartin Blumenstingl const struct iio_chan_spec *chan, 5403adbf342SMartin Blumenstingl int *val, int *val2, long mask) 5413adbf342SMartin Blumenstingl { 5423adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 5433adbf342SMartin Blumenstingl int ret; 5443adbf342SMartin Blumenstingl 5453adbf342SMartin Blumenstingl switch (mask) { 5463adbf342SMartin Blumenstingl case IIO_CHAN_INFO_RAW: 5473adbf342SMartin Blumenstingl return meson_sar_adc_get_sample(indio_dev, chan, NO_AVERAGING, 5483adbf342SMartin Blumenstingl ONE_SAMPLE, val); 5493adbf342SMartin Blumenstingl break; 5503adbf342SMartin Blumenstingl 5513adbf342SMartin Blumenstingl case IIO_CHAN_INFO_AVERAGE_RAW: 5523adbf342SMartin Blumenstingl return meson_sar_adc_get_sample(indio_dev, chan, 5533adbf342SMartin Blumenstingl MEAN_AVERAGING, EIGHT_SAMPLES, 5543adbf342SMartin Blumenstingl val); 5553adbf342SMartin Blumenstingl break; 5563adbf342SMartin Blumenstingl 5573adbf342SMartin Blumenstingl case IIO_CHAN_INFO_SCALE: 5583adbf342SMartin Blumenstingl ret = regulator_get_voltage(priv->vref); 5593adbf342SMartin Blumenstingl if (ret < 0) { 5603adbf342SMartin Blumenstingl dev_err(indio_dev->dev.parent, 5613adbf342SMartin Blumenstingl "failed to get vref voltage: %d\n", ret); 5623adbf342SMartin Blumenstingl return ret; 5633adbf342SMartin Blumenstingl } 5643adbf342SMartin Blumenstingl 5653adbf342SMartin Blumenstingl *val = ret / 1000; 566053ffe3cSYixun Lan *val2 = priv->data->param->resolution; 5673adbf342SMartin Blumenstingl return IIO_VAL_FRACTIONAL_LOG2; 5683adbf342SMartin Blumenstingl 56948ba7c3cSHeiner Kallweit case IIO_CHAN_INFO_CALIBBIAS: 57048ba7c3cSHeiner Kallweit *val = priv->calibbias; 57148ba7c3cSHeiner Kallweit return IIO_VAL_INT; 57248ba7c3cSHeiner Kallweit 57348ba7c3cSHeiner Kallweit case IIO_CHAN_INFO_CALIBSCALE: 57448ba7c3cSHeiner Kallweit *val = priv->calibscale / MILLION; 57548ba7c3cSHeiner Kallweit *val2 = priv->calibscale % MILLION; 57648ba7c3cSHeiner Kallweit return IIO_VAL_INT_PLUS_MICRO; 57748ba7c3cSHeiner Kallweit 5783adbf342SMartin Blumenstingl default: 5793adbf342SMartin Blumenstingl return -EINVAL; 5803adbf342SMartin Blumenstingl } 5813adbf342SMartin Blumenstingl } 5823adbf342SMartin Blumenstingl 5833adbf342SMartin Blumenstingl static int meson_sar_adc_clk_init(struct iio_dev *indio_dev, 5843adbf342SMartin Blumenstingl void __iomem *base) 5853adbf342SMartin Blumenstingl { 5863adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 5873adbf342SMartin Blumenstingl struct clk_init_data init; 5883adbf342SMartin Blumenstingl const char *clk_parents[1]; 5893adbf342SMartin Blumenstingl 5903921db46SRob Herring init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%pOF#adc_div", 5913921db46SRob Herring indio_dev->dev.of_node); 5923adbf342SMartin Blumenstingl init.flags = 0; 5933adbf342SMartin Blumenstingl init.ops = &clk_divider_ops; 5943adbf342SMartin Blumenstingl clk_parents[0] = __clk_get_name(priv->clkin); 5953adbf342SMartin Blumenstingl init.parent_names = clk_parents; 5963adbf342SMartin Blumenstingl init.num_parents = 1; 5973adbf342SMartin Blumenstingl 5983adbf342SMartin Blumenstingl priv->clk_div.reg = base + MESON_SAR_ADC_REG3; 5993adbf342SMartin Blumenstingl priv->clk_div.shift = MESON_SAR_ADC_REG3_ADC_CLK_DIV_SHIFT; 6003adbf342SMartin Blumenstingl priv->clk_div.width = MESON_SAR_ADC_REG3_ADC_CLK_DIV_WIDTH; 6013adbf342SMartin Blumenstingl priv->clk_div.hw.init = &init; 6023adbf342SMartin Blumenstingl priv->clk_div.flags = 0; 6033adbf342SMartin Blumenstingl 6043adbf342SMartin Blumenstingl priv->adc_div_clk = devm_clk_register(&indio_dev->dev, 6053adbf342SMartin Blumenstingl &priv->clk_div.hw); 6063adbf342SMartin Blumenstingl if (WARN_ON(IS_ERR(priv->adc_div_clk))) 6073adbf342SMartin Blumenstingl return PTR_ERR(priv->adc_div_clk); 6083adbf342SMartin Blumenstingl 6093921db46SRob Herring init.name = devm_kasprintf(&indio_dev->dev, GFP_KERNEL, "%pOF#adc_en", 6103921db46SRob Herring indio_dev->dev.of_node); 6113adbf342SMartin Blumenstingl init.flags = CLK_SET_RATE_PARENT; 6123adbf342SMartin Blumenstingl init.ops = &clk_gate_ops; 6133adbf342SMartin Blumenstingl clk_parents[0] = __clk_get_name(priv->adc_div_clk); 6143adbf342SMartin Blumenstingl init.parent_names = clk_parents; 6153adbf342SMartin Blumenstingl init.num_parents = 1; 6163adbf342SMartin Blumenstingl 6173adbf342SMartin Blumenstingl priv->clk_gate.reg = base + MESON_SAR_ADC_REG3; 6187a6b0420SMartin Blumenstingl priv->clk_gate.bit_idx = __ffs(MESON_SAR_ADC_REG3_CLK_EN); 6193adbf342SMartin Blumenstingl priv->clk_gate.hw.init = &init; 6203adbf342SMartin Blumenstingl 6213adbf342SMartin Blumenstingl priv->adc_clk = devm_clk_register(&indio_dev->dev, &priv->clk_gate.hw); 6223adbf342SMartin Blumenstingl if (WARN_ON(IS_ERR(priv->adc_clk))) 6233adbf342SMartin Blumenstingl return PTR_ERR(priv->adc_clk); 6243adbf342SMartin Blumenstingl 6253adbf342SMartin Blumenstingl return 0; 6263adbf342SMartin Blumenstingl } 6273adbf342SMartin Blumenstingl 6283adbf342SMartin Blumenstingl static int meson_sar_adc_init(struct iio_dev *indio_dev) 6293adbf342SMartin Blumenstingl { 6303adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 631ab569a4cSMartin Blumenstingl int regval, i, ret; 6323adbf342SMartin Blumenstingl 6333adbf342SMartin Blumenstingl /* 6343adbf342SMartin Blumenstingl * make sure we start at CH7 input since the other muxes are only used 6353adbf342SMartin Blumenstingl * for internal calibration. 6363adbf342SMartin Blumenstingl */ 6373adbf342SMartin Blumenstingl meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_CH7_INPUT); 6383adbf342SMartin Blumenstingl 639053ffe3cSYixun Lan if (priv->data->param->has_bl30_integration) { 6403adbf342SMartin Blumenstingl /* 6416c76ed31SMartin Blumenstingl * leave sampling delay and the input clocks as configured by 6426c76ed31SMartin Blumenstingl * BL30 to make sure BL30 gets the values it expects when 6436c76ed31SMartin Blumenstingl * reading the temperature sensor. 6443adbf342SMartin Blumenstingl */ 6453adbf342SMartin Blumenstingl regmap_read(priv->regmap, MESON_SAR_ADC_REG3, ®val); 6463adbf342SMartin Blumenstingl if (regval & MESON_SAR_ADC_REG3_BL30_INITIALIZED) 6473adbf342SMartin Blumenstingl return 0; 6486c76ed31SMartin Blumenstingl } 6493adbf342SMartin Blumenstingl 6503adbf342SMartin Blumenstingl meson_sar_adc_stop_sample_engine(indio_dev); 6513adbf342SMartin Blumenstingl 6523adbf342SMartin Blumenstingl /* update the channel 6 MUX to select the temperature sensor */ 6533adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, 6543adbf342SMartin Blumenstingl MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL, 6553adbf342SMartin Blumenstingl MESON_SAR_ADC_REG0_ADC_TEMP_SEN_SEL); 6563adbf342SMartin Blumenstingl 6573adbf342SMartin Blumenstingl /* disable all channels by default */ 6583adbf342SMartin Blumenstingl regmap_write(priv->regmap, MESON_SAR_ADC_CHAN_LIST, 0x0); 6593adbf342SMartin Blumenstingl 6603adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, 6613adbf342SMartin Blumenstingl MESON_SAR_ADC_REG3_CTRL_SAMPLING_CLOCK_PHASE, 0); 6623adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, 6633adbf342SMartin Blumenstingl MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY, 6643adbf342SMartin Blumenstingl MESON_SAR_ADC_REG3_CNTL_USE_SC_DLY); 6653adbf342SMartin Blumenstingl 6663adbf342SMartin Blumenstingl /* delay between two samples = (10+1) * 1uS */ 6673adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, 6683adbf342SMartin Blumenstingl MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, 6693adbf342SMartin Blumenstingl FIELD_PREP(MESON_SAR_ADC_DELAY_SAMPLE_DLY_CNT_MASK, 6703adbf342SMartin Blumenstingl 10)); 6713adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, 6723adbf342SMartin Blumenstingl MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK, 6733adbf342SMartin Blumenstingl FIELD_PREP(MESON_SAR_ADC_DELAY_SAMPLE_DLY_SEL_MASK, 6743adbf342SMartin Blumenstingl 0)); 6753adbf342SMartin Blumenstingl 6763adbf342SMartin Blumenstingl /* delay between two samples = (10+1) * 1uS */ 6773adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, 6783adbf342SMartin Blumenstingl MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, 6793adbf342SMartin Blumenstingl FIELD_PREP(MESON_SAR_ADC_DELAY_INPUT_DLY_CNT_MASK, 6803adbf342SMartin Blumenstingl 10)); 6813adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_DELAY, 6823adbf342SMartin Blumenstingl MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK, 6833adbf342SMartin Blumenstingl FIELD_PREP(MESON_SAR_ADC_DELAY_INPUT_DLY_SEL_MASK, 6843adbf342SMartin Blumenstingl 1)); 6853adbf342SMartin Blumenstingl 686ab569a4cSMartin Blumenstingl /* 687ab569a4cSMartin Blumenstingl * set up the input channel muxes in MESON_SAR_ADC_CHAN_10_SW 688ab569a4cSMartin Blumenstingl * (0 = SAR_ADC_CH0, 1 = SAR_ADC_CH1) 689ab569a4cSMartin Blumenstingl */ 690ab569a4cSMartin Blumenstingl regval = FIELD_PREP(MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK, 0); 691ab569a4cSMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, 692ab569a4cSMartin Blumenstingl MESON_SAR_ADC_CHAN_10_SW_CHAN0_MUX_SEL_MASK, 693ab569a4cSMartin Blumenstingl regval); 694ab569a4cSMartin Blumenstingl regval = FIELD_PREP(MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK, 1); 695ab569a4cSMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_CHAN_10_SW, 696ab569a4cSMartin Blumenstingl MESON_SAR_ADC_CHAN_10_SW_CHAN1_MUX_SEL_MASK, 697ab569a4cSMartin Blumenstingl regval); 698ab569a4cSMartin Blumenstingl 699ab569a4cSMartin Blumenstingl /* 700ab569a4cSMartin Blumenstingl * set up the input channel muxes in MESON_SAR_ADC_AUX_SW 701ab569a4cSMartin Blumenstingl * (2 = SAR_ADC_CH2, 3 = SAR_ADC_CH3, ...) and enable 702ab569a4cSMartin Blumenstingl * MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW and 703ab569a4cSMartin Blumenstingl * MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW like the vendor driver. 704ab569a4cSMartin Blumenstingl */ 705ab569a4cSMartin Blumenstingl regval = 0; 706ab569a4cSMartin Blumenstingl for (i = 2; i <= 7; i++) 707ab569a4cSMartin Blumenstingl regval |= i << MESON_SAR_ADC_AUX_SW_MUX_SEL_CHAN_SHIFT(i); 708ab569a4cSMartin Blumenstingl regval |= MESON_SAR_ADC_AUX_SW_YP_DRIVE_SW; 709ab569a4cSMartin Blumenstingl regval |= MESON_SAR_ADC_AUX_SW_XP_DRIVE_SW; 710ab569a4cSMartin Blumenstingl regmap_write(priv->regmap, MESON_SAR_ADC_AUX_SW, regval); 711ab569a4cSMartin Blumenstingl 7123adbf342SMartin Blumenstingl ret = clk_set_parent(priv->adc_sel_clk, priv->clkin); 7133adbf342SMartin Blumenstingl if (ret) { 7143adbf342SMartin Blumenstingl dev_err(indio_dev->dev.parent, 7153adbf342SMartin Blumenstingl "failed to set adc parent to clkin\n"); 7163adbf342SMartin Blumenstingl return ret; 7173adbf342SMartin Blumenstingl } 7183adbf342SMartin Blumenstingl 719053ffe3cSYixun Lan ret = clk_set_rate(priv->adc_clk, priv->data->param->clock_rate); 7203adbf342SMartin Blumenstingl if (ret) { 7213adbf342SMartin Blumenstingl dev_err(indio_dev->dev.parent, 7223adbf342SMartin Blumenstingl "failed to set adc clock rate\n"); 7233adbf342SMartin Blumenstingl return ret; 7243adbf342SMartin Blumenstingl } 7253adbf342SMartin Blumenstingl 7263adbf342SMartin Blumenstingl return 0; 7273adbf342SMartin Blumenstingl } 7283adbf342SMartin Blumenstingl 729d85eed9fSMartin Blumenstingl static void meson_sar_adc_set_bandgap(struct iio_dev *indio_dev, bool on_off) 730d85eed9fSMartin Blumenstingl { 731d85eed9fSMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 732053ffe3cSYixun Lan const struct meson_sar_adc_param *param = priv->data->param; 733d85eed9fSMartin Blumenstingl u32 enable_mask; 734d85eed9fSMartin Blumenstingl 735053ffe3cSYixun Lan if (param->bandgap_reg == MESON_SAR_ADC_REG11) 736d85eed9fSMartin Blumenstingl enable_mask = MESON_SAR_ADC_REG11_BANDGAP_EN; 737d85eed9fSMartin Blumenstingl else 738d85eed9fSMartin Blumenstingl enable_mask = MESON_SAR_ADC_DELTA_10_TS_VBG_EN; 739d85eed9fSMartin Blumenstingl 740053ffe3cSYixun Lan regmap_update_bits(priv->regmap, param->bandgap_reg, enable_mask, 741d85eed9fSMartin Blumenstingl on_off ? enable_mask : 0); 742d85eed9fSMartin Blumenstingl } 743d85eed9fSMartin Blumenstingl 7443adbf342SMartin Blumenstingl static int meson_sar_adc_hw_enable(struct iio_dev *indio_dev) 7453adbf342SMartin Blumenstingl { 7463adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 7473adbf342SMartin Blumenstingl int ret; 7483af10913SHeiner Kallweit u32 regval; 7493adbf342SMartin Blumenstingl 7503adbf342SMartin Blumenstingl ret = meson_sar_adc_lock(indio_dev); 7513adbf342SMartin Blumenstingl if (ret) 7523adbf342SMartin Blumenstingl goto err_lock; 7533adbf342SMartin Blumenstingl 7543adbf342SMartin Blumenstingl ret = regulator_enable(priv->vref); 7553adbf342SMartin Blumenstingl if (ret < 0) { 7563adbf342SMartin Blumenstingl dev_err(indio_dev->dev.parent, 7573adbf342SMartin Blumenstingl "failed to enable vref regulator\n"); 7583adbf342SMartin Blumenstingl goto err_vref; 7593adbf342SMartin Blumenstingl } 7603adbf342SMartin Blumenstingl 7613adbf342SMartin Blumenstingl ret = clk_prepare_enable(priv->core_clk); 7623adbf342SMartin Blumenstingl if (ret) { 7633adbf342SMartin Blumenstingl dev_err(indio_dev->dev.parent, "failed to enable core clk\n"); 7643adbf342SMartin Blumenstingl goto err_core_clk; 7653adbf342SMartin Blumenstingl } 7663adbf342SMartin Blumenstingl 7673af10913SHeiner Kallweit regval = FIELD_PREP(MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, 1); 7683af10913SHeiner Kallweit regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG0, 7693af10913SHeiner Kallweit MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, regval); 770d85eed9fSMartin Blumenstingl 771d85eed9fSMartin Blumenstingl meson_sar_adc_set_bandgap(indio_dev, true); 772d85eed9fSMartin Blumenstingl 7733adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, 7743adbf342SMartin Blumenstingl MESON_SAR_ADC_REG3_ADC_EN, 7753adbf342SMartin Blumenstingl MESON_SAR_ADC_REG3_ADC_EN); 7763adbf342SMartin Blumenstingl 7773adbf342SMartin Blumenstingl udelay(5); 7783adbf342SMartin Blumenstingl 7793adbf342SMartin Blumenstingl ret = clk_prepare_enable(priv->adc_clk); 7803adbf342SMartin Blumenstingl if (ret) { 7813adbf342SMartin Blumenstingl dev_err(indio_dev->dev.parent, "failed to enable adc clk\n"); 7823adbf342SMartin Blumenstingl goto err_adc_clk; 7833adbf342SMartin Blumenstingl } 7843adbf342SMartin Blumenstingl 7853adbf342SMartin Blumenstingl meson_sar_adc_unlock(indio_dev); 7863adbf342SMartin Blumenstingl 7873adbf342SMartin Blumenstingl return 0; 7883adbf342SMartin Blumenstingl 7893adbf342SMartin Blumenstingl err_adc_clk: 7903adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, 7913adbf342SMartin Blumenstingl MESON_SAR_ADC_REG3_ADC_EN, 0); 792d85eed9fSMartin Blumenstingl meson_sar_adc_set_bandgap(indio_dev, false); 7933adbf342SMartin Blumenstingl clk_disable_unprepare(priv->core_clk); 7943adbf342SMartin Blumenstingl err_core_clk: 7953adbf342SMartin Blumenstingl regulator_disable(priv->vref); 7963adbf342SMartin Blumenstingl err_vref: 7973adbf342SMartin Blumenstingl meson_sar_adc_unlock(indio_dev); 7983adbf342SMartin Blumenstingl err_lock: 7993adbf342SMartin Blumenstingl return ret; 8003adbf342SMartin Blumenstingl } 8013adbf342SMartin Blumenstingl 8023adbf342SMartin Blumenstingl static int meson_sar_adc_hw_disable(struct iio_dev *indio_dev) 8033adbf342SMartin Blumenstingl { 8043adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 8053adbf342SMartin Blumenstingl int ret; 8063adbf342SMartin Blumenstingl 8073adbf342SMartin Blumenstingl ret = meson_sar_adc_lock(indio_dev); 8083adbf342SMartin Blumenstingl if (ret) 8093adbf342SMartin Blumenstingl return ret; 8103adbf342SMartin Blumenstingl 8113adbf342SMartin Blumenstingl clk_disable_unprepare(priv->adc_clk); 8123adbf342SMartin Blumenstingl 8133adbf342SMartin Blumenstingl regmap_update_bits(priv->regmap, MESON_SAR_ADC_REG3, 8143adbf342SMartin Blumenstingl MESON_SAR_ADC_REG3_ADC_EN, 0); 815d85eed9fSMartin Blumenstingl 816d85eed9fSMartin Blumenstingl meson_sar_adc_set_bandgap(indio_dev, false); 8173adbf342SMartin Blumenstingl 8183adbf342SMartin Blumenstingl clk_disable_unprepare(priv->core_clk); 8193adbf342SMartin Blumenstingl 8203adbf342SMartin Blumenstingl regulator_disable(priv->vref); 8213adbf342SMartin Blumenstingl 8223adbf342SMartin Blumenstingl meson_sar_adc_unlock(indio_dev); 8233adbf342SMartin Blumenstingl 8243adbf342SMartin Blumenstingl return 0; 8253adbf342SMartin Blumenstingl } 8263adbf342SMartin Blumenstingl 8273af10913SHeiner Kallweit static irqreturn_t meson_sar_adc_irq(int irq, void *data) 8283af10913SHeiner Kallweit { 8293af10913SHeiner Kallweit struct iio_dev *indio_dev = data; 8303af10913SHeiner Kallweit struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 8313af10913SHeiner Kallweit unsigned int cnt, threshold; 8323af10913SHeiner Kallweit u32 regval; 8333af10913SHeiner Kallweit 8343af10913SHeiner Kallweit regmap_read(priv->regmap, MESON_SAR_ADC_REG0, ®val); 8353af10913SHeiner Kallweit cnt = FIELD_GET(MESON_SAR_ADC_REG0_FIFO_COUNT_MASK, regval); 8363af10913SHeiner Kallweit threshold = FIELD_GET(MESON_SAR_ADC_REG0_FIFO_CNT_IRQ_MASK, regval); 8373af10913SHeiner Kallweit 8383af10913SHeiner Kallweit if (cnt < threshold) 8393af10913SHeiner Kallweit return IRQ_NONE; 8403af10913SHeiner Kallweit 8413af10913SHeiner Kallweit complete(&priv->done); 8423af10913SHeiner Kallweit 8433af10913SHeiner Kallweit return IRQ_HANDLED; 8443af10913SHeiner Kallweit } 8453af10913SHeiner Kallweit 84648ba7c3cSHeiner Kallweit static int meson_sar_adc_calib(struct iio_dev *indio_dev) 84748ba7c3cSHeiner Kallweit { 84848ba7c3cSHeiner Kallweit struct meson_sar_adc_priv *priv = iio_priv(indio_dev); 84948ba7c3cSHeiner Kallweit int ret, nominal0, nominal1, value0, value1; 85048ba7c3cSHeiner Kallweit 85148ba7c3cSHeiner Kallweit /* use points 25% and 75% for calibration */ 852053ffe3cSYixun Lan nominal0 = (1 << priv->data->param->resolution) / 4; 853053ffe3cSYixun Lan nominal1 = (1 << priv->data->param->resolution) * 3 / 4; 85448ba7c3cSHeiner Kallweit 85548ba7c3cSHeiner Kallweit meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_VDD_DIV4); 85648ba7c3cSHeiner Kallweit usleep_range(10, 20); 85748ba7c3cSHeiner Kallweit ret = meson_sar_adc_get_sample(indio_dev, 85848ba7c3cSHeiner Kallweit &meson_sar_adc_iio_channels[7], 85948ba7c3cSHeiner Kallweit MEAN_AVERAGING, EIGHT_SAMPLES, &value0); 86048ba7c3cSHeiner Kallweit if (ret < 0) 86148ba7c3cSHeiner Kallweit goto out; 86248ba7c3cSHeiner Kallweit 86348ba7c3cSHeiner Kallweit meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_VDD_MUL3_DIV4); 86448ba7c3cSHeiner Kallweit usleep_range(10, 20); 86548ba7c3cSHeiner Kallweit ret = meson_sar_adc_get_sample(indio_dev, 86648ba7c3cSHeiner Kallweit &meson_sar_adc_iio_channels[7], 86748ba7c3cSHeiner Kallweit MEAN_AVERAGING, EIGHT_SAMPLES, &value1); 86848ba7c3cSHeiner Kallweit if (ret < 0) 86948ba7c3cSHeiner Kallweit goto out; 87048ba7c3cSHeiner Kallweit 87148ba7c3cSHeiner Kallweit if (value1 <= value0) { 87248ba7c3cSHeiner Kallweit ret = -EINVAL; 87348ba7c3cSHeiner Kallweit goto out; 87448ba7c3cSHeiner Kallweit } 87548ba7c3cSHeiner Kallweit 87648ba7c3cSHeiner Kallweit priv->calibscale = div_s64((nominal1 - nominal0) * (s64)MILLION, 87748ba7c3cSHeiner Kallweit value1 - value0); 87848ba7c3cSHeiner Kallweit priv->calibbias = nominal0 - div_s64((s64)value0 * priv->calibscale, 87948ba7c3cSHeiner Kallweit MILLION); 88048ba7c3cSHeiner Kallweit ret = 0; 88148ba7c3cSHeiner Kallweit out: 88248ba7c3cSHeiner Kallweit meson_sar_adc_set_chan7_mux(indio_dev, CHAN7_MUX_CH7_INPUT); 88348ba7c3cSHeiner Kallweit 88448ba7c3cSHeiner Kallweit return ret; 88548ba7c3cSHeiner Kallweit } 88648ba7c3cSHeiner Kallweit 8873adbf342SMartin Blumenstingl static const struct iio_info meson_sar_adc_iio_info = { 8883adbf342SMartin Blumenstingl .read_raw = meson_sar_adc_iio_info_read_raw, 8893adbf342SMartin Blumenstingl }; 8903adbf342SMartin Blumenstingl 891053ffe3cSYixun Lan static const struct meson_sar_adc_param meson_sar_adc_meson8_param = { 8926c76ed31SMartin Blumenstingl .has_bl30_integration = false, 893fda29dbaSMartin Blumenstingl .clock_rate = 1150000, 894d85eed9fSMartin Blumenstingl .bandgap_reg = MESON_SAR_ADC_DELTA_10, 89596748823SMartin Blumenstingl .regmap_config = &meson_sar_adc_regmap_config_meson8, 8966c76ed31SMartin Blumenstingl .resolution = 10, 897053ffe3cSYixun Lan }; 898053ffe3cSYixun Lan 899053ffe3cSYixun Lan static const struct meson_sar_adc_param meson_sar_adc_gxbb_param = { 900053ffe3cSYixun Lan .has_bl30_integration = true, 901053ffe3cSYixun Lan .clock_rate = 1200000, 902053ffe3cSYixun Lan .bandgap_reg = MESON_SAR_ADC_REG11, 903053ffe3cSYixun Lan .regmap_config = &meson_sar_adc_regmap_config_gxbb, 904053ffe3cSYixun Lan .resolution = 10, 905053ffe3cSYixun Lan }; 906053ffe3cSYixun Lan 907053ffe3cSYixun Lan static const struct meson_sar_adc_param meson_sar_adc_gxl_param = { 908053ffe3cSYixun Lan .has_bl30_integration = true, 909053ffe3cSYixun Lan .clock_rate = 1200000, 910053ffe3cSYixun Lan .bandgap_reg = MESON_SAR_ADC_REG11, 911053ffe3cSYixun Lan .regmap_config = &meson_sar_adc_regmap_config_gxbb, 912053ffe3cSYixun Lan .resolution = 12, 913053ffe3cSYixun Lan }; 914053ffe3cSYixun Lan 915053ffe3cSYixun Lan static const struct meson_sar_adc_data meson_sar_adc_meson8_data = { 916053ffe3cSYixun Lan .param = &meson_sar_adc_meson8_param, 9176c76ed31SMartin Blumenstingl .name = "meson-meson8-saradc", 9186c76ed31SMartin Blumenstingl }; 9196c76ed31SMartin Blumenstingl 9206c76ed31SMartin Blumenstingl static const struct meson_sar_adc_data meson_sar_adc_meson8b_data = { 921053ffe3cSYixun Lan .param = &meson_sar_adc_meson8_param, 9226c76ed31SMartin Blumenstingl .name = "meson-meson8b-saradc", 9236c76ed31SMartin Blumenstingl }; 9246c76ed31SMartin Blumenstingl 925ffc0d638SMartin Blumenstingl static const struct meson_sar_adc_data meson_sar_adc_meson8m2_data = { 926ffc0d638SMartin Blumenstingl .param = &meson_sar_adc_meson8_param, 927ffc0d638SMartin Blumenstingl .name = "meson-meson8m2-saradc", 928ffc0d638SMartin Blumenstingl }; 929ffc0d638SMartin Blumenstingl 930c1c2de37SMartin Blumenstingl static const struct meson_sar_adc_data meson_sar_adc_gxbb_data = { 931053ffe3cSYixun Lan .param = &meson_sar_adc_gxbb_param, 9323adbf342SMartin Blumenstingl .name = "meson-gxbb-saradc", 9333adbf342SMartin Blumenstingl }; 9343adbf342SMartin Blumenstingl 935c1c2de37SMartin Blumenstingl static const struct meson_sar_adc_data meson_sar_adc_gxl_data = { 936053ffe3cSYixun Lan .param = &meson_sar_adc_gxl_param, 9373adbf342SMartin Blumenstingl .name = "meson-gxl-saradc", 9383adbf342SMartin Blumenstingl }; 9393adbf342SMartin Blumenstingl 940c1c2de37SMartin Blumenstingl static const struct meson_sar_adc_data meson_sar_adc_gxm_data = { 941053ffe3cSYixun Lan .param = &meson_sar_adc_gxl_param, 9423adbf342SMartin Blumenstingl .name = "meson-gxm-saradc", 9433adbf342SMartin Blumenstingl }; 9443adbf342SMartin Blumenstingl 945ff632ddaSXingyu Chen static const struct meson_sar_adc_data meson_sar_adc_axg_data = { 946ff632ddaSXingyu Chen .param = &meson_sar_adc_gxl_param, 947ff632ddaSXingyu Chen .name = "meson-axg-saradc", 948ff632ddaSXingyu Chen }; 949ff632ddaSXingyu Chen 9503adbf342SMartin Blumenstingl static const struct of_device_id meson_sar_adc_of_match[] = { 9513adbf342SMartin Blumenstingl { 9526c76ed31SMartin Blumenstingl .compatible = "amlogic,meson8-saradc", 9536c76ed31SMartin Blumenstingl .data = &meson_sar_adc_meson8_data, 9546c76ed31SMartin Blumenstingl }, 9556c76ed31SMartin Blumenstingl { 9566c76ed31SMartin Blumenstingl .compatible = "amlogic,meson8b-saradc", 9576c76ed31SMartin Blumenstingl .data = &meson_sar_adc_meson8b_data, 9586c76ed31SMartin Blumenstingl }, 9596c76ed31SMartin Blumenstingl { 960ffc0d638SMartin Blumenstingl .compatible = "amlogic,meson8m2-saradc", 961ffc0d638SMartin Blumenstingl .data = &meson_sar_adc_meson8m2_data, 962ffc0d638SMartin Blumenstingl }, 963ffc0d638SMartin Blumenstingl { 9643adbf342SMartin Blumenstingl .compatible = "amlogic,meson-gxbb-saradc", 9653adbf342SMartin Blumenstingl .data = &meson_sar_adc_gxbb_data, 9663adbf342SMartin Blumenstingl }, { 9673adbf342SMartin Blumenstingl .compatible = "amlogic,meson-gxl-saradc", 9683adbf342SMartin Blumenstingl .data = &meson_sar_adc_gxl_data, 9693adbf342SMartin Blumenstingl }, { 9703adbf342SMartin Blumenstingl .compatible = "amlogic,meson-gxm-saradc", 9713adbf342SMartin Blumenstingl .data = &meson_sar_adc_gxm_data, 972ff632ddaSXingyu Chen }, { 973ff632ddaSXingyu Chen .compatible = "amlogic,meson-axg-saradc", 974ff632ddaSXingyu Chen .data = &meson_sar_adc_axg_data, 9753adbf342SMartin Blumenstingl }, 9763adbf342SMartin Blumenstingl {}, 9773adbf342SMartin Blumenstingl }; 9783adbf342SMartin Blumenstingl MODULE_DEVICE_TABLE(of, meson_sar_adc_of_match); 9793adbf342SMartin Blumenstingl 9803adbf342SMartin Blumenstingl static int meson_sar_adc_probe(struct platform_device *pdev) 9813adbf342SMartin Blumenstingl { 9823adbf342SMartin Blumenstingl struct meson_sar_adc_priv *priv; 9833adbf342SMartin Blumenstingl struct iio_dev *indio_dev; 9843adbf342SMartin Blumenstingl struct resource *res; 9853adbf342SMartin Blumenstingl void __iomem *base; 9863adbf342SMartin Blumenstingl const struct of_device_id *match; 9873af10913SHeiner Kallweit int irq, ret; 9883adbf342SMartin Blumenstingl 9893adbf342SMartin Blumenstingl indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); 9903adbf342SMartin Blumenstingl if (!indio_dev) { 9913adbf342SMartin Blumenstingl dev_err(&pdev->dev, "failed allocating iio device\n"); 9923adbf342SMartin Blumenstingl return -ENOMEM; 9933adbf342SMartin Blumenstingl } 9943adbf342SMartin Blumenstingl 9953adbf342SMartin Blumenstingl priv = iio_priv(indio_dev); 9963af10913SHeiner Kallweit init_completion(&priv->done); 9973adbf342SMartin Blumenstingl 9983adbf342SMartin Blumenstingl match = of_match_device(meson_sar_adc_of_match, &pdev->dev); 9992f9aeeedSGustavo A. R. Silva if (!match) { 10002f9aeeedSGustavo A. R. Silva dev_err(&pdev->dev, "failed to match device\n"); 10012f9aeeedSGustavo A. R. Silva return -ENODEV; 10022f9aeeedSGustavo A. R. Silva } 10032f9aeeedSGustavo A. R. Silva 10043adbf342SMartin Blumenstingl priv->data = match->data; 10053adbf342SMartin Blumenstingl 10063adbf342SMartin Blumenstingl indio_dev->name = priv->data->name; 10073adbf342SMartin Blumenstingl indio_dev->dev.parent = &pdev->dev; 10083adbf342SMartin Blumenstingl indio_dev->dev.of_node = pdev->dev.of_node; 10093adbf342SMartin Blumenstingl indio_dev->modes = INDIO_DIRECT_MODE; 10103adbf342SMartin Blumenstingl indio_dev->info = &meson_sar_adc_iio_info; 10113adbf342SMartin Blumenstingl 10123adbf342SMartin Blumenstingl indio_dev->channels = meson_sar_adc_iio_channels; 10133adbf342SMartin Blumenstingl indio_dev->num_channels = ARRAY_SIZE(meson_sar_adc_iio_channels); 10143adbf342SMartin Blumenstingl 10153adbf342SMartin Blumenstingl res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 10163adbf342SMartin Blumenstingl base = devm_ioremap_resource(&pdev->dev, res); 10173adbf342SMartin Blumenstingl if (IS_ERR(base)) 10183adbf342SMartin Blumenstingl return PTR_ERR(base); 10193adbf342SMartin Blumenstingl 10203af10913SHeiner Kallweit irq = irq_of_parse_and_map(pdev->dev.of_node, 0); 10213af10913SHeiner Kallweit if (!irq) 10223af10913SHeiner Kallweit return -EINVAL; 10233af10913SHeiner Kallweit 10243af10913SHeiner Kallweit ret = devm_request_irq(&pdev->dev, irq, meson_sar_adc_irq, IRQF_SHARED, 10253af10913SHeiner Kallweit dev_name(&pdev->dev), indio_dev); 10263af10913SHeiner Kallweit if (ret) 10273af10913SHeiner Kallweit return ret; 10283af10913SHeiner Kallweit 10293adbf342SMartin Blumenstingl priv->regmap = devm_regmap_init_mmio(&pdev->dev, base, 1030053ffe3cSYixun Lan priv->data->param->regmap_config); 10313adbf342SMartin Blumenstingl if (IS_ERR(priv->regmap)) 10323adbf342SMartin Blumenstingl return PTR_ERR(priv->regmap); 10333adbf342SMartin Blumenstingl 10343adbf342SMartin Blumenstingl priv->clkin = devm_clk_get(&pdev->dev, "clkin"); 10353adbf342SMartin Blumenstingl if (IS_ERR(priv->clkin)) { 10363adbf342SMartin Blumenstingl dev_err(&pdev->dev, "failed to get clkin\n"); 10373adbf342SMartin Blumenstingl return PTR_ERR(priv->clkin); 10383adbf342SMartin Blumenstingl } 10393adbf342SMartin Blumenstingl 10403adbf342SMartin Blumenstingl priv->core_clk = devm_clk_get(&pdev->dev, "core"); 10413adbf342SMartin Blumenstingl if (IS_ERR(priv->core_clk)) { 10423adbf342SMartin Blumenstingl dev_err(&pdev->dev, "failed to get core clk\n"); 10433adbf342SMartin Blumenstingl return PTR_ERR(priv->core_clk); 10443adbf342SMartin Blumenstingl } 10453adbf342SMartin Blumenstingl 10463adbf342SMartin Blumenstingl priv->adc_clk = devm_clk_get(&pdev->dev, "adc_clk"); 10473adbf342SMartin Blumenstingl if (IS_ERR(priv->adc_clk)) { 10483adbf342SMartin Blumenstingl if (PTR_ERR(priv->adc_clk) == -ENOENT) { 10493adbf342SMartin Blumenstingl priv->adc_clk = NULL; 10503adbf342SMartin Blumenstingl } else { 10513adbf342SMartin Blumenstingl dev_err(&pdev->dev, "failed to get adc clk\n"); 10523adbf342SMartin Blumenstingl return PTR_ERR(priv->adc_clk); 10533adbf342SMartin Blumenstingl } 10543adbf342SMartin Blumenstingl } 10553adbf342SMartin Blumenstingl 10563adbf342SMartin Blumenstingl priv->adc_sel_clk = devm_clk_get(&pdev->dev, "adc_sel"); 10573adbf342SMartin Blumenstingl if (IS_ERR(priv->adc_sel_clk)) { 10583adbf342SMartin Blumenstingl if (PTR_ERR(priv->adc_sel_clk) == -ENOENT) { 10593adbf342SMartin Blumenstingl priv->adc_sel_clk = NULL; 10603adbf342SMartin Blumenstingl } else { 10613adbf342SMartin Blumenstingl dev_err(&pdev->dev, "failed to get adc_sel clk\n"); 10623adbf342SMartin Blumenstingl return PTR_ERR(priv->adc_sel_clk); 10633adbf342SMartin Blumenstingl } 10643adbf342SMartin Blumenstingl } 10653adbf342SMartin Blumenstingl 10663adbf342SMartin Blumenstingl /* on pre-GXBB SoCs the SAR ADC itself provides the ADC clock: */ 10673adbf342SMartin Blumenstingl if (!priv->adc_clk) { 10683adbf342SMartin Blumenstingl ret = meson_sar_adc_clk_init(indio_dev, base); 10693adbf342SMartin Blumenstingl if (ret) 10703adbf342SMartin Blumenstingl return ret; 10713adbf342SMartin Blumenstingl } 10723adbf342SMartin Blumenstingl 10733adbf342SMartin Blumenstingl priv->vref = devm_regulator_get(&pdev->dev, "vref"); 10743adbf342SMartin Blumenstingl if (IS_ERR(priv->vref)) { 10753adbf342SMartin Blumenstingl dev_err(&pdev->dev, "failed to get vref regulator\n"); 10763adbf342SMartin Blumenstingl return PTR_ERR(priv->vref); 10773adbf342SMartin Blumenstingl } 10783adbf342SMartin Blumenstingl 107948ba7c3cSHeiner Kallweit priv->calibscale = MILLION; 108048ba7c3cSHeiner Kallweit 10813adbf342SMartin Blumenstingl ret = meson_sar_adc_init(indio_dev); 10823adbf342SMartin Blumenstingl if (ret) 10833adbf342SMartin Blumenstingl goto err; 10843adbf342SMartin Blumenstingl 10853adbf342SMartin Blumenstingl ret = meson_sar_adc_hw_enable(indio_dev); 10863adbf342SMartin Blumenstingl if (ret) 10873adbf342SMartin Blumenstingl goto err; 10883adbf342SMartin Blumenstingl 108948ba7c3cSHeiner Kallweit ret = meson_sar_adc_calib(indio_dev); 109048ba7c3cSHeiner Kallweit if (ret) 109148ba7c3cSHeiner Kallweit dev_warn(&pdev->dev, "calibration failed\n"); 109248ba7c3cSHeiner Kallweit 10933adbf342SMartin Blumenstingl platform_set_drvdata(pdev, indio_dev); 10943adbf342SMartin Blumenstingl 10953adbf342SMartin Blumenstingl ret = iio_device_register(indio_dev); 10963adbf342SMartin Blumenstingl if (ret) 10973adbf342SMartin Blumenstingl goto err_hw; 10983adbf342SMartin Blumenstingl 10993adbf342SMartin Blumenstingl return 0; 11003adbf342SMartin Blumenstingl 11013adbf342SMartin Blumenstingl err_hw: 11023adbf342SMartin Blumenstingl meson_sar_adc_hw_disable(indio_dev); 11033adbf342SMartin Blumenstingl err: 11043adbf342SMartin Blumenstingl return ret; 11053adbf342SMartin Blumenstingl } 11063adbf342SMartin Blumenstingl 11073adbf342SMartin Blumenstingl static int meson_sar_adc_remove(struct platform_device *pdev) 11083adbf342SMartin Blumenstingl { 11093adbf342SMartin Blumenstingl struct iio_dev *indio_dev = platform_get_drvdata(pdev); 11103adbf342SMartin Blumenstingl 11113adbf342SMartin Blumenstingl iio_device_unregister(indio_dev); 11123adbf342SMartin Blumenstingl 11133adbf342SMartin Blumenstingl return meson_sar_adc_hw_disable(indio_dev); 11143adbf342SMartin Blumenstingl } 11153adbf342SMartin Blumenstingl 11163adbf342SMartin Blumenstingl static int __maybe_unused meson_sar_adc_suspend(struct device *dev) 11173adbf342SMartin Blumenstingl { 11183adbf342SMartin Blumenstingl struct iio_dev *indio_dev = dev_get_drvdata(dev); 11193adbf342SMartin Blumenstingl 11203adbf342SMartin Blumenstingl return meson_sar_adc_hw_disable(indio_dev); 11213adbf342SMartin Blumenstingl } 11223adbf342SMartin Blumenstingl 11233adbf342SMartin Blumenstingl static int __maybe_unused meson_sar_adc_resume(struct device *dev) 11243adbf342SMartin Blumenstingl { 11253adbf342SMartin Blumenstingl struct iio_dev *indio_dev = dev_get_drvdata(dev); 11263adbf342SMartin Blumenstingl 11273adbf342SMartin Blumenstingl return meson_sar_adc_hw_enable(indio_dev); 11283adbf342SMartin Blumenstingl } 11293adbf342SMartin Blumenstingl 11303adbf342SMartin Blumenstingl static SIMPLE_DEV_PM_OPS(meson_sar_adc_pm_ops, 11313adbf342SMartin Blumenstingl meson_sar_adc_suspend, meson_sar_adc_resume); 11323adbf342SMartin Blumenstingl 11333adbf342SMartin Blumenstingl static struct platform_driver meson_sar_adc_driver = { 11343adbf342SMartin Blumenstingl .probe = meson_sar_adc_probe, 11353adbf342SMartin Blumenstingl .remove = meson_sar_adc_remove, 11363adbf342SMartin Blumenstingl .driver = { 11373adbf342SMartin Blumenstingl .name = "meson-saradc", 11383adbf342SMartin Blumenstingl .of_match_table = meson_sar_adc_of_match, 11393adbf342SMartin Blumenstingl .pm = &meson_sar_adc_pm_ops, 11403adbf342SMartin Blumenstingl }, 11413adbf342SMartin Blumenstingl }; 11423adbf342SMartin Blumenstingl 11433adbf342SMartin Blumenstingl module_platform_driver(meson_sar_adc_driver); 11443adbf342SMartin Blumenstingl 11453adbf342SMartin Blumenstingl MODULE_AUTHOR("Martin Blumenstingl <martin.blumenstingl@googlemail.com>"); 11463adbf342SMartin Blumenstingl MODULE_DESCRIPTION("Amlogic Meson SAR ADC driver"); 11473adbf342SMartin Blumenstingl MODULE_LICENSE("GPL v2"); 1148