diff options
Diffstat (limited to 'drivers/hwmon')
-rw-r--r-- | drivers/hwmon/Kconfig | 13 | ||||
-rw-r--r-- | drivers/hwmon/Makefile | 1 | ||||
-rw-r--r-- | drivers/hwmon/ab8500.c | 206 | ||||
-rw-r--r-- | drivers/hwmon/abx500.c | 491 | ||||
-rw-r--r-- | drivers/hwmon/abx500.h | 69 |
5 files changed, 780 insertions, 0 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index f61d98a62967..9c333d471433 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -39,6 +39,19 @@ config HWMON_DEBUG_CHIP | |||
39 | 39 | ||
40 | comment "Native drivers" | 40 | comment "Native drivers" |
41 | 41 | ||
42 | config SENSORS_AB8500 | ||
43 | tristate "AB8500 thermal monitoring" | ||
44 | depends on AB8500_GPADC && AB8500_BM | ||
45 | default n | ||
46 | help | ||
47 | If you say yes here you get support for the thermal sensor part | ||
48 | of the AB8500 chip. The driver includes thermal management for | ||
49 | AB8500 die and two GPADC channels. The GPADC channel are preferably | ||
50 | used to access sensors outside the AB8500 chip. | ||
51 | |||
52 | This driver can also be built as a module. If so, the module | ||
53 | will be called abx500-temp. | ||
54 | |||
42 | config SENSORS_ABITUGURU | 55 | config SENSORS_ABITUGURU |
43 | tristate "Abit uGuru (rev 1 & 2)" | 56 | tristate "Abit uGuru (rev 1 & 2)" |
44 | depends on X86 && DMI | 57 | depends on X86 && DMI |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index c51b0dc35dc8..d17d3e64f9f4 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -19,6 +19,7 @@ obj-$(CONFIG_SENSORS_W83795) += w83795.o | |||
19 | obj-$(CONFIG_SENSORS_W83781D) += w83781d.o | 19 | obj-$(CONFIG_SENSORS_W83781D) += w83781d.o |
20 | obj-$(CONFIG_SENSORS_W83791D) += w83791d.o | 20 | obj-$(CONFIG_SENSORS_W83791D) += w83791d.o |
21 | 21 | ||
22 | obj-$(CONFIG_SENSORS_AB8500) += abx500.o ab8500.o | ||
22 | obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o | 23 | obj-$(CONFIG_SENSORS_ABITUGURU) += abituguru.o |
23 | obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o | 24 | obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o |
24 | obj-$(CONFIG_SENSORS_AD7314) += ad7314.o | 25 | obj-$(CONFIG_SENSORS_AD7314) += ad7314.o |
diff --git a/drivers/hwmon/ab8500.c b/drivers/hwmon/ab8500.c new file mode 100644 index 000000000000..d844dc806853 --- /dev/null +++ b/drivers/hwmon/ab8500.c | |||
@@ -0,0 +1,206 @@ | |||
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, pm_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/slab.h> | ||
25 | #include <linux/sysfs.h> | ||
26 | #include "abx500.h" | ||
27 | |||
28 | #define DEFAULT_POWER_OFF_DELAY (HZ * 10) | ||
29 | #define THERMAL_VCC 1800 | ||
30 | #define PULL_UP_RESISTOR 47000 | ||
31 | /* Number of monitored sensors should not greater than NUM_SENSORS */ | ||
32 | #define NUM_MONITORED_SENSORS 4 | ||
33 | |||
34 | struct ab8500_gpadc_cfg { | ||
35 | const struct abx500_res_to_temp *temp_tbl; | ||
36 | int tbl_sz; | ||
37 | int vcc; | ||
38 | int r_up; | ||
39 | }; | ||
40 | |||
41 | struct ab8500_temp { | ||
42 | struct ab8500_gpadc *gpadc; | ||
43 | struct ab8500_btemp *btemp; | ||
44 | struct delayed_work power_off_work; | ||
45 | struct ab8500_gpadc_cfg cfg; | ||
46 | struct abx500_temp *abx500_data; | ||
47 | }; | ||
48 | |||
49 | /* | ||
50 | * The hardware connection is like this: | ||
51 | * VCC----[ R_up ]-----[ NTC ]----GND | ||
52 | * where R_up is pull-up resistance, and GPADC measures voltage on NTC. | ||
53 | * and res_to_temp table is strictly sorted by falling resistance values. | ||
54 | */ | ||
55 | static int ab8500_voltage_to_temp(struct ab8500_gpadc_cfg *cfg, | ||
56 | int v_ntc, int *temp) | ||
57 | { | ||
58 | int r_ntc, i = 0, tbl_sz = cfg->tbl_sz; | ||
59 | const struct abx500_res_to_temp *tbl = cfg->temp_tbl; | ||
60 | |||
61 | if (cfg->vcc < 0 || v_ntc >= cfg->vcc) | ||
62 | return -EINVAL; | ||
63 | |||
64 | r_ntc = v_ntc * cfg->r_up / (cfg->vcc - v_ntc); | ||
65 | if (r_ntc > tbl[0].resist || r_ntc < tbl[tbl_sz - 1].resist) | ||
66 | return -EINVAL; | ||
67 | |||
68 | while (!(r_ntc <= tbl[i].resist && r_ntc > tbl[i + 1].resist) && | ||
69 | i < tbl_sz - 2) | ||
70 | i++; | ||
71 | |||
72 | /* return milli-Celsius */ | ||
73 | *temp = tbl[i].temp * 1000 + ((tbl[i + 1].temp - tbl[i].temp) * 1000 * | ||
74 | (r_ntc - tbl[i].resist)) / (tbl[i + 1].resist - tbl[i].resist); | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | static int ab8500_read_sensor(struct abx500_temp *data, u8 sensor, int *temp) | ||
80 | { | ||
81 | int voltage, ret; | ||
82 | struct ab8500_temp *ab8500_data = data->plat_data; | ||
83 | |||
84 | if (sensor == BAT_CTRL) { | ||
85 | *temp = ab8500_btemp_get_batctrl_temp(ab8500_data->btemp); | ||
86 | } else if (sensor == BTEMP_BALL) { | ||
87 | *temp = ab8500_btemp_get_temp(ab8500_data->btemp); | ||
88 | } else { | ||
89 | voltage = ab8500_gpadc_convert(ab8500_data->gpadc, sensor); | ||
90 | if (voltage < 0) | ||
91 | return voltage; | ||
92 | |||
93 | ret = ab8500_voltage_to_temp(&ab8500_data->cfg, voltage, temp); | ||
94 | if (ret < 0) | ||
95 | return ret; | ||
96 | } | ||
97 | |||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | static void ab8500_thermal_power_off(struct work_struct *work) | ||
102 | { | ||
103 | struct ab8500_temp *ab8500_data = container_of(work, | ||
104 | struct ab8500_temp, power_off_work.work); | ||
105 | struct abx500_temp *abx500_data = ab8500_data->abx500_data; | ||
106 | |||
107 | dev_warn(&abx500_data->pdev->dev, "Power off due to critical temp\n"); | ||
108 | |||
109 | pm_power_off(); | ||
110 | } | ||
111 | |||
112 | static ssize_t ab8500_show_name(struct device *dev, | ||
113 | struct device_attribute *devattr, char *buf) | ||
114 | { | ||
115 | return sprintf(buf, "ab8500\n"); | ||
116 | } | ||
117 | |||
118 | static ssize_t ab8500_show_label(struct device *dev, | ||
119 | struct device_attribute *devattr, char *buf) | ||
120 | { | ||
121 | char *label; | ||
122 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
123 | int index = attr->index; | ||
124 | |||
125 | switch (index) { | ||
126 | case 1: | ||
127 | label = "ext_adc1"; | ||
128 | break; | ||
129 | case 2: | ||
130 | label = "ext_adc2"; | ||
131 | break; | ||
132 | case 3: | ||
133 | label = "bat_temp"; | ||
134 | break; | ||
135 | case 4: | ||
136 | label = "bat_ctrl"; | ||
137 | break; | ||
138 | default: | ||
139 | return -EINVAL; | ||
140 | } | ||
141 | |||
142 | return sprintf(buf, "%s\n", label); | ||
143 | } | ||
144 | |||
145 | static int ab8500_temp_irq_handler(int irq, struct abx500_temp *data) | ||
146 | { | ||
147 | struct ab8500_temp *ab8500_data = data->plat_data; | ||
148 | |||
149 | dev_warn(&data->pdev->dev, "Power off in %d s\n", | ||
150 | DEFAULT_POWER_OFF_DELAY / HZ); | ||
151 | |||
152 | schedule_delayed_work(&ab8500_data->power_off_work, | ||
153 | DEFAULT_POWER_OFF_DELAY); | ||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | int abx500_hwmon_init(struct abx500_temp *data) | ||
158 | { | ||
159 | struct ab8500_temp *ab8500_data; | ||
160 | |||
161 | ab8500_data = devm_kzalloc(&data->pdev->dev, sizeof(*ab8500_data), | ||
162 | GFP_KERNEL); | ||
163 | if (!ab8500_data) | ||
164 | return -ENOMEM; | ||
165 | |||
166 | ab8500_data->gpadc = ab8500_gpadc_get("ab8500-gpadc.0"); | ||
167 | if (IS_ERR(ab8500_data->gpadc)) | ||
168 | return PTR_ERR(ab8500_data->gpadc); | ||
169 | |||
170 | ab8500_data->btemp = ab8500_btemp_get(); | ||
171 | if (IS_ERR(ab8500_data->btemp)) | ||
172 | return PTR_ERR(ab8500_data->btemp); | ||
173 | |||
174 | INIT_DELAYED_WORK(&ab8500_data->power_off_work, | ||
175 | ab8500_thermal_power_off); | ||
176 | |||
177 | ab8500_data->cfg.vcc = THERMAL_VCC; | ||
178 | ab8500_data->cfg.r_up = PULL_UP_RESISTOR; | ||
179 | ab8500_data->cfg.temp_tbl = ab8500_temp_tbl_a_thermistor; | ||
180 | ab8500_data->cfg.tbl_sz = ab8500_temp_tbl_a_size; | ||
181 | |||
182 | data->plat_data = ab8500_data; | ||
183 | |||
184 | /* | ||
185 | * ADC_AUX1 and ADC_AUX2, connected to external NTC | ||
186 | * BTEMP_BALL and BAT_CTRL, fixed usage | ||
187 | */ | ||
188 | data->gpadc_addr[0] = ADC_AUX1; | ||
189 | data->gpadc_addr[1] = ADC_AUX2; | ||
190 | data->gpadc_addr[2] = BTEMP_BALL; | ||
191 | data->gpadc_addr[3] = BAT_CTRL; | ||
192 | data->monitored_sensors = NUM_MONITORED_SENSORS; | ||
193 | |||
194 | data->ops.read_sensor = ab8500_read_sensor; | ||
195 | data->ops.irq_handler = ab8500_temp_irq_handler; | ||
196 | data->ops.show_name = ab8500_show_name; | ||
197 | data->ops.show_label = ab8500_show_label; | ||
198 | data->ops.is_visible = NULL; | ||
199 | |||
200 | return 0; | ||
201 | } | ||
202 | EXPORT_SYMBOL(abx500_hwmon_init); | ||
203 | |||
204 | MODULE_AUTHOR("Hongbo Zhang <hongbo.zhang@linaro.org>"); | ||
205 | MODULE_DESCRIPTION("AB8500 temperature driver"); | ||
206 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/hwmon/abx500.c b/drivers/hwmon/abx500.c new file mode 100644 index 000000000000..b4ad87b31a37 --- /dev/null +++ b/drivers/hwmon/abx500.c | |||
@@ -0,0 +1,491 @@ | |||
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 | * ABX500 does not provide auto ADC, so to monitor the required temperatures, | ||
8 | * a periodic work is used. It is more important to not wake up the CPU than | ||
9 | * to perform this job, hence the use of a deferred delay. | ||
10 | * | ||
11 | * A deferred delay for thermal monitor is considered safe because: | ||
12 | * If the chip gets too hot during a sleep state it's most likely due to | ||
13 | * external factors, such as the surrounding temperature. I.e. no SW decisions | ||
14 | * will make any difference. | ||
15 | */ | ||
16 | |||
17 | #include <linux/err.h> | ||
18 | #include <linux/hwmon.h> | ||
19 | #include <linux/hwmon-sysfs.h> | ||
20 | #include <linux/interrupt.h> | ||
21 | #include <linux/jiffies.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/mutex.h> | ||
24 | #include <linux/of.h> | ||
25 | #include <linux/platform_device.h> | ||
26 | #include <linux/pm.h> | ||
27 | #include <linux/slab.h> | ||
28 | #include <linux/sysfs.h> | ||
29 | #include <linux/workqueue.h> | ||
30 | #include "abx500.h" | ||
31 | |||
32 | #define DEFAULT_MONITOR_DELAY HZ | ||
33 | #define DEFAULT_MAX_TEMP 130 | ||
34 | |||
35 | static inline void schedule_monitor(struct abx500_temp *data) | ||
36 | { | ||
37 | data->work_active = true; | ||
38 | schedule_delayed_work(&data->work, DEFAULT_MONITOR_DELAY); | ||
39 | } | ||
40 | |||
41 | static void threshold_updated(struct abx500_temp *data) | ||
42 | { | ||
43 | int i; | ||
44 | for (i = 0; i < data->monitored_sensors; i++) | ||
45 | if (data->max[i] != 0 || data->min[i] != 0) { | ||
46 | schedule_monitor(data); | ||
47 | return; | ||
48 | } | ||
49 | |||
50 | dev_dbg(&data->pdev->dev, "No active thresholds.\n"); | ||
51 | cancel_delayed_work_sync(&data->work); | ||
52 | data->work_active = false; | ||
53 | } | ||
54 | |||
55 | static void gpadc_monitor(struct work_struct *work) | ||
56 | { | ||
57 | int temp, i, ret; | ||
58 | char alarm_node[30]; | ||
59 | bool updated_min_alarm, updated_max_alarm; | ||
60 | struct abx500_temp *data; | ||
61 | |||
62 | data = container_of(work, struct abx500_temp, work.work); | ||
63 | mutex_lock(&data->lock); | ||
64 | |||
65 | for (i = 0; i < data->monitored_sensors; i++) { | ||
66 | /* Thresholds are considered inactive if set to 0 */ | ||
67 | if (data->max[i] == 0 && data->min[i] == 0) | ||
68 | continue; | ||
69 | |||
70 | if (data->max[i] < data->min[i]) | ||
71 | continue; | ||
72 | |||
73 | ret = data->ops.read_sensor(data, data->gpadc_addr[i], &temp); | ||
74 | if (ret < 0) { | ||
75 | dev_err(&data->pdev->dev, "GPADC read failed\n"); | ||
76 | continue; | ||
77 | } | ||
78 | |||
79 | updated_min_alarm = false; | ||
80 | updated_max_alarm = false; | ||
81 | |||
82 | if (data->min[i] != 0) { | ||
83 | if (temp < data->min[i]) { | ||
84 | if (data->min_alarm[i] == false) { | ||
85 | data->min_alarm[i] = true; | ||
86 | updated_min_alarm = true; | ||
87 | } | ||
88 | } else { | ||
89 | if (data->min_alarm[i] == true) { | ||
90 | data->min_alarm[i] = false; | ||
91 | updated_min_alarm = true; | ||
92 | } | ||
93 | } | ||
94 | } | ||
95 | if (data->max[i] != 0) { | ||
96 | if (temp > data->max[i]) { | ||
97 | if (data->max_alarm[i] == false) { | ||
98 | data->max_alarm[i] = true; | ||
99 | updated_max_alarm = true; | ||
100 | } | ||
101 | } else if (temp < data->max[i] - data->max_hyst[i]) { | ||
102 | if (data->max_alarm[i] == true) { | ||
103 | data->max_alarm[i] = false; | ||
104 | updated_max_alarm = true; | ||
105 | } | ||
106 | } | ||
107 | } | ||
108 | |||
109 | if (updated_min_alarm) { | ||
110 | ret = sprintf(alarm_node, "temp%d_min_alarm", i + 1); | ||
111 | sysfs_notify(&data->pdev->dev.kobj, NULL, alarm_node); | ||
112 | } | ||
113 | if (updated_max_alarm) { | ||
114 | ret = sprintf(alarm_node, "temp%d_max_alarm", i + 1); | ||
115 | sysfs_notify(&data->pdev->dev.kobj, NULL, alarm_node); | ||
116 | } | ||
117 | } | ||
118 | |||
119 | schedule_monitor(data); | ||
120 | mutex_unlock(&data->lock); | ||
121 | } | ||
122 | |||
123 | /* HWMON sysfs interfaces */ | ||
124 | static ssize_t show_name(struct device *dev, struct device_attribute *devattr, | ||
125 | char *buf) | ||
126 | { | ||
127 | struct abx500_temp *data = dev_get_drvdata(dev); | ||
128 | /* Show chip name */ | ||
129 | return data->ops.show_name(dev, devattr, buf); | ||
130 | } | ||
131 | |||
132 | static ssize_t show_label(struct device *dev, | ||
133 | struct device_attribute *devattr, char *buf) | ||
134 | { | ||
135 | struct abx500_temp *data = dev_get_drvdata(dev); | ||
136 | /* Show each sensor label */ | ||
137 | return data->ops.show_label(dev, devattr, buf); | ||
138 | } | ||
139 | |||
140 | static ssize_t show_input(struct device *dev, | ||
141 | struct device_attribute *devattr, char *buf) | ||
142 | { | ||
143 | int ret, temp; | ||
144 | struct abx500_temp *data = dev_get_drvdata(dev); | ||
145 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
146 | u8 gpadc_addr = data->gpadc_addr[attr->index]; | ||
147 | |||
148 | ret = data->ops.read_sensor(data, gpadc_addr, &temp); | ||
149 | if (ret < 0) | ||
150 | return ret; | ||
151 | |||
152 | return sprintf(buf, "%d\n", temp); | ||
153 | } | ||
154 | |||
155 | /* Set functions (RW nodes) */ | ||
156 | static ssize_t set_min(struct device *dev, struct device_attribute *devattr, | ||
157 | const char *buf, size_t count) | ||
158 | { | ||
159 | unsigned long val; | ||
160 | struct abx500_temp *data = dev_get_drvdata(dev); | ||
161 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
162 | int res = kstrtol(buf, 10, &val); | ||
163 | if (res < 0) | ||
164 | return res; | ||
165 | |||
166 | val = clamp_val(val, 0, DEFAULT_MAX_TEMP); | ||
167 | |||
168 | mutex_lock(&data->lock); | ||
169 | data->min[attr->index] = val; | ||
170 | threshold_updated(data); | ||
171 | mutex_unlock(&data->lock); | ||
172 | |||
173 | return count; | ||
174 | } | ||
175 | |||
176 | static ssize_t set_max(struct device *dev, struct device_attribute *devattr, | ||
177 | const char *buf, size_t count) | ||
178 | { | ||
179 | unsigned long val; | ||
180 | struct abx500_temp *data = dev_get_drvdata(dev); | ||
181 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
182 | int res = kstrtol(buf, 10, &val); | ||
183 | if (res < 0) | ||
184 | return res; | ||
185 | |||
186 | val = clamp_val(val, 0, DEFAULT_MAX_TEMP); | ||
187 | |||
188 | mutex_lock(&data->lock); | ||
189 | data->max[attr->index] = val; | ||
190 | threshold_updated(data); | ||
191 | mutex_unlock(&data->lock); | ||
192 | |||
193 | return count; | ||
194 | } | ||
195 | |||
196 | static ssize_t set_max_hyst(struct device *dev, | ||
197 | struct device_attribute *devattr, | ||
198 | const char *buf, size_t count) | ||
199 | { | ||
200 | unsigned long val; | ||
201 | struct abx500_temp *data = dev_get_drvdata(dev); | ||
202 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
203 | int res = kstrtoul(buf, 10, &val); | ||
204 | if (res < 0) | ||
205 | return res; | ||
206 | |||
207 | val = clamp_val(val, 0, DEFAULT_MAX_TEMP); | ||
208 | |||
209 | mutex_lock(&data->lock); | ||
210 | data->max_hyst[attr->index] = val; | ||
211 | threshold_updated(data); | ||
212 | mutex_unlock(&data->lock); | ||
213 | |||
214 | return count; | ||
215 | } | ||
216 | |||
217 | /* Show functions (RO nodes) */ | ||
218 | static ssize_t show_min(struct device *dev, | ||
219 | struct device_attribute *devattr, char *buf) | ||
220 | { | ||
221 | struct abx500_temp *data = dev_get_drvdata(dev); | ||
222 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
223 | |||
224 | return sprintf(buf, "%ld\n", data->min[attr->index]); | ||
225 | } | ||
226 | |||
227 | static ssize_t show_max(struct device *dev, | ||
228 | struct device_attribute *devattr, char *buf) | ||
229 | { | ||
230 | struct abx500_temp *data = dev_get_drvdata(dev); | ||
231 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
232 | |||
233 | return sprintf(buf, "%ld\n", data->max[attr->index]); | ||
234 | } | ||
235 | |||
236 | static ssize_t show_max_hyst(struct device *dev, | ||
237 | struct device_attribute *devattr, char *buf) | ||
238 | { | ||
239 | struct abx500_temp *data = dev_get_drvdata(dev); | ||
240 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
241 | |||
242 | return sprintf(buf, "%ld\n", data->max_hyst[attr->index]); | ||
243 | } | ||
244 | |||
245 | static ssize_t show_min_alarm(struct device *dev, | ||
246 | struct device_attribute *devattr, char *buf) | ||
247 | { | ||
248 | struct abx500_temp *data = dev_get_drvdata(dev); | ||
249 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
250 | |||
251 | return sprintf(buf, "%d\n", data->min_alarm[attr->index]); | ||
252 | } | ||
253 | |||
254 | static ssize_t show_max_alarm(struct device *dev, | ||
255 | struct device_attribute *devattr, char *buf) | ||
256 | { | ||
257 | struct abx500_temp *data = dev_get_drvdata(dev); | ||
258 | struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); | ||
259 | |||
260 | return sprintf(buf, "%d\n", data->max_alarm[attr->index]); | ||
261 | } | ||
262 | |||
263 | static mode_t abx500_attrs_visible(struct kobject *kobj, | ||
264 | struct attribute *attr, int n) | ||
265 | { | ||
266 | struct device *dev = container_of(kobj, struct device, kobj); | ||
267 | struct abx500_temp *data = dev_get_drvdata(dev); | ||
268 | |||
269 | if (data->ops.is_visible) | ||
270 | return data->ops.is_visible(attr, n); | ||
271 | |||
272 | return attr->mode; | ||
273 | } | ||
274 | |||
275 | /* Chip name, required by hwmon */ | ||
276 | static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0); | ||
277 | |||
278 | /* GPADC - SENSOR1 */ | ||
279 | static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, show_label, NULL, 0); | ||
280 | static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_input, NULL, 0); | ||
281 | static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_min, set_min, 0); | ||
282 | static SENSOR_DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_max, set_max, 0); | ||
283 | static SENSOR_DEVICE_ATTR(temp1_max_hyst, S_IWUSR | S_IRUGO, | ||
284 | show_max_hyst, set_max_hyst, 0); | ||
285 | static SENSOR_DEVICE_ATTR(temp1_min_alarm, S_IRUGO, show_min_alarm, NULL, 0); | ||
286 | static SENSOR_DEVICE_ATTR(temp1_max_alarm, S_IRUGO, show_max_alarm, NULL, 0); | ||
287 | |||
288 | /* GPADC - SENSOR2 */ | ||
289 | static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, show_label, NULL, 1); | ||
290 | static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_input, NULL, 1); | ||
291 | static SENSOR_DEVICE_ATTR(temp2_min, S_IWUSR | S_IRUGO, show_min, set_min, 1); | ||
292 | static SENSOR_DEVICE_ATTR(temp2_max, S_IWUSR | S_IRUGO, show_max, set_max, 1); | ||
293 | static SENSOR_DEVICE_ATTR(temp2_max_hyst, S_IWUSR | S_IRUGO, | ||
294 | show_max_hyst, set_max_hyst, 1); | ||
295 | static SENSOR_DEVICE_ATTR(temp2_min_alarm, S_IRUGO, show_min_alarm, NULL, 1); | ||
296 | static SENSOR_DEVICE_ATTR(temp2_max_alarm, S_IRUGO, show_max_alarm, NULL, 1); | ||
297 | |||
298 | /* GPADC - SENSOR3 */ | ||
299 | static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, show_label, NULL, 2); | ||
300 | static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, show_input, NULL, 2); | ||
301 | static SENSOR_DEVICE_ATTR(temp3_min, S_IWUSR | S_IRUGO, show_min, set_min, 2); | ||
302 | static SENSOR_DEVICE_ATTR(temp3_max, S_IWUSR | S_IRUGO, show_max, set_max, 2); | ||
303 | static SENSOR_DEVICE_ATTR(temp3_max_hyst, S_IWUSR | S_IRUGO, | ||
304 | show_max_hyst, set_max_hyst, 2); | ||
305 | static SENSOR_DEVICE_ATTR(temp3_min_alarm, S_IRUGO, show_min_alarm, NULL, 2); | ||
306 | static SENSOR_DEVICE_ATTR(temp3_max_alarm, S_IRUGO, show_max_alarm, NULL, 2); | ||
307 | |||
308 | /* GPADC - SENSOR4 */ | ||
309 | static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, show_label, NULL, 3); | ||
310 | static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, show_input, NULL, 3); | ||
311 | static SENSOR_DEVICE_ATTR(temp4_min, S_IWUSR | S_IRUGO, show_min, set_min, 3); | ||
312 | static SENSOR_DEVICE_ATTR(temp4_max, S_IWUSR | S_IRUGO, show_max, set_max, 3); | ||
313 | static SENSOR_DEVICE_ATTR(temp4_max_hyst, S_IWUSR | S_IRUGO, | ||
314 | show_max_hyst, set_max_hyst, 3); | ||
315 | static SENSOR_DEVICE_ATTR(temp4_min_alarm, S_IRUGO, show_min_alarm, NULL, 3); | ||
316 | static SENSOR_DEVICE_ATTR(temp4_max_alarm, S_IRUGO, show_max_alarm, NULL, 3); | ||
317 | |||
318 | struct attribute *abx500_temp_attributes[] = { | ||
319 | &sensor_dev_attr_name.dev_attr.attr, | ||
320 | |||
321 | &sensor_dev_attr_temp1_label.dev_attr.attr, | ||
322 | &sensor_dev_attr_temp1_input.dev_attr.attr, | ||
323 | &sensor_dev_attr_temp1_min.dev_attr.attr, | ||
324 | &sensor_dev_attr_temp1_max.dev_attr.attr, | ||
325 | &sensor_dev_attr_temp1_max_hyst.dev_attr.attr, | ||
326 | &sensor_dev_attr_temp1_min_alarm.dev_attr.attr, | ||
327 | &sensor_dev_attr_temp1_max_alarm.dev_attr.attr, | ||
328 | |||
329 | &sensor_dev_attr_temp2_label.dev_attr.attr, | ||
330 | &sensor_dev_attr_temp2_input.dev_attr.attr, | ||
331 | &sensor_dev_attr_temp2_min.dev_attr.attr, | ||
332 | &sensor_dev_attr_temp2_max.dev_attr.attr, | ||
333 | &sensor_dev_attr_temp2_max_hyst.dev_attr.attr, | ||
334 | &sensor_dev_attr_temp2_min_alarm.dev_attr.attr, | ||
335 | &sensor_dev_attr_temp2_max_alarm.dev_attr.attr, | ||
336 | |||
337 | &sensor_dev_attr_temp3_label.dev_attr.attr, | ||
338 | &sensor_dev_attr_temp3_input.dev_attr.attr, | ||
339 | &sensor_dev_attr_temp3_min.dev_attr.attr, | ||
340 | &sensor_dev_attr_temp3_max.dev_attr.attr, | ||
341 | &sensor_dev_attr_temp3_max_hyst.dev_attr.attr, | ||
342 | &sensor_dev_attr_temp3_min_alarm.dev_attr.attr, | ||
343 | &sensor_dev_attr_temp3_max_alarm.dev_attr.attr, | ||
344 | |||
345 | &sensor_dev_attr_temp4_label.dev_attr.attr, | ||
346 | &sensor_dev_attr_temp4_input.dev_attr.attr, | ||
347 | &sensor_dev_attr_temp4_min.dev_attr.attr, | ||
348 | &sensor_dev_attr_temp4_max.dev_attr.attr, | ||
349 | &sensor_dev_attr_temp4_max_hyst.dev_attr.attr, | ||
350 | &sensor_dev_attr_temp4_min_alarm.dev_attr.attr, | ||
351 | &sensor_dev_attr_temp4_max_alarm.dev_attr.attr, | ||
352 | NULL | ||
353 | }; | ||
354 | |||
355 | static const struct attribute_group abx500_temp_group = { | ||
356 | .attrs = abx500_temp_attributes, | ||
357 | .is_visible = abx500_attrs_visible, | ||
358 | }; | ||
359 | |||
360 | static irqreturn_t abx500_temp_irq_handler(int irq, void *irq_data) | ||
361 | { | ||
362 | struct platform_device *pdev = irq_data; | ||
363 | struct abx500_temp *data = platform_get_drvdata(pdev); | ||
364 | |||
365 | data->ops.irq_handler(irq, data); | ||
366 | return IRQ_HANDLED; | ||
367 | } | ||
368 | |||
369 | static int setup_irqs(struct platform_device *pdev) | ||
370 | { | ||
371 | int ret; | ||
372 | int irq = platform_get_irq_byname(pdev, "ABX500_TEMP_WARM"); | ||
373 | |||
374 | if (irq < 0) { | ||
375 | dev_err(&pdev->dev, "Get irq by name failed\n"); | ||
376 | return irq; | ||
377 | } | ||
378 | |||
379 | ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, | ||
380 | abx500_temp_irq_handler, IRQF_NO_SUSPEND, "abx500-temp", pdev); | ||
381 | if (ret < 0) | ||
382 | dev_err(&pdev->dev, "Request threaded irq failed (%d)\n", ret); | ||
383 | |||
384 | return ret; | ||
385 | } | ||
386 | |||
387 | static int abx500_temp_probe(struct platform_device *pdev) | ||
388 | { | ||
389 | struct abx500_temp *data; | ||
390 | int err; | ||
391 | |||
392 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | ||
393 | if (!data) | ||
394 | return -ENOMEM; | ||
395 | |||
396 | data->pdev = pdev; | ||
397 | mutex_init(&data->lock); | ||
398 | |||
399 | /* Chip specific initialization */ | ||
400 | err = abx500_hwmon_init(data); | ||
401 | if (err < 0 || !data->ops.read_sensor || !data->ops.show_name || | ||
402 | !data->ops.show_label) | ||
403 | return err; | ||
404 | |||
405 | INIT_DEFERRABLE_WORK(&data->work, gpadc_monitor); | ||
406 | |||
407 | platform_set_drvdata(pdev, data); | ||
408 | |||
409 | err = sysfs_create_group(&pdev->dev.kobj, &abx500_temp_group); | ||
410 | if (err < 0) { | ||
411 | dev_err(&pdev->dev, "Create sysfs group failed (%d)\n", err); | ||
412 | return err; | ||
413 | } | ||
414 | |||
415 | data->hwmon_dev = hwmon_device_register(&pdev->dev); | ||
416 | if (IS_ERR(data->hwmon_dev)) { | ||
417 | err = PTR_ERR(data->hwmon_dev); | ||
418 | dev_err(&pdev->dev, "Class registration failed (%d)\n", err); | ||
419 | goto exit_sysfs_group; | ||
420 | } | ||
421 | |||
422 | if (data->ops.irq_handler) { | ||
423 | err = setup_irqs(pdev); | ||
424 | if (err < 0) | ||
425 | goto exit_hwmon_reg; | ||
426 | } | ||
427 | return 0; | ||
428 | |||
429 | exit_hwmon_reg: | ||
430 | hwmon_device_unregister(data->hwmon_dev); | ||
431 | exit_sysfs_group: | ||
432 | sysfs_remove_group(&pdev->dev.kobj, &abx500_temp_group); | ||
433 | return err; | ||
434 | } | ||
435 | |||
436 | static int abx500_temp_remove(struct platform_device *pdev) | ||
437 | { | ||
438 | struct abx500_temp *data = platform_get_drvdata(pdev); | ||
439 | |||
440 | cancel_delayed_work_sync(&data->work); | ||
441 | hwmon_device_unregister(data->hwmon_dev); | ||
442 | sysfs_remove_group(&pdev->dev.kobj, &abx500_temp_group); | ||
443 | |||
444 | return 0; | ||
445 | } | ||
446 | |||
447 | static int abx500_temp_suspend(struct platform_device *pdev, | ||
448 | pm_message_t state) | ||
449 | { | ||
450 | struct abx500_temp *data = platform_get_drvdata(pdev); | ||
451 | |||
452 | if (data->work_active) | ||
453 | cancel_delayed_work_sync(&data->work); | ||
454 | |||
455 | return 0; | ||
456 | } | ||
457 | |||
458 | static int abx500_temp_resume(struct platform_device *pdev) | ||
459 | { | ||
460 | struct abx500_temp *data = platform_get_drvdata(pdev); | ||
461 | |||
462 | if (data->work_active) | ||
463 | schedule_monitor(data); | ||
464 | |||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | #ifdef CONFIG_OF | ||
469 | static const struct of_device_id abx500_temp_match[] = { | ||
470 | { .compatible = "stericsson,abx500-temp" }, | ||
471 | {}, | ||
472 | }; | ||
473 | #endif | ||
474 | |||
475 | static struct platform_driver abx500_temp_driver = { | ||
476 | .driver = { | ||
477 | .owner = THIS_MODULE, | ||
478 | .name = "abx500-temp", | ||
479 | .of_match_table = of_match_ptr(abx500_temp_match), | ||
480 | }, | ||
481 | .suspend = abx500_temp_suspend, | ||
482 | .resume = abx500_temp_resume, | ||
483 | .probe = abx500_temp_probe, | ||
484 | .remove = abx500_temp_remove, | ||
485 | }; | ||
486 | |||
487 | module_platform_driver(abx500_temp_driver); | ||
488 | |||
489 | MODULE_AUTHOR("Martin Persson <martin.persson@stericsson.com>"); | ||
490 | MODULE_DESCRIPTION("ABX500 temperature driver"); | ||
491 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/hwmon/abx500.h b/drivers/hwmon/abx500.h new file mode 100644 index 000000000000..9b295e684d0e --- /dev/null +++ b/drivers/hwmon/abx500.h | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson 2010 - 2013 | ||
3 | * License terms: GNU General Public License v2 | ||
4 | * Author: Martin Persson <martin.persson@stericsson.com> | ||
5 | * Hongbo Zhang <hongbo.zhang@linaro.com> | ||
6 | */ | ||
7 | |||
8 | #ifndef _ABX500_H | ||
9 | #define _ABX500_H | ||
10 | |||
11 | #define NUM_SENSORS 5 | ||
12 | |||
13 | struct abx500_temp; | ||
14 | |||
15 | /* | ||
16 | * struct abx500_temp_ops - abx500 chip specific ops | ||
17 | * @read_sensor: reads gpadc output | ||
18 | * @irq_handler: irq handler | ||
19 | * @show_name: hwmon device name | ||
20 | * @show_label: hwmon attribute label | ||
21 | * @is_visible: is attribute visible | ||
22 | */ | ||
23 | struct abx500_temp_ops { | ||
24 | int (*read_sensor)(struct abx500_temp *, u8, int *); | ||
25 | int (*irq_handler)(int, struct abx500_temp *); | ||
26 | ssize_t (*show_name)(struct device *, | ||
27 | struct device_attribute *, char *); | ||
28 | ssize_t (*show_label) (struct device *, | ||
29 | struct device_attribute *, char *); | ||
30 | int (*is_visible)(struct attribute *, int); | ||
31 | }; | ||
32 | |||
33 | /* | ||
34 | * struct abx500_temp - representation of temp mon device | ||
35 | * @pdev: platform device | ||
36 | * @hwmon_dev: hwmon device | ||
37 | * @ops: abx500 chip specific ops | ||
38 | * @gpadc_addr: gpadc channel address | ||
39 | * @min: sensor temperature min value | ||
40 | * @max: sensor temperature max value | ||
41 | * @max_hyst: sensor temperature hysteresis value for max limit | ||
42 | * @min_alarm: sensor temperature min alarm | ||
43 | * @max_alarm: sensor temperature max alarm | ||
44 | * @work: delayed work scheduled to monitor temperature periodically | ||
45 | * @work_active: True if work is active | ||
46 | * @lock: mutex | ||
47 | * @monitored_sensors: number of monitored sensors | ||
48 | * @plat_data: private usage, usually points to platform specific data | ||
49 | */ | ||
50 | struct abx500_temp { | ||
51 | struct platform_device *pdev; | ||
52 | struct device *hwmon_dev; | ||
53 | struct abx500_temp_ops ops; | ||
54 | u8 gpadc_addr[NUM_SENSORS]; | ||
55 | unsigned long min[NUM_SENSORS]; | ||
56 | unsigned long max[NUM_SENSORS]; | ||
57 | unsigned long max_hyst[NUM_SENSORS]; | ||
58 | bool min_alarm[NUM_SENSORS]; | ||
59 | bool max_alarm[NUM_SENSORS]; | ||
60 | struct delayed_work work; | ||
61 | bool work_active; | ||
62 | struct mutex lock; | ||
63 | int monitored_sensors; | ||
64 | void *plat_data; | ||
65 | }; | ||
66 | |||
67 | int abx500_hwmon_init(struct abx500_temp *data); | ||
68 | |||
69 | #endif /* _ABX500_H */ | ||