1/* 2 * Copyright (C) ST-Ericsson 2010 - 2013 3 * Author: Martin Persson <martin.persson@stericsson.com> 4 * Hongbo Zhang <hongbo.zhang@linaro.org> 5 * License Terms: GNU General Public License v2 6 * 7 * When the AB8500 thermal warning temperature is reached (threshold cannot 8 * be changed by SW), an interrupt is set, and if no further action is taken 9 * within a certain time frame, kernel_power_off will be called. 10 * 11 * When AB8500 thermal shutdown temperature is reached a hardware shutdown of 12 * the AB8500 will occur. 13 */ 14 15#include <linux/err.h> 16#include <linux/hwmon.h> 17#include <linux/hwmon-sysfs.h> 18#include <linux/mfd/abx500.h> 19#include <linux/mfd/abx500/ab8500-bm.h> 20#include <linux/mfd/abx500/ab8500-gpadc.h> 21#include <linux/module.h> 22#include <linux/platform_device.h> 23#include <linux/power/ab8500.h> 24#include <linux/reboot.h> 25#include <linux/slab.h> 26#include <linux/sysfs.h> 27#include "abx500.h" 28 29#define DEFAULT_POWER_OFF_DELAY (HZ * 10) 30#define THERMAL_VCC 1800 31#define PULL_UP_RESISTOR 47000 32/* Number of monitored sensors should not greater than NUM_SENSORS */ 33#define NUM_MONITORED_SENSORS 4 34 35struct ab8500_gpadc_cfg { 36 const struct abx500_res_to_temp *temp_tbl; 37 int tbl_sz; 38 int vcc; 39 int r_up; 40}; 41 42struct ab8500_temp { 43 struct ab8500_gpadc *gpadc; 44 struct ab8500_btemp *btemp; 45 struct delayed_work power_off_work; 46 struct ab8500_gpadc_cfg cfg; 47 struct abx500_temp *abx500_data; 48}; 49 50/* 51 * The hardware connection is like this: 52 * VCC----[ R_up ]-----[ NTC ]----GND 53 * where R_up is pull-up resistance, and GPADC measures voltage on NTC. 54 * and res_to_temp table is strictly sorted by falling resistance values. 55 */ 56static int ab8500_voltage_to_temp(struct ab8500_gpadc_cfg *cfg, 57 int v_ntc, int *temp) 58{ 59 int r_ntc, i = 0, tbl_sz = cfg->tbl_sz; 60 const struct abx500_res_to_temp *tbl = cfg->temp_tbl; 61 62 if (cfg->vcc < 0 || v_ntc >= cfg->vcc) 63 return -EINVAL; 64 65 r_ntc = v_ntc * cfg->r_up / (cfg->vcc - v_ntc); 66 if (r_ntc > tbl[0].resist || r_ntc < tbl[tbl_sz - 1].resist) 67 return -EINVAL; 68 69 while (!(r_ntc <= tbl[i].resist && r_ntc > tbl[i + 1].resist) && 70 i < tbl_sz - 2) 71 i++; 72 73 /* return milli-Celsius */ 74 *temp = tbl[i].temp * 1000 + ((tbl[i + 1].temp - tbl[i].temp) * 1000 * 75 (r_ntc - tbl[i].resist)) / (tbl[i + 1].resist - tbl[i].resist); 76 77 return 0; 78} 79 80static int ab8500_read_sensor(struct abx500_temp *data, u8 sensor, int *temp) 81{ 82 int voltage, ret; 83 struct ab8500_temp *ab8500_data = data->plat_data; 84 85 if (sensor == BAT_CTRL) { 86 *temp = ab8500_btemp_get_batctrl_temp(ab8500_data->btemp); 87 } else if (sensor == BTEMP_BALL) { 88 *temp = ab8500_btemp_get_temp(ab8500_data->btemp); 89 } else { 90 voltage = ab8500_gpadc_convert(ab8500_data->gpadc, sensor); 91 if (voltage < 0) 92 return voltage; 93 94 ret = ab8500_voltage_to_temp(&ab8500_data->cfg, voltage, temp); 95 if (ret < 0) 96 return ret; 97 } 98 99 return 0; 100} 101 102static void ab8500_thermal_power_off(struct work_struct *work) 103{ 104 struct ab8500_temp *ab8500_data = container_of(work, 105 struct ab8500_temp, power_off_work.work); 106 struct abx500_temp *abx500_data = ab8500_data->abx500_data; 107 108 dev_warn(&abx500_data->pdev->dev, "Power off due to critical temp\n"); 109 110 kernel_power_off(); 111} 112 113static ssize_t ab8500_show_name(struct device *dev, 114 struct device_attribute *devattr, char *buf) 115{ 116 return sprintf(buf, "ab8500\n"); 117} 118 119static ssize_t ab8500_show_label(struct device *dev, 120 struct device_attribute *devattr, char *buf) 121{ 122 char *label; 123 struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); 124 int index = attr->index; 125 126 switch (index) { 127 case 1: 128 label = "ext_adc1"; 129 break; 130 case 2: 131 label = "ext_adc2"; 132 break; 133 case 3: 134 label = "bat_temp"; 135 break; 136 case 4: 137 label = "bat_ctrl"; 138 break; 139 default: 140 return -EINVAL; 141 } 142 143 return sprintf(buf, "%s\n", label); 144} 145 146static int ab8500_temp_irq_handler(int irq, struct abx500_temp *data) 147{ 148 struct ab8500_temp *ab8500_data = data->plat_data; 149 150 dev_warn(&data->pdev->dev, "Power off in %d s\n", 151 DEFAULT_POWER_OFF_DELAY / HZ); 152 153 schedule_delayed_work(&ab8500_data->power_off_work, 154 DEFAULT_POWER_OFF_DELAY); 155 return 0; 156} 157 158int abx500_hwmon_init(struct abx500_temp *data) 159{ 160 struct ab8500_temp *ab8500_data; 161 162 ab8500_data = devm_kzalloc(&data->pdev->dev, sizeof(*ab8500_data), 163 GFP_KERNEL); 164 if (!ab8500_data) 165 return -ENOMEM; 166 167 ab8500_data->gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); 168 if (IS_ERR(ab8500_data->gpadc)) 169 return PTR_ERR(ab8500_data->gpadc); 170 171 ab8500_data->btemp = ab8500_btemp_get(); 172 if (IS_ERR(ab8500_data->btemp)) 173 return PTR_ERR(ab8500_data->btemp); 174 175 INIT_DELAYED_WORK(&ab8500_data->power_off_work, 176 ab8500_thermal_power_off); 177 178 ab8500_data->cfg.vcc = THERMAL_VCC; 179 ab8500_data->cfg.r_up = PULL_UP_RESISTOR; 180 ab8500_data->cfg.temp_tbl = ab8500_temp_tbl_a_thermistor; 181 ab8500_data->cfg.tbl_sz = ab8500_temp_tbl_a_size; 182 183 data->plat_data = ab8500_data; 184 185 /* 186 * ADC_AUX1 and ADC_AUX2, connected to external NTC 187 * BTEMP_BALL and BAT_CTRL, fixed usage 188 */ 189 data->gpadc_addr[0] = ADC_AUX1; 190 data->gpadc_addr[1] = ADC_AUX2; 191 data->gpadc_addr[2] = BTEMP_BALL; 192 data->gpadc_addr[3] = BAT_CTRL; 193 data->monitored_sensors = NUM_MONITORED_SENSORS; 194 195 data->ops.read_sensor = ab8500_read_sensor; 196 data->ops.irq_handler = ab8500_temp_irq_handler; 197 data->ops.show_name = ab8500_show_name; 198 data->ops.show_label = ab8500_show_label; 199 data->ops.is_visible = NULL; 200 201 return 0; 202} 203EXPORT_SYMBOL(abx500_hwmon_init); 204 205MODULE_AUTHOR("Hongbo Zhang <hongbo.zhang@linaro.org>"); 206MODULE_DESCRIPTION("AB8500 temperature driver"); 207MODULE_LICENSE("GPL"); 208