|
@@ -24,7 +24,11 @@
|
|
|
#include <linux/bitops.h>
|
|
|
#include "pmbus.h"
|
|
|
|
|
|
-enum chips { adm1075, adm1275, adm1276 };
|
|
|
+enum chips { adm1075, adm1275, adm1276, adm1293, adm1294 };
|
|
|
+
|
|
|
+#define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0)
|
|
|
+#define ADM1293_MFR_STATUS_VAUX_UV_WARN BIT(5)
|
|
|
+#define ADM1293_MFR_STATUS_VAUX_OV_WARN BIT(6)
|
|
|
|
|
|
#define ADM1275_PEAK_IOUT 0xd0
|
|
|
#define ADM1275_PEAK_VIN 0xd1
|
|
@@ -37,18 +41,30 @@ enum chips { adm1075, adm1275, adm1276 };
|
|
|
#define ADM1075_IRANGE_25 BIT(3)
|
|
|
#define ADM1075_IRANGE_MASK (BIT(3) | BIT(4))
|
|
|
|
|
|
+#define ADM1293_IRANGE_25 0
|
|
|
+#define ADM1293_IRANGE_50 BIT(6)
|
|
|
+#define ADM1293_IRANGE_100 BIT(7)
|
|
|
+#define ADM1293_IRANGE_200 (BIT(6) | BIT(7))
|
|
|
+#define ADM1293_IRANGE_MASK (BIT(6) | BIT(7))
|
|
|
+
|
|
|
+#define ADM1293_VIN_SEL_012 BIT(2)
|
|
|
+#define ADM1293_VIN_SEL_074 BIT(3)
|
|
|
+#define ADM1293_VIN_SEL_210 (BIT(2) | BIT(3))
|
|
|
+#define ADM1293_VIN_SEL_MASK (BIT(2) | BIT(3))
|
|
|
+
|
|
|
+#define ADM1293_VAUX_EN BIT(1)
|
|
|
+
|
|
|
#define ADM1275_IOUT_WARN2_LIMIT 0xd7
|
|
|
#define ADM1275_DEVICE_CONFIG 0xd8
|
|
|
|
|
|
#define ADM1275_IOUT_WARN2_SELECT BIT(4)
|
|
|
|
|
|
#define ADM1276_PEAK_PIN 0xda
|
|
|
-
|
|
|
-#define ADM1275_MFR_STATUS_IOUT_WARN2 BIT(0)
|
|
|
-
|
|
|
#define ADM1075_READ_VAUX 0xdd
|
|
|
#define ADM1075_VAUX_OV_WARN_LIMIT 0xde
|
|
|
#define ADM1075_VAUX_UV_WARN_LIMIT 0xdf
|
|
|
+#define ADM1293_IOUT_MIN 0xe3
|
|
|
+#define ADM1293_PIN_MIN 0xe4
|
|
|
#define ADM1075_VAUX_STATUS 0xf6
|
|
|
|
|
|
#define ADM1075_VAUX_OV_WARN BIT(7)
|
|
@@ -60,6 +76,9 @@ struct adm1275_data {
|
|
|
bool have_uc_fault;
|
|
|
bool have_vout;
|
|
|
bool have_vaux_status;
|
|
|
+ bool have_mfr_vaux_status;
|
|
|
+ bool have_iout_min;
|
|
|
+ bool have_pin_min;
|
|
|
bool have_pin_max;
|
|
|
struct pmbus_driver_info info;
|
|
|
};
|
|
@@ -94,6 +113,28 @@ static const struct coefficients adm1276_coefficients[] = {
|
|
|
[4] = { 2115, 0, -1 }, /* power, vrange not set */
|
|
|
};
|
|
|
|
|
|
+static const struct coefficients adm1293_coefficients[] = {
|
|
|
+ [0] = { 3333, -1, 0 }, /* voltage, vrange 1.2V */
|
|
|
+ [1] = { 5552, -5, -1 }, /* voltage, vrange 7.4V */
|
|
|
+ [2] = { 19604, -50, -2 }, /* voltage, vrange 21V */
|
|
|
+ [3] = { 8000, -100, -2 }, /* current, irange25 */
|
|
|
+ [4] = { 4000, -100, -2 }, /* current, irange50 */
|
|
|
+ [5] = { 20000, -1000, -3 }, /* current, irange100 */
|
|
|
+ [6] = { 10000, -1000, -3 }, /* current, irange200 */
|
|
|
+ [7] = { 10417, 0, -1 }, /* power, 1.2V, irange25 */
|
|
|
+ [8] = { 5208, 0, -1 }, /* power, 1.2V, irange50 */
|
|
|
+ [9] = { 26042, 0, -2 }, /* power, 1.2V, irange100 */
|
|
|
+ [10] = { 13021, 0, -2 }, /* power, 1.2V, irange200 */
|
|
|
+ [11] = { 17351, 0, -2 }, /* power, 7.4V, irange25 */
|
|
|
+ [12] = { 8676, 0, -2 }, /* power, 7.4V, irange50 */
|
|
|
+ [13] = { 4338, 0, -2 }, /* power, 7.4V, irange100 */
|
|
|
+ [14] = { 21689, 0, -3 }, /* power, 7.4V, irange200 */
|
|
|
+ [15] = { 6126, 0, -2 }, /* power, 21V, irange25 */
|
|
|
+ [16] = { 30631, 0, -3 }, /* power, 21V, irange50 */
|
|
|
+ [17] = { 15316, 0, -3 }, /* power, 21V, irange100 */
|
|
|
+ [18] = { 7658, 0, -3 }, /* power, 21V, irange200 */
|
|
|
+};
|
|
|
+
|
|
|
static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
|
|
|
{
|
|
|
const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
|
@@ -131,6 +172,11 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
|
|
|
return -ENODATA;
|
|
|
ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX);
|
|
|
break;
|
|
|
+ case PMBUS_VIRT_READ_IOUT_MIN:
|
|
|
+ if (!data->have_iout_min)
|
|
|
+ return -ENXIO;
|
|
|
+ ret = pmbus_read_word_data(client, 0, ADM1293_IOUT_MIN);
|
|
|
+ break;
|
|
|
case PMBUS_VIRT_READ_IOUT_MAX:
|
|
|
ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT);
|
|
|
break;
|
|
@@ -140,6 +186,11 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
|
|
|
case PMBUS_VIRT_READ_VIN_MAX:
|
|
|
ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN);
|
|
|
break;
|
|
|
+ case PMBUS_VIRT_READ_PIN_MIN:
|
|
|
+ if (!data->have_pin_min)
|
|
|
+ return -ENXIO;
|
|
|
+ ret = pmbus_read_word_data(client, 0, ADM1293_PIN_MIN);
|
|
|
+ break;
|
|
|
case PMBUS_VIRT_READ_PIN_MAX:
|
|
|
if (!data->have_pin_max)
|
|
|
return -ENXIO;
|
|
@@ -163,6 +214,8 @@ static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
|
|
|
static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
|
|
|
u16 word)
|
|
|
{
|
|
|
+ const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
|
|
|
+ const struct adm1275_data *data = to_adm1275_data(info);
|
|
|
int ret;
|
|
|
|
|
|
if (page)
|
|
@@ -176,6 +229,9 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
|
|
|
break;
|
|
|
case PMBUS_VIRT_RESET_IOUT_HISTORY:
|
|
|
ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0);
|
|
|
+ if (!ret && data->have_iout_min)
|
|
|
+ ret = pmbus_write_word_data(client, 0,
|
|
|
+ ADM1293_IOUT_MIN, 0);
|
|
|
break;
|
|
|
case PMBUS_VIRT_RESET_VOUT_HISTORY:
|
|
|
ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0);
|
|
@@ -185,6 +241,9 @@ static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
|
|
|
break;
|
|
|
case PMBUS_VIRT_RESET_PIN_HISTORY:
|
|
|
ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0);
|
|
|
+ if (!ret && data->have_pin_min)
|
|
|
+ ret = pmbus_write_word_data(client, 0,
|
|
|
+ ADM1293_PIN_MIN, 0);
|
|
|
break;
|
|
|
default:
|
|
|
ret = -ENODATA;
|
|
@@ -231,6 +290,15 @@ static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg)
|
|
|
ret |= PB_VOLTAGE_OV_WARNING;
|
|
|
if (mfr_status & ADM1075_VAUX_UV_WARN)
|
|
|
ret |= PB_VOLTAGE_UV_WARNING;
|
|
|
+ } else if (data->have_mfr_vaux_status) {
|
|
|
+ mfr_status = pmbus_read_byte_data(client, page,
|
|
|
+ PMBUS_STATUS_MFR_SPECIFIC);
|
|
|
+ if (mfr_status < 0)
|
|
|
+ return mfr_status;
|
|
|
+ if (mfr_status & ADM1293_MFR_STATUS_VAUX_OV_WARN)
|
|
|
+ ret |= PB_VOLTAGE_OV_WARNING;
|
|
|
+ if (mfr_status & ADM1293_MFR_STATUS_VAUX_UV_WARN)
|
|
|
+ ret |= PB_VOLTAGE_UV_WARNING;
|
|
|
}
|
|
|
break;
|
|
|
default:
|
|
@@ -244,6 +312,8 @@ static const struct i2c_device_id adm1275_id[] = {
|
|
|
{ "adm1075", adm1075 },
|
|
|
{ "adm1275", adm1275 },
|
|
|
{ "adm1276", adm1276 },
|
|
|
+ { "adm1293", adm1293 },
|
|
|
+ { "adm1294", adm1294 },
|
|
|
{ }
|
|
|
};
|
|
|
MODULE_DEVICE_TABLE(i2c, adm1275_id);
|
|
@@ -258,7 +328,7 @@ static int adm1275_probe(struct i2c_client *client,
|
|
|
struct adm1275_data *data;
|
|
|
const struct i2c_device_id *mid;
|
|
|
const struct coefficients *coefficients;
|
|
|
- int vindex = -1, cindex = -1, pindex = -1;
|
|
|
+ int vindex = -1, voindex = -1, cindex = -1, pindex = -1;
|
|
|
|
|
|
if (!i2c_check_functionality(client->adapter,
|
|
|
I2C_FUNC_SMBUS_READ_BYTE_DATA
|
|
@@ -390,17 +460,72 @@ static int adm1275_probe(struct i2c_client *client,
|
|
|
info->func[0] |=
|
|
|
PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
|
|
|
break;
|
|
|
+ case adm1293:
|
|
|
+ case adm1294:
|
|
|
+ data->have_iout_min = true;
|
|
|
+ data->have_pin_min = true;
|
|
|
+ data->have_pin_max = true;
|
|
|
+ data->have_mfr_vaux_status = true;
|
|
|
+
|
|
|
+ coefficients = adm1293_coefficients;
|
|
|
+
|
|
|
+ voindex = 0;
|
|
|
+ switch (config & ADM1293_VIN_SEL_MASK) {
|
|
|
+ case ADM1293_VIN_SEL_012: /* 1.2V */
|
|
|
+ vindex = 0;
|
|
|
+ break;
|
|
|
+ case ADM1293_VIN_SEL_074: /* 7.4V */
|
|
|
+ vindex = 1;
|
|
|
+ break;
|
|
|
+ case ADM1293_VIN_SEL_210: /* 21V */
|
|
|
+ vindex = 2;
|
|
|
+ break;
|
|
|
+ default: /* disabled */
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ switch (config & ADM1293_IRANGE_MASK) {
|
|
|
+ case ADM1293_IRANGE_25:
|
|
|
+ cindex = 3;
|
|
|
+ break;
|
|
|
+ case ADM1293_IRANGE_50:
|
|
|
+ cindex = 4;
|
|
|
+ break;
|
|
|
+ case ADM1293_IRANGE_100:
|
|
|
+ cindex = 5;
|
|
|
+ break;
|
|
|
+ case ADM1293_IRANGE_200:
|
|
|
+ cindex = 6;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (vindex >= 0)
|
|
|
+ pindex = 7 + vindex * 4 + (cindex - 3);
|
|
|
+
|
|
|
+ if (config & ADM1293_VAUX_EN)
|
|
|
+ info->func[0] |=
|
|
|
+ PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
|
|
|
+
|
|
|
+ info->func[0] |= PMBUS_HAVE_PIN |
|
|
|
+ PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
|
|
|
+
|
|
|
+ break;
|
|
|
default:
|
|
|
dev_err(&client->dev, "Unsupported device\n");
|
|
|
return -ENODEV;
|
|
|
}
|
|
|
+
|
|
|
+ if (voindex < 0)
|
|
|
+ voindex = vindex;
|
|
|
if (vindex >= 0) {
|
|
|
info->m[PSC_VOLTAGE_IN] = coefficients[vindex].m;
|
|
|
info->b[PSC_VOLTAGE_IN] = coefficients[vindex].b;
|
|
|
info->R[PSC_VOLTAGE_IN] = coefficients[vindex].R;
|
|
|
- info->m[PSC_VOLTAGE_OUT] = coefficients[vindex].m;
|
|
|
- info->b[PSC_VOLTAGE_OUT] = coefficients[vindex].b;
|
|
|
- info->R[PSC_VOLTAGE_OUT] = coefficients[vindex].R;
|
|
|
+ }
|
|
|
+ if (voindex >= 0) {
|
|
|
+ info->m[PSC_VOLTAGE_OUT] = coefficients[voindex].m;
|
|
|
+ info->b[PSC_VOLTAGE_OUT] = coefficients[voindex].b;
|
|
|
+ info->R[PSC_VOLTAGE_OUT] = coefficients[voindex].R;
|
|
|
}
|
|
|
if (cindex >= 0) {
|
|
|
info->m[PSC_CURRENT_OUT] = coefficients[cindex].m;
|