jc42.c (41be702a542a0d14bb0b1c16e824fa9ed27616ec) jc42.c (d397276b0c833b0089cb19d94fbc35a43ada58a7)
1/*
2 * jc42.c - driver for Jedec JC42.4 compliant temperature sensors
3 *
4 * Copyright (c) 2010 Ericsson AB.
5 *
6 * Derived from lm77.c by Andras BALI <drewie@freemail.hu>.
7 *
8 * JC42.4 compliant temperature sensors are typically used on memory modules.

--- 162 unchanged lines hidden (view full) ---

171 u16 orig_config; /* original configuration */
172 u16 config; /* current configuration */
173 u16 temp_input; /* Temperatures */
174 u16 temp_crit;
175 u16 temp_min;
176 u16 temp_max;
177};
178
1/*
2 * jc42.c - driver for Jedec JC42.4 compliant temperature sensors
3 *
4 * Copyright (c) 2010 Ericsson AB.
5 *
6 * Derived from lm77.c by Andras BALI <drewie@freemail.hu>.
7 *
8 * JC42.4 compliant temperature sensors are typically used on memory modules.

--- 162 unchanged lines hidden (view full) ---

171 u16 orig_config; /* original configuration */
172 u16 config; /* current configuration */
173 u16 temp_input; /* Temperatures */
174 u16 temp_crit;
175 u16 temp_min;
176 u16 temp_max;
177};
178
179static int jc42_probe(struct i2c_client *client,
180 const struct i2c_device_id *id);
181static int jc42_detect(struct i2c_client *client, struct i2c_board_info *info);
182static int jc42_remove(struct i2c_client *client);
183
184static struct jc42_data *jc42_update_device(struct device *dev);
185
186static const struct i2c_device_id jc42_id[] = {
187 { "jc42", 0 },
188 { }
189};
190MODULE_DEVICE_TABLE(i2c, jc42_id);
191
192#ifdef CONFIG_PM
193
194static int jc42_suspend(struct device *dev)
195{
196 struct jc42_data *data = dev_get_drvdata(dev);
197
198 data->config |= JC42_CFG_SHUTDOWN;
199 i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG,
200 data->config);
201 return 0;
202}
203
204static int jc42_resume(struct device *dev)
205{
206 struct jc42_data *data = dev_get_drvdata(dev);
207
208 data->config &= ~JC42_CFG_SHUTDOWN;
209 i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG,
210 data->config);
211 return 0;
212}
213
214static const struct dev_pm_ops jc42_dev_pm_ops = {
215 .suspend = jc42_suspend,
216 .resume = jc42_resume,
217};
218
219#define JC42_DEV_PM_OPS (&jc42_dev_pm_ops)
220#else
221#define JC42_DEV_PM_OPS NULL
222#endif /* CONFIG_PM */
223
224/* This is the driver that will be inserted */
225static struct i2c_driver jc42_driver = {
226 .class = I2C_CLASS_SPD,
227 .driver = {
228 .name = "jc42",
229 .pm = JC42_DEV_PM_OPS,
230 },
231 .probe = jc42_probe,
232 .remove = jc42_remove,
233 .id_table = jc42_id,
234 .detect = jc42_detect,
235 .address_list = normal_i2c,
236};
237
238#define JC42_TEMP_MIN_EXTENDED (-40000)
239#define JC42_TEMP_MIN 0
240#define JC42_TEMP_MAX 125000
241
242static u16 jc42_temp_to_reg(int temp, bool extended)
243{
244 int ntemp = clamp_val(temp,
245 extended ? JC42_TEMP_MIN_EXTENDED :

--- 10 unchanged lines hidden (view full) ---

256 /* sign extend register */
257 if (reg & 0x1000)
258 reg |= 0xf000;
259
260 /* convert from 0.0625 to 0.001 resolution */
261 return reg * 125 / 2;
262}
263
179#define JC42_TEMP_MIN_EXTENDED (-40000)
180#define JC42_TEMP_MIN 0
181#define JC42_TEMP_MAX 125000
182
183static u16 jc42_temp_to_reg(int temp, bool extended)
184{
185 int ntemp = clamp_val(temp,
186 extended ? JC42_TEMP_MIN_EXTENDED :

--- 10 unchanged lines hidden (view full) ---

197 /* sign extend register */
198 if (reg & 0x1000)
199 reg |= 0xf000;
200
201 /* convert from 0.0625 to 0.001 resolution */
202 return reg * 125 / 2;
203}
204
205static struct jc42_data *jc42_update_device(struct device *dev)
206{
207 struct jc42_data *data = dev_get_drvdata(dev);
208 struct i2c_client *client = data->client;
209 struct jc42_data *ret = data;
210 int val;
211
212 mutex_lock(&data->update_lock);
213
214 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
215 val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP);
216 if (val < 0) {
217 ret = ERR_PTR(val);
218 goto abort;
219 }
220 data->temp_input = val;
221
222 val = i2c_smbus_read_word_swapped(client,
223 JC42_REG_TEMP_CRITICAL);
224 if (val < 0) {
225 ret = ERR_PTR(val);
226 goto abort;
227 }
228 data->temp_crit = val;
229
230 val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_LOWER);
231 if (val < 0) {
232 ret = ERR_PTR(val);
233 goto abort;
234 }
235 data->temp_min = val;
236
237 val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_UPPER);
238 if (val < 0) {
239 ret = ERR_PTR(val);
240 goto abort;
241 }
242 data->temp_max = val;
243
244 data->last_updated = jiffies;
245 data->valid = true;
246 }
247abort:
248 mutex_unlock(&data->update_lock);
249 return ret;
250}
251
264/* sysfs stuff */
265
266/* read routines for temperature limits */
267#define show(value) \
268static ssize_t show_##value(struct device *dev, \
269 struct device_attribute *attr, \
270 char *buf) \
271{ \

--- 260 unchanged lines hidden (view full) ---

532
533 config = (data->orig_config & ~JC42_CFG_HYST_MASK)
534 | (data->config & JC42_CFG_HYST_MASK);
535 i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, config);
536 }
537 return 0;
538}
539
252/* sysfs stuff */
253
254/* read routines for temperature limits */
255#define show(value) \
256static ssize_t show_##value(struct device *dev, \
257 struct device_attribute *attr, \
258 char *buf) \
259{ \

--- 260 unchanged lines hidden (view full) ---

520
521 config = (data->orig_config & ~JC42_CFG_HYST_MASK)
522 | (data->config & JC42_CFG_HYST_MASK);
523 i2c_smbus_write_word_swapped(client, JC42_REG_CONFIG, config);
524 }
525 return 0;
526}
527
540static struct jc42_data *jc42_update_device(struct device *dev)
528#ifdef CONFIG_PM
529
530static int jc42_suspend(struct device *dev)
541{
542 struct jc42_data *data = dev_get_drvdata(dev);
531{
532 struct jc42_data *data = dev_get_drvdata(dev);
543 struct i2c_client *client = data->client;
544 struct jc42_data *ret = data;
545 int val;
546
533
547 mutex_lock(&data->update_lock);
534 data->config |= JC42_CFG_SHUTDOWN;
535 i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG,
536 data->config);
537 return 0;
538}
548
539
549 if (time_after(jiffies, data->last_updated + HZ) || !data->valid) {
550 val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP);
551 if (val < 0) {
552 ret = ERR_PTR(val);
553 goto abort;
554 }
555 data->temp_input = val;
540static int jc42_resume(struct device *dev)
541{
542 struct jc42_data *data = dev_get_drvdata(dev);
556
543
557 val = i2c_smbus_read_word_swapped(client,
558 JC42_REG_TEMP_CRITICAL);
559 if (val < 0) {
560 ret = ERR_PTR(val);
561 goto abort;
562 }
563 data->temp_crit = val;
544 data->config &= ~JC42_CFG_SHUTDOWN;
545 i2c_smbus_write_word_swapped(data->client, JC42_REG_CONFIG,
546 data->config);
547 return 0;
548}
564
549
565 val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_LOWER);
566 if (val < 0) {
567 ret = ERR_PTR(val);
568 goto abort;
569 }
570 data->temp_min = val;
550static const struct dev_pm_ops jc42_dev_pm_ops = {
551 .suspend = jc42_suspend,
552 .resume = jc42_resume,
553};
571
554
572 val = i2c_smbus_read_word_swapped(client, JC42_REG_TEMP_UPPER);
573 if (val < 0) {
574 ret = ERR_PTR(val);
575 goto abort;
576 }
577 data->temp_max = val;
555#define JC42_DEV_PM_OPS (&jc42_dev_pm_ops)
556#else
557#define JC42_DEV_PM_OPS NULL
558#endif /* CONFIG_PM */
578
559
579 data->last_updated = jiffies;
580 data->valid = true;
581 }
582abort:
583 mutex_unlock(&data->update_lock);
584 return ret;
585}
560static const struct i2c_device_id jc42_id[] = {
561 { "jc42", 0 },
562 { }
563};
564MODULE_DEVICE_TABLE(i2c, jc42_id);
586
565
566static struct i2c_driver jc42_driver = {
567 .class = I2C_CLASS_SPD,
568 .driver = {
569 .name = "jc42",
570 .pm = JC42_DEV_PM_OPS,
571 },
572 .probe = jc42_probe,
573 .remove = jc42_remove,
574 .id_table = jc42_id,
575 .detect = jc42_detect,
576 .address_list = normal_i2c,
577};
578
587module_i2c_driver(jc42_driver);
588
589MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
590MODULE_DESCRIPTION("JC42 driver");
591MODULE_LICENSE("GPL");
579module_i2c_driver(jc42_driver);
580
581MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
582MODULE_DESCRIPTION("JC42 driver");
583MODULE_LICENSE("GPL");