File Index
Files and directories
Sign in
FILE

ltc3815.c

File preview with syntax highlighting.

linux-6.19.14/drivers/hwmon/pmbus/ltc3815.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * Hardware monitoring driver for LTC3815
  4 *
  5 * Copyright (c) 2015 Linear Technology
  6 * Copyright (c) 2015 Guenter Roeck
  7 */
  8
  9#include <linux/err.h>
 10#include <linux/i2c.h>
 11#include <linux/init.h>
 12#include <linux/jiffies.h>
 13#include <linux/kernel.h>
 14#include <linux/module.h>
 15#include "pmbus.h"
 16
 17#define LTC3815_MFR_IOUT_PEAK	0xd7
 18#define LTC3815_MFR_VOUT_PEAK	0xdd
 19#define LTC3815_MFR_VIN_PEAK	0xde
 20#define LTC3815_MFR_TEMP_PEAK	0xdf
 21#define LTC3815_MFR_IIN_PEAK	0xe1
 22#define LTC3815_MFR_SPECIAL_ID	0xe7
 23
 24#define LTC3815_ID		0x8000
 25#define LTC3815_ID_MASK		0xff00
 26
 27static int ltc3815_read_byte_data(struct i2c_client *client, int page, int reg)
 28{
 29	int ret;
 30
 31	switch (reg) {
 32	case PMBUS_VOUT_MODE:
 33		/*
 34		 * The chip returns 0x3e, suggesting VID mode with manufacturer
 35		 * specific VID codes. Since the output voltage is reported
 36		 * with a LSB of 0.5mV, override and report direct mode with
 37		 * appropriate coefficients.
 38		 */
 39		ret = 0x40;
 40		break;
 41	default:
 42		ret = -ENODATA;
 43		break;
 44	}
 45	return ret;
 46}
 47
 48static int ltc3815_write_byte(struct i2c_client *client, int page, u8 reg)
 49{
 50	int ret;
 51
 52	switch (reg) {
 53	case PMBUS_CLEAR_FAULTS:
 54		/*
 55		 * LTC3815 does not support the CLEAR_FAULTS command.
 56		 * Emulate it by clearing the status register.
 57		 */
 58		ret = pmbus_read_word_data(client, 0, 0xff, PMBUS_STATUS_WORD);
 59		if (ret > 0) {
 60			pmbus_write_word_data(client, 0, PMBUS_STATUS_WORD,
 61					      ret);
 62			ret = 0;
 63		}
 64		break;
 65	default:
 66		ret = -ENODATA;
 67		break;
 68	}
 69	return ret;
 70}
 71
 72static int ltc3815_read_word_data(struct i2c_client *client, int page,
 73				  int phase, int reg)
 74{
 75	int ret;
 76
 77	switch (reg) {
 78	case PMBUS_VIRT_READ_VIN_MAX:
 79		ret = pmbus_read_word_data(client, page, phase,
 80					   LTC3815_MFR_VIN_PEAK);
 81		break;
 82	case PMBUS_VIRT_READ_VOUT_MAX:
 83		ret = pmbus_read_word_data(client, page, phase,
 84					   LTC3815_MFR_VOUT_PEAK);
 85		break;
 86	case PMBUS_VIRT_READ_TEMP_MAX:
 87		ret = pmbus_read_word_data(client, page, phase,
 88					   LTC3815_MFR_TEMP_PEAK);
 89		break;
 90	case PMBUS_VIRT_READ_IOUT_MAX:
 91		ret = pmbus_read_word_data(client, page, phase,
 92					   LTC3815_MFR_IOUT_PEAK);
 93		break;
 94	case PMBUS_VIRT_READ_IIN_MAX:
 95		ret = pmbus_read_word_data(client, page, phase,
 96					   LTC3815_MFR_IIN_PEAK);
 97		break;
 98	case PMBUS_VIRT_RESET_VOUT_HISTORY:
 99	case PMBUS_VIRT_RESET_VIN_HISTORY:
100	case PMBUS_VIRT_RESET_TEMP_HISTORY:
101	case PMBUS_VIRT_RESET_IOUT_HISTORY:
102	case PMBUS_VIRT_RESET_IIN_HISTORY:
103		ret = 0;
104		break;
105	default:
106		ret = -ENODATA;
107		break;
108	}
109	return ret;
110}
111
112static int ltc3815_write_word_data(struct i2c_client *client, int page,
113				   int reg, u16 word)
114{
115	int ret;
116
117	switch (reg) {
118	case PMBUS_VIRT_RESET_IIN_HISTORY:
119		ret = pmbus_write_word_data(client, page,
120					    LTC3815_MFR_IIN_PEAK, 0);
121		break;
122	case PMBUS_VIRT_RESET_IOUT_HISTORY:
123		ret = pmbus_write_word_data(client, page,
124					    LTC3815_MFR_IOUT_PEAK, 0);
125		break;
126	case PMBUS_VIRT_RESET_VOUT_HISTORY:
127		ret = pmbus_write_word_data(client, page,
128					    LTC3815_MFR_VOUT_PEAK, 0);
129		break;
130	case PMBUS_VIRT_RESET_VIN_HISTORY:
131		ret = pmbus_write_word_data(client, page,
132					    LTC3815_MFR_VIN_PEAK, 0);
133		break;
134	case PMBUS_VIRT_RESET_TEMP_HISTORY:
135		ret = pmbus_write_word_data(client, page,
136					    LTC3815_MFR_TEMP_PEAK, 0);
137		break;
138	default:
139		ret = -ENODATA;
140		break;
141	}
142	return ret;
143}
144
145static const struct i2c_device_id ltc3815_id[] = {
146	{"ltc3815"},
147	{ }
148};
149MODULE_DEVICE_TABLE(i2c, ltc3815_id);
150
151static struct pmbus_driver_info ltc3815_info = {
152	.pages = 1,
153	.format[PSC_VOLTAGE_IN] = direct,
154	.format[PSC_VOLTAGE_OUT] = direct,
155	.format[PSC_CURRENT_IN] = direct,
156	.format[PSC_CURRENT_OUT] = direct,
157	.format[PSC_TEMPERATURE] = direct,
158	.m[PSC_VOLTAGE_IN] = 250,
159	.b[PSC_VOLTAGE_IN] = 0,
160	.R[PSC_VOLTAGE_IN] = 0,
161	.m[PSC_VOLTAGE_OUT] = 2,
162	.b[PSC_VOLTAGE_OUT] = 0,
163	.R[PSC_VOLTAGE_OUT] = 3,
164	.m[PSC_CURRENT_IN] = 1,
165	.b[PSC_CURRENT_IN] = 0,
166	.R[PSC_CURRENT_IN] = 2,
167	.m[PSC_CURRENT_OUT] = 1,
168	.b[PSC_CURRENT_OUT] = 0,
169	.R[PSC_CURRENT_OUT] = 2,
170	.m[PSC_TEMPERATURE] = 1,
171	.b[PSC_TEMPERATURE] = 0,
172	.R[PSC_TEMPERATURE] = 0,
173	.func[0] = PMBUS_HAVE_VIN | PMBUS_HAVE_IIN | PMBUS_HAVE_VOUT |
174		PMBUS_HAVE_IOUT | PMBUS_HAVE_TEMP,
175	.read_byte_data = ltc3815_read_byte_data,
176	.read_word_data = ltc3815_read_word_data,
177	.write_byte = ltc3815_write_byte,
178	.write_word_data = ltc3815_write_word_data,
179};
180
181static int ltc3815_probe(struct i2c_client *client)
182{
183	int chip_id;
184
185	if (!i2c_check_functionality(client->adapter,
186				     I2C_FUNC_SMBUS_READ_WORD_DATA))
187		return -ENODEV;
188
189	chip_id = i2c_smbus_read_word_data(client, LTC3815_MFR_SPECIAL_ID);
190	if (chip_id < 0)
191		return chip_id;
192	if ((chip_id & LTC3815_ID_MASK) != LTC3815_ID)
193		return -ENODEV;
194
195	return pmbus_do_probe(client, &ltc3815_info);
196}
197
198static struct i2c_driver ltc3815_driver = {
199	.driver = {
200		   .name = "ltc3815",
201		   },
202	.probe = ltc3815_probe,
203	.id_table = ltc3815_id,
204};
205
206module_i2c_driver(ltc3815_driver);
207
208MODULE_AUTHOR("Guenter Roeck");
209MODULE_DESCRIPTION("PMBus driver for LTC3815");
210MODULE_LICENSE("GPL");
211MODULE_IMPORT_NS("PMBUS");
~/ Read-only file preview.