// SPDX-License-Identifier: GPL-2.0
/*
 * System Control and Management Interface(SCMI) based hwmon sensor driver
 *
 * Copyright (C) 2018 ARM Ltd.
 * Sudeep Holla <sudeep.holla@arm.com>
 */

#include <linux/hwmon.h>
#include <linux/module.h>
#include <linux/scmi_protocol.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
#include <linux/thermal.h>

struct scmi_sensors {
	const struct scmi_handle *handle;
	const struct scmi_sensor_info **info[hwmon_max];
};

static inline u64 __pow10(u8 x)
{
	u64 r = 1;

	while (x--)
		r *= 10;

	return r;
}

static int scmi_hwmon_scale(const struct scmi_sensor_info *sensor, u64 *value)
{
	s8 scale = sensor->scale;
	u64 f;

	switch (sensor->type) {
	case TEMPERATURE_C:
	case VOLTAGE:
	case CURRENT:
		scale += 3;
		break;
	case POWER:
	case ENERGY:
		scale += 6;
		break;
	default:
		break;
	}

	if (scale == 0)
		return 0;

	if (abs(scale) > 19)
		return -E2BIG;

	f = __pow10(abs(scale));
	if (scale > 0)
		*value *= f;
	else
		*value = div64_u64(*value, f);

	return 0;
}

static int scmi_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
			   u32 attr, int channel, long *val)
{
	int ret;
	u64 value;
	const struct scmi_sensor_info *sensor;
	struct scmi_sensors *scmi_sensors = dev_get_drvdata(dev);
	const struct scmi_handle *h = scmi_sensors->handle;

	sensor = *(scmi_sensors->info[type] + channel);
	ret = h->sensor_ops->reading_get(h, sensor->id, &value);
	if (ret)
		return ret;

	ret = scmi_hwmon_scale(sensor, &value);
	if (!ret)
		*val = value;

	return ret;
}

static int
scmi_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type,
		       u32 attr, int channel, const char **str)
{
	const struct scmi_sensor_info *sensor;
	struct scmi_sensors *scmi_sensors = dev_get_drvdata(dev);

	sensor = *(scmi_sensors->info[type] + channel);
	*str = sensor->name;

	return 0;
}

static umode_t
scmi_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type,
		      u32 attr, int channel)
{
	const struct scmi_sensor_info *sensor;
	const struct scmi_sensors *scmi_sensors = drvdata;

	sensor = *(scmi_sensors->info[type] + channel);
	if (sensor)
		return 0444;

	return 0;
}

static const struct hwmon_ops scmi_hwmon_ops = {
	.is_visible = scmi_hwmon_is_visible,
	.read = scmi_hwmon_read,
	.read_string = scmi_hwmon_read_string,
};

static struct hwmon_chip_info scmi_chip_info = {
	.ops = &scmi_hwmon_ops,
	.info = NULL,
};

static int scmi_hwmon_add_chan_info(struct hwmon_channel_info *scmi_hwmon_chan,
				    struct device *dev, int num,
				    enum hwmon_sensor_types type, u32 config)
{
	int i;
	u32 *cfg = devm_kcalloc(dev, num + 1, sizeof(*cfg), GFP_KERNEL);

	if (!cfg)
		return -ENOMEM;

	scmi_hwmon_chan->type = type;
	scmi_hwmon_chan->config = cfg;
	for (i = 0; i < num; i++, cfg++)
		*cfg = config;

	return 0;
}

static enum hwmon_sensor_types scmi_types[] = {
	[TEMPERATURE_C] = hwmon_temp,
	[VOLTAGE] = hwmon_in,
	[CURRENT] = hwmon_curr,
	[POWER] = hwmon_power,
	[ENERGY] = hwmon_energy,
};

static u32 hwmon_attributes[] = {
	[hwmon_chip] = HWMON_C_REGISTER_TZ,
	[hwmon_temp] = HWMON_T_INPUT | HWMON_T_LABEL,
	[hwmon_in] = HWMON_I_INPUT | HWMON_I_LABEL,
	[hwmon_curr] = HWMON_C_INPUT | HWMON_C_LABEL,
	[hwmon_power] = HWMON_P_INPUT | HWMON_P_LABEL,
	[hwmon_energy] = HWMON_E_INPUT | HWMON_E_LABEL,
};

