Commit e04d1ce9 authored by Michael Jones's avatar Michael Jones Committed by Guenter Roeck

hwmon: (ltc2978) Add polling for chips requiring it

Some of the LTC chips supported by this driver have to be polled
to ensure that they are ready to accept commands.
Signed-off-by: default avatarMichael Jones <mike@proclivis.com>
[Guenter Roeck: simplifications and formatting changes]
Signed-off-by: default avatarGuenter Roeck <linux@roeck-us.net>
parent d830e27d
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
* *
* Copyright (c) 2011 Ericsson AB. * Copyright (c) 2011 Ericsson AB.
* Copyright (c) 2013, 2014, 2015 Guenter Roeck * Copyright (c) 2013, 2014, 2015 Guenter Roeck
* Copyright (c) 2015 Linear Technology
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
...@@ -15,6 +16,8 @@ ...@@ -15,6 +16,8 @@
* GNU General Public License for more details. * GNU General Public License for more details.
*/ */
#include <linux/delay.h>
#include <linux/jiffies.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -32,6 +35,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, ...@@ -32,6 +35,7 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882,
#define LTC2978_MFR_VIN_PEAK 0xde #define LTC2978_MFR_VIN_PEAK 0xde
#define LTC2978_MFR_TEMPERATURE_PEAK 0xdf #define LTC2978_MFR_TEMPERATURE_PEAK 0xdf
#define LTC2978_MFR_SPECIAL_ID 0xe7 /* Undocumented on LTC3882 */ #define LTC2978_MFR_SPECIAL_ID 0xe7 /* Undocumented on LTC3882 */
#define LTC2978_MFR_COMMON 0xef
/* LTC2974, LTC2975, LCT2977, LTC2980, LTC2978, and LTM2987 */ /* LTC2974, LTC2975, LCT2977, LTC2980, LTC2978, and LTM2987 */
#define LTC2978_MFR_VOUT_MIN 0xfb #define LTC2978_MFR_VOUT_MIN 0xfb
...@@ -82,6 +86,11 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882, ...@@ -82,6 +86,11 @@ enum chips { ltc2974, ltc2975, ltc2977, ltc2978, ltc2980, ltc3880, ltc3882,
#define LTC3880_NUM_PAGES 2 #define LTC3880_NUM_PAGES 2
#define LTC3883_NUM_PAGES 1 #define LTC3883_NUM_PAGES 1
#define LTC_POLL_TIMEOUT 100 /* in milli-seconds */
#define LTC_NOT_BUSY BIT(5)
#define LTC_NOT_PENDING BIT(4)
/* /*
* LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which * LTC2978 clears peak data whenever the CLEAR_FAULTS command is executed, which
* happens pretty much each time chip data is updated. Raw peak data therefore * happens pretty much each time chip data is updated. Raw peak data therefore
...@@ -105,8 +114,81 @@ struct ltc2978_data { ...@@ -105,8 +114,81 @@ struct ltc2978_data {
#define to_ltc2978_data(x) container_of(x, struct ltc2978_data, info) #define to_ltc2978_data(x) container_of(x, struct ltc2978_data, info)
#define FEAT_CLEAR_PEAKS BIT(0) #define FEAT_CLEAR_PEAKS BIT(0)
#define FEAT_NEEDS_POLLING BIT(1)
#define has_clear_peaks(d) ((d)->features & FEAT_CLEAR_PEAKS) #define has_clear_peaks(d) ((d)->features & FEAT_CLEAR_PEAKS)
#define needs_polling(d) ((d)->features & FEAT_NEEDS_POLLING)
static int ltc_wait_ready(struct i2c_client *client)
{
unsigned long timeout = jiffies + msecs_to_jiffies(LTC_POLL_TIMEOUT);
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
struct ltc2978_data *data = to_ltc2978_data(info);
int status;
u8 mask;
if (!needs_polling(data))
return 0;
/*
* LTC3883 does not support LTC_NOT_PENDING, even though
* the datasheet claims that it does.
*/
mask = LTC_NOT_BUSY;
if (data->id != ltc3883)
mask |= LTC_NOT_PENDING;
do {
status = pmbus_read_byte_data(client, 0, LTC2978_MFR_COMMON);
if (status == -EBADMSG || status == -ENXIO) {
/* PEC error or NACK: chip may be busy, try again */
usleep_range(50, 100);
continue;
}
if (status < 0)
return status;
if ((status & mask) == mask)
return 0;
usleep_range(50, 100);
} while (time_before(jiffies, timeout));
return -ETIMEDOUT;
}
static int ltc_read_word_data(struct i2c_client *client, int page, int reg)
{
int ret;
ret = ltc_wait_ready(client);
if (ret < 0)
return ret;
return pmbus_read_word_data(client, page, reg);
}
static int ltc_read_byte_data(struct i2c_client *client, int page, int reg)
{
int ret;
ret = ltc_wait_ready(client);
if (ret < 0)
return ret;
return pmbus_read_byte_data(client, page, reg);
}
static int ltc_write_byte(struct i2c_client *client, int page, u8 byte)
{
int ret;
ret = ltc_wait_ready(client);
if (ret < 0)
return ret;
return pmbus_write_byte(client, page, byte);
}
static inline int lin11_to_val(int data) static inline int lin11_to_val(int data)
{ {
...@@ -126,7 +208,7 @@ static int ltc_get_max(struct ltc2978_data *data, struct i2c_client *client, ...@@ -126,7 +208,7 @@ static int ltc_get_max(struct ltc2978_data *data, struct i2c_client *client,
{ {
int ret; int ret;
ret = pmbus_read_word_data(client, page, reg); ret = ltc_read_word_data(client, page, reg);
if (ret >= 0) { if (ret >= 0) {
if (lin11_to_val(ret) > lin11_to_val(*pmax)) if (lin11_to_val(ret) > lin11_to_val(*pmax))
*pmax = ret; *pmax = ret;
...@@ -140,7 +222,7 @@ static int ltc_get_min(struct ltc2978_data *data, struct i2c_client *client, ...@@ -140,7 +222,7 @@ static int ltc_get_min(struct ltc2978_data *data, struct i2c_client *client,
{ {
int ret; int ret;
ret = pmbus_read_word_data(client, page, reg); ret = ltc_read_word_data(client, page, reg);
if (ret >= 0) { if (ret >= 0) {
if (lin11_to_val(ret) < lin11_to_val(*pmin)) if (lin11_to_val(ret) < lin11_to_val(*pmin))
*pmin = ret; *pmin = ret;
...@@ -162,7 +244,7 @@ static int ltc2978_read_word_data_common(struct i2c_client *client, int page, ...@@ -162,7 +244,7 @@ static int ltc2978_read_word_data_common(struct i2c_client *client, int page,
&data->vin_max); &data->vin_max);
break; break;
case PMBUS_VIRT_READ_VOUT_MAX: case PMBUS_VIRT_READ_VOUT_MAX:
ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_PEAK); ret = ltc_read_word_data(client, page, LTC2978_MFR_VOUT_PEAK);
if (ret >= 0) { if (ret >= 0) {
/* /*
* VOUT is 16 bit unsigned with fixed exponent, * VOUT is 16 bit unsigned with fixed exponent,
...@@ -184,6 +266,9 @@ static int ltc2978_read_word_data_common(struct i2c_client *client, int page, ...@@ -184,6 +266,9 @@ static int ltc2978_read_word_data_common(struct i2c_client *client, int page,
ret = 0; ret = 0;
break; break;
default: default:
ret = ltc_wait_ready(client);
if (ret < 0)
return ret;
ret = -ENODATA; ret = -ENODATA;
break; break;
} }
...@@ -202,7 +287,7 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg) ...@@ -202,7 +287,7 @@ static int ltc2978_read_word_data(struct i2c_client *client, int page, int reg)
&data->vin_min); &data->vin_min);
break; break;
case PMBUS_VIRT_READ_VOUT_MIN: case PMBUS_VIRT_READ_VOUT_MIN:
ret = pmbus_read_word_data(client, page, LTC2978_MFR_VOUT_MIN); ret = ltc_read_word_data(client, page, LTC2978_MFR_VOUT_MIN);
if (ret >= 0) { if (ret >= 0) {
/* /*
* VOUT_MIN is known to not be supported on some lots * VOUT_MIN is known to not be supported on some lots
...@@ -353,9 +438,9 @@ static int ltc2978_clear_peaks(struct ltc2978_data *data, ...@@ -353,9 +438,9 @@ static int ltc2978_clear_peaks(struct ltc2978_data *data,
int ret; int ret;
if (has_clear_peaks(data)) if (has_clear_peaks(data))
ret = pmbus_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS); ret = ltc_write_byte(client, 0, LTC3880_MFR_CLEAR_PEAKS);
else else
ret = pmbus_write_byte(client, page, PMBUS_CLEAR_FAULTS); ret = ltc_write_byte(client, page, PMBUS_CLEAR_FAULTS);
return ret; return ret;
} }
...@@ -403,6 +488,9 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page, ...@@ -403,6 +488,9 @@ static int ltc2978_write_word_data(struct i2c_client *client, int page,
ret = ltc2978_clear_peaks(data, client, page); ret = ltc2978_clear_peaks(data, client, page);
break; break;
default: default:
ret = ltc_wait_ready(client);
if (ret < 0)
return ret;
ret = -ENODATA; ret = -ENODATA;
break; break;
} }
...@@ -530,6 +618,9 @@ static int ltc2978_probe(struct i2c_client *client, ...@@ -530,6 +618,9 @@ static int ltc2978_probe(struct i2c_client *client,
info = &data->info; info = &data->info;
info->write_word_data = ltc2978_write_word_data; info->write_word_data = ltc2978_write_word_data;
info->write_byte = ltc_write_byte;
info->read_word_data = ltc_read_word_data;
info->read_byte_data = ltc_read_byte_data;
data->vin_min = 0x7bff; data->vin_min = 0x7bff;
data->vin_max = 0x7c00; data->vin_max = 0x7c00;
...@@ -588,7 +679,7 @@ static int ltc2978_probe(struct i2c_client *client, ...@@ -588,7 +679,7 @@ static int ltc2978_probe(struct i2c_client *client,
case ltc3880: case ltc3880:
case ltc3887: case ltc3887:
case ltm4676: case ltm4676:
data->features |= FEAT_CLEAR_PEAKS; data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
info->read_word_data = ltc3880_read_word_data; info->read_word_data = ltc3880_read_word_data;
info->pages = LTC3880_NUM_PAGES; info->pages = LTC3880_NUM_PAGES;
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
...@@ -603,7 +694,7 @@ static int ltc2978_probe(struct i2c_client *client, ...@@ -603,7 +694,7 @@ static int ltc2978_probe(struct i2c_client *client,
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
break; break;
case ltc3882: case ltc3882:
data->features |= FEAT_CLEAR_PEAKS; data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
info->read_word_data = ltc3880_read_word_data; info->read_word_data = ltc3880_read_word_data;
info->pages = LTC3880_NUM_PAGES; info->pages = LTC3880_NUM_PAGES;
info->func[0] = PMBUS_HAVE_VIN info->func[0] = PMBUS_HAVE_VIN
...@@ -618,7 +709,7 @@ static int ltc2978_probe(struct i2c_client *client, ...@@ -618,7 +709,7 @@ static int ltc2978_probe(struct i2c_client *client,
| PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP; | PMBUS_HAVE_TEMP | PMBUS_HAVE_STATUS_TEMP;
break; break;
case ltc3883: case ltc3883:
data->features |= FEAT_CLEAR_PEAKS; data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
info->read_word_data = ltc3883_read_word_data; info->read_word_data = ltc3883_read_word_data;
info->pages = LTC3883_NUM_PAGES; info->pages = LTC3883_NUM_PAGES;
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
...@@ -629,7 +720,7 @@ static int ltc2978_probe(struct i2c_client *client, ...@@ -629,7 +720,7 @@ static int ltc2978_probe(struct i2c_client *client,
| PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP; | PMBUS_HAVE_TEMP2 | PMBUS_HAVE_STATUS_TEMP;
break; break;
case ltc3886: case ltc3886:
data->features |= FEAT_CLEAR_PEAKS; data->features |= FEAT_CLEAR_PEAKS | FEAT_NEEDS_POLLING;
info->read_word_data = ltc3883_read_word_data; info->read_word_data = ltc3883_read_word_data;
info->pages = LTC3880_NUM_PAGES; info->pages = LTC3880_NUM_PAGES;
info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN info->func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment