diff --git a/drivers/thermal/rk3368_thermal.c b/drivers/thermal/rk3368_thermal.c deleted file mode 100644 index 84a2cc70f8d1..000000000000 --- a/drivers/thermal/rk3368_thermal.c +++ /dev/null @@ -1,1180 +0,0 @@ -/* - * Copyright (c) 2017, Fuzhou Rockchip Electronics Co., Ltd - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * If the temperature over a period of time High, - * the resulting TSHUT gave CRU module,let it reset the entire chip, - * or via GPIO give PMIC. - */ -enum tshut_mode { - TSHUT_MODE_CRU = 0, - TSHUT_MODE_GPIO, -}; - -enum tsadc_mode { - TSADC_AUTO_MODE = 0, - TSHUT_USER_MODE, -}; - -/** - * the system Temperature Sensors tshut(tshut) polarity - * the bit 8 is tshut polarity. - * 0: low active, 1: high active - */ -enum tshut_polarity { - TSHUT_LOW_ACTIVE = 0, - TSHUT_HIGH_ACTIVE, -}; - -#define NUM_SENSORS 2 - -/* TSADC V2 Sensor info define: */ -#define TSADCV2_USER_CON 0x00 -#define TSADCV2_AUTO_CON 0x04 -#define TSADCV2_INT_EN 0x08 -#define TSADCV2_INT_PD 0x0c -#define TSADCV2_DATA(chn) (0x20 + (chn) * 0x04) - -#define TSADC_CLK_CYCLE_TIME 32 /* usec */ -#define TSADCV3_DATA_MASK 0x3ff - -/** - * The conversion table has the adc value and temperature. - * ADC_DECREMENT: the adc value is of diminishing.(e.g. rk3288_code_table) - * ADC_INCREMENT: the adc value is incremental.(e.g. rk3368_code_table) - */ -enum adc_sort_mode { - ADC_DECREMENT = 0, - ADC_INCREMENT, -}; - -#define TIME_OUT_TOTAL 2000 -#define INVALID_EFUSE_VALUE 0xff - -enum { - ACCESS_FORBIDDEN = 0, -}; - -#define MIN_TEMP (-40000) -#define MAX_TEMP (125000) -#define INVALID_TEMP INT_MAX - -#define BASE (1024) -#define BASE_SHIFT (10) -#define START_BOUNDING_COUNT (100) -#define HIGHER_BOUNDING_TEMP (30) -#define LOWER_BOUNDING_TEMP (15) - -/** - * struct tsadc_table - hold information about code and temp mapping - * @code: raw code from tsadc ip - * @temp: the mapping temperature - */ - -struct tsadc_table { - unsigned long code; - int temp; -}; - -/** - * struct chip_tsadc_table - hold information about chip-specific differences - * @id: conversion table - * @length: size of conversion table - * @data_mask: mask to apply on data inputs - * @mode: sort mode of this adc variant (incrementing or decrementing) - */ -struct chip_tsadc_table { - const struct tsadc_table *id; - unsigned int length; - u32 data_mask; - enum adc_sort_mode mode; -}; - -/** - * struct rk3368_tsadc_chip - hold the private data of tsadc chip - * @chn_id[SOC_MAX_SENSORS]: the sensor id of chip correspond to the channel - * @chn_num: the channel number of tsadc chip - * @tshut_temp: the hardware-controlled shutdown temperature value - * @tshut_mode: the hardware-controlled shutdown mode (0:CRU 1:GPIO) - * @tshut_polarity: the hardware-controlled active polarity (0:LOW 1:HIGH) - * @chip_tsadc_table: the chip-specific conversion table - * @get_temp: get the temperature - * @set_alarm_temp: set the high temperature interrupt - * @set_tshut_temp: set the hardware-controlled shutdown temperature - * @set_tshut_mode: set the hardware-controlled shutdown mode - */ -struct rk3368_tsadc_chip { - int chn_id[NUM_SENSORS]; - int chn_num; - long hw_shut_temp; - enum tshut_mode tshut_mode; - enum tsadc_mode mode; - enum tshut_polarity tshut_polarity; - int latency_bound; - - const struct chip_tsadc_table *temp_table; - - /* Per-sensor methods */ - int (*get_temp)(const struct chip_tsadc_table *table, - int chn, void __iomem *reg, int *temp); - void (*set_alarm_temp)(const struct chip_tsadc_table *table, - int chn, void __iomem *reg, int temp); - void (*set_tshut_temp)(const struct chip_tsadc_table *table, - int chn, void __iomem *reg, int temp); - void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m); -}; - -/** - * struct rk3368_thermal_sensor - hold the information of thermal sensor - * @ctx: pointer to the platform/configuration data - * @tzd: pointer to a thermal zone - * @id: identifier of the thermal sensor - */ -struct rk3368_thermal_sensor { - struct rk3368_thermal_data *ctx; - struct thermal_zone_device *tzd; - int id; -}; - -/** - * struct rk3368_thermal_data - hold the private data of thermal driver - * @chip: pointer to the platform/configuration data - * @pdev: platform device of thermal - * @reset: the reset controller of tsadc - * @sensors[SOC_MAX_SENSORS]: the thermal sensor - * @clk: the controller clock is divided by the external 24MHz - * @pclk: the advanced peripherals bus clock - * @regs: the base address of tsadc controller - * @tshut_temp: the hardware-controlled shutdown temperature value - * @tshut_mode: the hardware-controlled shutdown mode (0:CRU 1:GPIO) - * @tshut_polarity: the hardware-controlled active polarity (0:LOW 1:HIGH) - * @cpu_temp_adjust: efuse value used to ajust the temperature - * @gpu_temp_adjust: efuse value used to ajust the temperature - * @cpu_temp: the current cpu's temperature - * @logout: switch to control log output or not - * @rk3368_thermal_kobj: node in sys fs - */ -struct rk3368_thermal_data { - const struct rk3368_tsadc_chip *chip; - struct platform_device *pdev; - struct reset_control *reset; - - struct rk3368_thermal_sensor sensors[NUM_SENSORS]; - - struct clk *clk; - struct clk *pclk; - void __iomem *regs; - - long hw_shut_temp; - enum tshut_mode tshut_mode; - enum tshut_polarity tshut_polarity; - - int cpu_temp_adjust; - int gpu_temp_adjust; - int cpu_temp; - bool logout; - struct kobject *rk3368_thermal_kobj; - struct regulator *ref_regulator; - int regulator_uv; - int latency_req; - int latency_bound; - struct notifier_block tsadc_nb; -}; - -static struct rk3368_thermal_data *thermal_ctx; - -static DEFINE_MUTEX(thermal_reg_mutex); - -static DEFINE_MUTEX(thermal_lat_mutex); - -static const struct tsadc_table code_table_3368[] = { - {0, MIN_TEMP}, - {106, MIN_TEMP}, - {108, -35000}, - {110, -30000}, - {112, -25000}, - {114, -20000}, - {116, -15000}, - {118, -10000}, - {120, -5000}, - {122, 0}, - {124, 5000}, - {126, 10000}, - {128, 15000}, - {130, 20000}, - {132, 25000}, - {134, 30000}, - {136, 35000}, - {138, 40000}, - {140, 45000}, - {142, 50000}, - {144, 55000}, - {146, 60000}, - {148, 65000}, - {150, 70000}, - {152, 75000}, - {154, 80000}, - {156, 85000}, - {158, 90000}, - {160, 95000}, - {162, 100000}, - {163, 105000}, - {165, 110000}, - {167, 115000}, - {169, 120000}, - {171, MAX_TEMP}, - {TSADCV3_DATA_MASK, MAX_TEMP}, -}; - -static const struct chip_tsadc_table tsadc_table_3368 = { - .id = code_table_3368, - .length = ARRAY_SIZE(code_table_3368), - .data_mask = TSADCV3_DATA_MASK, - .mode = ADC_INCREMENT, -}; - -static int rk3368_get_ajust_code(struct device_node *np, int *ajust_code) -{ - struct nvmem_cell *cell; - unsigned char *buf; - size_t len; - - cell = of_nvmem_cell_get(np, "temp_adjust"); - if (IS_ERR(cell)) { - pr_err("avs failed to get temp_adjust cell\n"); - return PTR_ERR(cell); - } - - buf = (unsigned char *)nvmem_cell_read(cell, &len); - - nvmem_cell_put(cell); - - if (IS_ERR(buf)) - return PTR_ERR(buf); - - if (buf[0] == INVALID_EFUSE_VALUE) - return -EINVAL; - - if (buf[0] & 0x80) - *ajust_code = -(buf[0] & 0x7f); - else - *ajust_code = buf[0]; - - kfree(buf); - - return 0; -} - -static struct rk3368_thermal_data *rk3368_thermal_get_data(void) -{ - WARN_ON(!thermal_ctx); - return thermal_ctx; -} - -static int rk3368_temp_to_code(const struct chip_tsadc_table *tmp_table, - long temp, u32 *code) -{ - unsigned int low = 1; - unsigned int high = tmp_table->length - 1; - unsigned int mid = (low + high) / 2; - unsigned int num; - unsigned long denom; - *code = tmp_table->data_mask; - - WARN_ON(tmp_table->length < 2); - - if (temp < tmp_table->id[low].temp) - return -EAGAIN; /* Incorrect reading */ - - while (low <= high) { - if (temp == tmp_table->id[mid].temp) { - *code = tmp_table->id[mid].code; - break; - } else if (temp > tmp_table->id[mid].temp) { - low = mid + 1; - } else { - high = mid - 1; - } - - mid = (low + high) / 2; - } - /* - * The 5C granularity provided by the table is too much. Let's - * assume that the relationship between sensor readings and - * temperature between 2 table entries is linear and interpolate - * to produce less granular result. - */ - if (*code == tmp_table->data_mask) { - num = abs(tmp_table->id[low].code - tmp_table->id[high].code); - num *= abs(tmp_table->id[high].temp - temp); - denom = abs(tmp_table->id[high].temp - tmp_table->id[low].temp); - *code = tmp_table->id[high].code + (num / denom); - } - - return 0; -} - -static int rk3368_code_to_temp(const struct chip_tsadc_table *tmp_table, - u32 code, int *temp) -{ - unsigned int low = 1; - unsigned int high = tmp_table->length - 1; - unsigned int mid = (low + high) / 2; - unsigned int num; - unsigned long denom; - *temp = INVALID_TEMP; - - WARN_ON(tmp_table->length < 2); - - switch (tmp_table->mode) { - case ADC_DECREMENT: - code &= tmp_table->data_mask; - if (code < tmp_table->id[high].code) - return -EAGAIN; /* Incorrect reading */ - - while (low <= high) { - if (code == tmp_table->id[mid].code) { - *temp = tmp_table->id[mid].temp; - break; - } else if (code < tmp_table->id[mid].code) { - low = mid + 1; - } else { - high = mid - 1; - } - - mid = (low + high) / 2; - } - break; - case ADC_INCREMENT: - code &= tmp_table->data_mask; - if (code < tmp_table->id[low].code) - return -EAGAIN; /* Incorrect reading */ - - while (low <= high) { - if (code == tmp_table->id[mid].code) { - *temp = tmp_table->id[mid].temp; - break; - } else if (code > tmp_table->id[mid].code) { - low = mid + 1; - } else { - high = mid - 1; - } - - mid = (low + high) / 2; - } - break; - default: - pr_err("Invalid the conversion table\n"); - } - - /* - * The 5C granularity provided by the table is too much. Let's - * assume that the relationship between sensor readings and - * temperature between 2 table entries is linear and interpolate - * to produce less granular result. - */ - if (*temp == INVALID_TEMP) { - num = abs(tmp_table->id[low].temp - tmp_table->id[high].temp); - num *= abs(tmp_table->id[high].code - code); - denom = abs(tmp_table->id[high].code - tmp_table->id[low].code); - *temp = tmp_table->id[high].temp + (num / denom); - } - - return 0; -} - -static const struct rk3368_tsadc_chip rk3368_tsadc_data = { - .tshut_mode = TSHUT_MODE_GPIO, /* default TSHUT via GPIO give PMIC */ - .tshut_polarity = TSHUT_LOW_ACTIVE, /* default TSHUT LOW ACTIVE */ - .latency_bound = 50000, /* default 50000 us */ - .hw_shut_temp = 125000, - .mode = TSHUT_USER_MODE, - .chn_num = 2, - .chn_id[0] = 0, - .chn_id[1] = 1, - .temp_table = &tsadc_table_3368, -}; - -static int rk3368_configure_from_dt(struct device *dev, - struct device_node *np, - struct rk3368_thermal_data *thermal) -{ - u32 shut_temp; - u32 rate; - u32 cycle; - int lat_bound; - int ret; - - if (of_property_read_u32(np, "clock-frequency", &rate)) { - dev_err(dev, "Missing clock-frequency property in the DT.\n"); - return -EINVAL; - } - ret = clk_set_rate(thermal->clk, rate); - - cycle = DIV_ROUND_UP(1000000000, rate) / 1000; - - if (scpi_thermal_set_clk_cycle(cycle)) { - dev_err(dev, "scpi_thermal_set_clk_cycle error.\n"); - return -EINVAL; - } - - if (of_property_read_u32(np, "hw-shut-temp", &shut_temp)) { - dev_warn(dev, - "Missing tshut temp property, using default %ld\n", - thermal->chip->hw_shut_temp); - thermal->hw_shut_temp = thermal->chip->hw_shut_temp; - } else { - thermal->hw_shut_temp = shut_temp; - } - - if (of_property_read_u32(np, "latency-bound", &lat_bound)) { - dev_warn(dev, - "Missing latency-bound property, using default %d\n", - thermal->chip->latency_bound); - thermal->latency_bound = thermal->chip->latency_bound; - } else { - thermal->latency_bound = lat_bound; - } - - if (thermal->hw_shut_temp > INT_MAX) { - dev_err(dev, "Invalid tshut temperature specified: %ld\n", - thermal->hw_shut_temp); - return -ERANGE; - } - - return 0; -} - -static int predict_temp(int temp) -{ - int cov_q = 18; - int cov_r = 542; - - int gain; - int temp_mid; - int temp_now; - int prob_mid; - int prob_now; - static int temp_last = 25; - static int prob_last = 20; - static int bounding_cnt; - - struct rk3368_thermal_data *ctx = rk3368_thermal_get_data(); - - if (!ctx) - return INVALID_TEMP; - - if (bounding_cnt++ > START_BOUNDING_COUNT) { - bounding_cnt = START_BOUNDING_COUNT; - if (temp - temp_last > HIGHER_BOUNDING_TEMP) - temp = temp_last + HIGHER_BOUNDING_TEMP / 3; - if (temp_last - temp > LOWER_BOUNDING_TEMP) - temp = temp_last - LOWER_BOUNDING_TEMP / 3; - } - - temp_mid = temp_last; - prob_mid = prob_last + cov_q; - gain = (prob_mid * BASE) / (prob_mid + cov_r); - - temp_now = temp_mid + (gain * (temp - temp_mid) >> BASE_SHIFT); - prob_now = ((BASE - gain) * prob_mid) >> BASE_SHIFT; - - prob_last = prob_now; - temp_last = temp_now; - - if (ctx->logout) - pr_info("prob_now %d, temp_last %d, temp %d gain %d", prob_now, - temp_now, temp, gain); - - return temp_last; -} - -static int get_raw_code_internal(void) -{ - u32 val_cpu_pd; - int val_cpu = INVALID_TEMP; - int i; - struct rk3368_thermal_data *ctx = rk3368_thermal_get_data(); - - if (!ctx) - return INVALID_TEMP; - - /* power up, channel 0 */ - writel_relaxed(0x18, ctx->regs + TSADCV2_USER_CON); - - udelay(TSADC_CLK_CYCLE_TIME * 2); - /* start working */ - writel_relaxed(0x38, ctx->regs + TSADCV2_USER_CON); - udelay(TSADC_CLK_CYCLE_TIME * 13); - - /* try 50 times */ - for (i = 0; i < 50; i++) { - udelay(TSADC_CLK_CYCLE_TIME); - val_cpu_pd = readl_relaxed(ctx->regs + TSADCV2_INT_PD); - - if ((val_cpu_pd & 0x100) == 0x100) { - udelay(1); - /*clear eoc inter */ - writel_relaxed(0x100, ctx->regs + TSADCV2_INT_PD); - /*read adc data */ - val_cpu = readl_relaxed(ctx->regs + TSADCV2_DATA(0)); - break; - } - } - /*power down, channel 0 */ - writel_relaxed(0x0, ctx->regs + TSADCV2_USER_CON); - - return val_cpu; -} - -#define RAW_CODE_MIN (50) -#define RAW_CODE_MAX (225) - -static int rk3368_get_raw_code(struct rk3368_thermal_data *ctx) -{ - static int old_data = 130; - int tsadc_data = 0; - - if (ctx->latency_req > ctx->latency_bound) - tsadc_data = scpi_thermal_get_temperature(); - else - tsadc_data = get_raw_code_internal(); - - if ((tsadc_data < RAW_CODE_MIN) || (tsadc_data > RAW_CODE_MAX)) - tsadc_data = old_data; - else - old_data = tsadc_data; - - return tsadc_data; -} - -static int rk3368_convert_code_2_temp(int tsadc_data, int voltage) -{ - struct rk3368_thermal_data *ctx = rk3368_thermal_get_data(); - const struct rk3368_tsadc_chip *tsadc; - int out_temp; - static int old_temp; - int data_adjust; - - u32 code_temp; - u32 tmp_code1; - u32 tmp_code2; - - if (!ctx) - return INVALID_TEMP; - - tsadc = ctx->chip; - - rk3368_temp_to_code(tsadc->temp_table, - ctx->cpu_temp_adjust * 1000, &tmp_code1); - rk3368_temp_to_code(tsadc->temp_table, 0, &tmp_code2); - data_adjust = tmp_code1 - tmp_code2; - code_temp = - ((tsadc_data * voltage - data_adjust * 1000000) + 500000) / 1000000; - rk3368_code_to_temp(tsadc->temp_table, code_temp, &out_temp); - - if (ctx->logout) - pr_info("cpu code temp:[%d, %d], voltage: %d\n", - tsadc_data, out_temp / 1000, voltage); - - if ((out_temp < MIN_TEMP) || (out_temp > MAX_TEMP)) - out_temp = old_temp; - else - old_temp = out_temp; - - ctx->cpu_temp = out_temp / 1000; - return out_temp; -} - -static int rk3368_thermal_set_trips(void *_sensor, int low, int high) -{ - return 0; -} - -static int rk3368_thermal_get_temp(void *_sensor, int *out_temp) -{ - int raw_code; - int temp; - struct rk3368_thermal_data *ctx = rk3368_thermal_get_data(); - struct platform_device *pdev; - - if (!ctx) - return INVALID_TEMP; - - pdev = ctx->pdev; - - mutex_lock(&thermal_reg_mutex); - raw_code = rk3368_get_raw_code(ctx); - temp = rk3368_convert_code_2_temp(raw_code, ctx->regulator_uv); - *out_temp = predict_temp(temp / 1000) * 1000; - mutex_unlock(&thermal_reg_mutex); - - return 0; -} - -static const struct thermal_zone_of_device_ops rk3368_of_thermal_ops = { - .get_temp = rk3368_thermal_get_temp, - .set_trips = rk3368_thermal_set_trips, -}; - -static int -rk3368_thermal_register_sensor(struct platform_device *pdev, - struct rk3368_thermal_data *ctx, - struct rk3368_thermal_sensor *sensor, int id) -{ - int error; - - sensor->ctx = ctx; - sensor->id = id; - sensor->tzd = devm_thermal_zone_of_sensor_register(&pdev->dev, id, - sensor, - &rk3368_of_thermal_ops); - if (IS_ERR(sensor->tzd)) { - error = PTR_ERR(sensor->tzd); - dev_err(&pdev->dev, "failed to register sensor %d: %d\n", - id, error); - return error; - } - - return 0; -} - -/* - * Reset TSADC Controller, reset all tsadc registers. - */ -static void rk3368_thermal_reset_controller(struct reset_control *reset) -{ - reset_control_assert(reset); - udelay(10); - reset_control_deassert(reset); -} - -static ssize_t rk3368_thermal_temp_adjust_test_store(struct kobject *kobj, - struct kobj_attribute - *attr, const char *buf, - size_t n) -{ - struct rk3368_thermal_data *ctx = rk3368_thermal_get_data(); - int getdata; - char cmd; - const char *buftmp = buf; - int ret; - - if (!ctx) - return n; - - ret = sscanf(buftmp, "%c ", &cmd); - if (ret != 1) - return -EINVAL; - - switch (cmd) { - case 'c': - ret = sscanf(buftmp, "%c %d", &cmd, &getdata); - if (ret != 2) - return -EINVAL; - ctx->cpu_temp_adjust = getdata; - pr_info("get cpu_temp_adjust value = %d\n", getdata); - - break; - case 'g': - ret = sscanf(buftmp, "%c %d", &cmd, &getdata); - if (ret != 2) - return -EINVAL; - ctx->gpu_temp_adjust = getdata; - pr_info("get gpu_temp_adjust value = %d\n", getdata); - - break; - default: - pr_info("Unknown command\n"); - break; - } - - return n; -} - -static ssize_t rk3368_thermal_temp_adjust_test_show(struct kobject *kobj, - struct kobj_attribute - *attr, char *buf) -{ - struct rk3368_thermal_data *ctx = rk3368_thermal_get_data(); - char *str = buf; - - if (!ctx) - return 0; - - str += - sprintf(str, "rk3368_thermal: cpu:%d, gpu:%d\n", - ctx->cpu_temp_adjust, ctx->gpu_temp_adjust); - return (str - buf); -} - -static ssize_t rk3368_thermal_temp_test_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t n) -{ - struct rk3368_thermal_data *ctx = rk3368_thermal_get_data(); - char cmd; - const char *buftmp = buf; - int ret; - - if (!ctx) - return n; - - ret = sscanf(buftmp, "%c", &cmd); - if (ret != 1) - return -EINVAL; - - switch (cmd) { - case 't': - ctx->logout = true; - break; - case 'f': - ctx->logout = false; - break; - default: - pr_info("Unknown command\n"); - break; - } - - return n; -} - -static ssize_t rk3368_thermal_temp_test_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - struct rk3368_thermal_data *ctx = rk3368_thermal_get_data(); - char *str = buf; - - if (!ctx) - return 0; - - str += sprintf(str, "current cpu_temp:%d\n", ctx->cpu_temp); - return (str - buf); -} - -struct rk3368_thermal_attribute { - struct attribute attr; - ssize_t (*show) (struct kobject *kobj, struct kobj_attribute *attr, - char *buf); - ssize_t (*store) (struct kobject *kobj, struct kobj_attribute *attr, - const char *buf, size_t n); -}; - -static struct rk3368_thermal_attribute rk3368_thermal_attrs[] = { - /*node_name permission show_func store_func */ - __ATTR(temp_adjust, 0644, - rk3368_thermal_temp_adjust_test_show, - rk3368_thermal_temp_adjust_test_store), - __ATTR(temp, 0644, rk3368_thermal_temp_test_show, - rk3368_thermal_temp_test_store), -}; - -static void rk3368_dump_temperature(void) -{ - struct rk3368_thermal_data *ctx = rk3368_thermal_get_data(); - struct platform_device *pdev; - - if (!ctx) - return; - - pdev = ctx->pdev; - - if (ctx->cpu_temp != INVALID_TEMP) - dev_warn(&pdev->dev, "cpu channal temperature(%d C)\n", - ctx->cpu_temp); - - if (ctx->regs) { - pr_warn("THERMAL REGS:\n"); - print_hex_dump(KERN_WARNING, "", DUMP_PREFIX_OFFSET, - 32, 4, ctx->regs, 0x88, false); - } -} -EXPORT_SYMBOL_GPL(rk3368_dump_temperature); - -static int rk3368_thermal_panic(struct notifier_block *this, - unsigned long ev, void *ptr) -{ - rk3368_dump_temperature(); - return NOTIFY_DONE; -} - -static struct notifier_block rk3368_thermal_panic_block = { - .notifier_call = rk3368_thermal_panic, -}; - -static int rk3368_thermal_notify(struct notifier_block *nb, - unsigned long event, void *data) -{ - struct rk3368_thermal_data *ctx = rk3368_thermal_get_data(); - struct platform_device *pdev; - - if (!ctx) - return NOTIFY_OK; - - pdev = ctx->pdev; - - if (event & REGULATOR_EVENT_PRE_VOLTAGE_CHANGE) { - mutex_lock(&thermal_reg_mutex); - } else if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE | - REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) { - ctx->regulator_uv = (unsigned long)data; - if (mutex_is_locked(&thermal_reg_mutex)) - mutex_unlock(&thermal_reg_mutex); - } else { - return NOTIFY_OK; - } - return NOTIFY_OK; -} - -/* - * This function gets called when a part of the kernel has a new latency - * requirement. We record this requirement to instruct us to get temperature. - */ -static int tsadc_latency_notify(struct notifier_block *b, - unsigned long l, void *v) -{ - struct rk3368_thermal_data *ctx = rk3368_thermal_get_data(); - - if (!ctx) - return NOTIFY_OK; - - mutex_lock(&thermal_lat_mutex); - ctx->latency_req = (int)l; - mutex_unlock(&thermal_lat_mutex); - - return NOTIFY_OK; -} - -static struct notifier_block tsadc_latency_notifier = { - .notifier_call = tsadc_latency_notify, -}; - -static inline int tsadc_add_latency_notifier(struct notifier_block *n) -{ - return pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY, n); -} - -static inline int tsadc_remove_latency_notifier(struct notifier_block *n) -{ - return pm_qos_remove_notifier(PM_QOS_CPU_DMA_LATENCY, n); -} - -static const struct of_device_id of_rk3368_thermal_match[] = { - { - .compatible = "rockchip,rk3368-tsadc-legacy", - .data = (void *)&rk3368_tsadc_data, - }, - - { /* end */ }, -}; -MODULE_DEVICE_TABLE(of, of_rk3368_thermal_match); - -static int rk3368_thermal_probe(struct platform_device *pdev) -{ - struct device_node *np = pdev->dev.of_node; - struct rk3368_thermal_data *ctx; - const struct of_device_id *match; - struct resource *res; - int irq; - int i, j; - int error; - int uv; - int ajust_code = 0; - int latency_req = 0; - - match = of_match_node(of_rk3368_thermal_match, np); - if (!match) - return -ENXIO; - - irq = platform_get_irq(pdev, 0); - if (irq < 0) { - dev_err(&pdev->dev, "no irq resource?\n"); - return -EINVAL; - } - - ctx = devm_kzalloc(&pdev->dev, sizeof(struct rk3368_thermal_data), - GFP_KERNEL); - if (!ctx) - return -ENOMEM; - - ctx->pdev = pdev; - - ctx->chip = (const struct rk3368_tsadc_chip *)match->data; - if (!ctx->chip) - return -EINVAL; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - ctx->regs = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(ctx->regs)) - return PTR_ERR(ctx->regs); - - ctx->reset = devm_reset_control_get(&pdev->dev, "tsadc-apb"); - if (IS_ERR(ctx->reset)) { - error = PTR_ERR(ctx->reset); - dev_err(&pdev->dev, "failed to get tsadc reset: %d\n", error); - return error; - } - - ctx->clk = devm_clk_get(&pdev->dev, "tsadc"); - if (IS_ERR(ctx->clk)) { - error = PTR_ERR(ctx->clk); - dev_err(&pdev->dev, "failed to get tsadc clock: %d\n", error); - return error; - } - - ctx->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); - if (IS_ERR(ctx->pclk)) { - error = PTR_ERR(ctx->pclk); - dev_err(&pdev->dev, "failed to get apb_pclk clock: %d\n", - error); - return error; - } - - error = clk_prepare_enable(ctx->clk); - if (error) { - dev_err(&pdev->dev, "failed to enable converter clock: %d\n", - error); - return error; - } - - error = clk_prepare_enable(ctx->pclk); - if (error) { - dev_err(&pdev->dev, "failed to enable pclk: %d\n", error); - goto err_disable_clk; - } - - rk3368_thermal_reset_controller(ctx->reset); - - error = rk3368_configure_from_dt(&pdev->dev, np, ctx); - if (error) { - dev_err(&pdev->dev, "failed to parse device tree data: %d\n", - error); - goto err_disable_pclk; - } - - thermal_ctx = ctx; - ctx->ref_regulator = devm_regulator_get_optional(&pdev->dev, "tsadc"); - - if (IS_ERR(ctx->ref_regulator)) { - error = PTR_ERR(ctx->ref_regulator); - - if (error != -EPROBE_DEFER) - dev_err(&pdev->dev, - "couldn't get regulator tsadc-supply\n"); - goto err_disable_pclk; - } - - ctx->tsadc_nb.notifier_call = rk3368_thermal_notify; - - /* register regulator notifier */ - error = - regulator_register_notifier(ctx->ref_regulator, &ctx->tsadc_nb); - if (error) { - dev_err(&pdev->dev, "regulator notifier request failed\n"); - goto err_disable_pclk; - } - - uv = regulator_get_voltage(ctx->ref_regulator); - if (uv <= 0) { - dev_WARN(&pdev->dev, "regulator get failed\n"); - uv = 1000000; - } - - mutex_lock(&thermal_reg_mutex); - if (!ctx->regulator_uv) - ctx->regulator_uv = uv; - mutex_unlock(&thermal_reg_mutex); - - error = tsadc_add_latency_notifier(&tsadc_latency_notifier); - if (error) { - dev_err(&pdev->dev, "latency notifier request failed\n"); - goto err_unreg_notifier; - } - - latency_req = pm_qos_request(PM_QOS_CPU_DMA_LATENCY); - - mutex_lock(&thermal_lat_mutex); - if (!ctx->latency_req) - ctx->latency_req = latency_req; - mutex_unlock(&thermal_lat_mutex); - - rk3368_get_ajust_code(np, &ajust_code); - - ctx->cpu_temp_adjust = (int)ajust_code; - - for (i = 0; i < ctx->chip->chn_num; i++) { - error = rk3368_thermal_register_sensor(pdev, ctx, - &ctx->sensors[i], - ctx->chip->chn_id[i]); - if (error) { - dev_err(&pdev->dev, - "failed to register thermal sensor %d : error= %d\n", - i, error); - for (j = 0; j < i; j++) - thermal_zone_of_sensor_unregister(&pdev->dev, - ctx->sensors[j].tzd); - goto err_remove_latancy_notifier; - } - } - - ctx->rk3368_thermal_kobj = - kobject_create_and_add("rk3368_thermal", NULL); - if (!ctx->rk3368_thermal_kobj) { - error = -ENOMEM; - dev_err(&pdev->dev, - "failed to creat debug node : error= %d\n", error); - goto err_remove_latancy_notifier; - } - - for (i = 0; i < ARRAY_SIZE(rk3368_thermal_attrs); i++) { - error = - sysfs_create_file(ctx->rk3368_thermal_kobj, - &rk3368_thermal_attrs[i].attr); - if (error) { - dev_err(&pdev->dev, - "failed to register thermal sensor %d : error= %d\n", - i, error); - for (j = 0; j < i; j++) - sysfs_remove_file(ctx->rk3368_thermal_kobj, - &rk3368_thermal_attrs[j].attr); - - goto err_remove_latancy_notifier; - } - } - - platform_set_drvdata(pdev, ctx); - - atomic_notifier_chain_register(&panic_notifier_list, - &rk3368_thermal_panic_block); - - ctx->cpu_temp = INVALID_TEMP; - - pr_info("rk3368 tsadc probed successfully\n"); - - return 0; - -err_remove_latancy_notifier: - tsadc_remove_latency_notifier(&tsadc_latency_notifier); -err_unreg_notifier: - regulator_unregister_notifier(ctx->ref_regulator, &ctx->tsadc_nb); - -err_disable_pclk: - clk_disable_unprepare(ctx->pclk); -err_disable_clk: - clk_disable_unprepare(ctx->clk); - - return error; -} - -static int rk3368_thermal_remove(struct platform_device *pdev) -{ - struct rk3368_thermal_data *ctx = platform_get_drvdata(pdev); - int i; - - atomic_notifier_chain_unregister(&panic_notifier_list, - &rk3368_thermal_panic_block); - for (i = 0; i < ctx->chip->chn_num; i++) { - struct rk3368_thermal_sensor *sensor = &ctx->sensors[i]; - - thermal_zone_of_sensor_unregister(&pdev->dev, sensor->tzd); - } - tsadc_remove_latency_notifier(&tsadc_latency_notifier); - regulator_unregister_notifier(ctx->ref_regulator, &ctx->tsadc_nb); - clk_disable_unprepare(ctx->pclk); - clk_disable_unprepare(ctx->clk); - - return 0; -} - -static int __maybe_unused rk3368_thermal_suspend(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct rk3368_thermal_data *ctx = platform_get_drvdata(pdev); - - clk_disable(ctx->pclk); - clk_disable(ctx->clk); - return 0; -} - -static int __maybe_unused rk3368_thermal_resume(struct device *dev) -{ - struct platform_device *pdev = to_platform_device(dev); - struct rk3368_thermal_data *ctx = platform_get_drvdata(pdev); - int error; - - error = clk_enable(ctx->clk); - if (error) - return error; - - error = clk_enable(ctx->pclk); - if (error) { - clk_disable(ctx->clk); - return error; - } - - rk3368_thermal_reset_controller(ctx->reset); - - return 0; -} - -static SIMPLE_DEV_PM_OPS(rk3368_thermal_pm_ops, - rk3368_thermal_suspend, rk3368_thermal_resume); - -static struct platform_driver rk3368_thermal_driver = { - .driver = { - .name = "rk3368-thermal", - .pm = &rk3368_thermal_pm_ops, - .of_match_table = of_rk3368_thermal_match, - }, - .probe = rk3368_thermal_probe, - .remove = rk3368_thermal_remove, -}; - -/* rk3368 thermal needs a clock source of 32k from rk818, so this init process - * is postponed - */ -static int __init rk3368_thermal_init_driver(void) -{ - return platform_driver_register(&rk3368_thermal_driver); -} -late_initcall(rk3368_thermal_init_driver); - -MODULE_DESCRIPTION("ROCKCHIP THERMAL Driver"); -MODULE_AUTHOR("Rockchip, Inc."); -MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:rk3368-thermal");