static int scmi_hwmon_probe(struct scmi_device *sdev)
{
	int i, idx;
	u16 nr_sensors;
	enum hwmon_sensor_types type;
	struct scmi_sensors *scmi_sensors;
	const struct scmi_sensor_info *sensor;
	int nr_count[hwmon_max] = {0}, nr_types = 0;
	const struct hwmon_chip_info *chip_info;
	struct device *hwdev, *dev = &sdev->dev;
	struct hwmon_channel_info *scmi_hwmon_chan;
	const struct hwmon_channel_info **ptr_scmi_ci;
	const struct scmi_handle *handle = sdev->handle;

	if (!handle || !handle->sensor_ops)
		return -ENODEV;

	nr_sensors = handle->sensor_ops->count_get(handle);
	if (!nr_sensors)
		return -EIO;

	scmi_sensors = devm_kzalloc(dev, sizeof(*scmi_sensors), GFP_KERNEL);
	if (!scmi_sensors)
		return -ENOMEM;

	scmi_sensors->handle = handle;

	for (i = 0; i < nr_sensors; i++) {
		sensor = handle->sensor_ops->info_get(handle, i);
		if (!sensor)
			return -EINVAL;

		switch (sensor->type) {
		case TEMPERATURE_C:
		case VOLTAGE:
		case CURRENT:
		case POWER:
		case ENERGY:
			type = scmi_types[sensor->type];
			if (!nr_count[type])
				nr_types++;
			nr_count[type]++;
			break;
		}
	}

	if (nr_count[hwmon_temp])
		nr_count[hwmon_chip]++, nr_types++;

	scmi_hwmon_chan = devm_kcalloc(dev, nr_types, sizeof(*scmi_hwmon_chan),
				       GFP_KERNEL);
	if (!scmi_hwmon_chan)
		return -ENOMEM;

	ptr_scmi_ci = devm_kcalloc(dev, nr_types + 1, sizeof(*ptr_scmi_ci),
				   GFP_KERNEL);
	if (!ptr_scmi_ci)
		return -ENOMEM;

	scmi_chip_info.info = ptr_scmi_ci;
	chip_info = &scmi_chip_info;

	for (type = 0; type < hwmon_max; type++) {
		if (!nr_count[type])
			continue;

		scmi_hwmon_add_chan_info(scmi_hwmon_chan, dev, nr_count[type],
					 type, hwmon_attributes[type]);
		*ptr_scmi_ci++ = scmi_hwmon_chan++;

		scmi_sensors->info[type] =
			devm_kcalloc(dev, nr_count[type],
				     sizeof(*scmi_sensors->info), GFP_KERNEL);
		if (!scmi_sensors->info[type])
			return -ENOMEM;
	}

	for (i = nr_sensors - 1; i >= 0 ; i--) {
		sensor = handle->sensor_ops->info_get(handle, i);
		if (!sensor)
			continue;

		switch (sensor->type) {
		case TEMPERATURE_C:
		case VOLTAGE:
		case CURRENT:
		case POWER:
		case ENERGY:
			type = scmi_types[sensor->type];
			idx = --nr_count[type];
			*(scmi_sensors->info[type] + idx) = sensor;
			break;
		}
	}

	hwdev = devm_hwmon_device_register_with_info(dev, "scmi_sensors",
						     scmi_sensors, chip_info,
						     NULL);

	return PTR_ERR_OR_ZERO(hwdev);
}

static const struct scmi_device_id scmi_id_table[] = {
	{ SCMI_PROTOCOL_SENSOR, "hwmon" },
	{ },
};
MODULE_DEVICE_TABLE(scmi, scmi_id_table);

static struct scmi_driver scmi_hwmon_drv = {
	.name		= "scmi-hwmon",
	.probe		= scmi_hwmon_probe,
	.id_table	= scmi_id_table,
};
module_scmi_driver(scmi_hwmon_drv);

MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
MODULE_DESCRIPTION("ARM SCMI HWMON interface driver");
MODULE_LICENSE("GPL v2");
