]> Git Repo - linux.git/blob - drivers/hwmon/lenovo-ec-sensors.c
drm/vc4: Run DRM default client setup
[linux.git] / drivers / hwmon / lenovo-ec-sensors.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * HWMON driver for Lenovo ThinkStation based workstations
4  * via the embedded controller registers
5  *
6  * Copyright (C) 2024 David Ober (Lenovo) <[email protected]>
7  *
8  * EC provides:
9  * - CPU temperature
10  * - DIMM temperature
11  * - Chassis zone temperatures
12  * - CPU fan RPM
13  * - DIMM fan RPM
14  * - Chassis fans RPM
15  */
16
17 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
18
19 #include <linux/acpi.h>
20 #include <linux/bits.h>
21 #include <linux/delay.h>
22 #include <linux/device.h>
23 #include <linux/dmi.h>
24 #include <linux/err.h>
25 #include <linux/hwmon.h>
26 #include <linux/io.h>
27 #include <linux/ioport.h>
28 #include <linux/module.h>
29 #include <linux/mutex.h>
30 #include <linux/platform_device.h>
31 #include <linux/types.h>
32 #include <linux/units.h>
33
34 #define MCHP_SING_IDX                   0x0000
35 #define MCHP_EMI0_APPLICATION_ID        0x090C
36 #define MCHP_EMI0_EC_ADDRESS            0x0902
37 #define MCHP_EMI0_EC_DATA_BYTE0         0x0904
38 #define MCHP_EMI0_EC_DATA_BYTE1         0x0905
39 #define MCHP_EMI0_EC_DATA_BYTE2         0x0906
40 #define MCHP_EMI0_EC_DATA_BYTE3         0x0907
41 #define IO_REGION_START                 0x0900
42 #define IO_REGION_LENGTH                0xD
43
44 static inline u8
45 get_ec_reg(unsigned char page, unsigned char index)
46 {
47         u8 onebyte;
48         unsigned short m_index;
49         unsigned short phy_index = page * 256 + index;
50
51         outb_p(0x01, MCHP_EMI0_APPLICATION_ID);
52
53         m_index = phy_index & GENMASK(14, 2);
54         outw_p(m_index, MCHP_EMI0_EC_ADDRESS);
55
56         onebyte = inb_p(MCHP_EMI0_EC_DATA_BYTE0 + (phy_index & GENMASK(1, 0)));
57
58         outb_p(0x01, MCHP_EMI0_APPLICATION_ID);  /* write 0x01 again to clean */
59         return onebyte;
60 }
61
62 enum systems {
63         LENOVO_PX,
64         LENOVO_P7,
65         LENOVO_P5,
66         LENOVO_P8,
67 };
68
69 static int px_temp_map[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
70
71 static const char * const lenovo_px_ec_temp_label[] = {
72         "CPU1",
73         "CPU2",
74         "R_DIMM1",
75         "L_DIMM1",
76         "R_DIMM2",
77         "L_DIMM2",
78         "PCH",
79         "M2_R",
80         "M2_Z1R",
81         "M2_Z2R",
82         "PCI_Z1",
83         "PCI_Z2",
84         "PCI_Z3",
85         "PCI_Z4",
86         "AMB",
87 };
88
89 static int gen_temp_map[] = {0, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
90
91 static const char * const lenovo_gen_ec_temp_label[] = {
92         "CPU1",
93         "R_DIMM",
94         "L_DIMM",
95         "PCH",
96         "M2_R",
97         "M2_Z1R",
98         "M2_Z2R",
99         "PCI_Z1",
100         "PCI_Z2",
101         "PCI_Z3",
102         "PCI_Z4",
103         "AMB",
104 };
105
106 static int px_fan_map[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
107
108 static const char * const px_ec_fan_label[] = {
109         "CPU1_Fan",
110         "CPU2_Fan",
111         "Front_Fan1-1",
112         "Front_Fan1-2",
113         "Front_Fan2",
114         "Front_Fan3",
115         "MEM_Fan1",
116         "MEM_Fan2",
117         "Rear_Fan1",
118         "Rear_Fan2",
119         "Flex_Bay_Fan1",
120         "Flex_Bay_Fan2",
121         "Flex_Bay_Fan2",
122         "PSU_HDD_Fan",
123         "PSU1_Fan",
124         "PSU2_Fan",
125 };
126
127 static int p7_fan_map[] = {0, 2, 3, 4, 5, 6, 7, 8, 10, 11, 14};
128
129 static const char * const p7_ec_fan_label[] = {
130         "CPU1_Fan",
131         "HP_CPU_Fan1",
132         "HP_CPU_Fan2",
133         "PCIE1_4_Fan",
134         "PCIE5_7_Fan",
135         "MEM_Fan1",
136         "MEM_Fan2",
137         "Rear_Fan1",
138         "BCB_Fan",
139         "Flex_Bay_Fan",
140         "PSU_Fan",
141 };
142
143 static int p5_fan_map[] = {0, 5, 6, 7, 8, 10, 11, 14};
144
145 static const char * const p5_ec_fan_label[] = {
146         "CPU_Fan",
147         "HDD_Fan",
148         "Duct_Fan1",
149         "MEM_Fan",
150         "Rear_Fan",
151         "Front_Fan",
152         "Flex_Bay_Fan",
153         "PSU_Fan",
154 };
155
156 static int p8_fan_map[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14};
157
158 static const char * const p8_ec_fan_label[] = {
159         "CPU1_Fan",
160         "CPU2_Fan",
161         "HP_CPU_Fan1",
162         "HP_CPU_Fan2",
163         "PCIE1_4_Fan",
164         "PCIE5_7_Fan",
165         "DIMM1_Fan1",
166         "DIMM1_Fan2",
167         "DIMM2_Fan1",
168         "DIMM2_Fan2",
169         "Rear_Fan",
170         "HDD_Bay_Fan",
171         "Flex_Bay_Fan",
172         "PSU_Fan",
173 };
174
175 struct ec_sensors_data {
176         struct mutex mec_mutex; /* lock for sensor data access */
177         const char *const *fan_labels;
178         const char *const *temp_labels;
179         const int *fan_map;
180         const int *temp_map;
181 };
182
183 static int
184 lenovo_ec_do_read_temp(struct ec_sensors_data *data, u32 attr, int channel, long *val)
185 {
186         u8 lsb;
187
188         switch (attr) {
189         case hwmon_temp_input:
190                 mutex_lock(&data->mec_mutex);
191                 lsb = get_ec_reg(2, 0x81 + channel);
192                 mutex_unlock(&data->mec_mutex);
193                 if (lsb <= 0x40)
194                         return -ENODATA;
195                 *val = (lsb - 0x40) * 1000;
196                 return 0;
197         default:
198                 return -EOPNOTSUPP;
199         }
200 }
201
202 static int
203 lenovo_ec_do_read_fan(struct ec_sensors_data *data, u32 attr, int channel, long *val)
204 {
205         u8 lsb, msb;
206
207         channel *= 2;
208         switch (attr) {
209         case hwmon_fan_input:
210                 mutex_lock(&data->mec_mutex);
211                 lsb = get_ec_reg(4, 0x20 + channel);
212                 msb = get_ec_reg(4, 0x21 + channel);
213                 mutex_unlock(&data->mec_mutex);
214                 *val = (msb << 8) + lsb;
215                 return 0;
216         case hwmon_fan_max:
217                 mutex_lock(&data->mec_mutex);
218                 lsb = get_ec_reg(4, 0x40 + channel);
219                 msb = get_ec_reg(4, 0x41 + channel);
220                 mutex_unlock(&data->mec_mutex);
221                 *val = (msb << 8) + lsb;
222                 return 0;
223         default:
224                 return -EOPNOTSUPP;
225         }
226 }
227
228 static int
229 lenovo_ec_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type,
230                             u32 attr, int channel, const char **str)
231 {
232         struct ec_sensors_data *state = dev_get_drvdata(dev);
233
234         switch (type) {
235         case hwmon_temp:
236                 *str = state->temp_labels[channel];
237                 return 0;
238         case hwmon_fan:
239                 *str = state->fan_labels[channel];
240                 return 0;
241         default:
242                 return -EOPNOTSUPP;
243         }
244 }
245
246 static int
247 lenovo_ec_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
248                      u32 attr, int channel, long *val)
249 {
250         struct ec_sensors_data *data = dev_get_drvdata(dev);
251
252         switch (type) {
253         case hwmon_temp:
254                 return lenovo_ec_do_read_temp(data, attr, data->temp_map[channel], val);
255         case hwmon_fan:
256                 return lenovo_ec_do_read_fan(data, attr, data->fan_map[channel], val);
257         default:
258                 return -EOPNOTSUPP;
259         }
260 }
261
262 static umode_t
263 lenovo_ec_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
264                            u32 attr, int channel)
265 {
266         switch (type) {
267         case hwmon_temp:
268                 if (attr == hwmon_temp_input || attr == hwmon_temp_label)
269                         return 0444;
270                 return 0;
271         case hwmon_fan:
272                 if (attr == hwmon_fan_input || attr == hwmon_fan_max || attr == hwmon_fan_label)
273                         return 0444;
274                 return 0;
275         default:
276                 return 0;
277         }
278 }
279
280 static const struct hwmon_channel_info *lenovo_ec_hwmon_info_px[] = {
281         HWMON_CHANNEL_INFO(temp,
282                            HWMON_T_INPUT | HWMON_T_LABEL,
283                            HWMON_T_INPUT | HWMON_T_LABEL,
284                            HWMON_T_INPUT | HWMON_T_LABEL,
285                            HWMON_T_INPUT | HWMON_T_LABEL,
286                            HWMON_T_INPUT | HWMON_T_LABEL,
287                            HWMON_T_INPUT | HWMON_T_LABEL,
288                            HWMON_T_INPUT | HWMON_T_LABEL,
289                            HWMON_T_INPUT | HWMON_T_LABEL,
290                            HWMON_T_INPUT | HWMON_T_LABEL,
291                            HWMON_T_INPUT | HWMON_T_LABEL,
292                            HWMON_T_INPUT | HWMON_T_LABEL,
293                            HWMON_T_INPUT | HWMON_T_LABEL,
294                            HWMON_T_INPUT | HWMON_T_LABEL,
295                            HWMON_T_INPUT | HWMON_T_LABEL,
296                            HWMON_T_INPUT | HWMON_T_LABEL),
297         HWMON_CHANNEL_INFO(fan,
298                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
299                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
300                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
301                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
302                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
303                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
304                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
305                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
306                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
307                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
308                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
309                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
310                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
311                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
312                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
313                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX),
314         NULL
315 };
316
317 static const struct hwmon_channel_info *lenovo_ec_hwmon_info_p8[] = {
318         HWMON_CHANNEL_INFO(temp,
319                            HWMON_T_INPUT | HWMON_T_LABEL,
320                            HWMON_T_INPUT | HWMON_T_LABEL,
321                            HWMON_T_INPUT | HWMON_T_LABEL,
322                            HWMON_T_INPUT | HWMON_T_LABEL,
323                            HWMON_T_INPUT | HWMON_T_LABEL,
324                            HWMON_T_INPUT | HWMON_T_LABEL,
325                            HWMON_T_INPUT | HWMON_T_LABEL,
326                            HWMON_T_INPUT | HWMON_T_LABEL,
327                            HWMON_T_INPUT | HWMON_T_LABEL,
328                            HWMON_T_INPUT | HWMON_T_LABEL,
329                            HWMON_T_INPUT | HWMON_T_LABEL,
330                            HWMON_T_INPUT | HWMON_T_LABEL),
331         HWMON_CHANNEL_INFO(fan,
332                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
333                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
334                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
335                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
336                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
337                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
338                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
339                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
340                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
341                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
342                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
343                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
344                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
345                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX),
346         NULL
347 };
348
349 static const struct hwmon_channel_info *lenovo_ec_hwmon_info_p7[] = {
350         HWMON_CHANNEL_INFO(temp,
351                            HWMON_T_INPUT | HWMON_T_LABEL,
352                            HWMON_T_INPUT | HWMON_T_LABEL,
353                            HWMON_T_INPUT | HWMON_T_LABEL,
354                            HWMON_T_INPUT | HWMON_T_LABEL,
355                            HWMON_T_INPUT | HWMON_T_LABEL,
356                            HWMON_T_INPUT | HWMON_T_LABEL,
357                            HWMON_T_INPUT | HWMON_T_LABEL,
358                            HWMON_T_INPUT | HWMON_T_LABEL,
359                            HWMON_T_INPUT | HWMON_T_LABEL,
360                            HWMON_T_INPUT | HWMON_T_LABEL,
361                            HWMON_T_INPUT | HWMON_T_LABEL,
362                            HWMON_T_INPUT | HWMON_T_LABEL),
363         HWMON_CHANNEL_INFO(fan,
364                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
365                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
366                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
367                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
368                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
369                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
370                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
371                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
372                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
373                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
374                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX),
375         NULL
376 };
377
378 static const struct hwmon_channel_info *lenovo_ec_hwmon_info_p5[] = {
379         HWMON_CHANNEL_INFO(temp,
380                            HWMON_T_INPUT | HWMON_T_LABEL,
381                            HWMON_T_INPUT | HWMON_T_LABEL,
382                            HWMON_T_INPUT | HWMON_T_LABEL,
383                            HWMON_T_INPUT | HWMON_T_LABEL,
384                            HWMON_T_INPUT | HWMON_T_LABEL,
385                            HWMON_T_INPUT | HWMON_T_LABEL,
386                            HWMON_T_INPUT | HWMON_T_LABEL,
387                            HWMON_T_INPUT | HWMON_T_LABEL,
388                            HWMON_T_INPUT | HWMON_T_LABEL,
389                            HWMON_T_INPUT | HWMON_T_LABEL,
390                            HWMON_T_INPUT | HWMON_T_LABEL,
391                            HWMON_T_INPUT | HWMON_T_LABEL),
392         HWMON_CHANNEL_INFO(fan,
393                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
394                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
395                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
396                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
397                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
398                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
399                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX,
400                            HWMON_F_INPUT | HWMON_F_LABEL | HWMON_F_MAX),
401         NULL
402 };
403
404 static const struct hwmon_ops lenovo_ec_hwmon_ops = {
405         .is_visible = lenovo_ec_hwmon_is_visible,
406         .read = lenovo_ec_hwmon_read,
407         .read_string = lenovo_ec_hwmon_read_string,
408 };
409
410 static struct hwmon_chip_info lenovo_ec_chip_info = {
411         .ops = &lenovo_ec_hwmon_ops,
412 };
413
414 static const struct dmi_system_id thinkstation_dmi_table[] = {
415         {
416                 .ident = "LENOVO_PX",
417                 .driver_data = (void *)(long)LENOVO_PX,
418                 .matches = {
419                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
420                         DMI_MATCH(DMI_PRODUCT_NAME, "30EU"),
421                 },
422         },
423         {
424                 .ident = "LENOVO_PX",
425                 .driver_data = (void *)(long)LENOVO_PX,
426                 .matches = {
427                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
428                         DMI_MATCH(DMI_PRODUCT_NAME, "30EV"),
429                 },
430         },
431         {
432                 .ident = "LENOVO_P7",
433                 .driver_data = (void *)(long)LENOVO_P7,
434                 .matches = {
435                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
436                         DMI_MATCH(DMI_PRODUCT_NAME, "30F2"),
437                 },
438         },
439         {
440                 .ident = "LENOVO_P7",
441                 .driver_data = (void *)(long)LENOVO_P7,
442                 .matches = {
443                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
444                         DMI_MATCH(DMI_PRODUCT_NAME, "30F3"),
445                 },
446         },
447         {
448                 .ident = "LENOVO_P5",
449                 .driver_data = (void *)(long)LENOVO_P5,
450                 .matches = {
451                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
452                         DMI_MATCH(DMI_PRODUCT_NAME, "30G9"),
453                 },
454         },
455         {
456                 .ident = "LENOVO_P5",
457                 .driver_data = (void *)(long)LENOVO_P5,
458                 .matches = {
459                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
460                         DMI_MATCH(DMI_PRODUCT_NAME, "30GA"),
461                 },
462         },
463         {
464                 .ident = "LENOVO_P8",
465                 .driver_data = (void *)(long)LENOVO_P8,
466                 .matches = {
467                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
468                         DMI_MATCH(DMI_PRODUCT_NAME, "30HH"),
469                 },
470         },
471         {
472                 .ident = "LENOVO_P8",
473                 .driver_data = (void *)(long)LENOVO_P8,
474                 .matches = {
475                         DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
476                         DMI_MATCH(DMI_PRODUCT_NAME, "30HJ"),
477                 },
478         },
479         {}
480 };
481 MODULE_DEVICE_TABLE(dmi, thinkstation_dmi_table);
482
483 static int lenovo_ec_probe(struct platform_device *pdev)
484 {
485         struct device *hwdev;
486         struct ec_sensors_data *ec_data;
487         const struct hwmon_chip_info *chip_info;
488         struct device *dev = &pdev->dev;
489         const struct dmi_system_id *dmi_id;
490         int app_id;
491
492         ec_data = devm_kzalloc(dev, sizeof(struct ec_sensors_data), GFP_KERNEL);
493         if (!ec_data)
494                 return -ENOMEM;
495
496         if (!request_region(IO_REGION_START, IO_REGION_LENGTH, "LNV-WKS")) {
497                 pr_err(":request fail\n");
498                 return -EIO;
499         }
500
501         dev_set_drvdata(dev, ec_data);
502
503         chip_info = &lenovo_ec_chip_info;
504
505         mutex_init(&ec_data->mec_mutex);
506
507         mutex_lock(&ec_data->mec_mutex);
508         app_id = inb_p(MCHP_EMI0_APPLICATION_ID);
509         if (app_id) /* check EMI Application ID Value */
510                 outb_p(app_id, MCHP_EMI0_APPLICATION_ID); /* set EMI Application ID to 0 */
511         outw_p(MCHP_SING_IDX, MCHP_EMI0_EC_ADDRESS);
512         mutex_unlock(&ec_data->mec_mutex);
513
514         if ((inb_p(MCHP_EMI0_EC_DATA_BYTE0) != 'M') &&
515             (inb_p(MCHP_EMI0_EC_DATA_BYTE1) != 'C') &&
516             (inb_p(MCHP_EMI0_EC_DATA_BYTE2) != 'H') &&
517             (inb_p(MCHP_EMI0_EC_DATA_BYTE3) != 'P')) {
518                 release_region(IO_REGION_START, IO_REGION_LENGTH);
519                 return -ENODEV;
520         }
521
522         dmi_id = dmi_first_match(thinkstation_dmi_table);
523
524         switch ((long)dmi_id->driver_data) {
525         case 0:
526                 ec_data->fan_labels = px_ec_fan_label;
527                 ec_data->temp_labels = lenovo_px_ec_temp_label;
528                 ec_data->fan_map = px_fan_map;
529                 ec_data->temp_map = px_temp_map;
530                 lenovo_ec_chip_info.info = lenovo_ec_hwmon_info_px;
531                 break;
532         case 1:
533                 ec_data->fan_labels = p7_ec_fan_label;
534                 ec_data->temp_labels = lenovo_gen_ec_temp_label;
535                 ec_data->fan_map = p7_fan_map;
536                 ec_data->temp_map = gen_temp_map;
537                 lenovo_ec_chip_info.info = lenovo_ec_hwmon_info_p7;
538                 break;
539         case 2:
540                 ec_data->fan_labels = p5_ec_fan_label;
541                 ec_data->temp_labels = lenovo_gen_ec_temp_label;
542                 ec_data->fan_map = p5_fan_map;
543                 ec_data->temp_map = gen_temp_map;
544                 lenovo_ec_chip_info.info = lenovo_ec_hwmon_info_p5;
545                 break;
546         case 3:
547                 ec_data->fan_labels = p8_ec_fan_label;
548                 ec_data->temp_labels = lenovo_gen_ec_temp_label;
549                 ec_data->fan_map = p8_fan_map;
550                 ec_data->temp_map = gen_temp_map;
551                 lenovo_ec_chip_info.info = lenovo_ec_hwmon_info_p8;
552                 break;
553         default:
554                 release_region(IO_REGION_START, IO_REGION_LENGTH);
555                 return -ENODEV;
556         }
557
558         hwdev = devm_hwmon_device_register_with_info(dev, "lenovo_ec",
559                                                      ec_data,
560                                                      chip_info, NULL);
561
562         return PTR_ERR_OR_ZERO(hwdev);
563 }
564
565 static struct platform_driver lenovo_ec_sensors_platform_driver = {
566         .driver = {
567                 .name   = "lenovo-ec-sensors",
568         },
569         .probe = lenovo_ec_probe,
570 };
571
572 static struct platform_device *lenovo_ec_sensors_platform_device;
573
574 static int __init lenovo_ec_init(void)
575 {
576         if (!dmi_check_system(thinkstation_dmi_table))
577                 return -ENODEV;
578
579         lenovo_ec_sensors_platform_device =
580                 platform_create_bundle(&lenovo_ec_sensors_platform_driver,
581                                        lenovo_ec_probe, NULL, 0, NULL, 0);
582
583         if (IS_ERR(lenovo_ec_sensors_platform_device)) {
584                 release_region(IO_REGION_START, IO_REGION_LENGTH);
585                 return PTR_ERR(lenovo_ec_sensors_platform_device);
586         }
587
588         return 0;
589 }
590 module_init(lenovo_ec_init);
591
592 static void __exit lenovo_ec_exit(void)
593 {
594         release_region(IO_REGION_START, IO_REGION_LENGTH);
595         platform_device_unregister(lenovo_ec_sensors_platform_device);
596         platform_driver_unregister(&lenovo_ec_sensors_platform_driver);
597 }
598 module_exit(lenovo_ec_exit);
599
600 MODULE_AUTHOR("David Ober <[email protected]>");
601 MODULE_DESCRIPTION("HWMON driver for sensors accessible via EC in LENOVO motherboards");
602 MODULE_LICENSE("GPL");
This page took 0.067258 seconds and 4 git commands to generate.