1 // SPDX-License-Identifier: GPL-2.0
3 * System Control and Management Interface(SCMI) based hwmon sensor driver
5 * Copyright (C) 2018-2021 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>
16 static const struct scmi_sensor_proto_ops
*sensor_ops
;
19 const struct scmi_protocol_handle
*ph
;
20 const struct scmi_sensor_info
**info
[hwmon_max
];
23 static inline u64
__pow10(u8 x
)
33 static int scmi_hwmon_scale(const struct scmi_sensor_info
*sensor
, u64
*value
)
35 int scale
= sensor
->scale
;
38 switch (sensor
->type
) {
58 f
= __pow10(abs(scale
));
62 *value
= div64_u64(*value
, f
);
67 static int scmi_hwmon_read(struct device
*dev
, enum hwmon_sensor_types type
,
68 u32 attr
, int channel
, long *val
)
72 const struct scmi_sensor_info
*sensor
;
73 struct scmi_sensors
*scmi_sensors
= dev_get_drvdata(dev
);
75 sensor
= *(scmi_sensors
->info
[type
] + channel
);
76 ret
= sensor_ops
->reading_get(scmi_sensors
->ph
, sensor
->id
, &value
);
80 ret
= scmi_hwmon_scale(sensor
, &value
);
88 scmi_hwmon_read_string(struct device
*dev
, enum hwmon_sensor_types type
,
89 u32 attr
, int channel
, const char **str
)
91 const struct scmi_sensor_info
*sensor
;
92 struct scmi_sensors
*scmi_sensors
= dev_get_drvdata(dev
);
94 sensor
= *(scmi_sensors
->info
[type
] + channel
);
101 scmi_hwmon_is_visible(const void *drvdata
, enum hwmon_sensor_types type
,
102 u32 attr
, int channel
)
104 const struct scmi_sensor_info
*sensor
;
105 const struct scmi_sensors
*scmi_sensors
= drvdata
;
107 sensor
= *(scmi_sensors
->info
[type
] + channel
);
114 static const struct hwmon_ops scmi_hwmon_ops
= {
115 .is_visible
= scmi_hwmon_is_visible
,
116 .read
= scmi_hwmon_read
,
117 .read_string
= scmi_hwmon_read_string
,
120 static struct hwmon_chip_info scmi_chip_info
= {
121 .ops
= &scmi_hwmon_ops
,
125 static int scmi_hwmon_add_chan_info(struct hwmon_channel_info
*scmi_hwmon_chan
,
126 struct device
*dev
, int num
,
127 enum hwmon_sensor_types type
, u32 config
)
130 u32
*cfg
= devm_kcalloc(dev
, num
+ 1, sizeof(*cfg
), GFP_KERNEL
);
135 scmi_hwmon_chan
->type
= type
;
136 scmi_hwmon_chan
->config
= cfg
;
137 for (i
= 0; i
< num
; i
++, cfg
++)
143 static enum hwmon_sensor_types scmi_types
[] = {
144 [TEMPERATURE_C
] = hwmon_temp
,
145 [VOLTAGE
] = hwmon_in
,
146 [CURRENT
] = hwmon_curr
,
147 [POWER
] = hwmon_power
,
148 [ENERGY
] = hwmon_energy
,
151 static u32 hwmon_attributes
[hwmon_max
] = {
152 [hwmon_chip
] = HWMON_C_REGISTER_TZ
,
153 [hwmon_temp
] = HWMON_T_INPUT
| HWMON_T_LABEL
,
154 [hwmon_in
] = HWMON_I_INPUT
| HWMON_I_LABEL
,
155 [hwmon_curr
] = HWMON_C_INPUT
| HWMON_C_LABEL
,
156 [hwmon_power
] = HWMON_P_INPUT
| HWMON_P_LABEL
,
157 [hwmon_energy
] = HWMON_E_INPUT
| HWMON_E_LABEL
,
160 static int scmi_hwmon_probe(struct scmi_device
*sdev
)
164 enum hwmon_sensor_types type
;
165 struct scmi_sensors
*scmi_sensors
;
166 const struct scmi_sensor_info
*sensor
;
167 int nr_count
[hwmon_max
] = {0}, nr_types
= 0;
168 const struct hwmon_chip_info
*chip_info
;
169 struct device
*hwdev
, *dev
= &sdev
->dev
;
170 struct hwmon_channel_info
*scmi_hwmon_chan
;
171 const struct hwmon_channel_info
**ptr_scmi_ci
;
172 const struct scmi_handle
*handle
= sdev
->handle
;
173 struct scmi_protocol_handle
*ph
;
178 sensor_ops
= handle
->devm_protocol_get(sdev
, SCMI_PROTOCOL_SENSOR
, &ph
);
179 if (IS_ERR(sensor_ops
))
180 return PTR_ERR(sensor_ops
);
182 nr_sensors
= sensor_ops
->count_get(ph
);
186 scmi_sensors
= devm_kzalloc(dev
, sizeof(*scmi_sensors
), GFP_KERNEL
);
190 scmi_sensors
->ph
= ph
;
192 for (i
= 0; i
< nr_sensors
; i
++) {
193 sensor
= sensor_ops
->info_get(ph
, i
);
197 switch (sensor
->type
) {
203 type
= scmi_types
[sensor
->type
];
211 if (nr_count
[hwmon_temp
]) {
212 nr_count
[hwmon_chip
]++;
216 scmi_hwmon_chan
= devm_kcalloc(dev
, nr_types
, sizeof(*scmi_hwmon_chan
),
218 if (!scmi_hwmon_chan
)
221 ptr_scmi_ci
= devm_kcalloc(dev
, nr_types
+ 1, sizeof(*ptr_scmi_ci
),
226 scmi_chip_info
.info
= ptr_scmi_ci
;
227 chip_info
= &scmi_chip_info
;
229 for (type
= 0; type
< hwmon_max
; type
++) {
233 scmi_hwmon_add_chan_info(scmi_hwmon_chan
, dev
, nr_count
[type
],
234 type
, hwmon_attributes
[type
]);
235 *ptr_scmi_ci
++ = scmi_hwmon_chan
++;
237 scmi_sensors
->info
[type
] =
238 devm_kcalloc(dev
, nr_count
[type
],
239 sizeof(*scmi_sensors
->info
), GFP_KERNEL
);
240 if (!scmi_sensors
->info
[type
])
244 for (i
= nr_sensors
- 1; i
>= 0 ; i
--) {
245 sensor
= sensor_ops
->info_get(ph
, i
);
249 switch (sensor
->type
) {
255 type
= scmi_types
[sensor
->type
];
256 idx
= --nr_count
[type
];
257 *(scmi_sensors
->info
[type
] + idx
) = sensor
;
262 hwdev
= devm_hwmon_device_register_with_info(dev
, "scmi_sensors",
263 scmi_sensors
, chip_info
,
266 return PTR_ERR_OR_ZERO(hwdev
);
269 static const struct scmi_device_id scmi_id_table
[] = {
270 { SCMI_PROTOCOL_SENSOR
, "hwmon" },
273 MODULE_DEVICE_TABLE(scmi
, scmi_id_table
);
275 static struct scmi_driver scmi_hwmon_drv
= {
276 .name
= "scmi-hwmon",
277 .probe
= scmi_hwmon_probe
,
278 .id_table
= scmi_id_table
,
280 module_scmi_driver(scmi_hwmon_drv
);
282 MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
283 MODULE_DESCRIPTION("ARM SCMI HWMON interface driver");
284 MODULE_LICENSE("GPL v2");