Commit | Line | Data |
---|---|---|
1e406332 ER |
1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* | |
3 | * Hardware monitoring driver for Maxim MAX15301 | |
4 | * | |
5 | * Copyright (c) 2021 Flextronics International Sweden AB | |
6 | * | |
7 | * Even though the specification does not specifically mention it, | |
8 | * extensive empirical testing has revealed that auto-detection of | |
9 | * limit-registers will fail in a random fashion unless the delay | |
10 | * parameter is set to above about 80us. The default delay is set | |
11 | * to 100us to include some safety margin. | |
12 | */ | |
13 | ||
14 | #include <linux/kernel.h> | |
15 | #include <linux/module.h> | |
16 | #include <linux/init.h> | |
17 | #include <linux/err.h> | |
18 | #include <linux/slab.h> | |
19 | #include <linux/i2c.h> | |
20 | #include <linux/ktime.h> | |
21 | #include <linux/delay.h> | |
22 | #include <linux/pmbus.h> | |
23 | #include "pmbus.h" | |
24 | ||
25 | static const struct i2c_device_id max15301_id[] = { | |
26 | {"bmr461", 0}, | |
27 | {"max15301", 0}, | |
28 | {} | |
29 | }; | |
30 | MODULE_DEVICE_TABLE(i2c, max15301_id); | |
31 | ||
32 | struct max15301_data { | |
33 | int id; | |
34 | ktime_t access; /* Chip access time */ | |
35 | int delay; /* Delay between chip accesses in us */ | |
36 | struct pmbus_driver_info info; | |
37 | }; | |
38 | ||
39 | #define to_max15301_data(x) container_of(x, struct max15301_data, info) | |
40 | ||
41 | #define MAX15301_WAIT_TIME 100 /* us */ | |
42 | ||
43 | static ushort delay = MAX15301_WAIT_TIME; | |
44 | module_param(delay, ushort, 0644); | |
45 | MODULE_PARM_DESC(delay, "Delay between chip accesses in us"); | |
46 | ||
47 | static struct max15301_data max15301_data = { | |
48 | .info = { | |
49 | .pages = 1, | |
50 | .func[0] = PMBUS_HAVE_VOUT | PMBUS_HAVE_STATUS_VOUT | |
51 | | PMBUS_HAVE_VIN | PMBUS_HAVE_STATUS_INPUT | |
52 | | PMBUS_HAVE_TEMP | PMBUS_HAVE_TEMP2 | |
53 | | PMBUS_HAVE_STATUS_TEMP | |
54 | | PMBUS_HAVE_IOUT | PMBUS_HAVE_STATUS_IOUT, | |
55 | } | |
56 | }; | |
57 | ||
58 | /* This chip needs a delay between accesses */ | |
59 | static inline void max15301_wait(const struct max15301_data *data) | |
60 | { | |
61 | if (data->delay) { | |
62 | s64 delta = ktime_us_delta(ktime_get(), data->access); | |
63 | ||
64 | if (delta < data->delay) | |
65 | udelay(data->delay - delta); | |
66 | } | |
67 | } | |
68 | ||
69 | static int max15301_read_word_data(struct i2c_client *client, int page, | |
70 | int phase, int reg) | |
71 | { | |
72 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | |
73 | struct max15301_data *data = to_max15301_data(info); | |
74 | int ret; | |
75 | ||
76 | if (page > 0) | |
77 | return -ENXIO; | |
78 | ||
79 | if (reg >= PMBUS_VIRT_BASE) | |
80 | return -ENXIO; | |
81 | ||
82 | max15301_wait(data); | |
83 | ret = pmbus_read_word_data(client, page, phase, reg); | |
84 | data->access = ktime_get(); | |
85 | ||
86 | return ret; | |
87 | } | |
88 | ||
89 | static int max15301_read_byte_data(struct i2c_client *client, int page, int reg) | |
90 | { | |
91 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | |
92 | struct max15301_data *data = to_max15301_data(info); | |
93 | int ret; | |
94 | ||
95 | if (page > 0) | |
96 | return -ENXIO; | |
97 | ||
98 | max15301_wait(data); | |
99 | ret = pmbus_read_byte_data(client, page, reg); | |
100 | data->access = ktime_get(); | |
101 | ||
102 | return ret; | |
103 | } | |
104 | ||
105 | static int max15301_write_word_data(struct i2c_client *client, int page, int reg, | |
106 | u16 word) | |
107 | { | |
108 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | |
109 | struct max15301_data *data = to_max15301_data(info); | |
110 | int ret; | |
111 | ||
112 | if (page > 0) | |
113 | return -ENXIO; | |
114 | ||
115 | if (reg >= PMBUS_VIRT_BASE) | |
116 | return -ENXIO; | |
117 | ||
118 | max15301_wait(data); | |
119 | ret = pmbus_write_word_data(client, page, reg, word); | |
120 | data->access = ktime_get(); | |
121 | ||
122 | return ret; | |
123 | } | |
124 | ||
125 | static int max15301_write_byte(struct i2c_client *client, int page, u8 value) | |
126 | { | |
127 | const struct pmbus_driver_info *info = pmbus_get_driver_info(client); | |
128 | struct max15301_data *data = to_max15301_data(info); | |
129 | int ret; | |
130 | ||
131 | if (page > 0) | |
132 | return -ENXIO; | |
133 | ||
134 | max15301_wait(data); | |
135 | ret = pmbus_write_byte(client, page, value); | |
136 | data->access = ktime_get(); | |
137 | ||
138 | return ret; | |
139 | } | |
140 | ||
141 | static int max15301_probe(struct i2c_client *client) | |
142 | { | |
143 | int status; | |
144 | u8 device_id[I2C_SMBUS_BLOCK_MAX + 1]; | |
145 | const struct i2c_device_id *mid; | |
146 | struct pmbus_driver_info *info = &max15301_data.info; | |
147 | ||
148 | if (!i2c_check_functionality(client->adapter, | |
149 | I2C_FUNC_SMBUS_READ_BYTE_DATA | |
150 | | I2C_FUNC_SMBUS_BLOCK_DATA)) | |
151 | return -ENODEV; | |
152 | ||
153 | status = i2c_smbus_read_block_data(client, PMBUS_IC_DEVICE_ID, device_id); | |
154 | if (status < 0) { | |
155 | dev_err(&client->dev, "Failed to read Device Id\n"); | |
156 | return status; | |
157 | } | |
158 | for (mid = max15301_id; mid->name[0]; mid++) { | |
159 | if (!strncasecmp(mid->name, device_id, strlen(mid->name))) | |
160 | break; | |
161 | } | |
162 | if (!mid->name[0]) { | |
163 | dev_err(&client->dev, "Unsupported device\n"); | |
164 | return -ENODEV; | |
165 | } | |
166 | ||
167 | max15301_data.delay = delay; | |
168 | ||
169 | info->read_byte_data = max15301_read_byte_data; | |
170 | info->read_word_data = max15301_read_word_data; | |
171 | info->write_byte = max15301_write_byte; | |
172 | info->write_word_data = max15301_write_word_data; | |
173 | ||
174 | return pmbus_do_probe(client, info); | |
175 | } | |
176 | ||
177 | static struct i2c_driver max15301_driver = { | |
178 | .driver = { | |
179 | .name = "max15301", | |
180 | }, | |
181 | .probe_new = max15301_probe, | |
182 | .id_table = max15301_id, | |
183 | }; | |
184 | ||
185 | module_i2c_driver(max15301_driver); | |
186 | ||
187 | MODULE_AUTHOR("Erik Rosen <erik.rosen@metormote.com>"); | |
188 | MODULE_DESCRIPTION("PMBus driver for Maxim MAX15301"); | |
189 | MODULE_LICENSE("GPL"); | |
b94ca77e | 190 | MODULE_IMPORT_NS(PMBUS); |