xref: /openbmc/linux/drivers/hwmon/mc34vr500.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1  // SPDX-License-Identifier: GPL-2.0-or-later
2  /*
3   * An hwmon driver for the NXP MC34VR500 PMIC
4   *
5   * Author: Mario Kicherer <dev@kicherer.org>
6   */
7  
8  #include <linux/bits.h>
9  #include <linux/dev_printk.h>
10  #include <linux/device.h>
11  #include <linux/err.h>
12  #include <linux/errno.h>
13  #include <linux/hwmon.h>
14  #include <linux/i2c.h>
15  #include <linux/interrupt.h>
16  #include <linux/irqreturn.h>
17  #include <linux/module.h>
18  #include <linux/of.h>
19  #include <linux/regmap.h>
20  
21  #define MC34VR500_I2C_ADDR		0x08
22  #define MC34VR500_DEVICEID_VALUE	0x14
23  
24  /* INTSENSE0 */
25  #define ENS_BIT		BIT(0)
26  #define LOWVINS_BIT	BIT(1)
27  #define THERM110S_BIT	BIT(2)
28  #define THERM120S_BIT	BIT(3)
29  #define THERM125S_BIT	BIT(4)
30  #define THERM130S_BIT	BIT(5)
31  
32  #define MC34VR500_DEVICEID	0x00
33  
34  #define MC34VR500_SILICONREVID	0x03
35  #define MC34VR500_FABID		0x04
36  #define MC34VR500_INTSTAT0	0x05
37  #define MC34VR500_INTMASK0	0x06
38  #define MC34VR500_INTSENSE0	0x07
39  
40  struct mc34vr500_data {
41  	struct device *hwmon_dev;
42  	struct regmap *regmap;
43  };
44  
mc34vr500_process_interrupt(int irq,void * userdata)45  static irqreturn_t mc34vr500_process_interrupt(int irq, void *userdata)
46  {
47  	struct mc34vr500_data *data = (struct mc34vr500_data *)userdata;
48  	unsigned int reg;
49  	int ret;
50  
51  	ret = regmap_read(data->regmap, MC34VR500_INTSTAT0, &reg);
52  	if (ret < 0)
53  		return IRQ_HANDLED;
54  
55  	if (reg) {
56  		if (reg & LOWVINS_BIT)
57  			hwmon_notify_event(data->hwmon_dev, hwmon_in,
58  					   hwmon_in_min_alarm, 0);
59  
60  		if (reg & THERM110S_BIT)
61  			hwmon_notify_event(data->hwmon_dev, hwmon_temp,
62  					   hwmon_temp_max_alarm, 0);
63  
64  		if (reg & THERM120S_BIT)
65  			hwmon_notify_event(data->hwmon_dev, hwmon_temp,
66  					   hwmon_temp_crit_alarm, 0);
67  
68  		if (reg & THERM130S_BIT)
69  			hwmon_notify_event(data->hwmon_dev, hwmon_temp,
70  					   hwmon_temp_emergency_alarm, 0);
71  
72  		/* write 1 to clear */
73  		regmap_write(data->regmap, MC34VR500_INTSTAT0, LOWVINS_BIT |
74  			     THERM110S_BIT | THERM120S_BIT | THERM130S_BIT);
75  	}
76  
77  	return IRQ_HANDLED;
78  }
79  
mc34vr500_is_visible(const void * data,enum hwmon_sensor_types type,u32 attr,int channel)80  static umode_t mc34vr500_is_visible(const void *data,
81  				    enum hwmon_sensor_types type,
82  				    u32 attr, int channel)
83  {
84  	switch (attr) {
85  	case hwmon_in_min_alarm:
86  	case hwmon_temp_max_alarm:
87  	case hwmon_temp_crit_alarm:
88  	case hwmon_temp_emergency_alarm:
89  		return 0444;
90  	default:
91  		break;
92  	}
93  
94  	return 0;
95  }
96  
mc34vr500_alarm_read(struct mc34vr500_data * data,int index,long * val)97  static int mc34vr500_alarm_read(struct mc34vr500_data *data, int index,
98  				long *val)
99  {
100  	unsigned int reg;
101  	int ret;
102  
103  	ret = regmap_read(data->regmap, MC34VR500_INTSENSE0, &reg);
104  	if (ret < 0)
105  		return ret;
106  
107  	*val = !!(reg & index);
108  
109  	return 0;
110  }
111  
mc34vr500_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)112  static int mc34vr500_read(struct device *dev, enum hwmon_sensor_types type,
113  			  u32 attr, int channel, long *val)
114  {
115  	struct mc34vr500_data *data = dev_get_drvdata(dev);
116  
117  	switch (type) {
118  	case hwmon_in:
119  		switch (attr) {
120  		case hwmon_in_min_alarm:
121  			return mc34vr500_alarm_read(data, LOWVINS_BIT, val);
122  		default:
123  			return -EOPNOTSUPP;
124  		}
125  	case hwmon_temp:
126  		switch (attr) {
127  		case hwmon_temp_max_alarm:
128  			return mc34vr500_alarm_read(data, THERM110S_BIT, val);
129  		case hwmon_temp_crit_alarm:
130  			return mc34vr500_alarm_read(data, THERM120S_BIT, val);
131  		case hwmon_temp_emergency_alarm:
132  			return mc34vr500_alarm_read(data, THERM130S_BIT, val);
133  		default:
134  			return -EOPNOTSUPP;
135  		}
136  	default:
137  		return -EOPNOTSUPP;
138  	}
139  }
140  
141  static const struct hwmon_channel_info * const mc34vr500_info[] = {
142  	HWMON_CHANNEL_INFO(in, HWMON_I_MIN_ALARM),
143  	HWMON_CHANNEL_INFO(temp, HWMON_T_MAX_ALARM | HWMON_T_CRIT_ALARM
144  			   | HWMON_T_EMERGENCY_ALARM),
145  	NULL,
146  };
147  
148  static const struct hwmon_ops mc34vr500_hwmon_ops = {
149  	.is_visible = mc34vr500_is_visible,
150  	.read = mc34vr500_read,
151  };
152  
153  static const struct hwmon_chip_info mc34vr500_chip_info = {
154  	.ops = &mc34vr500_hwmon_ops,
155  	.info = mc34vr500_info,
156  };
157  
158  static const struct regmap_config mc34vr500_regmap_config = {
159  	.reg_bits = 8,
160  	.val_bits = 8,
161  	.max_register = MC34VR500_INTSENSE0,
162  };
163  
mc34vr500_probe(struct i2c_client * client)164  static int mc34vr500_probe(struct i2c_client *client)
165  {
166  	struct device *dev = &client->dev;
167  	struct mc34vr500_data *data;
168  	struct device *hwmon_dev;
169  	int ret;
170  	unsigned int reg, revid, fabid;
171  	struct regmap *regmap;
172  
173  	regmap = devm_regmap_init_i2c(client, &mc34vr500_regmap_config);
174  	if (IS_ERR(regmap))
175  		return PTR_ERR(regmap);
176  
177  	data = devm_kzalloc(dev, sizeof(struct mc34vr500_data), GFP_KERNEL);
178  	if (!data)
179  		return -ENOMEM;
180  
181  	data->regmap = regmap;
182  
183  	ret = regmap_read(regmap, MC34VR500_DEVICEID, &reg);
184  	if (ret < 0)
185  		return ret;
186  
187  	if (reg != MC34VR500_DEVICEID_VALUE)
188  		return -ENODEV;
189  
190  	ret = regmap_read(regmap, MC34VR500_SILICONREVID, &revid);
191  	if (ret < 0)
192  		return ret;
193  
194  	ret = regmap_read(regmap, MC34VR500_FABID, &fabid);
195  	if (ret < 0)
196  		return ret;
197  
198  	dev_dbg(dev, "mc34vr500: revid 0x%x fabid 0x%x\n", revid, fabid);
199  
200  	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name,
201  							 data,
202  							 &mc34vr500_chip_info,
203  							 NULL);
204  	if (IS_ERR(hwmon_dev))
205  		return PTR_ERR(hwmon_dev);
206  
207  	data->hwmon_dev = hwmon_dev;
208  
209  	if (client->irq) {
210  		ret = devm_request_threaded_irq(dev, client->irq, NULL,
211  						mc34vr500_process_interrupt,
212  						IRQF_TRIGGER_RISING |
213  						IRQF_ONESHOT |
214  						IRQF_SHARED,
215  						dev_name(dev), data);
216  		if (ret)
217  			return ret;
218  
219  		/* write 1 to clear interrupts */
220  		ret = regmap_write(regmap, MC34VR500_INTSTAT0, LOWVINS_BIT |
221  				   THERM110S_BIT | THERM120S_BIT |
222  				   THERM130S_BIT);
223  		if (ret)
224  			return ret;
225  
226  		/* unmask interrupts */
227  		ret = regmap_write(regmap, MC34VR500_INTMASK0,
228  				   (unsigned int) ~(LOWVINS_BIT | THERM110S_BIT |
229  						    THERM120S_BIT | THERM130S_BIT));
230  		if (ret)
231  			return ret;
232  	}
233  
234  	return 0;
235  }
236  
237  static const struct i2c_device_id mc34vr500_id[] = {
238  	{ "mc34vr500", 0 },
239  	{ },
240  };
241  MODULE_DEVICE_TABLE(i2c, mc34vr500_id);
242  
243  static const struct of_device_id __maybe_unused mc34vr500_of_match[] = {
244  	{ .compatible = "nxp,mc34vr500" },
245  	{ },
246  };
247  MODULE_DEVICE_TABLE(of, mc34vr500_of_match);
248  
249  static struct i2c_driver mc34vr500_driver = {
250  	.driver = {
251  		   .name = "mc34vr500",
252  		   .of_match_table = of_match_ptr(mc34vr500_of_match),
253  		    },
254  	.probe = mc34vr500_probe,
255  	.id_table = mc34vr500_id,
256  };
257  
258  module_i2c_driver(mc34vr500_driver);
259  
260  MODULE_AUTHOR("Mario Kicherer <dev@kicherer.org>");
261  
262  MODULE_DESCRIPTION("MC34VR500 driver");
263  MODULE_LICENSE("GPL");
264