^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * System Control and Power Interface(SCPI) based hwmon sensor driver
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2015 ARM Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Punit Agrawal <punit.agrawal@arm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/hwmon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/scpi_protocol.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/sysfs.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/thermal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) struct sensor_data {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) unsigned int scale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) struct scpi_sensor_info info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) struct device_attribute dev_attr_input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) struct device_attribute dev_attr_label;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) char input[20];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) char label[20];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) struct scpi_thermal_zone {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) int sensor_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) struct scpi_sensors *scpi_sensors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) struct scpi_sensors {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) struct scpi_ops *scpi_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) struct sensor_data *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) struct list_head thermal_zones;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) struct attribute **attrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) struct attribute_group group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) const struct attribute_group *groups[2];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) static const u32 gxbb_scpi_scale[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) [TEMPERATURE] = 1, /* (celsius) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) [VOLTAGE] = 1000, /* (millivolts) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) [CURRENT] = 1000, /* (milliamperes) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) [POWER] = 1000000, /* (microwatts) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) [ENERGY] = 1000000, /* (microjoules) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) static const u32 scpi_scale[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) [TEMPERATURE] = 1000, /* (millicelsius) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) [VOLTAGE] = 1000, /* (millivolts) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) [CURRENT] = 1000, /* (milliamperes) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) [POWER] = 1000000, /* (microwatts) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) [ENERGY] = 1000000, /* (microjoules) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) static void scpi_scale_reading(u64 *value, struct sensor_data *sensor)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) if (scpi_scale[sensor->info.class] != sensor->scale) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) *value *= scpi_scale[sensor->info.class];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) do_div(*value, sensor->scale);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) static int scpi_read_temp(void *dev, int *temp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) struct scpi_thermal_zone *zone = dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) struct scpi_sensors *scpi_sensors = zone->scpi_sensors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) struct scpi_ops *scpi_ops = scpi_sensors->scpi_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) struct sensor_data *sensor = &scpi_sensors->data[zone->sensor_id];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) u64 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) ret = scpi_ops->sensor_get_value(sensor->info.sensor_id, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) scpi_scale_reading(&value, sensor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) *temp = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) /* hwmon callback functions */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) scpi_show_sensor(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) struct scpi_sensors *scpi_sensors = dev_get_drvdata(dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) struct scpi_ops *scpi_ops = scpi_sensors->scpi_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct sensor_data *sensor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) u64 value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) sensor = container_of(attr, struct sensor_data, dev_attr_input);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) ret = scpi_ops->sensor_get_value(sensor->info.sensor_id, &value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) scpi_scale_reading(&value, sensor);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) * Temperature sensor values are treated as signed values based on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * observation even though that is not explicitly specified, and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * because an unsigned u64 temperature does not really make practical
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * sense especially when the temperature is below zero degrees Celsius.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) if (sensor->info.class == TEMPERATURE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) return sprintf(buf, "%lld\n", (s64)value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return sprintf(buf, "%llu\n", value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static ssize_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) scpi_show_label(struct device *dev, struct device_attribute *attr, char *buf)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) struct sensor_data *sensor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) sensor = container_of(attr, struct sensor_data, dev_attr_label);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return sprintf(buf, "%s\n", sensor->info.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static const struct thermal_zone_of_device_ops scpi_sensor_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) .get_temp = scpi_read_temp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) static const struct of_device_id scpi_of_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) {.compatible = "arm,scpi-sensors", .data = &scpi_scale},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {.compatible = "amlogic,meson-gxbb-scpi-sensors", .data = &gxbb_scpi_scale},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) {},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) MODULE_DEVICE_TABLE(of, scpi_of_match);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) static int scpi_hwmon_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) u16 nr_sensors, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) const u32 *scale;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) int num_temp = 0, num_volt = 0, num_current = 0, num_power = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) int num_energy = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) struct scpi_ops *scpi_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) struct device *hwdev, *dev = &pdev->dev;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) struct scpi_sensors *scpi_sensors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) const struct of_device_id *of_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) int idx, ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) scpi_ops = get_scpi_ops();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (!scpi_ops)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return -EPROBE_DEFER;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) ret = scpi_ops->sensor_get_capability(&nr_sensors);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) if (!nr_sensors)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) scpi_sensors = devm_kzalloc(dev, sizeof(*scpi_sensors), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (!scpi_sensors)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) scpi_sensors->data = devm_kcalloc(dev, nr_sensors,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) sizeof(*scpi_sensors->data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) if (!scpi_sensors->data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) scpi_sensors->attrs = devm_kcalloc(dev, (nr_sensors * 2) + 1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) sizeof(*scpi_sensors->attrs), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (!scpi_sensors->attrs)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) scpi_sensors->scpi_ops = scpi_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) of_id = of_match_device(scpi_of_match, &pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (!of_id) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) dev_err(&pdev->dev, "Unable to initialize scpi-hwmon data\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) scale = of_id->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) for (i = 0, idx = 0; i < nr_sensors; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) struct sensor_data *sensor = &scpi_sensors->data[idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) ret = scpi_ops->sensor_get_info(i, &sensor->info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) switch (sensor->info.class) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) case TEMPERATURE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) snprintf(sensor->input, sizeof(sensor->input),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) "temp%d_input", num_temp + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) snprintf(sensor->label, sizeof(sensor->input),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) "temp%d_label", num_temp + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) num_temp++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) case VOLTAGE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) snprintf(sensor->input, sizeof(sensor->input),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) "in%d_input", num_volt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) snprintf(sensor->label, sizeof(sensor->input),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) "in%d_label", num_volt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) num_volt++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) case CURRENT:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) snprintf(sensor->input, sizeof(sensor->input),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) "curr%d_input", num_current + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) snprintf(sensor->label, sizeof(sensor->input),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) "curr%d_label", num_current + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) num_current++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) case POWER:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) snprintf(sensor->input, sizeof(sensor->input),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) "power%d_input", num_power + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) snprintf(sensor->label, sizeof(sensor->input),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) "power%d_label", num_power + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) num_power++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) case ENERGY:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) snprintf(sensor->input, sizeof(sensor->input),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) "energy%d_input", num_energy + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) snprintf(sensor->label, sizeof(sensor->input),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) "energy%d_label", num_energy + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) num_energy++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) sensor->scale = scale[sensor->info.class];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) sensor->dev_attr_input.attr.mode = 0444;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) sensor->dev_attr_input.show = scpi_show_sensor;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) sensor->dev_attr_input.attr.name = sensor->input;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) sensor->dev_attr_label.attr.mode = 0444;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) sensor->dev_attr_label.show = scpi_show_label;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) sensor->dev_attr_label.attr.name = sensor->label;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) scpi_sensors->attrs[idx << 1] = &sensor->dev_attr_input.attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) scpi_sensors->attrs[(idx << 1) + 1] = &sensor->dev_attr_label.attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) sysfs_attr_init(scpi_sensors->attrs[idx << 1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) sysfs_attr_init(scpi_sensors->attrs[(idx << 1) + 1]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) scpi_sensors->group.attrs = scpi_sensors->attrs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) scpi_sensors->groups[0] = &scpi_sensors->group;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) platform_set_drvdata(pdev, scpi_sensors);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) hwdev = devm_hwmon_device_register_with_groups(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) "scpi_sensors", scpi_sensors, scpi_sensors->groups);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) if (IS_ERR(hwdev))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return PTR_ERR(hwdev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) * Register the temperature sensors with the thermal framework
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) * to allow their usage in setting up the thermal zones from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) * device tree.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) * NOTE: Not all temperature sensors maybe used for thermal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) * control
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) INIT_LIST_HEAD(&scpi_sensors->thermal_zones);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) for (i = 0; i < nr_sensors; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) struct sensor_data *sensor = &scpi_sensors->data[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) struct thermal_zone_device *z;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) struct scpi_thermal_zone *zone;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) if (sensor->info.class != TEMPERATURE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) zone = devm_kzalloc(dev, sizeof(*zone), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) if (!zone)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) zone->sensor_id = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) zone->scpi_sensors = scpi_sensors;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) z = devm_thermal_zone_of_sensor_register(dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) sensor->info.sensor_id,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) zone,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) &scpi_sensor_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) * The call to thermal_zone_of_sensor_register returns
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) * an error for sensors that are not associated with
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) * any thermal zones or if the thermal subsystem is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) * not configured.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) if (IS_ERR(z))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) devm_kfree(dev, zone);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) static struct platform_driver scpi_hwmon_platdrv = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) .driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) .name = "scpi-hwmon",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) .of_match_table = scpi_of_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) .probe = scpi_hwmon_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) module_platform_driver(scpi_hwmon_platdrv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) MODULE_AUTHOR("Punit Agrawal <punit.agrawal@arm.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) MODULE_DESCRIPTION("ARM SCPI HWMON interface driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) MODULE_LICENSE("GPL v2");