12d71d8deSAmit Kucheria // SPDX-License-Identifier: GPL-2.0 220d4fd84SRajendra Nayak /* 320d4fd84SRajendra Nayak * Copyright (c) 2015, The Linux Foundation. All rights reserved. 420d4fd84SRajendra Nayak */ 520d4fd84SRajendra Nayak 620d4fd84SRajendra Nayak #include <linux/platform_device.h> 720d4fd84SRajendra Nayak #include <linux/delay.h> 820d4fd84SRajendra Nayak #include <linux/bitops.h> 920d4fd84SRajendra Nayak #include <linux/regmap.h> 1020d4fd84SRajendra Nayak #include <linux/thermal.h> 1120d4fd84SRajendra Nayak #include "tsens.h" 1220d4fd84SRajendra Nayak 1320d4fd84SRajendra Nayak #define CAL_MDEGC 30000 1420d4fd84SRajendra Nayak 1520d4fd84SRajendra Nayak #define CONFIG_ADDR 0x3640 1620d4fd84SRajendra Nayak #define CONFIG_ADDR_8660 0x3620 1720d4fd84SRajendra Nayak /* CONFIG_ADDR bitmasks */ 1820d4fd84SRajendra Nayak #define CONFIG 0x9b 1920d4fd84SRajendra Nayak #define CONFIG_MASK 0xf 2020d4fd84SRajendra Nayak #define CONFIG_8660 1 2120d4fd84SRajendra Nayak #define CONFIG_SHIFT_8660 28 2220d4fd84SRajendra Nayak #define CONFIG_MASK_8660 (3 << CONFIG_SHIFT_8660) 2320d4fd84SRajendra Nayak 2420d4fd84SRajendra Nayak #define STATUS_CNTL_ADDR_8064 0x3660 2520d4fd84SRajendra Nayak #define CNTL_ADDR 0x3620 2620d4fd84SRajendra Nayak /* CNTL_ADDR bitmasks */ 2720d4fd84SRajendra Nayak #define EN BIT(0) 2820d4fd84SRajendra Nayak #define SW_RST BIT(1) 2920d4fd84SRajendra Nayak #define SENSOR0_EN BIT(3) 3020d4fd84SRajendra Nayak #define SLP_CLK_ENA BIT(26) 3120d4fd84SRajendra Nayak #define SLP_CLK_ENA_8660 BIT(24) 3220d4fd84SRajendra Nayak #define MEASURE_PERIOD 1 3320d4fd84SRajendra Nayak #define SENSOR0_SHIFT 3 3420d4fd84SRajendra Nayak 3520d4fd84SRajendra Nayak /* INT_STATUS_ADDR bitmasks */ 3620d4fd84SRajendra Nayak #define MIN_STATUS_MASK BIT(0) 3720d4fd84SRajendra Nayak #define LOWER_STATUS_CLR BIT(1) 3820d4fd84SRajendra Nayak #define UPPER_STATUS_CLR BIT(2) 3920d4fd84SRajendra Nayak #define MAX_STATUS_MASK BIT(3) 4020d4fd84SRajendra Nayak 4120d4fd84SRajendra Nayak #define THRESHOLD_ADDR 0x3624 4220d4fd84SRajendra Nayak /* THRESHOLD_ADDR bitmasks */ 4320d4fd84SRajendra Nayak #define THRESHOLD_MAX_LIMIT_SHIFT 24 4420d4fd84SRajendra Nayak #define THRESHOLD_MIN_LIMIT_SHIFT 16 4520d4fd84SRajendra Nayak #define THRESHOLD_UPPER_LIMIT_SHIFT 8 4620d4fd84SRajendra Nayak #define THRESHOLD_LOWER_LIMIT_SHIFT 0 4720d4fd84SRajendra Nayak 4820d4fd84SRajendra Nayak /* Initial temperature threshold values */ 4920d4fd84SRajendra Nayak #define LOWER_LIMIT_TH 0x50 5020d4fd84SRajendra Nayak #define UPPER_LIMIT_TH 0xdf 5120d4fd84SRajendra Nayak #define MIN_LIMIT_TH 0x0 5220d4fd84SRajendra Nayak #define MAX_LIMIT_TH 0xff 5320d4fd84SRajendra Nayak 5420d4fd84SRajendra Nayak #define S0_STATUS_ADDR 0x3628 5520d4fd84SRajendra Nayak #define INT_STATUS_ADDR 0x363c 5620d4fd84SRajendra Nayak #define TRDY_MASK BIT(7) 5720d4fd84SRajendra Nayak #define TIMEOUT_US 100 5820d4fd84SRajendra Nayak 5920d4fd84SRajendra Nayak static int suspend_8960(struct tsens_device *tmdev) 6020d4fd84SRajendra Nayak { 6120d4fd84SRajendra Nayak int ret; 6220d4fd84SRajendra Nayak unsigned int mask; 6367b0f5e0SAmit Kucheria struct regmap *map = tmdev->tm_map; 6420d4fd84SRajendra Nayak 6520d4fd84SRajendra Nayak ret = regmap_read(map, THRESHOLD_ADDR, &tmdev->ctx.threshold); 6620d4fd84SRajendra Nayak if (ret) 6720d4fd84SRajendra Nayak return ret; 6820d4fd84SRajendra Nayak 6920d4fd84SRajendra Nayak ret = regmap_read(map, CNTL_ADDR, &tmdev->ctx.control); 7020d4fd84SRajendra Nayak if (ret) 7120d4fd84SRajendra Nayak return ret; 7220d4fd84SRajendra Nayak 7320d4fd84SRajendra Nayak if (tmdev->num_sensors > 1) 7420d4fd84SRajendra Nayak mask = SLP_CLK_ENA | EN; 7520d4fd84SRajendra Nayak else 7620d4fd84SRajendra Nayak mask = SLP_CLK_ENA_8660 | EN; 7720d4fd84SRajendra Nayak 7820d4fd84SRajendra Nayak ret = regmap_update_bits(map, CNTL_ADDR, mask, 0); 7920d4fd84SRajendra Nayak if (ret) 8020d4fd84SRajendra Nayak return ret; 8120d4fd84SRajendra Nayak 8220d4fd84SRajendra Nayak return 0; 8320d4fd84SRajendra Nayak } 8420d4fd84SRajendra Nayak 8520d4fd84SRajendra Nayak static int resume_8960(struct tsens_device *tmdev) 8620d4fd84SRajendra Nayak { 8720d4fd84SRajendra Nayak int ret; 8867b0f5e0SAmit Kucheria struct regmap *map = tmdev->tm_map; 8920d4fd84SRajendra Nayak 9020d4fd84SRajendra Nayak ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST); 9120d4fd84SRajendra Nayak if (ret) 9220d4fd84SRajendra Nayak return ret; 9320d4fd84SRajendra Nayak 9420d4fd84SRajendra Nayak /* 9520d4fd84SRajendra Nayak * Separate CONFIG restore is not needed only for 8660 as 9620d4fd84SRajendra Nayak * config is part of CTRL Addr and its restored as such 9720d4fd84SRajendra Nayak */ 9820d4fd84SRajendra Nayak if (tmdev->num_sensors > 1) { 9920d4fd84SRajendra Nayak ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG); 10020d4fd84SRajendra Nayak if (ret) 10120d4fd84SRajendra Nayak return ret; 10220d4fd84SRajendra Nayak } 10320d4fd84SRajendra Nayak 10420d4fd84SRajendra Nayak ret = regmap_write(map, THRESHOLD_ADDR, tmdev->ctx.threshold); 10520d4fd84SRajendra Nayak if (ret) 10620d4fd84SRajendra Nayak return ret; 10720d4fd84SRajendra Nayak 10820d4fd84SRajendra Nayak ret = regmap_write(map, CNTL_ADDR, tmdev->ctx.control); 10920d4fd84SRajendra Nayak if (ret) 11020d4fd84SRajendra Nayak return ret; 11120d4fd84SRajendra Nayak 11220d4fd84SRajendra Nayak return 0; 11320d4fd84SRajendra Nayak } 11420d4fd84SRajendra Nayak 11520d4fd84SRajendra Nayak static int enable_8960(struct tsens_device *tmdev, int id) 11620d4fd84SRajendra Nayak { 11720d4fd84SRajendra Nayak int ret; 11820d4fd84SRajendra Nayak u32 reg, mask; 11920d4fd84SRajendra Nayak 12067b0f5e0SAmit Kucheria ret = regmap_read(tmdev->tm_map, CNTL_ADDR, ®); 12120d4fd84SRajendra Nayak if (ret) 12220d4fd84SRajendra Nayak return ret; 12320d4fd84SRajendra Nayak 12420d4fd84SRajendra Nayak mask = BIT(id + SENSOR0_SHIFT); 12567b0f5e0SAmit Kucheria ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg | SW_RST); 12620d4fd84SRajendra Nayak if (ret) 12720d4fd84SRajendra Nayak return ret; 12820d4fd84SRajendra Nayak 12920d4fd84SRajendra Nayak if (tmdev->num_sensors > 1) 13020d4fd84SRajendra Nayak reg |= mask | SLP_CLK_ENA | EN; 13120d4fd84SRajendra Nayak else 13220d4fd84SRajendra Nayak reg |= mask | SLP_CLK_ENA_8660 | EN; 13320d4fd84SRajendra Nayak 13467b0f5e0SAmit Kucheria ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg); 13520d4fd84SRajendra Nayak if (ret) 13620d4fd84SRajendra Nayak return ret; 13720d4fd84SRajendra Nayak 13820d4fd84SRajendra Nayak return 0; 13920d4fd84SRajendra Nayak } 14020d4fd84SRajendra Nayak 14120d4fd84SRajendra Nayak static void disable_8960(struct tsens_device *tmdev) 14220d4fd84SRajendra Nayak { 14320d4fd84SRajendra Nayak int ret; 14420d4fd84SRajendra Nayak u32 reg_cntl; 14520d4fd84SRajendra Nayak u32 mask; 14620d4fd84SRajendra Nayak 14720d4fd84SRajendra Nayak mask = GENMASK(tmdev->num_sensors - 1, 0); 14820d4fd84SRajendra Nayak mask <<= SENSOR0_SHIFT; 14920d4fd84SRajendra Nayak mask |= EN; 15020d4fd84SRajendra Nayak 15167b0f5e0SAmit Kucheria ret = regmap_read(tmdev->tm_map, CNTL_ADDR, ®_cntl); 15220d4fd84SRajendra Nayak if (ret) 15320d4fd84SRajendra Nayak return; 15420d4fd84SRajendra Nayak 15520d4fd84SRajendra Nayak reg_cntl &= ~mask; 15620d4fd84SRajendra Nayak 15720d4fd84SRajendra Nayak if (tmdev->num_sensors > 1) 15820d4fd84SRajendra Nayak reg_cntl &= ~SLP_CLK_ENA; 15920d4fd84SRajendra Nayak else 16020d4fd84SRajendra Nayak reg_cntl &= ~SLP_CLK_ENA_8660; 16120d4fd84SRajendra Nayak 16267b0f5e0SAmit Kucheria regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl); 16320d4fd84SRajendra Nayak } 16420d4fd84SRajendra Nayak 16520d4fd84SRajendra Nayak static int init_8960(struct tsens_device *tmdev) 16620d4fd84SRajendra Nayak { 16720d4fd84SRajendra Nayak int ret, i; 16820d4fd84SRajendra Nayak u32 reg_cntl; 16920d4fd84SRajendra Nayak 17067b0f5e0SAmit Kucheria tmdev->tm_map = dev_get_regmap(tmdev->dev, NULL); 17167b0f5e0SAmit Kucheria if (!tmdev->tm_map) 17220d4fd84SRajendra Nayak return -ENODEV; 17320d4fd84SRajendra Nayak 17420d4fd84SRajendra Nayak /* 17520d4fd84SRajendra Nayak * The status registers for each sensor are discontiguous 17620d4fd84SRajendra Nayak * because some SoCs have 5 sensors while others have more 17720d4fd84SRajendra Nayak * but the control registers stay in the same place, i.e 17820d4fd84SRajendra Nayak * directly after the first 5 status registers. 17920d4fd84SRajendra Nayak */ 18020d4fd84SRajendra Nayak for (i = 0; i < tmdev->num_sensors; i++) { 18120d4fd84SRajendra Nayak if (i >= 5) 18220d4fd84SRajendra Nayak tmdev->sensor[i].status = S0_STATUS_ADDR + 40; 18320d4fd84SRajendra Nayak tmdev->sensor[i].status += i * 4; 18420d4fd84SRajendra Nayak } 18520d4fd84SRajendra Nayak 18620d4fd84SRajendra Nayak reg_cntl = SW_RST; 18767b0f5e0SAmit Kucheria ret = regmap_update_bits(tmdev->tm_map, CNTL_ADDR, SW_RST, reg_cntl); 18820d4fd84SRajendra Nayak if (ret) 18920d4fd84SRajendra Nayak return ret; 19020d4fd84SRajendra Nayak 19120d4fd84SRajendra Nayak if (tmdev->num_sensors > 1) { 19220d4fd84SRajendra Nayak reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18); 19320d4fd84SRajendra Nayak reg_cntl &= ~SW_RST; 19467b0f5e0SAmit Kucheria ret = regmap_update_bits(tmdev->tm_map, CONFIG_ADDR, 19520d4fd84SRajendra Nayak CONFIG_MASK, CONFIG); 19620d4fd84SRajendra Nayak } else { 19720d4fd84SRajendra Nayak reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16); 19820d4fd84SRajendra Nayak reg_cntl &= ~CONFIG_MASK_8660; 19920d4fd84SRajendra Nayak reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660; 20020d4fd84SRajendra Nayak } 20120d4fd84SRajendra Nayak 20220d4fd84SRajendra Nayak reg_cntl |= GENMASK(tmdev->num_sensors - 1, 0) << SENSOR0_SHIFT; 20367b0f5e0SAmit Kucheria ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl); 20420d4fd84SRajendra Nayak if (ret) 20520d4fd84SRajendra Nayak return ret; 20620d4fd84SRajendra Nayak 20720d4fd84SRajendra Nayak reg_cntl |= EN; 20867b0f5e0SAmit Kucheria ret = regmap_write(tmdev->tm_map, CNTL_ADDR, reg_cntl); 20920d4fd84SRajendra Nayak if (ret) 21020d4fd84SRajendra Nayak return ret; 21120d4fd84SRajendra Nayak 21220d4fd84SRajendra Nayak return 0; 21320d4fd84SRajendra Nayak } 21420d4fd84SRajendra Nayak 21520d4fd84SRajendra Nayak static int calibrate_8960(struct tsens_device *tmdev) 21620d4fd84SRajendra Nayak { 21720d4fd84SRajendra Nayak int i; 21820d4fd84SRajendra Nayak char *data; 21920d4fd84SRajendra Nayak 22020d4fd84SRajendra Nayak ssize_t num_read = tmdev->num_sensors; 22120d4fd84SRajendra Nayak struct tsens_sensor *s = tmdev->sensor; 22220d4fd84SRajendra Nayak 22320d4fd84SRajendra Nayak data = qfprom_read(tmdev->dev, "calib"); 22420d4fd84SRajendra Nayak if (IS_ERR(data)) 22520d4fd84SRajendra Nayak data = qfprom_read(tmdev->dev, "calib_backup"); 22620d4fd84SRajendra Nayak if (IS_ERR(data)) 22720d4fd84SRajendra Nayak return PTR_ERR(data); 22820d4fd84SRajendra Nayak 22920d4fd84SRajendra Nayak for (i = 0; i < num_read; i++, s++) 23020d4fd84SRajendra Nayak s->offset = data[i]; 23120d4fd84SRajendra Nayak 23220d4fd84SRajendra Nayak return 0; 23320d4fd84SRajendra Nayak } 23420d4fd84SRajendra Nayak 23520d4fd84SRajendra Nayak /* Temperature on y axis and ADC-code on x-axis */ 23620d4fd84SRajendra Nayak static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s) 23720d4fd84SRajendra Nayak { 23820d4fd84SRajendra Nayak int slope, offset; 23920d4fd84SRajendra Nayak 24020d4fd84SRajendra Nayak slope = thermal_zone_get_slope(s->tzd); 24120d4fd84SRajendra Nayak offset = CAL_MDEGC - slope * s->offset; 24220d4fd84SRajendra Nayak 24320d4fd84SRajendra Nayak return adc_code * slope + offset; 24420d4fd84SRajendra Nayak } 24520d4fd84SRajendra Nayak 24620d4fd84SRajendra Nayak static int get_temp_8960(struct tsens_device *tmdev, int id, int *temp) 24720d4fd84SRajendra Nayak { 24820d4fd84SRajendra Nayak int ret; 24920d4fd84SRajendra Nayak u32 code, trdy; 25020d4fd84SRajendra Nayak const struct tsens_sensor *s = &tmdev->sensor[id]; 25120d4fd84SRajendra Nayak unsigned long timeout; 25220d4fd84SRajendra Nayak 25320d4fd84SRajendra Nayak timeout = jiffies + usecs_to_jiffies(TIMEOUT_US); 25420d4fd84SRajendra Nayak do { 25567b0f5e0SAmit Kucheria ret = regmap_read(tmdev->tm_map, INT_STATUS_ADDR, &trdy); 25620d4fd84SRajendra Nayak if (ret) 25720d4fd84SRajendra Nayak return ret; 25820d4fd84SRajendra Nayak if (!(trdy & TRDY_MASK)) 25920d4fd84SRajendra Nayak continue; 26067b0f5e0SAmit Kucheria ret = regmap_read(tmdev->tm_map, s->status, &code); 26120d4fd84SRajendra Nayak if (ret) 26220d4fd84SRajendra Nayak return ret; 26320d4fd84SRajendra Nayak *temp = code_to_mdegC(code, s); 26420d4fd84SRajendra Nayak return 0; 26520d4fd84SRajendra Nayak } while (time_before(jiffies, timeout)); 26620d4fd84SRajendra Nayak 26720d4fd84SRajendra Nayak return -ETIMEDOUT; 26820d4fd84SRajendra Nayak } 26920d4fd84SRajendra Nayak 270032d4057SEduardo Valentin static const struct tsens_ops ops_8960 = { 27120d4fd84SRajendra Nayak .init = init_8960, 27220d4fd84SRajendra Nayak .calibrate = calibrate_8960, 27320d4fd84SRajendra Nayak .get_temp = get_temp_8960, 27420d4fd84SRajendra Nayak .enable = enable_8960, 27520d4fd84SRajendra Nayak .disable = disable_8960, 27620d4fd84SRajendra Nayak .suspend = suspend_8960, 27720d4fd84SRajendra Nayak .resume = resume_8960, 27820d4fd84SRajendra Nayak }; 27920d4fd84SRajendra Nayak 2803c040ce0SAmit Kucheria const struct tsens_plat_data data_8960 = { 28120d4fd84SRajendra Nayak .num_sensors = 11, 28220d4fd84SRajendra Nayak .ops = &ops_8960, 28320d4fd84SRajendra Nayak }; 284