xref: /netbsd-src/sys/arch/arm/rockchip/rk_tsadc.c (revision d914a3c1b942947a8b1fa87645678df29ac8e6ab)
1*d914a3c1Smrg /*	$NetBSD: rk_tsadc.c,v 1.16 2021/12/11 19:24:21 mrg Exp $	*/
239e6bc2cSmrg 
339e6bc2cSmrg /*
439e6bc2cSmrg  * Copyright (c) 2019 Matthew R. Green
539e6bc2cSmrg  * All rights reserved.
639e6bc2cSmrg  *
739e6bc2cSmrg  * Redistribution and use in source and binary forms, with or without
839e6bc2cSmrg  * modification, are permitted provided that the following conditions
939e6bc2cSmrg  * are met:
1039e6bc2cSmrg  * 1. Redistributions of source code must retain the above copyright
1139e6bc2cSmrg  *    notice, this list of conditions and the following disclaimer.
1239e6bc2cSmrg  * 2. Redistributions in binary form must reproduce the above copyright
1339e6bc2cSmrg  *    notice, this list of conditions and the following disclaimer in the
1439e6bc2cSmrg  *    documentation and/or other materials provided with the distribution.
1539e6bc2cSmrg  *
1639e6bc2cSmrg  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1739e6bc2cSmrg  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1839e6bc2cSmrg  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1939e6bc2cSmrg  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2039e6bc2cSmrg  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
2139e6bc2cSmrg  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2239e6bc2cSmrg  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
2339e6bc2cSmrg  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2439e6bc2cSmrg  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2539e6bc2cSmrg  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2639e6bc2cSmrg  * SUCH DAMAGE.
2739e6bc2cSmrg  */
2839e6bc2cSmrg 
2939e6bc2cSmrg #include <sys/cdefs.h>
3039e6bc2cSmrg 
31*d914a3c1Smrg __KERNEL_RCSID(0, "$NetBSD: rk_tsadc.c,v 1.16 2021/12/11 19:24:21 mrg Exp $");
3239e6bc2cSmrg 
3339e6bc2cSmrg /*
3439e6bc2cSmrg  * Driver for the TSADC temperature sensor monitor in RK3328 and RK3399.
3539e6bc2cSmrg  *
3639e6bc2cSmrg  * TODO:
3739e6bc2cSmrg  * - handle setting various temp values
3839e6bc2cSmrg  * - handle DT trips/temp value defaults
3939e6bc2cSmrg  * - interrupts aren't triggered (test by lowering warn/crit values), and
4039e6bc2cSmrg  *   once they work, make the interrupt do something
4139e6bc2cSmrg  */
4239e6bc2cSmrg 
4339e6bc2cSmrg #include <sys/param.h>
4439e6bc2cSmrg #include <sys/bus.h>
4539e6bc2cSmrg #include <sys/device.h>
4639e6bc2cSmrg #include <sys/intr.h>
4739e6bc2cSmrg #include <sys/systm.h>
4839e6bc2cSmrg #include <sys/time.h>
4939e6bc2cSmrg #include <sys/kmem.h>
5039e6bc2cSmrg 
5139e6bc2cSmrg #include <dev/fdt/fdtvar.h>
5239e6bc2cSmrg #include <dev/fdt/syscon.h>
5339e6bc2cSmrg 
5439e6bc2cSmrg #include <dev/sysmon/sysmonvar.h>
5539e6bc2cSmrg 
5639e6bc2cSmrg #ifdef RKTSADC_DEBUG
5739e6bc2cSmrg #define DPRINTF(fmt, ...) \
5839e6bc2cSmrg 	printf("%s:%d: " fmt "\n", __func__, __LINE__, ## __VA_ARGS__)
5939e6bc2cSmrg #else
6039e6bc2cSmrg #define DPRINTF(fmt, ...)
6139e6bc2cSmrg #endif
6239e6bc2cSmrg 
6339e6bc2cSmrg /* Register definitions */
6439e6bc2cSmrg #define TSADC_USER_CON                          0x00
6539e6bc2cSmrg #define  TSADC_USER_CON_ADC_STATUS              __BIT(12)
6639e6bc2cSmrg #define  TSADC_USER_CON_INTER_PD_SOC            __BITS(11,6)
6739e6bc2cSmrg #define  TSADC_USER_CON_START                   __BIT(5)
6839e6bc2cSmrg #define  TSADC_USER_CON_START_MODE              __BIT(4)
6939e6bc2cSmrg #define  TSADC_USER_CON_ADC_POWER_CTRL          __BIT(3)
7039e6bc2cSmrg #define  TSADC_USER_CON_ADC_INPUT_SRC_SEL       __BITS(2,0)
7139e6bc2cSmrg #define TSADC_AUTO_CON                          0x04
7239e6bc2cSmrg #define  TSADC_AUTO_CON_LAST_TSHUT_2CRU         __BIT(25)
7339e6bc2cSmrg #define  TSADC_AUTO_CON_LAST_TSHUT_2GPIO        __BIT(24)
7439e6bc2cSmrg #define  TSADC_AUTO_CON_SAMPLE_DLY_SEL          __BIT(17)
7539e6bc2cSmrg #define  TSADC_AUTO_CON_AUTO_STATUS             __BIT(16)
7639e6bc2cSmrg #define  TSADC_AUTO_CON_SRC1_LT_EN              __BIT(13)
7739e6bc2cSmrg #define  TSADC_AUTO_CON_SRC0_LT_EN              __BIT(12)
7839e6bc2cSmrg #define  TSADC_AUTO_CON_TSHUT_POLARITY          __BIT(8)
7939e6bc2cSmrg #define  TSADC_AUTO_CON_SRC1_EN                 __BIT(5)
8039e6bc2cSmrg #define  TSADC_AUTO_CON_SRC0_EN                 __BIT(4)
8139e6bc2cSmrg #define  TSADC_AUTO_CON_Q_SEL                   __BIT(1)
8239e6bc2cSmrg #define  TSADC_AUTO_CON_AUTO_EN                 __BIT(0)
8339e6bc2cSmrg #define TSADC_INT_EN                            0x08
8439e6bc2cSmrg #define  TSADC_INT_EN_EOC_INT_EN                __BIT(16)
8539e6bc2cSmrg #define  TSADC_INT_EN_LT_INTEN_SRC1             __BIT(13)
8639e6bc2cSmrg #define  TSADC_INT_EN_LT_INTEN_SRC0             __BIT(12)
8739e6bc2cSmrg #define  TSADC_INT_EN_TSHUT_2CRU_EN_SRC1        __BIT(9)
8839e6bc2cSmrg #define  TSADC_INT_EN_TSHUT_2CRU_EN_SRC0        __BIT(8)
8939e6bc2cSmrg #define  TSADC_INT_EN_TSHUT_2GPIO_EN_SRC1       __BIT(5)
9039e6bc2cSmrg #define  TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0       __BIT(4)
9139e6bc2cSmrg #define  TSADC_INT_EN_HT_INTEN_SRC1             __BIT(1)
9239e6bc2cSmrg #define  TSADC_INT_EN_HT_INTEN_SRC0             __BIT(0)
9339e6bc2cSmrg #define TSADC_INT_PD                            0x0c
94c5e7cb41Sjmcneill #define  TSADC_INT_PD_EOC_INT_PD_V3             __BIT(16)
9539e6bc2cSmrg #define  TSADC_INT_PD_LT_IRQ_SRC1               __BIT(13)
9639e6bc2cSmrg #define  TSADC_INT_PD_LT_IRQ_SRC0               __BIT(12)
97c5e7cb41Sjmcneill #define  TSADC_INT_PD_EOC_INT_PD_V2             __BIT(8)
9839e6bc2cSmrg #define  TSADC_INT_PD_TSHUT_O_SRC1              __BIT(5)
9939e6bc2cSmrg #define  TSADC_INT_PD_TSHUT_O_SRC0              __BIT(4)
10039e6bc2cSmrg #define  TSADC_INT_PD_HT_IRQ_SRC1               __BIT(1)
10139e6bc2cSmrg #define  TSADC_INT_PD_HT_IRQ_SRC0               __BIT(0)
10239e6bc2cSmrg #define TSADC_DATA0                             0x20
10339e6bc2cSmrg #define  TSADC_DATA0_ADC_DATA                   __BITS(11,0)
10439e6bc2cSmrg #define TSADC_DATA1                             0x24
10539e6bc2cSmrg #define  TSADC_DATA1_ADC_DATA                   __BITS(11,0)
10639e6bc2cSmrg #define TSADC_COMP0_INT                         0x30
10739e6bc2cSmrg #define  TSADC_COMP0_INT_COMP_SRC0              __BITS(11,0)
10839e6bc2cSmrg #define TSADC_COMP1_INT                         0x34
10939e6bc2cSmrg #define  TSADC_COMP1_INT_COMP_SRC1              __BITS(11,0)
11039e6bc2cSmrg #define TSADC_COMP0_SHUT                        0x40
11139e6bc2cSmrg #define  TSADC_COMP0_SHUT_COMP_SRC0             __BITS(11,0)
11239e6bc2cSmrg #define TSADC_COMP1_SHUT                        0x44
11339e6bc2cSmrg #define  TSADC_COMP1_SHUT_COMP_SRC1             __BITS(11,0)
11439e6bc2cSmrg #define TSADC_HIGH_INT_DEBOUNCE                 0x60
11539e6bc2cSmrg #define  TSADC_HIGH_INT_DEBOUNCE_TEMP           __BITS(7,0)
11639e6bc2cSmrg #define TSADC_HIGH_TSHUT_DEBOUNCE               0x64
11739e6bc2cSmrg #define  TSADC_HIGH_TSHUT_DEBOUNCE_TEMP         __BITS(7,0)
11839e6bc2cSmrg #define TSADC_AUTO_PERIOD                       0x68
11939e6bc2cSmrg #define  TSADC_AUTO_PERIOD_TEMP                 __BITS(31,0)
12039e6bc2cSmrg #define TSADC_AUTO_PERIOD_HT                    0x6c
12139e6bc2cSmrg #define  TSADC_AUTO_PERIOD_HT_TEMP              __BITS(31,0)
12239e6bc2cSmrg #define TSADC_COMP0_LOW_INT                     0x80
12339e6bc2cSmrg #define  TSADC_COMP0_LOW_INT_COMP_SRC0          __BITS(11,0)
12439e6bc2cSmrg #define TSADC_COMP1_LOW_INT                     0x84
12539e6bc2cSmrg #define  TSADC_COMP1_LOW_INT_COMP_SRC1          __BITS(11,0)
12639e6bc2cSmrg 
127c5e7cb41Sjmcneill #define	RK3288_TSADC_AUTO_PERIOD_TIME		250 /* 250ms */
128c5e7cb41Sjmcneill #define	RK3288_TSADC_AUTO_PERIOD_HT_TIME	50  /* 50ms */
129863b2b98Smrg #define RK3328_TSADC_AUTO_PERIOD_TIME           250 /* 250ms */
130863b2b98Smrg #define RK3399_TSADC_AUTO_PERIOD_TIME           1875 /* 2.5ms */
13139e6bc2cSmrg #define TSADC_HT_DEBOUNCE_COUNT                 4
13239e6bc2cSmrg 
13339e6bc2cSmrg /*
13439e6bc2cSmrg  * All this magic is taking from the Linux rockchip_thermal driver.
13539e6bc2cSmrg  *
13639e6bc2cSmrg  * VCM means "voltage common mode", but the documentation for RK3399
13739e6bc2cSmrg  * does not mention this and I don't know what any of this really
13839e6bc2cSmrg  * is for.
13939e6bc2cSmrg  */
14039e6bc2cSmrg #define RK3399_GRF_SARADC_TESTBIT               0xe644
14139e6bc2cSmrg #define  RK3399_GRF_SARADC_TESTBIT_ON           (0x10001 << 2)
14239e6bc2cSmrg #define RK3399_GRF_TSADC_TESTBIT_L              0xe648
14339e6bc2cSmrg #define  RK3399_GRF_TSADC_TESTBIT_VCM_EN_L      (0x10001 << 7)
14439e6bc2cSmrg #define RK3399_GRF_TSADC_TESTBIT_H              0xe64c
14539e6bc2cSmrg #define  RK3399_GRF_TSADC_TESTBIT_VCM_EN_H      (0x10001 << 7)
14639e6bc2cSmrg #define  RK3399_GRF_TSADC_TESTBIT_H_ON          (0x10001 << 2)
14739e6bc2cSmrg 
14839e6bc2cSmrg #define TEMP_uC_TO_uK             273150000
14939e6bc2cSmrg 
15039e6bc2cSmrg #define TSHUT_MODE_CPU    0
15139e6bc2cSmrg #define TSHUT_MODE_GPIO   1
15239e6bc2cSmrg 
15339e6bc2cSmrg #define TSHUT_LOW_ACTIVE  0
15439e6bc2cSmrg #define TSHUT_HIGH_ACTIVE 1
15539e6bc2cSmrg 
15639e6bc2cSmrg #define TSHUT_DEF_TEMP    95000
15739e6bc2cSmrg 
15839e6bc2cSmrg #define TSADC_DATA_MAX    0xfff
15939e6bc2cSmrg 
1607ce6ce51Smrg #define MAX_SENSORS       2
16139e6bc2cSmrg 
162863b2b98Smrg typedef struct rk_data_array {
16339e6bc2cSmrg 	uint32_t data;  /* register value */
16439e6bc2cSmrg 	int temp;       /* micro-degC */
165863b2b98Smrg } rk_data_array;
166863b2b98Smrg 
167863b2b98Smrg struct rk_tsadc_softc;
1687ce6ce51Smrg typedef struct rk_data {
169c5e7cb41Sjmcneill 	const char		*rd_name;
1707ce6ce51Smrg 	const rk_data_array	*rd_array;
1717ce6ce51Smrg 	size_t			 rd_size;
1727ce6ce51Smrg 	void			(*rd_init)(struct rk_tsadc_softc *, int, int);
1737ce6ce51Smrg 	bool			 rd_decr;  /* lower values -> higher temp */
1747ce6ce51Smrg 	unsigned		 rd_min, rd_max;
1757ce6ce51Smrg 	unsigned		 rd_auto_period;
176c5e7cb41Sjmcneill 	unsigned		 rd_auto_period_ht;
1777ce6ce51Smrg 	unsigned		 rd_num_sensors;
178c5e7cb41Sjmcneill 	unsigned		 rd_version;
1797ce6ce51Smrg } rk_data;
18039e6bc2cSmrg 
18139e6bc2cSmrg /* Per-sensor data */
18239e6bc2cSmrg struct rk_tsadc_sensor {
18339e6bc2cSmrg 	envsys_data_t	s_data;
18439e6bc2cSmrg 	bool		s_attached;
18539e6bc2cSmrg 	/* TSADC register offsets for this sensor */
18639e6bc2cSmrg 	unsigned	s_data_reg;
18739e6bc2cSmrg 	unsigned	s_comp_tshut;
18839e6bc2cSmrg 	unsigned	s_comp_int;
1896bc30fa4Smrg 	/* enable bit in AUTO_CON register */
19039e6bc2cSmrg 	unsigned	s_comp_int_en;
19139e6bc2cSmrg 	/* warn/crit values in micro Kelvin */
19239e6bc2cSmrg 	int		s_warn;
19339e6bc2cSmrg 	int		s_tshut;
19439e6bc2cSmrg };
19539e6bc2cSmrg 
19639e6bc2cSmrg struct rk_tsadc_softc {
19739e6bc2cSmrg 	device_t		sc_dev;
19839e6bc2cSmrg 	int			sc_phandle;
19939e6bc2cSmrg 	bus_space_tag_t		sc_bst;
20039e6bc2cSmrg 	bus_space_handle_t	sc_bsh;
20139e6bc2cSmrg 	size_t			sc_size;
20239e6bc2cSmrg 	uint32_t		sc_data_mask;
20339e6bc2cSmrg 	void			*sc_ih;
20439e6bc2cSmrg 
20539e6bc2cSmrg 	struct sysmon_envsys	*sc_sme;
2067ce6ce51Smrg 	struct rk_tsadc_sensor	sc_sensors[MAX_SENSORS];
20739e6bc2cSmrg 
20839e6bc2cSmrg 	struct clk		*sc_clock;
20939e6bc2cSmrg 	struct clk		*sc_clockapb;
21039e6bc2cSmrg 	struct fdtbus_reset	*sc_reset;
21139e6bc2cSmrg 	struct syscon		*sc_syscon;
212863b2b98Smrg 
2137ce6ce51Smrg 	const rk_data		*sc_rd;
21439e6bc2cSmrg };
21539e6bc2cSmrg 
21639e6bc2cSmrg static int rk_tsadc_match(device_t, cfdata_t, void *);
21739e6bc2cSmrg static void rk_tsadc_attach(device_t, device_t, void *);
21839e6bc2cSmrg static int rk_tsadc_detach(device_t, int);
21939e6bc2cSmrg static int rk_tsadc_init_clocks(struct rk_tsadc_softc *);
22039e6bc2cSmrg static void rk_tsadc_init_counts(struct rk_tsadc_softc *);
22139e6bc2cSmrg static void rk_tsadc_tshut_set(struct rk_tsadc_softc *s);
22239e6bc2cSmrg static void rk_tsadc_init_tshut(struct rk_tsadc_softc *, int, int);
223c5e7cb41Sjmcneill static void rk_tsadc_init_common(struct rk_tsadc_softc *, int, int);
224863b2b98Smrg static void rk_tsadc_init_rk3399(struct rk_tsadc_softc *, int, int);
22539e6bc2cSmrg static void rk_tsadc_init_enable(struct rk_tsadc_softc *);
226863b2b98Smrg static void rk_tsadc_init(struct rk_tsadc_softc *, int, int);
22739e6bc2cSmrg static void rk_tsadc_refresh(struct sysmon_envsys *, envsys_data_t *);
22839e6bc2cSmrg static void rk_tsadc_get_limits(struct sysmon_envsys *, envsys_data_t *,
22939e6bc2cSmrg                                 sysmon_envsys_lim_t *, uint32_t *);
23039e6bc2cSmrg 
23139e6bc2cSmrg static int rk_tsadc_intr(void *);
23239e6bc2cSmrg static int rk_tsadc_data_to_temp(struct rk_tsadc_softc *, uint32_t);
23339e6bc2cSmrg static uint32_t rk_tsadc_temp_to_data(struct rk_tsadc_softc *, int);
23439e6bc2cSmrg 
23539e6bc2cSmrg /* RK3328/RK3399 compatible sensors */
23639e6bc2cSmrg static const struct rk_tsadc_sensor rk_tsadc_sensors[] = {
23739e6bc2cSmrg 	{
23839e6bc2cSmrg 	  .s_data = { .desc = "CPU" },
23939e6bc2cSmrg 	  .s_data_reg = TSADC_DATA0,
24039e6bc2cSmrg 	  .s_comp_tshut = TSADC_COMP0_SHUT,
24139e6bc2cSmrg 	  .s_comp_int = TSADC_COMP0_INT,
24239e6bc2cSmrg 	  .s_comp_int_en = TSADC_AUTO_CON_SRC0_EN,
24339e6bc2cSmrg 	  /*
24439e6bc2cSmrg 	   * XXX DT has:
24539e6bc2cSmrg 	   * cpu_alert1: cpu_alert1 {
24639e6bc2cSmrg 	   *	temperature = <75000>;
24739e6bc2cSmrg 	   *	hysteresis = <2000>;
24839e6bc2cSmrg 	   * cpu_crit: cpu_crit {
24939e6bc2cSmrg 	   *    temperature = <95000>;
25039e6bc2cSmrg 	   *    hysteresis = <2000>;
25139e6bc2cSmrg 	   * pull out of here?
25239e6bc2cSmrg 	   * do something with hysteresis?  put in debounce?
25339e6bc2cSmrg 	   *
254207defd0Sandvar 	   * Note that tshut may be overridden by the board specific DT.
25539e6bc2cSmrg 	   */
25639e6bc2cSmrg 	  .s_warn = 75000000,
25739e6bc2cSmrg 	  .s_tshut = 95000000,
25839e6bc2cSmrg 	}, {
25939e6bc2cSmrg 	  .s_data = { .desc = "GPU" },
26039e6bc2cSmrg 	  .s_data_reg = TSADC_DATA1,
26139e6bc2cSmrg 	  .s_comp_tshut = TSADC_COMP1_SHUT,
26239e6bc2cSmrg 	  .s_comp_int = TSADC_COMP1_INT,
26339e6bc2cSmrg 	  .s_comp_int_en = TSADC_AUTO_CON_SRC1_EN,
26439e6bc2cSmrg 	  .s_warn = 75000000,
26539e6bc2cSmrg 	  .s_tshut = 95000000,
26639e6bc2cSmrg 	},
26739e6bc2cSmrg };
26839e6bc2cSmrg 
2697ce6ce51Smrg /*
270c5e7cb41Sjmcneill  * Table from RK3288 manual.
271c5e7cb41Sjmcneill  */
272c5e7cb41Sjmcneill static const rk_data_array rk3288_data_array[] = {
273c5e7cb41Sjmcneill #define ENTRY(d,C)	{ .data = (d), .temp = (C) * 1000 * 1000, }
274c5e7cb41Sjmcneill 	ENTRY(TSADC_DATA_MAX, -40),
275c5e7cb41Sjmcneill 	ENTRY(3800, -40),
276c5e7cb41Sjmcneill 	ENTRY(3792, -35),
277c5e7cb41Sjmcneill 	ENTRY(3783, -30),
278c5e7cb41Sjmcneill 	ENTRY(3774, -25),
279c5e7cb41Sjmcneill 	ENTRY(3765, -20),
280c5e7cb41Sjmcneill 	ENTRY(3756, -15),
281c5e7cb41Sjmcneill 	ENTRY(3747, -10),
282c5e7cb41Sjmcneill 	ENTRY(3737, -5),
283c5e7cb41Sjmcneill 	ENTRY(3728, 0),
284c5e7cb41Sjmcneill 	ENTRY(3718, 5),
285c5e7cb41Sjmcneill 	ENTRY(3708, 10),
286c5e7cb41Sjmcneill 	ENTRY(3698, 15),
287c5e7cb41Sjmcneill 	ENTRY(3688, 20),
288c5e7cb41Sjmcneill 	ENTRY(3678, 25),
289c5e7cb41Sjmcneill 	ENTRY(3667, 30),
290c5e7cb41Sjmcneill 	ENTRY(3656, 35),
291c5e7cb41Sjmcneill 	ENTRY(3645, 40),
292c5e7cb41Sjmcneill 	ENTRY(3634, 45),
293c5e7cb41Sjmcneill 	ENTRY(3623, 50),
294c5e7cb41Sjmcneill 	ENTRY(3611, 55),
295c5e7cb41Sjmcneill 	ENTRY(3600, 60),
296c5e7cb41Sjmcneill 	ENTRY(3588, 65),
297c5e7cb41Sjmcneill 	ENTRY(3575, 70),
298c5e7cb41Sjmcneill 	ENTRY(3563, 75),
299c5e7cb41Sjmcneill 	ENTRY(3550, 80),
300c5e7cb41Sjmcneill 	ENTRY(3537, 85),
301c5e7cb41Sjmcneill 	ENTRY(3524, 90),
302c5e7cb41Sjmcneill 	ENTRY(3510, 95),
303c5e7cb41Sjmcneill 	ENTRY(3496, 100),
304c5e7cb41Sjmcneill 	ENTRY(3482, 105),
305c5e7cb41Sjmcneill 	ENTRY(3467, 110),
306c5e7cb41Sjmcneill 	ENTRY(3452, 115),
307c5e7cb41Sjmcneill 	ENTRY(3437, 120),
308c5e7cb41Sjmcneill 	ENTRY(3421, 125),
309c5e7cb41Sjmcneill 	ENTRY(0, 15),
310c5e7cb41Sjmcneill #undef ENTRY
311c5e7cb41Sjmcneill };
312c5e7cb41Sjmcneill 
313c5e7cb41Sjmcneill /*
3147ce6ce51Smrg  * Table from RK3328 manual.  Note that the manual lists valid numbers as
3157ce6ce51Smrg  * 4096 - number.  This also means it is increasing not decreasing for
3167ce6ce51Smrg  * higher temps, and the min and max are also offset from 4096.
3177ce6ce51Smrg  */
3187ce6ce51Smrg #define RK3328_DATA_OFFSET (4096)
319863b2b98Smrg static const rk_data_array rk3328_data_array[] = {
3207ce6ce51Smrg #define ENTRY(d,C) \
3217ce6ce51Smrg 	{ .data = RK3328_DATA_OFFSET - (d), .temp = (C) * 1000 * 1000, }
322863b2b98Smrg 	ENTRY(TSADC_DATA_MAX,    -40),
323863b2b98Smrg 	ENTRY(3800, -40),
324863b2b98Smrg 	ENTRY(3792, -35),
325863b2b98Smrg 	ENTRY(3783, -30),
326863b2b98Smrg 	ENTRY(3774, -25),
327863b2b98Smrg 	ENTRY(3765, -20),
328863b2b98Smrg 	ENTRY(3756, -15),
329863b2b98Smrg 	ENTRY(3747, -10),
330863b2b98Smrg 	ENTRY(3737,  -5),
331863b2b98Smrg 	ENTRY(3728,   0),
332863b2b98Smrg 	ENTRY(3718,   5),
333863b2b98Smrg 	ENTRY(3708,  10),
334863b2b98Smrg 	ENTRY(3698,  15),
335863b2b98Smrg 	ENTRY(3688,  20),
336863b2b98Smrg 	ENTRY(3678,  25),
337863b2b98Smrg 	ENTRY(3667,  30),
338863b2b98Smrg 	ENTRY(3656,  35),
339863b2b98Smrg 	ENTRY(3645,  40),
340863b2b98Smrg 	ENTRY(3634,  45),
341863b2b98Smrg 	ENTRY(3623,  50),
342863b2b98Smrg 	ENTRY(3611,  55),
343863b2b98Smrg 	ENTRY(3600,  60),
344863b2b98Smrg 	ENTRY(3588,  65),
345863b2b98Smrg 	ENTRY(3575,  70),
346863b2b98Smrg 	ENTRY(3563,  75),
347863b2b98Smrg 	ENTRY(3550,  80),
348863b2b98Smrg 	ENTRY(3537,  85),
349863b2b98Smrg 	ENTRY(3524,  90),
350863b2b98Smrg 	ENTRY(3510,  95),
351863b2b98Smrg 	ENTRY(3496, 100),
352863b2b98Smrg 	ENTRY(3482, 105),
353863b2b98Smrg 	ENTRY(3467, 110),
354863b2b98Smrg 	ENTRY(3452, 115),
355863b2b98Smrg 	ENTRY(3437, 120),
356863b2b98Smrg 	ENTRY(3421, 125),
357863b2b98Smrg 	ENTRY(0,    125),
358863b2b98Smrg #undef ENTRY
359863b2b98Smrg };
360863b2b98Smrg 
361863b2b98Smrg /* Table from RK3399 manual */
362863b2b98Smrg static const rk_data_array rk3399_data_array[] = {
363863b2b98Smrg #define ENTRY(d,C)	{ .data = (d), .temp = (C) * 1000 * 1000, }
364863b2b98Smrg 	ENTRY(0,   -40),
365863b2b98Smrg 	ENTRY(402, -40),
366863b2b98Smrg 	ENTRY(410, -35),
367863b2b98Smrg 	ENTRY(419, -30),
368863b2b98Smrg 	ENTRY(427, -25),
369863b2b98Smrg 	ENTRY(436, -20),
370863b2b98Smrg 	ENTRY(444, -15),
371863b2b98Smrg 	ENTRY(453, -10),
372863b2b98Smrg 	ENTRY(461,  -5),
373863b2b98Smrg 	ENTRY(470,   0),
374863b2b98Smrg 	ENTRY(478,   5),
375863b2b98Smrg 	ENTRY(487,  10),
376863b2b98Smrg 	ENTRY(496,  15),
377863b2b98Smrg 	ENTRY(504,  20),
378863b2b98Smrg 	ENTRY(513,  25),
379863b2b98Smrg 	ENTRY(521,  30),
380863b2b98Smrg 	ENTRY(530,  35),
381863b2b98Smrg 	ENTRY(538,  40),
382863b2b98Smrg 	ENTRY(547,  45),
383863b2b98Smrg 	ENTRY(555,  50),
384863b2b98Smrg 	ENTRY(564,  55),
385863b2b98Smrg 	ENTRY(573,  60),
386863b2b98Smrg 	ENTRY(581,  65),
387863b2b98Smrg 	ENTRY(590,  70),
388863b2b98Smrg 	ENTRY(599,  75),
389863b2b98Smrg 	ENTRY(607,  80),
390863b2b98Smrg 	ENTRY(616,  85),
391863b2b98Smrg 	ENTRY(624,  90),
392863b2b98Smrg 	ENTRY(633,  95),
393863b2b98Smrg 	ENTRY(642, 100),
394863b2b98Smrg 	ENTRY(650, 105),
395863b2b98Smrg 	ENTRY(659, 110),
396863b2b98Smrg 	ENTRY(668, 115),
397863b2b98Smrg 	ENTRY(677, 120),
398863b2b98Smrg 	ENTRY(685, 125),
399863b2b98Smrg 	ENTRY(TSADC_DATA_MAX, 125),
400863b2b98Smrg #undef ENTRY
401863b2b98Smrg };
402863b2b98Smrg 
403c5e7cb41Sjmcneill static const rk_data rk3288_data_table = {
404c5e7cb41Sjmcneill 	.rd_name = "RK3288",
405c5e7cb41Sjmcneill 	.rd_array = rk3288_data_array,
406c5e7cb41Sjmcneill 	.rd_size = __arraycount(rk3288_data_array),
407c5e7cb41Sjmcneill 	.rd_init = rk_tsadc_init_common,
408c5e7cb41Sjmcneill 	.rd_decr = true,
409c5e7cb41Sjmcneill 	.rd_max = 3800,
410c5e7cb41Sjmcneill 	.rd_min = 3421,
411c5e7cb41Sjmcneill 	.rd_auto_period = RK3288_TSADC_AUTO_PERIOD_TIME,
412c5e7cb41Sjmcneill 	.rd_auto_period_ht = RK3288_TSADC_AUTO_PERIOD_HT_TIME,
413c5e7cb41Sjmcneill 	.rd_num_sensors = 2,
414c5e7cb41Sjmcneill 	.rd_version = 2,
415c5e7cb41Sjmcneill };
416c5e7cb41Sjmcneill 
4177ce6ce51Smrg static const rk_data rk3328_data_table = {
418c5e7cb41Sjmcneill 	.rd_name = "RK3328",
4197ce6ce51Smrg 	.rd_array = rk3328_data_array,
4207ce6ce51Smrg 	.rd_size = __arraycount(rk3328_data_array),
421c5e7cb41Sjmcneill 	.rd_init = rk_tsadc_init_common,
4227ce6ce51Smrg 	.rd_decr = false,
4237ce6ce51Smrg 	.rd_max = RK3328_DATA_OFFSET - 3420,
4247ce6ce51Smrg 	.rd_min = RK3328_DATA_OFFSET - 3801,
4257ce6ce51Smrg 	.rd_auto_period = RK3328_TSADC_AUTO_PERIOD_TIME,
426c5e7cb41Sjmcneill 	.rd_auto_period_ht = RK3328_TSADC_AUTO_PERIOD_TIME,
4277ce6ce51Smrg 	.rd_num_sensors = 1,
428c5e7cb41Sjmcneill 	.rd_version = 3,
429863b2b98Smrg };
430863b2b98Smrg 
4317ce6ce51Smrg static const rk_data rk3399_data_table = {
432c5e7cb41Sjmcneill 	.rd_name = "RK3399",
4337ce6ce51Smrg 	.rd_array = rk3399_data_array,
4347ce6ce51Smrg 	.rd_size = __arraycount(rk3399_data_array),
4357ce6ce51Smrg 	.rd_init = rk_tsadc_init_rk3399,
4367ce6ce51Smrg 	.rd_decr = false,
4377ce6ce51Smrg 	.rd_max = 686,
4387ce6ce51Smrg 	.rd_min = 401,
4397ce6ce51Smrg 	.rd_auto_period = RK3399_TSADC_AUTO_PERIOD_TIME,
440c5e7cb41Sjmcneill 	.rd_auto_period_ht = RK3399_TSADC_AUTO_PERIOD_TIME,
4417ce6ce51Smrg 	.rd_num_sensors = 2,
442c5e7cb41Sjmcneill 	.rd_version = 3,
443863b2b98Smrg };
444863b2b98Smrg 
445622c6ae7Sthorpej static const struct device_compatible_entry compat_data[] = {
446c5e7cb41Sjmcneill 	{ .compat = "rockchip,rk3288-tsadc",	.data = &rk3288_data_table },
447622c6ae7Sthorpej 	{ .compat = "rockchip,rk3328-tsadc",	.data = &rk3328_data_table },
448622c6ae7Sthorpej 	{ .compat = "rockchip,rk3399-tsadc",	.data = &rk3399_data_table },
449ec189949Sthorpej 	DEVICE_COMPAT_EOL
45039e6bc2cSmrg };
45139e6bc2cSmrg 
45239e6bc2cSmrg #define	TSADC_READ(sc, reg)		\
45339e6bc2cSmrg 	bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg))
45439e6bc2cSmrg #define	TSADC_WRITE(sc, reg, val)	\
45539e6bc2cSmrg 	bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val))
45639e6bc2cSmrg 
45739e6bc2cSmrg CFATTACH_DECL3_NEW(rk_tsadc, sizeof(struct rk_tsadc_softc),
45839e6bc2cSmrg 	rk_tsadc_match, rk_tsadc_attach, rk_tsadc_detach, NULL, NULL, NULL,
45939e6bc2cSmrg 	DVF_DETACH_SHUTDOWN);
46039e6bc2cSmrg 
46139e6bc2cSmrg /* init/teardown support */
46239e6bc2cSmrg static int
rk_tsadc_match(device_t parent,cfdata_t cf,void * aux)46339e6bc2cSmrg rk_tsadc_match(device_t parent, cfdata_t cf, void *aux)
46439e6bc2cSmrg {
46539e6bc2cSmrg 	struct fdt_attach_args * const faa = aux;
46639e6bc2cSmrg 
4676e54367aSthorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
46839e6bc2cSmrg }
46939e6bc2cSmrg 
47039e6bc2cSmrg static void
rk_tsadc_attach(device_t parent,device_t self,void * aux)47139e6bc2cSmrg rk_tsadc_attach(device_t parent, device_t self, void *aux)
47239e6bc2cSmrg {
47339e6bc2cSmrg 	struct rk_tsadc_softc * const sc = device_private(self);
47439e6bc2cSmrg 	struct fdt_attach_args * const faa = aux;
47539e6bc2cSmrg 	char intrstr[128];
47639e6bc2cSmrg 	const int phandle = faa->faa_phandle;
47739e6bc2cSmrg 	bus_addr_t addr;
47839e6bc2cSmrg 	int mode, polarity, tshut_temp;
47939e6bc2cSmrg 
48039e6bc2cSmrg 	sc->sc_dev = self;
48139e6bc2cSmrg 	sc->sc_phandle = phandle;
48239e6bc2cSmrg 	sc->sc_bst = faa->faa_bst;
48339e6bc2cSmrg 
48439e6bc2cSmrg 	sc->sc_sme = sysmon_envsys_create();
48539e6bc2cSmrg 
48639e6bc2cSmrg 	sc->sc_sme->sme_name = device_xname(self);
48739e6bc2cSmrg 	sc->sc_sme->sme_cookie = sc;
48839e6bc2cSmrg 	sc->sc_sme->sme_refresh = rk_tsadc_refresh;
48939e6bc2cSmrg 	sc->sc_sme->sme_get_limits = rk_tsadc_get_limits;
4906bc30fa4Smrg 	sc->sc_data_mask = TSADC_DATA_MAX;
49139e6bc2cSmrg 
49239e6bc2cSmrg 	pmf_device_register(self, NULL, NULL);
49339e6bc2cSmrg 
4946e54367aSthorpej 	sc->sc_rd = of_compatible_lookup(faa->faa_phandle, compat_data)->data;
4957ce6ce51Smrg 
496c5e7cb41Sjmcneill 	aprint_naive("\n");
497c5e7cb41Sjmcneill 	aprint_normal(": %s Temperature Sensor ADC\n", sc->sc_rd->rd_name);
498c5e7cb41Sjmcneill 
49939e6bc2cSmrg 	/* Default to tshut via gpio and tshut low is active */
50039e6bc2cSmrg 	if (of_getprop_uint32(phandle, "rockchip,hw-tshut-mode",
50139e6bc2cSmrg 			      &mode) != 0) {
50239e6bc2cSmrg 		aprint_error(": could not get TSHUT mode, default to GPIO");
50339e6bc2cSmrg 		mode = TSHUT_MODE_GPIO;
50439e6bc2cSmrg 	}
50539e6bc2cSmrg 	if (mode != TSHUT_MODE_CPU && mode != TSHUT_MODE_GPIO) {
50639e6bc2cSmrg 		aprint_error(": TSHUT mode should be 0 or 1\n");
50739e6bc2cSmrg 		goto fail;
50839e6bc2cSmrg 	}
50939e6bc2cSmrg 
51039e6bc2cSmrg 	if (of_getprop_uint32(phandle, "rockchip,hw-tshut-polarity",
51139e6bc2cSmrg 			      &polarity) != 0) {
51239e6bc2cSmrg 		aprint_error(": could not get TSHUT polarity, default to low");
51339e6bc2cSmrg 		polarity = TSHUT_LOW_ACTIVE;
51439e6bc2cSmrg 	}
51539e6bc2cSmrg 	if (of_getprop_uint32(phandle,
51639e6bc2cSmrg 			      "rockchip,hw-tshut-temp", &tshut_temp) != 0) {
51739e6bc2cSmrg 		aprint_error(": could not get TSHUT temperature, default to %u",
51839e6bc2cSmrg 			     TSHUT_DEF_TEMP);
51939e6bc2cSmrg 		tshut_temp = TSHUT_DEF_TEMP;
52039e6bc2cSmrg 	}
5217c8cb6a3Smrg 	tshut_temp *= 1000;	/* convert fdt mK -> uK */
52239e6bc2cSmrg 
52339e6bc2cSmrg 	memcpy(sc->sc_sensors, rk_tsadc_sensors, sizeof(sc->sc_sensors));
5247ce6ce51Smrg 	for (unsigned n = 0; n < sc->sc_rd->rd_num_sensors; n++) {
52539e6bc2cSmrg 		struct rk_tsadc_sensor *rks = &sc->sc_sensors[n];
52639e6bc2cSmrg 
52739e6bc2cSmrg 		rks->s_data.flags = ENVSYS_FMONLIMITS;
52839e6bc2cSmrg 		rks->s_data.units = ENVSYS_STEMP;
52939e6bc2cSmrg 		rks->s_data.state = ENVSYS_SINVALID;
53039e6bc2cSmrg 
53139e6bc2cSmrg 		if (sysmon_envsys_sensor_attach(sc->sc_sme, &rks->s_data))
53239e6bc2cSmrg 			goto fail;
53339e6bc2cSmrg 		rks->s_attached = true;
53439e6bc2cSmrg 		rks->s_tshut = tshut_temp;
535e7c3d862Smrg #if 0
53639e6bc2cSmrg 		// testing
5376bc30fa4Smrg 		rks->s_tshut = 68000000;
5386bc30fa4Smrg 		rks->s_warn = 61000000;
53939e6bc2cSmrg #endif
54039e6bc2cSmrg 	}
54139e6bc2cSmrg 
54239e6bc2cSmrg 	sc->sc_syscon = fdtbus_syscon_acquire(phandle, "rockchip,grf");
54339e6bc2cSmrg 	if (sc->sc_syscon == NULL) {
54439e6bc2cSmrg 		aprint_error(": couldn't get grf syscon\n");
54539e6bc2cSmrg 		goto fail;
54639e6bc2cSmrg 	}
54739e6bc2cSmrg 	if (fdtbus_get_reg(phandle, 0, &addr, &sc->sc_size) != 0) {
54839e6bc2cSmrg 		aprint_error(": couldn't get registers\n");
54939e6bc2cSmrg 		sc->sc_size = 0;
55039e6bc2cSmrg 		goto fail;
55139e6bc2cSmrg 	}
55239e6bc2cSmrg 	if (bus_space_map(sc->sc_bst, addr, sc->sc_size, 0, &sc->sc_bsh) != 0) {
55339e6bc2cSmrg 		aprint_error(": couldn't map registers\n");
55439e6bc2cSmrg 		sc->sc_size = 0;
55539e6bc2cSmrg 		goto fail;
55639e6bc2cSmrg 	}
55739e6bc2cSmrg 
55839e6bc2cSmrg 	if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) {
55939e6bc2cSmrg 		aprint_error(": failed to decode interrupt\n");
56039e6bc2cSmrg 		goto fail;
56139e6bc2cSmrg 	}
56239e6bc2cSmrg 
56364e248edSryo 	sc->sc_ih = fdtbus_intr_establish_xname(phandle, 0, IPL_VM, FDT_INTR_MPSAFE,
56464e248edSryo 	    rk_tsadc_intr, sc, device_xname(self));
56539e6bc2cSmrg 	if (sc->sc_ih == NULL) {
56639e6bc2cSmrg 		aprint_error_dev(self, "couldn't establish interrupt on %s\n",
56739e6bc2cSmrg 		    intrstr);
56839e6bc2cSmrg 		goto fail;
56939e6bc2cSmrg 	}
57039e6bc2cSmrg 	aprint_normal_dev(self, "interrupting on %s\n", intrstr);
57139e6bc2cSmrg 
57239e6bc2cSmrg 	if (rk_tsadc_init_clocks(sc)) {
57339e6bc2cSmrg 		aprint_error(": couldn't enable clocks\n");
57439e6bc2cSmrg 		return;
57539e6bc2cSmrg 	}
57639e6bc2cSmrg 
57739e6bc2cSmrg 	/*
57839e6bc2cSmrg 	 * Manual says to setup auto period (both), high temp (interrupt),
57939e6bc2cSmrg 	 * high temp (shutdown), enable high temp resets (TSHUT to GPIO
58039e6bc2cSmrg 	 * or reset chip), set the debounce times, and, finally, enable the
58139e6bc2cSmrg 	 * controller iself.
58239e6bc2cSmrg 	 */
583863b2b98Smrg 	rk_tsadc_init(sc, mode, polarity);
58439e6bc2cSmrg 
58539e6bc2cSmrg 	return;
58639e6bc2cSmrg 
58739e6bc2cSmrg fail:
58839e6bc2cSmrg 	rk_tsadc_detach(self, 0);
58939e6bc2cSmrg }
59039e6bc2cSmrg 
59139e6bc2cSmrg static int
rk_tsadc_detach(device_t self,int flags)59239e6bc2cSmrg rk_tsadc_detach(device_t self, int flags)
59339e6bc2cSmrg {
59439e6bc2cSmrg 	struct rk_tsadc_softc *sc = device_private(self);
59539e6bc2cSmrg 
59639e6bc2cSmrg 	pmf_device_deregister(self);
59739e6bc2cSmrg 
5987ce6ce51Smrg 	for (unsigned n = 0; n < sc->sc_rd->rd_num_sensors; n++) {
59939e6bc2cSmrg 		struct rk_tsadc_sensor *rks = &sc->sc_sensors[n];
60039e6bc2cSmrg 
60139e6bc2cSmrg 		if (rks->s_attached) {
60239e6bc2cSmrg 			sysmon_envsys_sensor_detach(sc->sc_sme, &rks->s_data);
60339e6bc2cSmrg 			rks->s_attached = false;
60439e6bc2cSmrg 		}
60539e6bc2cSmrg 	}
60639e6bc2cSmrg 
60739e6bc2cSmrg 	sysmon_envsys_unregister(sc->sc_sme);
60839e6bc2cSmrg 
60939e6bc2cSmrg 	if (sc->sc_clockapb)
61039e6bc2cSmrg 		clk_disable(sc->sc_clockapb);
61139e6bc2cSmrg 	if (sc->sc_clock)
61239e6bc2cSmrg 		clk_disable(sc->sc_clock);
61339e6bc2cSmrg 
61439e6bc2cSmrg 	if (sc->sc_ih)
61539e6bc2cSmrg 		fdtbus_intr_disestablish(sc->sc_phandle, sc->sc_ih);
61639e6bc2cSmrg 
61739e6bc2cSmrg 	if (sc->sc_size)
61839e6bc2cSmrg 		bus_space_unmap(sc->sc_bst, sc->sc_bsh, sc->sc_size);
61939e6bc2cSmrg 
62039e6bc2cSmrg 	sysmon_envsys_destroy(sc->sc_sme);
62139e6bc2cSmrg 
62239e6bc2cSmrg 	return 0;
62339e6bc2cSmrg }
62439e6bc2cSmrg 
62539e6bc2cSmrg static int
rk_tsadc_init_clocks(struct rk_tsadc_softc * sc)62639e6bc2cSmrg rk_tsadc_init_clocks(struct rk_tsadc_softc *sc)
62739e6bc2cSmrg {
62839e6bc2cSmrg 	int error;
62939e6bc2cSmrg 
63039e6bc2cSmrg 	fdtbus_clock_assign(sc->sc_phandle);
63139e6bc2cSmrg 
63239e6bc2cSmrg 	sc->sc_reset = fdtbus_reset_get(sc->sc_phandle, "tsadc-apb");
63339e6bc2cSmrg 	sc->sc_clock = fdtbus_clock_get(sc->sc_phandle, "tsadc");
63439e6bc2cSmrg 	sc->sc_clockapb = fdtbus_clock_get(sc->sc_phandle, "apb_pclk");
63539e6bc2cSmrg 	if (sc->sc_reset == NULL ||
63639e6bc2cSmrg 	    sc->sc_clock == NULL ||
63739e6bc2cSmrg 	    sc->sc_clockapb == NULL)
63839e6bc2cSmrg 		return EINVAL;
63939e6bc2cSmrg 
64039e6bc2cSmrg 	fdtbus_reset_assert(sc->sc_reset);
64139e6bc2cSmrg 
64239e6bc2cSmrg 	error = clk_enable(sc->sc_clock);
64339e6bc2cSmrg 	if (error) {
64439e6bc2cSmrg 		fdtbus_reset_deassert(sc->sc_reset);
64539e6bc2cSmrg 		return error;
64639e6bc2cSmrg 	}
64739e6bc2cSmrg 
64839e6bc2cSmrg 	error = clk_enable(sc->sc_clockapb);
64939e6bc2cSmrg 
65039e6bc2cSmrg 	DELAY(20);
65139e6bc2cSmrg 	fdtbus_reset_deassert(sc->sc_reset);
65239e6bc2cSmrg 
65339e6bc2cSmrg 	return error;
65439e6bc2cSmrg }
65539e6bc2cSmrg 
65639e6bc2cSmrg static void
rk_tsadc_init_counts(struct rk_tsadc_softc * sc)65739e6bc2cSmrg rk_tsadc_init_counts(struct rk_tsadc_softc *sc)
65839e6bc2cSmrg {
65939e6bc2cSmrg 
6607ce6ce51Smrg 	TSADC_WRITE(sc, TSADC_AUTO_PERIOD, sc->sc_rd->rd_auto_period);
661c5e7cb41Sjmcneill 	TSADC_WRITE(sc, TSADC_AUTO_PERIOD_HT, sc->sc_rd->rd_auto_period_ht);
66239e6bc2cSmrg 	TSADC_WRITE(sc, TSADC_HIGH_INT_DEBOUNCE, TSADC_HT_DEBOUNCE_COUNT);
66339e6bc2cSmrg 	TSADC_WRITE(sc, TSADC_HIGH_TSHUT_DEBOUNCE, TSADC_HT_DEBOUNCE_COUNT);
66439e6bc2cSmrg }
66539e6bc2cSmrg 
66639e6bc2cSmrg /* Configure the hardware with the tshut setup. */
66739e6bc2cSmrg static void
rk_tsadc_tshut_set(struct rk_tsadc_softc * sc)66839e6bc2cSmrg rk_tsadc_tshut_set(struct rk_tsadc_softc *sc)
66939e6bc2cSmrg {
67039e6bc2cSmrg 	uint32_t val = TSADC_READ(sc, TSADC_AUTO_CON);
67139e6bc2cSmrg 
6727ce6ce51Smrg 	for (unsigned n = 0; n < sc->sc_rd->rd_num_sensors; n++) {
67339e6bc2cSmrg 		struct rk_tsadc_sensor *rks = &sc->sc_sensors[n];
6747ce6ce51Smrg 		uint32_t data, warndata;
6757ce6ce51Smrg 
6767ce6ce51Smrg 		if (!rks->s_attached)
6777ce6ce51Smrg 			continue;
6787ce6ce51Smrg 
6797ce6ce51Smrg 		data = rk_tsadc_temp_to_data(sc, rks->s_tshut);
6807ce6ce51Smrg 		warndata = rk_tsadc_temp_to_data(sc, rks->s_warn);
68139e6bc2cSmrg 
68239e6bc2cSmrg 		DPRINTF("(%s:%s): tshut/data %d/%u warn/data %d/%u",
68339e6bc2cSmrg 			sc->sc_sme->sme_name, rks->s_data.desc,
68439e6bc2cSmrg 			rks->s_tshut, data,
68539e6bc2cSmrg 			rks->s_warn, warndata);
68639e6bc2cSmrg 
68739e6bc2cSmrg 		if (data == sc->sc_data_mask) {
68839e6bc2cSmrg 			aprint_error_dev(sc->sc_dev,
68939e6bc2cSmrg 			    "Failed converting critical temp %u.%06u to code",
69039e6bc2cSmrg 			    rks->s_tshut / 1000000, rks->s_tshut % 1000000);
69139e6bc2cSmrg 			continue;
69239e6bc2cSmrg 		}
69339e6bc2cSmrg 		if (warndata == sc->sc_data_mask) {
69439e6bc2cSmrg 			aprint_error_dev(sc->sc_dev,
69539e6bc2cSmrg 			    "Failed converting warn temp %u.%06u to code",
69639e6bc2cSmrg 			    rks->s_warn / 1000000, rks->s_warn % 1000000);
69739e6bc2cSmrg 			continue;
69839e6bc2cSmrg 		}
69939e6bc2cSmrg 
70039e6bc2cSmrg 		TSADC_WRITE(sc, rks->s_comp_tshut, data);
70139e6bc2cSmrg 		TSADC_WRITE(sc, rks->s_comp_int, warndata);
70239e6bc2cSmrg 
70339e6bc2cSmrg 		val |= rks->s_comp_int_en;
70439e6bc2cSmrg 	}
70539e6bc2cSmrg 	TSADC_WRITE(sc, TSADC_AUTO_CON, val);
70639e6bc2cSmrg }
70739e6bc2cSmrg 
70839e6bc2cSmrg static void
rk_tsadc_init_tshut(struct rk_tsadc_softc * sc,int mode,int polarity)70939e6bc2cSmrg rk_tsadc_init_tshut(struct rk_tsadc_softc *sc, int mode, int polarity)
71039e6bc2cSmrg {
71139e6bc2cSmrg 	uint32_t val;
71239e6bc2cSmrg 
71339e6bc2cSmrg 	/* Handle TSHUT temp setting. */
71439e6bc2cSmrg 	rk_tsadc_tshut_set(sc);
71539e6bc2cSmrg 
71639e6bc2cSmrg 	/* Handle TSHUT mode setting. */
71739e6bc2cSmrg 	val = TSADC_READ(sc, TSADC_INT_EN);
71839e6bc2cSmrg 	if (mode == TSHUT_MODE_CPU) {
71939e6bc2cSmrg 		val |= TSADC_INT_EN_TSHUT_2CRU_EN_SRC1 |
72039e6bc2cSmrg 		       TSADC_INT_EN_TSHUT_2CRU_EN_SRC0;
72139e6bc2cSmrg 		val &= ~(TSADC_INT_EN_TSHUT_2GPIO_EN_SRC1 |
72239e6bc2cSmrg 			 TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0);
72339e6bc2cSmrg 	} else {
72439e6bc2cSmrg 		KASSERT(mode == TSHUT_MODE_GPIO);
72539e6bc2cSmrg 		val &= ~(TSADC_INT_EN_TSHUT_2CRU_EN_SRC1 |
72639e6bc2cSmrg 			 TSADC_INT_EN_TSHUT_2CRU_EN_SRC0);
7270445ffd2Sjmcneill 		val |= TSADC_INT_EN_TSHUT_2GPIO_EN_SRC1 |
72839e6bc2cSmrg 		       TSADC_INT_EN_TSHUT_2GPIO_EN_SRC0;
72939e6bc2cSmrg 	}
73039e6bc2cSmrg 	TSADC_WRITE(sc, TSADC_INT_EN, val);
73139e6bc2cSmrg 
73239e6bc2cSmrg 	/* Handle TSHUT polarity setting. */
73339e6bc2cSmrg 	val = TSADC_READ(sc, TSADC_AUTO_CON);
73439e6bc2cSmrg 	if (polarity == TSHUT_HIGH_ACTIVE)
73539e6bc2cSmrg 		val |= TSADC_AUTO_CON_TSHUT_POLARITY;
73639e6bc2cSmrg 	else
73739e6bc2cSmrg 		val &= ~TSADC_AUTO_CON_TSHUT_POLARITY;
73839e6bc2cSmrg 	TSADC_WRITE(sc, TSADC_AUTO_CON, val);
73939e6bc2cSmrg }
74039e6bc2cSmrg 
74139e6bc2cSmrg static void
rk_tsadc_init_common(struct rk_tsadc_softc * sc,int mode,int polarity)742c5e7cb41Sjmcneill rk_tsadc_init_common(struct rk_tsadc_softc *sc, int mode, int polarity)
743863b2b98Smrg {
744863b2b98Smrg 
745863b2b98Smrg 	rk_tsadc_init_tshut(sc, mode, polarity);
746863b2b98Smrg 	rk_tsadc_init_counts(sc);
747863b2b98Smrg }
748863b2b98Smrg 
749863b2b98Smrg static void
rk_tsadc_init_rk3399(struct rk_tsadc_softc * sc,int mode,int polarity)750863b2b98Smrg rk_tsadc_init_rk3399(struct rk_tsadc_softc *sc, int mode, int polarity)
75139e6bc2cSmrg {
75239e6bc2cSmrg 
75339e6bc2cSmrg 	syscon_lock(sc->sc_syscon);
75439e6bc2cSmrg 	syscon_write_4(sc->sc_syscon, RK3399_GRF_TSADC_TESTBIT_L,
75539e6bc2cSmrg 				      RK3399_GRF_TSADC_TESTBIT_VCM_EN_L);
75639e6bc2cSmrg 	syscon_write_4(sc->sc_syscon, RK3399_GRF_TSADC_TESTBIT_H,
75739e6bc2cSmrg 				      RK3399_GRF_TSADC_TESTBIT_VCM_EN_H);
75839e6bc2cSmrg 
75939e6bc2cSmrg 	DELAY(20);
76039e6bc2cSmrg 	syscon_write_4(sc->sc_syscon, RK3399_GRF_SARADC_TESTBIT,
76139e6bc2cSmrg 				      RK3399_GRF_SARADC_TESTBIT_ON);
76239e6bc2cSmrg 	syscon_write_4(sc->sc_syscon, RK3399_GRF_TSADC_TESTBIT_H,
76339e6bc2cSmrg 				      RK3399_GRF_TSADC_TESTBIT_H_ON);
76439e6bc2cSmrg 	DELAY(100);
76539e6bc2cSmrg 	syscon_unlock(sc->sc_syscon);
766863b2b98Smrg 
767c5e7cb41Sjmcneill 	rk_tsadc_init_common(sc, mode, polarity);
76839e6bc2cSmrg }
76939e6bc2cSmrg 
77039e6bc2cSmrg static void
rk_tsadc_init_enable(struct rk_tsadc_softc * sc)77139e6bc2cSmrg rk_tsadc_init_enable(struct rk_tsadc_softc *sc)
77239e6bc2cSmrg {
77339e6bc2cSmrg 	uint32_t val;
77439e6bc2cSmrg 
77539e6bc2cSmrg 	val = TSADC_READ(sc, TSADC_AUTO_CON);
77639e6bc2cSmrg 	val |= TSADC_AUTO_CON_AUTO_STATUS |
7776bc30fa4Smrg 	       TSADC_AUTO_CON_SRC1_LT_EN | TSADC_AUTO_CON_SRC0_LT_EN;
77839e6bc2cSmrg 	TSADC_WRITE(sc, TSADC_AUTO_CON, val);
77939e6bc2cSmrg 
78039e6bc2cSmrg 	/* Finally, register & enable the controller */
78139e6bc2cSmrg 	sysmon_envsys_register(sc->sc_sme);
78239e6bc2cSmrg 
78339e6bc2cSmrg 	val = TSADC_READ(sc, TSADC_AUTO_CON);
784c5e7cb41Sjmcneill 	val |= TSADC_AUTO_CON_AUTO_EN;
785c5e7cb41Sjmcneill 	if (sc->sc_rd->rd_version >= 3) {
786c5e7cb41Sjmcneill 		val |= TSADC_AUTO_CON_Q_SEL;
787c5e7cb41Sjmcneill 	}
78839e6bc2cSmrg 	TSADC_WRITE(sc, TSADC_AUTO_CON, val);
78939e6bc2cSmrg }
79039e6bc2cSmrg 
791863b2b98Smrg static void
rk_tsadc_init(struct rk_tsadc_softc * sc,int mode,int polarity)792863b2b98Smrg rk_tsadc_init(struct rk_tsadc_softc *sc, int mode, int polarity)
793863b2b98Smrg {
794863b2b98Smrg 
7957ce6ce51Smrg 	(*sc->sc_rd->rd_init)(sc, mode, polarity);
796863b2b98Smrg 	rk_tsadc_init_enable(sc);
797863b2b98Smrg }
798863b2b98Smrg 
79939e6bc2cSmrg /* run time support */
80039e6bc2cSmrg 
8017ce6ce51Smrg /* given edata, find the matching rk sensor structure */
80239e6bc2cSmrg static struct rk_tsadc_sensor *
rk_tsadc_edata_to_sensor(struct rk_tsadc_softc * const sc,envsys_data_t * edata)80339e6bc2cSmrg rk_tsadc_edata_to_sensor(struct rk_tsadc_softc * const sc, envsys_data_t *edata)
80439e6bc2cSmrg {
805863b2b98Smrg 
8067ce6ce51Smrg 	for (unsigned n = 0; n < sc->sc_rd->rd_num_sensors; n++) {
80739e6bc2cSmrg 		struct rk_tsadc_sensor *rks = &sc->sc_sensors[n];
80839e6bc2cSmrg 
80939e6bc2cSmrg 		if (&rks->s_data == edata)
81039e6bc2cSmrg 			return rks;
81139e6bc2cSmrg 	}
81239e6bc2cSmrg 	return NULL;
81339e6bc2cSmrg }
81439e6bc2cSmrg 
81539e6bc2cSmrg static void
rk_tsadc_refresh(struct sysmon_envsys * sme,envsys_data_t * edata)81639e6bc2cSmrg rk_tsadc_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
81739e6bc2cSmrg {
81839e6bc2cSmrg 	struct rk_tsadc_softc * const sc = sme->sme_cookie;
81939e6bc2cSmrg 	struct rk_tsadc_sensor *rks = rk_tsadc_edata_to_sensor(sc, edata);
82039e6bc2cSmrg 	unsigned data;
82139e6bc2cSmrg 	int temp;
82239e6bc2cSmrg 
82339e6bc2cSmrg 	if (rks == NULL)
82439e6bc2cSmrg 		return;
82539e6bc2cSmrg 
82639e6bc2cSmrg 	data = TSADC_READ(sc, rks->s_data_reg) & sc->sc_data_mask;
82739e6bc2cSmrg 	temp = rk_tsadc_data_to_temp(sc, data);
82839e6bc2cSmrg 
829863b2b98Smrg 	DPRINTF("(%s:%s): temp/data %d/%u",
830863b2b98Smrg 		sc->sc_sme->sme_name, rks->s_data.desc,
831863b2b98Smrg 		temp, data);
832863b2b98Smrg 
83339e6bc2cSmrg 	if (temp == sc->sc_data_mask) {
83439e6bc2cSmrg 		edata->state = ENVSYS_SINVALID;
83539e6bc2cSmrg 	} else {
83639e6bc2cSmrg 		edata->value_cur = temp + TEMP_uC_TO_uK;
83739e6bc2cSmrg 		edata->state = ENVSYS_SVALID;
83839e6bc2cSmrg 	}
83939e6bc2cSmrg }
84039e6bc2cSmrg 
84139e6bc2cSmrg static void
rk_tsadc_get_limits(struct sysmon_envsys * sme,envsys_data_t * edata,sysmon_envsys_lim_t * lim,uint32_t * props)84239e6bc2cSmrg rk_tsadc_get_limits(struct sysmon_envsys *sme,
84339e6bc2cSmrg 		    envsys_data_t *edata,
84439e6bc2cSmrg 		    sysmon_envsys_lim_t *lim,
84539e6bc2cSmrg 		    uint32_t *props)
84639e6bc2cSmrg {
84739e6bc2cSmrg 	struct rk_tsadc_softc *sc = sme->sme_cookie;
84839e6bc2cSmrg 	struct rk_tsadc_sensor *rks = rk_tsadc_edata_to_sensor(sc, edata);
84939e6bc2cSmrg 
85039e6bc2cSmrg 	if (rks == NULL)
85139e6bc2cSmrg 		return;
85239e6bc2cSmrg 
85339e6bc2cSmrg 	lim->sel_critmax = rks->s_tshut + TEMP_uC_TO_uK;
85439e6bc2cSmrg 	lim->sel_warnmax = rks->s_warn + TEMP_uC_TO_uK;
85539e6bc2cSmrg 
85639e6bc2cSmrg 	*props = PROP_CRITMAX | PROP_WARNMAX;
85739e6bc2cSmrg }
85839e6bc2cSmrg 
85939e6bc2cSmrg /* XXX do something with interrupts that don't happen yet.  */
86039e6bc2cSmrg static int
rk_tsadc_intr(void * arg)86139e6bc2cSmrg rk_tsadc_intr(void *arg)
86239e6bc2cSmrg {
86339e6bc2cSmrg 	struct rk_tsadc_softc * const sc = arg;
86439e6bc2cSmrg 	uint32_t val;
86539e6bc2cSmrg 
86639e6bc2cSmrg 	/* XXX */
86739e6bc2cSmrg 	DPRINTF("(%s): interrupted", sc->sc_sme->sme_name);
868cd3d18e7Sjoerg 	for (unsigned n = 0; n < __arraycount(rk_tsadc_sensors); n++) {
86939e6bc2cSmrg 		struct rk_tsadc_sensor *rks = &sc->sc_sensors[n];
87039e6bc2cSmrg 
87139e6bc2cSmrg 		rk_tsadc_refresh(sc->sc_sme, (envsys_data_t *)rks);
87239e6bc2cSmrg 	}
87339e6bc2cSmrg 
87439e6bc2cSmrg 	/* ack interrupt */
87539e6bc2cSmrg 	val = TSADC_READ(sc, TSADC_INT_PD);
876c5e7cb41Sjmcneill 	if (sc->sc_rd->rd_version >= 3) {
877c5e7cb41Sjmcneill 		TSADC_WRITE(sc, TSADC_INT_PD,
878c5e7cb41Sjmcneill 		    val & ~TSADC_INT_PD_EOC_INT_PD_V3);
879c5e7cb41Sjmcneill 	} else {
880c5e7cb41Sjmcneill 		TSADC_WRITE(sc, TSADC_INT_PD,
881c5e7cb41Sjmcneill 		    val & ~TSADC_INT_PD_EOC_INT_PD_V2);
882c5e7cb41Sjmcneill 	}
88339e6bc2cSmrg 
88439e6bc2cSmrg 	return 1;
88539e6bc2cSmrg }
88639e6bc2cSmrg 
88739e6bc2cSmrg /*
88839e6bc2cSmrg  * Convert TDASC data codes to temp and reverse.  The manual only has codes
88939e6bc2cSmrg  * and temperature values in 5 degC intervals, but says that interpolation
89039e6bc2cSmrg  * can be done to achieve better resolution between these values, and that
89139e6bc2cSmrg  * the spacing is linear.
89239e6bc2cSmrg  */
89339e6bc2cSmrg static int
rk_tsadc_data_to_temp(struct rk_tsadc_softc * sc,uint32_t data)89439e6bc2cSmrg rk_tsadc_data_to_temp(struct rk_tsadc_softc *sc, uint32_t data)
89539e6bc2cSmrg {
89639e6bc2cSmrg 	unsigned i;
8977ce6ce51Smrg 	const rk_data *rd = sc->sc_rd;
89839e6bc2cSmrg 
8997ce6ce51Smrg 	if (data > rd->rd_max || data < rd->rd_min) {
9007ce6ce51Smrg 		DPRINTF("data out of range (%u > %u || %u < %u)",
9017ce6ce51Smrg 			data, rd->rd_max, data, rd->rd_min);
902863b2b98Smrg 		return sc->sc_data_mask;
903863b2b98Smrg 	}
9047ce6ce51Smrg 	for (i = 1; i < rd->rd_size; i++) {
9057ce6ce51Smrg 		if (rd->rd_array[i].data >= data) {
9066bc30fa4Smrg 			int temprange, offset;
9076bc30fa4Smrg 			uint32_t datarange, datadiff;
908863b2b98Smrg 			unsigned first, secnd;
9096bc30fa4Smrg 
9107ce6ce51Smrg 			if (rd->rd_array[i].data == data)
9117ce6ce51Smrg 				return rd->rd_array[i].temp;
9126bc30fa4Smrg 
9136bc30fa4Smrg 			/* must interpolate */
9147ce6ce51Smrg 			if (rd->rd_decr) {
915863b2b98Smrg 				first = i;
916863b2b98Smrg 				secnd = i+1;
917863b2b98Smrg 			} else {
918863b2b98Smrg 				first = i;
919863b2b98Smrg 				secnd = i-1;
920863b2b98Smrg 			}
921863b2b98Smrg 
9227ce6ce51Smrg 			temprange = rd->rd_array[first].temp -
9237ce6ce51Smrg 				    rd->rd_array[secnd].temp;
9247ce6ce51Smrg 			datarange = rd->rd_array[first].data -
9257ce6ce51Smrg 				    rd->rd_array[secnd].data;
9267ce6ce51Smrg 			datadiff = data - rd->rd_array[secnd].data;
9276bc30fa4Smrg 
9286bc30fa4Smrg 			offset = (temprange * datadiff) / datarange;
9297ce6ce51Smrg 			return rd->rd_array[secnd].temp + offset;
93039e6bc2cSmrg 		}
93139e6bc2cSmrg 	}
932863b2b98Smrg 	panic("didn't find range");
93339e6bc2cSmrg }
93439e6bc2cSmrg 
93539e6bc2cSmrg static uint32_t
rk_tsadc_temp_to_data(struct rk_tsadc_softc * sc,int temp)93639e6bc2cSmrg rk_tsadc_temp_to_data(struct rk_tsadc_softc *sc, int temp)
93739e6bc2cSmrg {
93839e6bc2cSmrg 	unsigned i;
9397ce6ce51Smrg 	const rk_data *rd = sc->sc_rd;
94039e6bc2cSmrg 
9417ce6ce51Smrg 	for (i = 1; i < rd->rd_size; i++) {
9427ce6ce51Smrg 		if (rd->rd_array[i].temp >= temp) {
9436bc30fa4Smrg 			int temprange, tempdiff;
9446bc30fa4Smrg 			uint32_t datarange, offset;
945863b2b98Smrg 			unsigned first, secnd;
9466bc30fa4Smrg 
9477ce6ce51Smrg 			if (rd->rd_array[i].temp == temp)
9487ce6ce51Smrg 				return rd->rd_array[i].data;
9496bc30fa4Smrg 
9506bc30fa4Smrg 			/* must interpolate */
9517ce6ce51Smrg 			if (rd->rd_decr) {
952863b2b98Smrg 				first = i;
953863b2b98Smrg 				secnd = i+1;
954863b2b98Smrg 			} else {
955863b2b98Smrg 				first = i;
956863b2b98Smrg 				secnd = i-1;
957863b2b98Smrg 			}
958863b2b98Smrg 
9597ce6ce51Smrg 			datarange = rd->rd_array[first].data -
9607ce6ce51Smrg 				    rd->rd_array[secnd].data;
9617ce6ce51Smrg 			temprange = rd->rd_array[first].temp -
9627ce6ce51Smrg 				    rd->rd_array[secnd].temp;
9637ce6ce51Smrg 			tempdiff = temp - rd->rd_array[secnd].temp;
9646bc30fa4Smrg 
9656bc30fa4Smrg 			offset = (datarange * tempdiff) / temprange;
9667ce6ce51Smrg 			return rd->rd_array[secnd].data + offset;
96739e6bc2cSmrg 		}
96839e6bc2cSmrg 	}
96939e6bc2cSmrg 
97039e6bc2cSmrg 	return sc->sc_data_mask;
97139e6bc2cSmrg }
972