xref: /linux/drivers/hwmon/pmbus/adm1275.c (revision 9048539b7cd6ca99e03e6d9745779473349426f7)
19d2ecfb7SGuenter Roeck /*
29d2ecfb7SGuenter Roeck  * Hardware monitoring driver for Analog Devices ADM1275 Hot-Swap Controller
39d2ecfb7SGuenter Roeck  * and Digital Power Monitor
49d2ecfb7SGuenter Roeck  *
59d2ecfb7SGuenter Roeck  * Copyright (c) 2011 Ericsson AB.
69d2ecfb7SGuenter Roeck  *
79d2ecfb7SGuenter Roeck  * This program is free software; you can redistribute it and/or modify
89d2ecfb7SGuenter Roeck  * it under the terms of the GNU General Public License as published by
99d2ecfb7SGuenter Roeck  * the Free Software Foundation; either version 2 of the License, or
109d2ecfb7SGuenter Roeck  * (at your option) any later version.
119d2ecfb7SGuenter Roeck  *
129d2ecfb7SGuenter Roeck  * This program is distributed in the hope that it will be useful,
139d2ecfb7SGuenter Roeck  * but WITHOUT ANY WARRANTY; without even the implied warranty of
149d2ecfb7SGuenter Roeck  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
159d2ecfb7SGuenter Roeck  * GNU General Public License for more details.
169d2ecfb7SGuenter Roeck  */
179d2ecfb7SGuenter Roeck 
189d2ecfb7SGuenter Roeck #include <linux/kernel.h>
199d2ecfb7SGuenter Roeck #include <linux/module.h>
209d2ecfb7SGuenter Roeck #include <linux/init.h>
219d2ecfb7SGuenter Roeck #include <linux/err.h>
229d2ecfb7SGuenter Roeck #include <linux/slab.h>
239d2ecfb7SGuenter Roeck #include <linux/i2c.h>
2499b41608SGuenter Roeck #include <linux/bitops.h>
259d2ecfb7SGuenter Roeck #include "pmbus.h"
269d2ecfb7SGuenter Roeck 
2792711269SGuenter Roeck enum chips { adm1075, adm1275, adm1276 };
285cf231a3SGuenter Roeck 
29c576e30cSGuenter Roeck #define ADM1275_PEAK_IOUT		0xd0
30c576e30cSGuenter Roeck #define ADM1275_PEAK_VIN		0xd1
31c576e30cSGuenter Roeck #define ADM1275_PEAK_VOUT		0xd2
329d2ecfb7SGuenter Roeck #define ADM1275_PMON_CONFIG		0xd4
339d2ecfb7SGuenter Roeck 
3499b41608SGuenter Roeck #define ADM1275_VIN_VOUT_SELECT		BIT(6)
3599b41608SGuenter Roeck #define ADM1275_VRANGE			BIT(5)
3699b41608SGuenter Roeck #define ADM1075_IRANGE_50		BIT(4)
3799b41608SGuenter Roeck #define ADM1075_IRANGE_25		BIT(3)
3899b41608SGuenter Roeck #define ADM1075_IRANGE_MASK		(BIT(3) | BIT(4))
399d2ecfb7SGuenter Roeck 
40c5e67636SGuenter Roeck #define ADM1275_IOUT_WARN2_LIMIT	0xd7
41c5e67636SGuenter Roeck #define ADM1275_DEVICE_CONFIG		0xd8
42c5e67636SGuenter Roeck 
4399b41608SGuenter Roeck #define ADM1275_IOUT_WARN2_SELECT	BIT(4)
44c5e67636SGuenter Roeck 
455cf231a3SGuenter Roeck #define ADM1276_PEAK_PIN		0xda
465cf231a3SGuenter Roeck 
4799b41608SGuenter Roeck #define ADM1275_MFR_STATUS_IOUT_WARN2	BIT(0)
48c5e67636SGuenter Roeck 
4992711269SGuenter Roeck #define ADM1075_READ_VAUX		0xdd
5092711269SGuenter Roeck #define ADM1075_VAUX_OV_WARN_LIMIT	0xde
5192711269SGuenter Roeck #define ADM1075_VAUX_UV_WARN_LIMIT	0xdf
5292711269SGuenter Roeck #define ADM1075_VAUX_STATUS		0xf6
5392711269SGuenter Roeck 
5499b41608SGuenter Roeck #define ADM1075_VAUX_OV_WARN		BIT(7)
5599b41608SGuenter Roeck #define ADM1075_VAUX_UV_WARN		BIT(6)
5692711269SGuenter Roeck 
57c5e67636SGuenter Roeck struct adm1275_data {
585cf231a3SGuenter Roeck 	int id;
59c5e67636SGuenter Roeck 	bool have_oc_fault;
60*9048539bSGuenter Roeck 	bool have_uc_fault;
61*9048539bSGuenter Roeck 	bool have_vout;
62*9048539bSGuenter Roeck 	bool have_vaux_status;
63*9048539bSGuenter Roeck 	bool have_pin_max;
64c5e67636SGuenter Roeck 	struct pmbus_driver_info info;
65c5e67636SGuenter Roeck };
66c5e67636SGuenter Roeck 
67c5e67636SGuenter Roeck #define to_adm1275_data(x)  container_of(x, struct adm1275_data, info)
68c5e67636SGuenter Roeck 
69904b296fSGuenter Roeck struct coefficients {
70904b296fSGuenter Roeck 	s16 m;
71904b296fSGuenter Roeck 	s16 b;
72904b296fSGuenter Roeck 	s16 R;
73904b296fSGuenter Roeck };
74904b296fSGuenter Roeck 
75904b296fSGuenter Roeck static const struct coefficients adm1075_coefficients[] = {
76904b296fSGuenter Roeck 	[0] = { 27169, 0, -1 },		/* voltage */
77904b296fSGuenter Roeck 	[1] = { 806, 20475, -1 },	/* current, irange25 */
78904b296fSGuenter Roeck 	[2] = { 404, 20475, -1 },	/* current, irange50 */
79904b296fSGuenter Roeck 	[3] = { 0, -1, 8549 },		/* power, irange25 */
80904b296fSGuenter Roeck 	[4] = { 0, -1, 4279 },		/* power, irange50 */
81904b296fSGuenter Roeck };
82904b296fSGuenter Roeck 
83904b296fSGuenter Roeck static const struct coefficients adm1275_coefficients[] = {
84904b296fSGuenter Roeck 	[0] = { 19199, 0, -2 },		/* voltage, vrange set */
85904b296fSGuenter Roeck 	[1] = { 6720, 0, -1 },		/* voltage, vrange not set */
86904b296fSGuenter Roeck 	[2] = { 807, 20475, -1 },	/* current */
87904b296fSGuenter Roeck };
88904b296fSGuenter Roeck 
89904b296fSGuenter Roeck static const struct coefficients adm1276_coefficients[] = {
90904b296fSGuenter Roeck 	[0] = { 19199, 0, -2 },		/* voltage, vrange set */
91904b296fSGuenter Roeck 	[1] = { 6720, 0, -1 },		/* voltage, vrange not set */
92904b296fSGuenter Roeck 	[2] = { 807, 20475, -1 },	/* current */
93904b296fSGuenter Roeck 	[3] = { 6043, 0, -2 },		/* power, vrange set */
94904b296fSGuenter Roeck 	[4] = { 2115, 0, -1 },		/* power, vrange not set */
95904b296fSGuenter Roeck };
96904b296fSGuenter Roeck 
97c576e30cSGuenter Roeck static int adm1275_read_word_data(struct i2c_client *client, int page, int reg)
98c576e30cSGuenter Roeck {
99c5e67636SGuenter Roeck 	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
100c5e67636SGuenter Roeck 	const struct adm1275_data *data = to_adm1275_data(info);
1015cf231a3SGuenter Roeck 	int ret = 0;
102c576e30cSGuenter Roeck 
103c576e30cSGuenter Roeck 	if (page)
104c5e67636SGuenter Roeck 		return -ENXIO;
105c576e30cSGuenter Roeck 
106c576e30cSGuenter Roeck 	switch (reg) {
107c5e67636SGuenter Roeck 	case PMBUS_IOUT_UC_FAULT_LIMIT:
108*9048539bSGuenter Roeck 		if (!data->have_uc_fault)
109*9048539bSGuenter Roeck 			return -ENXIO;
110c5e67636SGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
111c5e67636SGuenter Roeck 		break;
112c5e67636SGuenter Roeck 	case PMBUS_IOUT_OC_FAULT_LIMIT:
113*9048539bSGuenter Roeck 		if (!data->have_oc_fault)
114*9048539bSGuenter Roeck 			return -ENXIO;
115c5e67636SGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT);
116c5e67636SGuenter Roeck 		break;
11792711269SGuenter Roeck 	case PMBUS_VOUT_OV_WARN_LIMIT:
118*9048539bSGuenter Roeck 		if (data->have_vout)
119*9048539bSGuenter Roeck 			return -ENODATA;
12092711269SGuenter Roeck 		ret = pmbus_read_word_data(client, 0,
12192711269SGuenter Roeck 					   ADM1075_VAUX_OV_WARN_LIMIT);
12292711269SGuenter Roeck 		break;
12392711269SGuenter Roeck 	case PMBUS_VOUT_UV_WARN_LIMIT:
124*9048539bSGuenter Roeck 		if (data->have_vout)
125*9048539bSGuenter Roeck 			return -ENODATA;
12692711269SGuenter Roeck 		ret = pmbus_read_word_data(client, 0,
12792711269SGuenter Roeck 					   ADM1075_VAUX_UV_WARN_LIMIT);
12892711269SGuenter Roeck 		break;
12992711269SGuenter Roeck 	case PMBUS_READ_VOUT:
130*9048539bSGuenter Roeck 		if (data->have_vout)
131*9048539bSGuenter Roeck 			return -ENODATA;
13292711269SGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1075_READ_VAUX);
13392711269SGuenter Roeck 		break;
134c576e30cSGuenter Roeck 	case PMBUS_VIRT_READ_IOUT_MAX:
135c576e30cSGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_IOUT);
136c576e30cSGuenter Roeck 		break;
137c576e30cSGuenter Roeck 	case PMBUS_VIRT_READ_VOUT_MAX:
138c576e30cSGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VOUT);
139c576e30cSGuenter Roeck 		break;
140c576e30cSGuenter Roeck 	case PMBUS_VIRT_READ_VIN_MAX:
141c576e30cSGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1275_PEAK_VIN);
142c576e30cSGuenter Roeck 		break;
1435cf231a3SGuenter Roeck 	case PMBUS_VIRT_READ_PIN_MAX:
144*9048539bSGuenter Roeck 		if (!data->have_pin_max)
145*9048539bSGuenter Roeck 			return -ENXIO;
1465cf231a3SGuenter Roeck 		ret = pmbus_read_word_data(client, 0, ADM1276_PEAK_PIN);
1475cf231a3SGuenter Roeck 		break;
148c576e30cSGuenter Roeck 	case PMBUS_VIRT_RESET_IOUT_HISTORY:
149c576e30cSGuenter Roeck 	case PMBUS_VIRT_RESET_VOUT_HISTORY:
150c576e30cSGuenter Roeck 	case PMBUS_VIRT_RESET_VIN_HISTORY:
1515cf231a3SGuenter Roeck 		break;
1525cf231a3SGuenter Roeck 	case PMBUS_VIRT_RESET_PIN_HISTORY:
153*9048539bSGuenter Roeck 		if (!data->have_pin_max)
154*9048539bSGuenter Roeck 			return -ENXIO;
155c576e30cSGuenter Roeck 		break;
156c576e30cSGuenter Roeck 	default:
157c576e30cSGuenter Roeck 		ret = -ENODATA;
158c576e30cSGuenter Roeck 		break;
159c576e30cSGuenter Roeck 	}
160c576e30cSGuenter Roeck 	return ret;
161c576e30cSGuenter Roeck }
162c576e30cSGuenter Roeck 
163c576e30cSGuenter Roeck static int adm1275_write_word_data(struct i2c_client *client, int page, int reg,
164c576e30cSGuenter Roeck 				   u16 word)
165c576e30cSGuenter Roeck {
166c576e30cSGuenter Roeck 	int ret;
167c576e30cSGuenter Roeck 
168c576e30cSGuenter Roeck 	if (page)
169c5e67636SGuenter Roeck 		return -ENXIO;
170c576e30cSGuenter Roeck 
171c576e30cSGuenter Roeck 	switch (reg) {
172c5e67636SGuenter Roeck 	case PMBUS_IOUT_UC_FAULT_LIMIT:
173c5e67636SGuenter Roeck 	case PMBUS_IOUT_OC_FAULT_LIMIT:
174c5e67636SGuenter Roeck 		ret = pmbus_write_word_data(client, 0, ADM1275_IOUT_WARN2_LIMIT,
175c5e67636SGuenter Roeck 					    word);
176c5e67636SGuenter Roeck 		break;
177c576e30cSGuenter Roeck 	case PMBUS_VIRT_RESET_IOUT_HISTORY:
178c576e30cSGuenter Roeck 		ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_IOUT, 0);
179c576e30cSGuenter Roeck 		break;
180c576e30cSGuenter Roeck 	case PMBUS_VIRT_RESET_VOUT_HISTORY:
181c576e30cSGuenter Roeck 		ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VOUT, 0);
182c576e30cSGuenter Roeck 		break;
183c576e30cSGuenter Roeck 	case PMBUS_VIRT_RESET_VIN_HISTORY:
184c576e30cSGuenter Roeck 		ret = pmbus_write_word_data(client, 0, ADM1275_PEAK_VIN, 0);
185c576e30cSGuenter Roeck 		break;
1865cf231a3SGuenter Roeck 	case PMBUS_VIRT_RESET_PIN_HISTORY:
1875cf231a3SGuenter Roeck 		ret = pmbus_write_word_data(client, 0, ADM1276_PEAK_PIN, 0);
1885cf231a3SGuenter Roeck 		break;
189c576e30cSGuenter Roeck 	default:
190c576e30cSGuenter Roeck 		ret = -ENODATA;
191c576e30cSGuenter Roeck 		break;
192c576e30cSGuenter Roeck 	}
193c576e30cSGuenter Roeck 	return ret;
194c576e30cSGuenter Roeck }
195c576e30cSGuenter Roeck 
196c5e67636SGuenter Roeck static int adm1275_read_byte_data(struct i2c_client *client, int page, int reg)
197c5e67636SGuenter Roeck {
198c5e67636SGuenter Roeck 	const struct pmbus_driver_info *info = pmbus_get_driver_info(client);
199c5e67636SGuenter Roeck 	const struct adm1275_data *data = to_adm1275_data(info);
200c5e67636SGuenter Roeck 	int mfr_status, ret;
201c5e67636SGuenter Roeck 
202da8e48abSGuenter Roeck 	if (page > 0)
203c5e67636SGuenter Roeck 		return -ENXIO;
204c5e67636SGuenter Roeck 
205c5e67636SGuenter Roeck 	switch (reg) {
206c5e67636SGuenter Roeck 	case PMBUS_STATUS_IOUT:
207c5e67636SGuenter Roeck 		ret = pmbus_read_byte_data(client, page, PMBUS_STATUS_IOUT);
208c5e67636SGuenter Roeck 		if (ret < 0)
209c5e67636SGuenter Roeck 			break;
210*9048539bSGuenter Roeck 		if (!data->have_oc_fault && !data->have_uc_fault)
211*9048539bSGuenter Roeck 			break;
212c5e67636SGuenter Roeck 		mfr_status = pmbus_read_byte_data(client, page,
213c5e67636SGuenter Roeck 						  PMBUS_STATUS_MFR_SPECIFIC);
214*9048539bSGuenter Roeck 		if (mfr_status < 0)
215*9048539bSGuenter Roeck 			return mfr_status;
216c5e67636SGuenter Roeck 		if (mfr_status & ADM1275_MFR_STATUS_IOUT_WARN2) {
217c5e67636SGuenter Roeck 			ret |= data->have_oc_fault ?
218c5e67636SGuenter Roeck 			  PB_IOUT_OC_FAULT : PB_IOUT_UC_FAULT;
219c5e67636SGuenter Roeck 		}
220c5e67636SGuenter Roeck 		break;
22192711269SGuenter Roeck 	case PMBUS_STATUS_VOUT:
222*9048539bSGuenter Roeck 		if (data->have_vout)
223*9048539bSGuenter Roeck 			return -ENODATA;
22492711269SGuenter Roeck 		ret = 0;
225*9048539bSGuenter Roeck 		if (data->have_vaux_status) {
22692711269SGuenter Roeck 			mfr_status = pmbus_read_byte_data(client, 0,
22792711269SGuenter Roeck 							  ADM1075_VAUX_STATUS);
228*9048539bSGuenter Roeck 			if (mfr_status < 0)
229*9048539bSGuenter Roeck 				return mfr_status;
23092711269SGuenter Roeck 			if (mfr_status & ADM1075_VAUX_OV_WARN)
23192711269SGuenter Roeck 				ret |= PB_VOLTAGE_OV_WARNING;
23292711269SGuenter Roeck 			if (mfr_status & ADM1075_VAUX_UV_WARN)
23392711269SGuenter Roeck 				ret |= PB_VOLTAGE_UV_WARNING;
234*9048539bSGuenter Roeck 		}
23592711269SGuenter Roeck 		break;
236c5e67636SGuenter Roeck 	default:
237c5e67636SGuenter Roeck 		ret = -ENODATA;
238c5e67636SGuenter Roeck 		break;
239c5e67636SGuenter Roeck 	}
240c5e67636SGuenter Roeck 	return ret;
241c5e67636SGuenter Roeck }
242c5e67636SGuenter Roeck 
24387102808SGuenter Roeck static const struct i2c_device_id adm1275_id[] = {
24492711269SGuenter Roeck 	{ "adm1075", adm1075 },
24587102808SGuenter Roeck 	{ "adm1275", adm1275 },
24687102808SGuenter Roeck 	{ "adm1276", adm1276 },
24787102808SGuenter Roeck 	{ }
24887102808SGuenter Roeck };
24987102808SGuenter Roeck MODULE_DEVICE_TABLE(i2c, adm1275_id);
25087102808SGuenter Roeck 
2519d2ecfb7SGuenter Roeck static int adm1275_probe(struct i2c_client *client,
2529d2ecfb7SGuenter Roeck 			 const struct i2c_device_id *id)
2539d2ecfb7SGuenter Roeck {
25487102808SGuenter Roeck 	u8 block_buffer[I2C_SMBUS_BLOCK_MAX + 1];
255c5e67636SGuenter Roeck 	int config, device_config;
2569d2ecfb7SGuenter Roeck 	int ret;
2579d2ecfb7SGuenter Roeck 	struct pmbus_driver_info *info;
258c5e67636SGuenter Roeck 	struct adm1275_data *data;
25987102808SGuenter Roeck 	const struct i2c_device_id *mid;
260904b296fSGuenter Roeck 	const struct coefficients *coefficients;
261904b296fSGuenter Roeck 	int vindex = -1, cindex = -1, pindex = -1;
2629d2ecfb7SGuenter Roeck 
2639d2ecfb7SGuenter Roeck 	if (!i2c_check_functionality(client->adapter,
26487102808SGuenter Roeck 				     I2C_FUNC_SMBUS_READ_BYTE_DATA
26587102808SGuenter Roeck 				     | I2C_FUNC_SMBUS_BLOCK_DATA))
2669d2ecfb7SGuenter Roeck 		return -ENODEV;
2679d2ecfb7SGuenter Roeck 
26887102808SGuenter Roeck 	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_ID, block_buffer);
26987102808SGuenter Roeck 	if (ret < 0) {
27087102808SGuenter Roeck 		dev_err(&client->dev, "Failed to read Manufacturer ID\n");
27187102808SGuenter Roeck 		return ret;
27287102808SGuenter Roeck 	}
27387102808SGuenter Roeck 	if (ret != 3 || strncmp(block_buffer, "ADI", 3)) {
27487102808SGuenter Roeck 		dev_err(&client->dev, "Unsupported Manufacturer ID\n");
27587102808SGuenter Roeck 		return -ENODEV;
27687102808SGuenter Roeck 	}
27787102808SGuenter Roeck 
27887102808SGuenter Roeck 	ret = i2c_smbus_read_block_data(client, PMBUS_MFR_MODEL, block_buffer);
27987102808SGuenter Roeck 	if (ret < 0) {
28087102808SGuenter Roeck 		dev_err(&client->dev, "Failed to read Manufacturer Model\n");
28187102808SGuenter Roeck 		return ret;
28287102808SGuenter Roeck 	}
28387102808SGuenter Roeck 	for (mid = adm1275_id; mid->name[0]; mid++) {
28487102808SGuenter Roeck 		if (!strncasecmp(mid->name, block_buffer, strlen(mid->name)))
28587102808SGuenter Roeck 			break;
28687102808SGuenter Roeck 	}
28787102808SGuenter Roeck 	if (!mid->name[0]) {
28887102808SGuenter Roeck 		dev_err(&client->dev, "Unsupported device\n");
28987102808SGuenter Roeck 		return -ENODEV;
29087102808SGuenter Roeck 	}
29187102808SGuenter Roeck 
29287102808SGuenter Roeck 	if (id->driver_data != mid->driver_data)
29387102808SGuenter Roeck 		dev_notice(&client->dev,
29487102808SGuenter Roeck 			   "Device mismatch: Configured %s, detected %s\n",
29587102808SGuenter Roeck 			   id->name, mid->name);
29687102808SGuenter Roeck 
29787102808SGuenter Roeck 	config = i2c_smbus_read_byte_data(client, ADM1275_PMON_CONFIG);
29887102808SGuenter Roeck 	if (config < 0)
29987102808SGuenter Roeck 		return config;
30087102808SGuenter Roeck 
30187102808SGuenter Roeck 	device_config = i2c_smbus_read_byte_data(client, ADM1275_DEVICE_CONFIG);
30287102808SGuenter Roeck 	if (device_config < 0)
30387102808SGuenter Roeck 		return device_config;
30487102808SGuenter Roeck 
3058b313ca7SGuenter Roeck 	data = devm_kzalloc(&client->dev, sizeof(struct adm1275_data),
3068b313ca7SGuenter Roeck 			    GFP_KERNEL);
307c5e67636SGuenter Roeck 	if (!data)
3089d2ecfb7SGuenter Roeck 		return -ENOMEM;
3099d2ecfb7SGuenter Roeck 
31087102808SGuenter Roeck 	data->id = mid->driver_data;
3119d2ecfb7SGuenter Roeck 
312c5e67636SGuenter Roeck 	info = &data->info;
313c5e67636SGuenter Roeck 
3149d2ecfb7SGuenter Roeck 	info->pages = 1;
3151061d851SGuenter Roeck 	info->format[PSC_VOLTAGE_IN] = direct;
3161061d851SGuenter Roeck 	info->format[PSC_VOLTAGE_OUT] = direct;
3171061d851SGuenter Roeck 	info->format[PSC_CURRENT_OUT] = direct;
318904b296fSGuenter Roeck 	info->format[PSC_POWER] = direct;
3199d2ecfb7SGuenter Roeck 	info->func[0] = PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT;
3209d2ecfb7SGuenter Roeck 
321c576e30cSGuenter Roeck 	info->read_word_data = adm1275_read_word_data;
322c5e67636SGuenter Roeck 	info->read_byte_data = adm1275_read_byte_data;
323c576e30cSGuenter Roeck 	info->write_word_data = adm1275_write_word_data;
324c576e30cSGuenter Roeck 
32587102808SGuenter Roeck 	switch (data->id) {
32692711269SGuenter Roeck 	case adm1075:
327*9048539bSGuenter Roeck 		if (device_config & ADM1275_IOUT_WARN2_SELECT)
328*9048539bSGuenter Roeck 			data->have_oc_fault = true;
329*9048539bSGuenter Roeck 		else
330*9048539bSGuenter Roeck 			data->have_uc_fault = true;
331*9048539bSGuenter Roeck 		data->have_pin_max = true;
332*9048539bSGuenter Roeck 		data->have_vaux_status = true;
333*9048539bSGuenter Roeck 
334904b296fSGuenter Roeck 		coefficients = adm1075_coefficients;
335904b296fSGuenter Roeck 		vindex = 0;
33692711269SGuenter Roeck 		switch (config & ADM1075_IRANGE_MASK) {
33792711269SGuenter Roeck 		case ADM1075_IRANGE_25:
338904b296fSGuenter Roeck 			cindex = 1;
339904b296fSGuenter Roeck 			pindex = 3;
34092711269SGuenter Roeck 			break;
34192711269SGuenter Roeck 		case ADM1075_IRANGE_50:
342904b296fSGuenter Roeck 			cindex = 2;
343904b296fSGuenter Roeck 			pindex = 4;
34492711269SGuenter Roeck 			break;
34592711269SGuenter Roeck 		default:
34692711269SGuenter Roeck 			dev_err(&client->dev, "Invalid input current range");
34792711269SGuenter Roeck 			break;
34892711269SGuenter Roeck 		}
349904b296fSGuenter Roeck 
35092711269SGuenter Roeck 		info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN
35192711269SGuenter Roeck 		  | PMBUS_HAVE_STATUS_INPUT;
35292711269SGuenter Roeck 		if (config & ADM1275_VIN_VOUT_SELECT)
35392711269SGuenter Roeck 			info->func[0] |=
35492711269SGuenter Roeck 			  PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
35592711269SGuenter Roeck 		break;
3565cf231a3SGuenter Roeck 	case adm1275:
357*9048539bSGuenter Roeck 		if (device_config & ADM1275_IOUT_WARN2_SELECT)
358*9048539bSGuenter Roeck 			data->have_oc_fault = true;
359*9048539bSGuenter Roeck 		else
360*9048539bSGuenter Roeck 			data->have_uc_fault = true;
361*9048539bSGuenter Roeck 		data->have_vout = true;
362*9048539bSGuenter Roeck 
363904b296fSGuenter Roeck 		coefficients = adm1275_coefficients;
364904b296fSGuenter Roeck 		vindex = (config & ADM1275_VRANGE) ? 0 : 1;
365904b296fSGuenter Roeck 		cindex = 2;
366904b296fSGuenter Roeck 
3679d2ecfb7SGuenter Roeck 		if (config & ADM1275_VIN_VOUT_SELECT)
3685cf231a3SGuenter Roeck 			info->func[0] |=
3695cf231a3SGuenter Roeck 			  PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
3709d2ecfb7SGuenter Roeck 		else
3715cf231a3SGuenter Roeck 			info->func[0] |=
3725cf231a3SGuenter Roeck 			  PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT;
3735cf231a3SGuenter Roeck 		break;
3745cf231a3SGuenter Roeck 	case adm1276:
375*9048539bSGuenter Roeck 		if (device_config & ADM1275_IOUT_WARN2_SELECT)
376*9048539bSGuenter Roeck 			data->have_oc_fault = true;
377*9048539bSGuenter Roeck 		else
378*9048539bSGuenter Roeck 			data->have_uc_fault = true;
379*9048539bSGuenter Roeck 		data->have_vout = true;
380*9048539bSGuenter Roeck 		data->have_pin_max = true;
381*9048539bSGuenter Roeck 
382904b296fSGuenter Roeck 		coefficients = adm1276_coefficients;
383904b296fSGuenter Roeck 		vindex = (config & ADM1275_VRANGE) ? 0 : 1;
384904b296fSGuenter Roeck 		cindex = 2;
385904b296fSGuenter Roeck 		pindex = (config & ADM1275_VRANGE) ? 3 : 4;
386904b296fSGuenter Roeck 
3875cf231a3SGuenter Roeck 		info->func[0] |= PMBUS_HAVE_VIN | PMBUS_HAVE_PIN
3885cf231a3SGuenter Roeck 		  | PMBUS_HAVE_STATUS_INPUT;
3895cf231a3SGuenter Roeck 		if (config & ADM1275_VIN_VOUT_SELECT)
3905cf231a3SGuenter Roeck 			info->func[0] |=
3915cf231a3SGuenter Roeck 			  PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT;
3925cf231a3SGuenter Roeck 		break;
393904b296fSGuenter Roeck 	default:
394904b296fSGuenter Roeck 		dev_err(&client->dev, "Unsupported device\n");
395904b296fSGuenter Roeck 		return -ENODEV;
396904b296fSGuenter Roeck 	}
397904b296fSGuenter Roeck 	if (vindex >= 0) {
398904b296fSGuenter Roeck 		info->m[PSC_VOLTAGE_IN] = coefficients[vindex].m;
399904b296fSGuenter Roeck 		info->b[PSC_VOLTAGE_IN] = coefficients[vindex].b;
400904b296fSGuenter Roeck 		info->R[PSC_VOLTAGE_IN] = coefficients[vindex].R;
401904b296fSGuenter Roeck 		info->m[PSC_VOLTAGE_OUT] = coefficients[vindex].m;
402904b296fSGuenter Roeck 		info->b[PSC_VOLTAGE_OUT] = coefficients[vindex].b;
403904b296fSGuenter Roeck 		info->R[PSC_VOLTAGE_OUT] = coefficients[vindex].R;
404904b296fSGuenter Roeck 	}
405904b296fSGuenter Roeck 	if (cindex >= 0) {
406904b296fSGuenter Roeck 		info->m[PSC_CURRENT_OUT] = coefficients[cindex].m;
407904b296fSGuenter Roeck 		info->b[PSC_CURRENT_OUT] = coefficients[cindex].b;
408904b296fSGuenter Roeck 		info->R[PSC_CURRENT_OUT] = coefficients[cindex].R;
409904b296fSGuenter Roeck 	}
410904b296fSGuenter Roeck 	if (pindex >= 0) {
411904b296fSGuenter Roeck 		info->m[PSC_POWER] = coefficients[pindex].m;
412904b296fSGuenter Roeck 		info->b[PSC_POWER] = coefficients[pindex].b;
413904b296fSGuenter Roeck 		info->R[PSC_POWER] = coefficients[pindex].R;
4145cf231a3SGuenter Roeck 	}
4159d2ecfb7SGuenter Roeck 
4168b313ca7SGuenter Roeck 	return pmbus_do_probe(client, id, info);
4179d2ecfb7SGuenter Roeck }
4189d2ecfb7SGuenter Roeck 
4199d2ecfb7SGuenter Roeck static struct i2c_driver adm1275_driver = {
4209d2ecfb7SGuenter Roeck 	.driver = {
4219d2ecfb7SGuenter Roeck 		   .name = "adm1275",
4229d2ecfb7SGuenter Roeck 		   },
4239d2ecfb7SGuenter Roeck 	.probe = adm1275_probe,
424dd285ad7SGuenter Roeck 	.remove = pmbus_do_remove,
4259d2ecfb7SGuenter Roeck 	.id_table = adm1275_id,
4269d2ecfb7SGuenter Roeck };
4279d2ecfb7SGuenter Roeck 
428f0967eeaSAxel Lin module_i2c_driver(adm1275_driver);
4299d2ecfb7SGuenter Roeck 
4309d2ecfb7SGuenter Roeck MODULE_AUTHOR("Guenter Roeck");
4315cf231a3SGuenter Roeck MODULE_DESCRIPTION("PMBus driver for Analog Devices ADM1275 and compatibles");
4329d2ecfb7SGuenter Roeck MODULE_LICENSE("GPL");
433