2 * drivers/misc/nct1008.c
4 * Driver for NCT1008, temperature monitoring device from ON Semiconductors
6 * Copyright (c) 2010, NVIDIA Corporation.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 #include <linux/interrupt.h>
25 #include <linux/mutex.h>
26 #include <linux/module.h>
27 #include <linux/i2c.h>
28 #include <linux/slab.h>
29 #include <linux/err.h>
30 #include <linux/gpio.h>
32 #include <linux/nct1008.h>
34 #define DRIVER_NAME "nct1008"
36 /* Register Addresses */
37 #define LOCAL_TEMP_RD 0x00
38 #define STATUS_RD 0x02
39 #define CONFIG_RD 0x03
41 #define CONFIG_WR 0x09
42 #define CONV_RATE_WR 0x0A
43 #define LOCAL_TEMP_HI_LIMIT_WR 0x0B
44 #define EXT_TEMP_HI_LIMIT_HI_BYTE 0x0D
45 #define OFFSET_WR 0x11
46 #define EXT_THERM_LIMIT_WR 0x19
47 #define LOCAL_THERM_LIMIT_WR 0x20
48 #define THERM_HYSTERESIS_WR 0x21
50 /* Configuration Register Bits */
51 #define EXTENDED_RANGE_BIT (0x1 << 2)
52 #define THERM2_BIT (0x1 << 5)
53 #define STANDBY_BIT (0x1 << 6)
55 /* Max Temperature Measurements */
56 #define EXTENDED_RANGE_OFFSET 64U
57 #define STANDARD_RANGE_MAX 127U
58 #define EXTENDED_RANGE_MAX (150U + EXTENDED_RANGE_OFFSET)
61 struct work_struct work;
62 struct i2c_client *client;
65 void (*alarm_fn)(bool raised);
68 static void nct1008_enable(struct i2c_client *client)
70 struct nct1008_data *data = i2c_get_clientdata(client);
72 i2c_smbus_write_byte_data(client, CONFIG_WR,
73 data->config & ~STANDBY_BIT);
76 static void nct1008_disable(struct i2c_client *client)
78 struct nct1008_data *data = i2c_get_clientdata(client);
80 i2c_smbus_write_byte_data(client, CONFIG_WR,
81 data->config | STANDBY_BIT);
85 static void nct1008_work_func(struct work_struct *work)
87 struct nct1008_data *data = container_of(work, struct nct1008_data, work);
88 int irq = data->client->irq;
90 mutex_lock(&data->mutex);
93 /* Therm2 line is active low */
94 data->alarm_fn(!gpio_get_value(irq_to_gpio(irq)));
97 mutex_unlock(&data->mutex);
100 static irqreturn_t nct1008_irq(int irq, void *dev_id)
102 struct nct1008_data *data = dev_id;
103 schedule_work(&data->work);
108 static inline u8 value_to_temperature(bool extended, u8 value)
110 return (extended ? (u8)(value - EXTENDED_RANGE_OFFSET) : value);
113 static inline u8 temperature_to_value(bool extended, u8 temp)
115 return (extended ? (u8)(temp + EXTENDED_RANGE_OFFSET) : temp);
118 static int __devinit nct1008_configure_sensor(struct nct1008_data* data)
120 struct i2c_client *client = data->client;
121 struct nct1008_platform_data *pdata = client->dev.platform_data;
125 if (!pdata || !pdata->supported_hwrev)
129 * Initial Configuration - device is placed in standby and
130 * ALERT/THERM2 pin is configured as THERM2
132 data->config = value = pdata->ext_range ?
133 (STANDBY_BIT | THERM2_BIT | EXTENDED_RANGE_BIT) :
134 (STANDBY_BIT | THERM2_BIT);
136 err = i2c_smbus_write_byte_data(client, CONFIG_WR, value);
140 /* Temperature conversion rate */
141 err = i2c_smbus_write_byte_data(client, CONV_RATE_WR, pdata->conv_rate);
145 /* External temperature h/w shutdown limit */
146 value = temperature_to_value(pdata->ext_range, pdata->shutdown_ext_limit);
147 err = i2c_smbus_write_byte_data(client, EXT_THERM_LIMIT_WR, value);
151 /* Local temperature h/w shutdown limit */
152 value = temperature_to_value(pdata->ext_range, pdata->shutdown_local_limit);
153 err = i2c_smbus_write_byte_data(client, LOCAL_THERM_LIMIT_WR, value);
157 /* External Temperature Throttling limit */
158 value = temperature_to_value(pdata->ext_range, pdata->throttling_ext_limit);
159 err = i2c_smbus_write_byte_data(client, EXT_TEMP_HI_LIMIT_HI_BYTE, value);
163 /* Local Temperature Throttling limit */
164 value = pdata->ext_range ? EXTENDED_RANGE_MAX : STANDARD_RANGE_MAX;
165 err = i2c_smbus_write_byte_data(client, LOCAL_TEMP_HI_LIMIT_WR, value);
169 /* Remote channel offset */
170 err = i2c_smbus_write_byte_data(client, OFFSET_WR, pdata->offset);
174 /* THERM hysteresis */
175 err = i2c_smbus_write_byte_data(client, THERM_HYSTERESIS_WR, pdata->hysteresis);
179 data->alarm_fn = pdata->alarm_fn;
185 static int __devinit nct1008_configure_irq(struct nct1008_data *data)
187 INIT_WORK(&data->work, nct1008_work_func);
189 return request_irq(data->client->irq, nct1008_irq, IRQF_TRIGGER_RISING |
190 IRQF_TRIGGER_FALLING, DRIVER_NAME, data);
193 static int __devinit nct1008_probe(struct i2c_client *client, const struct i2c_device_id *id)
195 struct nct1008_data *data;
198 data = kzalloc(sizeof(struct nct1008_data), GFP_KERNEL);
203 data->client = client;
204 i2c_set_clientdata(client, data);
205 mutex_init(&data->mutex);
207 err = nct1008_configure_sensor(data); /* sensor is in standby */
211 err = nct1008_configure_irq(data);
215 nct1008_enable(client); /* sensor is running */
217 schedule_work(&data->work); /* check initial state */
226 static int __devexit nct1008_remove(struct i2c_client *client)
228 struct nct1008_data *data = i2c_get_clientdata(client);
230 free_irq(data->client->irq, data);
231 cancel_work_sync(&data->work);
238 static int nct1008_suspend(struct i2c_client *client, pm_message_t state)
240 disable_irq(client->irq);
241 nct1008_disable(client);
246 static int nct1008_resume(struct i2c_client *client)
248 struct nct1008_data *data = i2c_get_clientdata(client);
250 nct1008_enable(client);
251 enable_irq(client->irq);
252 schedule_work(&data->work);
258 static const struct i2c_device_id nct1008_id[] = {
262 MODULE_DEVICE_TABLE(i2c, nct1008_id);
264 static struct i2c_driver nct1008_driver = {
268 .probe = nct1008_probe,
269 .remove = __devexit_p(nct1008_remove),
270 .id_table = nct1008_id,
272 .suspend = nct1008_suspend,
273 .resume = nct1008_resume,
277 static int __init nct1008_init(void)
279 return i2c_add_driver(&nct1008_driver);
282 static void __exit nct1008_exit(void)
284 i2c_del_driver(&nct1008_driver);
287 MODULE_DESCRIPTION("Temperature sensor driver for OnSemi NCT1008");
288 MODULE_LICENSE("GPL");
290 module_init (nct1008_init);
291 module_exit (nct1008_exit);