linux/drivers/thermal/qcom/tsens-8960.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
   3 *
   4 * This program is free software; you can redistribute it and/or modify
   5 * it under the terms of the GNU General Public License version 2 and
   6 * only version 2 as published by the Free Software Foundation.
   7 *
   8 * This program is distributed in the hope that it will be useful,
   9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11 * GNU General Public License for more details.
  12 *
  13 */
  14
  15#include <linux/platform_device.h>
  16#include <linux/delay.h>
  17#include <linux/bitops.h>
  18#include <linux/regmap.h>
  19#include <linux/thermal.h>
  20#include "tsens.h"
  21
  22#define CAL_MDEGC               30000
  23
  24#define CONFIG_ADDR             0x3640
  25#define CONFIG_ADDR_8660        0x3620
  26/* CONFIG_ADDR bitmasks */
  27#define CONFIG                  0x9b
  28#define CONFIG_MASK             0xf
  29#define CONFIG_8660             1
  30#define CONFIG_SHIFT_8660       28
  31#define CONFIG_MASK_8660        (3 << CONFIG_SHIFT_8660)
  32
  33#define STATUS_CNTL_ADDR_8064   0x3660
  34#define CNTL_ADDR               0x3620
  35/* CNTL_ADDR bitmasks */
  36#define EN                      BIT(0)
  37#define SW_RST                  BIT(1)
  38#define SENSOR0_EN              BIT(3)
  39#define SLP_CLK_ENA             BIT(26)
  40#define SLP_CLK_ENA_8660        BIT(24)
  41#define MEASURE_PERIOD          1
  42#define SENSOR0_SHIFT           3
  43
  44/* INT_STATUS_ADDR bitmasks */
  45#define MIN_STATUS_MASK         BIT(0)
  46#define LOWER_STATUS_CLR        BIT(1)
  47#define UPPER_STATUS_CLR        BIT(2)
  48#define MAX_STATUS_MASK         BIT(3)
  49
  50#define THRESHOLD_ADDR          0x3624
  51/* THRESHOLD_ADDR bitmasks */
  52#define THRESHOLD_MAX_LIMIT_SHIFT       24
  53#define THRESHOLD_MIN_LIMIT_SHIFT       16
  54#define THRESHOLD_UPPER_LIMIT_SHIFT     8
  55#define THRESHOLD_LOWER_LIMIT_SHIFT     0
  56
  57/* Initial temperature threshold values */
  58#define LOWER_LIMIT_TH          0x50
  59#define UPPER_LIMIT_TH          0xdf
  60#define MIN_LIMIT_TH            0x0
  61#define MAX_LIMIT_TH            0xff
  62
  63#define S0_STATUS_ADDR          0x3628
  64#define INT_STATUS_ADDR         0x363c
  65#define TRDY_MASK               BIT(7)
  66#define TIMEOUT_US              100
  67
  68static int suspend_8960(struct tsens_device *tmdev)
  69{
  70        int ret;
  71        unsigned int mask;
  72        struct regmap *map = tmdev->map;
  73
  74        ret = regmap_read(map, THRESHOLD_ADDR, &tmdev->ctx.threshold);
  75        if (ret)
  76                return ret;
  77
  78        ret = regmap_read(map, CNTL_ADDR, &tmdev->ctx.control);
  79        if (ret)
  80                return ret;
  81
  82        if (tmdev->num_sensors > 1)
  83                mask = SLP_CLK_ENA | EN;
  84        else
  85                mask = SLP_CLK_ENA_8660 | EN;
  86
  87        ret = regmap_update_bits(map, CNTL_ADDR, mask, 0);
  88        if (ret)
  89                return ret;
  90
  91        return 0;
  92}
  93
  94static int resume_8960(struct tsens_device *tmdev)
  95{
  96        int ret;
  97        struct regmap *map = tmdev->map;
  98
  99        ret = regmap_update_bits(map, CNTL_ADDR, SW_RST, SW_RST);
 100        if (ret)
 101                return ret;
 102
 103        /*
 104         * Separate CONFIG restore is not needed only for 8660 as
 105         * config is part of CTRL Addr and its restored as such
 106         */
 107        if (tmdev->num_sensors > 1) {
 108                ret = regmap_update_bits(map, CONFIG_ADDR, CONFIG_MASK, CONFIG);
 109                if (ret)
 110                        return ret;
 111        }
 112
 113        ret = regmap_write(map, THRESHOLD_ADDR, tmdev->ctx.threshold);
 114        if (ret)
 115                return ret;
 116
 117        ret = regmap_write(map, CNTL_ADDR, tmdev->ctx.control);
 118        if (ret)
 119                return ret;
 120
 121        return 0;
 122}
 123
 124static int enable_8960(struct tsens_device *tmdev, int id)
 125{
 126        int ret;
 127        u32 reg, mask;
 128
 129        ret = regmap_read(tmdev->map, CNTL_ADDR, &reg);
 130        if (ret)
 131                return ret;
 132
 133        mask = BIT(id + SENSOR0_SHIFT);
 134        ret = regmap_write(tmdev->map, CNTL_ADDR, reg | SW_RST);
 135        if (ret)
 136                return ret;
 137
 138        if (tmdev->num_sensors > 1)
 139                reg |= mask | SLP_CLK_ENA | EN;
 140        else
 141                reg |= mask | SLP_CLK_ENA_8660 | EN;
 142
 143        ret = regmap_write(tmdev->map, CNTL_ADDR, reg);
 144        if (ret)
 145                return ret;
 146
 147        return 0;
 148}
 149
 150static void disable_8960(struct tsens_device *tmdev)
 151{
 152        int ret;
 153        u32 reg_cntl;
 154        u32 mask;
 155
 156        mask = GENMASK(tmdev->num_sensors - 1, 0);
 157        mask <<= SENSOR0_SHIFT;
 158        mask |= EN;
 159
 160        ret = regmap_read(tmdev->map, CNTL_ADDR, &reg_cntl);
 161        if (ret)
 162                return;
 163
 164        reg_cntl &= ~mask;
 165
 166        if (tmdev->num_sensors > 1)
 167                reg_cntl &= ~SLP_CLK_ENA;
 168        else
 169                reg_cntl &= ~SLP_CLK_ENA_8660;
 170
 171        regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
 172}
 173
 174static int init_8960(struct tsens_device *tmdev)
 175{
 176        int ret, i;
 177        u32 reg_cntl;
 178
 179        tmdev->map = dev_get_regmap(tmdev->dev, NULL);
 180        if (!tmdev->map)
 181                return -ENODEV;
 182
 183        /*
 184         * The status registers for each sensor are discontiguous
 185         * because some SoCs have 5 sensors while others have more
 186         * but the control registers stay in the same place, i.e
 187         * directly after the first 5 status registers.
 188         */
 189        for (i = 0; i < tmdev->num_sensors; i++) {
 190                if (i >= 5)
 191                        tmdev->sensor[i].status = S0_STATUS_ADDR + 40;
 192                tmdev->sensor[i].status += i * 4;
 193        }
 194
 195        reg_cntl = SW_RST;
 196        ret = regmap_update_bits(tmdev->map, CNTL_ADDR, SW_RST, reg_cntl);
 197        if (ret)
 198                return ret;
 199
 200        if (tmdev->num_sensors > 1) {
 201                reg_cntl |= SLP_CLK_ENA | (MEASURE_PERIOD << 18);
 202                reg_cntl &= ~SW_RST;
 203                ret = regmap_update_bits(tmdev->map, CONFIG_ADDR,
 204                                         CONFIG_MASK, CONFIG);
 205        } else {
 206                reg_cntl |= SLP_CLK_ENA_8660 | (MEASURE_PERIOD << 16);
 207                reg_cntl &= ~CONFIG_MASK_8660;
 208                reg_cntl |= CONFIG_8660 << CONFIG_SHIFT_8660;
 209        }
 210
 211        reg_cntl |= GENMASK(tmdev->num_sensors - 1, 0) << SENSOR0_SHIFT;
 212        ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
 213        if (ret)
 214                return ret;
 215
 216        reg_cntl |= EN;
 217        ret = regmap_write(tmdev->map, CNTL_ADDR, reg_cntl);
 218        if (ret)
 219                return ret;
 220
 221        return 0;
 222}
 223
 224static int calibrate_8960(struct tsens_device *tmdev)
 225{
 226        int i;
 227        char *data;
 228
 229        ssize_t num_read = tmdev->num_sensors;
 230        struct tsens_sensor *s = tmdev->sensor;
 231
 232        data = qfprom_read(tmdev->dev, "calib");
 233        if (IS_ERR(data))
 234                data = qfprom_read(tmdev->dev, "calib_backup");
 235        if (IS_ERR(data))
 236                return PTR_ERR(data);
 237
 238        for (i = 0; i < num_read; i++, s++)
 239                s->offset = data[i];
 240
 241        return 0;
 242}
 243
 244/* Temperature on y axis and ADC-code on x-axis */
 245static inline int code_to_mdegC(u32 adc_code, const struct tsens_sensor *s)
 246{
 247        int slope, offset;
 248
 249        slope = thermal_zone_get_slope(s->tzd);
 250        offset = CAL_MDEGC - slope * s->offset;
 251
 252        return adc_code * slope + offset;
 253}
 254
 255static int get_temp_8960(struct tsens_device *tmdev, int id, int *temp)
 256{
 257        int ret;
 258        u32 code, trdy;
 259        const struct tsens_sensor *s = &tmdev->sensor[id];
 260        unsigned long timeout;
 261
 262        timeout = jiffies + usecs_to_jiffies(TIMEOUT_US);
 263        do {
 264                ret = regmap_read(tmdev->map, INT_STATUS_ADDR, &trdy);
 265                if (ret)
 266                        return ret;
 267                if (!(trdy & TRDY_MASK))
 268                        continue;
 269                ret = regmap_read(tmdev->map, s->status, &code);
 270                if (ret)
 271                        return ret;
 272                *temp = code_to_mdegC(code, s);
 273                return 0;
 274        } while (time_before(jiffies, timeout));
 275
 276        return -ETIMEDOUT;
 277}
 278
 279static const struct tsens_ops ops_8960 = {
 280        .init           = init_8960,
 281        .calibrate      = calibrate_8960,
 282        .get_temp       = get_temp_8960,
 283        .enable         = enable_8960,
 284        .disable        = disable_8960,
 285        .suspend        = suspend_8960,
 286        .resume         = resume_8960,
 287};
 288
 289const struct tsens_data data_8960 = {
 290        .num_sensors    = 11,
 291        .ops            = &ops_8960,
 292};
 293