1 // SPDX-License-Identifier: GPL-2.0
3 * System Control and Management Interface(SCMI) based hwmon sensor driver
5 * Copyright (C) 2018 ARM Ltd.
6 * Sudeep Holla <sudeep.holla@arm.com>
9 #include <linux/hwmon.h>
10 #include <linux/module.h>
11 #include <linux/scmi_protocol.h>
12 #include <linux/slab.h>
13 #include <linux/sysfs.h>
14 #include <linux/thermal.h>
17 const struct scmi_handle
*handle
;
18 const struct scmi_sensor_info
**info
[hwmon_max
];
21 static int scmi_hwmon_read(struct device
*dev
, enum hwmon_sensor_types type
,
22 u32 attr
, int channel
, long *val
)
26 const struct scmi_sensor_info
*sensor
;
27 struct scmi_sensors
*scmi_sensors
= dev_get_drvdata(dev
);
28 const struct scmi_handle
*h
= scmi_sensors
->handle
;
30 sensor
= *(scmi_sensors
->info
[type
] + channel
);
31 ret
= h
->sensor_ops
->reading_get(h
, sensor
->id
, false, &value
);
39 scmi_hwmon_read_string(struct device
*dev
, enum hwmon_sensor_types type
,
40 u32 attr
, int channel
, const char **str
)
42 const struct scmi_sensor_info
*sensor
;
43 struct scmi_sensors
*scmi_sensors
= dev_get_drvdata(dev
);
45 sensor
= *(scmi_sensors
->info
[type
] + channel
);
52 scmi_hwmon_is_visible(const void *drvdata
, enum hwmon_sensor_types type
,
53 u32 attr
, int channel
)
55 const struct scmi_sensor_info
*sensor
;
56 const struct scmi_sensors
*scmi_sensors
= drvdata
;
58 sensor
= *(scmi_sensors
->info
[type
] + channel
);
65 static const struct hwmon_ops scmi_hwmon_ops
= {
66 .is_visible
= scmi_hwmon_is_visible
,
67 .read
= scmi_hwmon_read
,
68 .read_string
= scmi_hwmon_read_string
,
71 static struct hwmon_chip_info scmi_chip_info
= {
72 .ops
= &scmi_hwmon_ops
,
76 static int scmi_hwmon_add_chan_info(struct hwmon_channel_info
*scmi_hwmon_chan
,
77 struct device
*dev
, int num
,
78 enum hwmon_sensor_types type
, u32 config
)
81 u32
*cfg
= devm_kcalloc(dev
, num
+ 1, sizeof(*cfg
), GFP_KERNEL
);
86 scmi_hwmon_chan
->type
= type
;
87 scmi_hwmon_chan
->config
= cfg
;
88 for (i
= 0; i
< num
; i
++, cfg
++)
94 static enum hwmon_sensor_types scmi_types
[] = {
95 [TEMPERATURE_C
] = hwmon_temp
,
97 [CURRENT
] = hwmon_curr
,
98 [POWER
] = hwmon_power
,
99 [ENERGY
] = hwmon_energy
,
102 static u32 hwmon_attributes
[] = {
103 [hwmon_chip
] = HWMON_C_REGISTER_TZ
,
104 [hwmon_temp
] = HWMON_T_INPUT
| HWMON_T_LABEL
,
105 [hwmon_in
] = HWMON_I_INPUT
| HWMON_I_LABEL
,
106 [hwmon_curr
] = HWMON_C_INPUT
| HWMON_C_LABEL
,
107 [hwmon_power
] = HWMON_P_INPUT
| HWMON_P_LABEL
,
108 [hwmon_energy
] = HWMON_E_INPUT
| HWMON_E_LABEL
,
111 static int scmi_hwmon_probe(struct scmi_device
*sdev
)
115 enum hwmon_sensor_types type
;
116 struct scmi_sensors
*scmi_sensors
;
117 const struct scmi_sensor_info
*sensor
;
118 int nr_count
[hwmon_max
] = {0}, nr_types
= 0;
119 const struct hwmon_chip_info
*chip_info
;
120 struct device
*hwdev
, *dev
= &sdev
->dev
;
121 struct hwmon_channel_info
*scmi_hwmon_chan
;
122 const struct hwmon_channel_info
**ptr_scmi_ci
;
123 const struct scmi_handle
*handle
= sdev
->handle
;
125 if (!handle
|| !handle
->sensor_ops
)
128 nr_sensors
= handle
->sensor_ops
->count_get(handle
);
132 scmi_sensors
= devm_kzalloc(dev
, sizeof(*scmi_sensors
), GFP_KERNEL
);
136 scmi_sensors
->handle
= handle
;
138 for (i
= 0; i
< nr_sensors
; i
++) {
139 sensor
= handle
->sensor_ops
->info_get(handle
, i
);
143 switch (sensor
->type
) {
149 type
= scmi_types
[sensor
->type
];
157 if (nr_count
[hwmon_temp
])
158 nr_count
[hwmon_chip
]++, nr_types
++;
160 scmi_hwmon_chan
= devm_kcalloc(dev
, nr_types
, sizeof(*scmi_hwmon_chan
),
162 if (!scmi_hwmon_chan
)
165 ptr_scmi_ci
= devm_kcalloc(dev
, nr_types
+ 1, sizeof(*ptr_scmi_ci
),
170 scmi_chip_info
.info
= ptr_scmi_ci
;
171 chip_info
= &scmi_chip_info
;
173 for (type
= 0; type
< hwmon_max
; type
++) {
177 scmi_hwmon_add_chan_info(scmi_hwmon_chan
, dev
, nr_count
[type
],
178 type
, hwmon_attributes
[type
]);
179 *ptr_scmi_ci
++ = scmi_hwmon_chan
++;
181 scmi_sensors
->info
[type
] =
182 devm_kcalloc(dev
, nr_count
[type
],
183 sizeof(*scmi_sensors
->info
), GFP_KERNEL
);
184 if (!scmi_sensors
->info
[type
])
188 for (i
= nr_sensors
- 1; i
>= 0 ; i
--) {
189 sensor
= handle
->sensor_ops
->info_get(handle
, i
);
193 switch (sensor
->type
) {
199 type
= scmi_types
[sensor
->type
];
200 idx
= --nr_count
[type
];
201 *(scmi_sensors
->info
[type
] + idx
) = sensor
;
206 hwdev
= devm_hwmon_device_register_with_info(dev
, "scmi_sensors",
207 scmi_sensors
, chip_info
,
210 return PTR_ERR_OR_ZERO(hwdev
);
213 static const struct scmi_device_id scmi_id_table
[] = {
214 { SCMI_PROTOCOL_SENSOR
},
217 MODULE_DEVICE_TABLE(scmi
, scmi_id_table
);
219 static struct scmi_driver scmi_hwmon_drv
= {
220 .name
= "scmi-hwmon",
221 .probe
= scmi_hwmon_probe
,
222 .id_table
= scmi_id_table
,
224 module_scmi_driver(scmi_hwmon_drv
);
226 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
227 MODULE_DESCRIPTION("ARM SCMI HWMON interface driver");
228 MODULE_LICENSE("GPL v2");