18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * PowerNV sensor code
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2013 IBM
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/delay.h>
98c2ecf20Sopenharmony_ci#include <linux/of_platform.h>
108c2ecf20Sopenharmony_ci#include <asm/opal.h>
118c2ecf20Sopenharmony_ci#include <asm/machdep.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci/*
148c2ecf20Sopenharmony_ci * This will return sensor information to driver based on the requested sensor
158c2ecf20Sopenharmony_ci * handle. A handle is an opaque id for the powernv, read by the driver from the
168c2ecf20Sopenharmony_ci * device tree..
178c2ecf20Sopenharmony_ci */
188c2ecf20Sopenharmony_ciint opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data)
198c2ecf20Sopenharmony_ci{
208c2ecf20Sopenharmony_ci	int ret, token;
218c2ecf20Sopenharmony_ci	struct opal_msg msg;
228c2ecf20Sopenharmony_ci	__be32 data;
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci	token = opal_async_get_token_interruptible();
258c2ecf20Sopenharmony_ci	if (token < 0)
268c2ecf20Sopenharmony_ci		return token;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci	ret = opal_sensor_read(sensor_hndl, token, &data);
298c2ecf20Sopenharmony_ci	switch (ret) {
308c2ecf20Sopenharmony_ci	case OPAL_ASYNC_COMPLETION:
318c2ecf20Sopenharmony_ci		ret = opal_async_wait_response(token, &msg);
328c2ecf20Sopenharmony_ci		if (ret) {
338c2ecf20Sopenharmony_ci			pr_err("%s: Failed to wait for the async response, %d\n",
348c2ecf20Sopenharmony_ci			       __func__, ret);
358c2ecf20Sopenharmony_ci			goto out;
368c2ecf20Sopenharmony_ci		}
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci		ret = opal_error_code(opal_get_async_rc(msg));
398c2ecf20Sopenharmony_ci		*sensor_data = be32_to_cpu(data);
408c2ecf20Sopenharmony_ci		break;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci	case OPAL_SUCCESS:
438c2ecf20Sopenharmony_ci		ret = 0;
448c2ecf20Sopenharmony_ci		*sensor_data = be32_to_cpu(data);
458c2ecf20Sopenharmony_ci		break;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	case OPAL_WRONG_STATE:
488c2ecf20Sopenharmony_ci		ret = -EIO;
498c2ecf20Sopenharmony_ci		break;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci	default:
528c2ecf20Sopenharmony_ci		ret = opal_error_code(ret);
538c2ecf20Sopenharmony_ci		break;
548c2ecf20Sopenharmony_ci	}
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ciout:
578c2ecf20Sopenharmony_ci	opal_async_release_token(token);
588c2ecf20Sopenharmony_ci	return ret;
598c2ecf20Sopenharmony_ci}
608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(opal_get_sensor_data);
618c2ecf20Sopenharmony_ci
628c2ecf20Sopenharmony_ciint opal_get_sensor_data_u64(u32 sensor_hndl, u64 *sensor_data)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	int ret, token;
658c2ecf20Sopenharmony_ci	struct opal_msg msg;
668c2ecf20Sopenharmony_ci	__be64 data;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	if (!opal_check_token(OPAL_SENSOR_READ_U64)) {
698c2ecf20Sopenharmony_ci		u32 sdata;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci		ret = opal_get_sensor_data(sensor_hndl, &sdata);
728c2ecf20Sopenharmony_ci		if (!ret)
738c2ecf20Sopenharmony_ci			*sensor_data = sdata;
748c2ecf20Sopenharmony_ci		return ret;
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	token = opal_async_get_token_interruptible();
788c2ecf20Sopenharmony_ci	if (token < 0)
798c2ecf20Sopenharmony_ci		return token;
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	ret = opal_sensor_read_u64(sensor_hndl, token, &data);
828c2ecf20Sopenharmony_ci	switch (ret) {
838c2ecf20Sopenharmony_ci	case OPAL_ASYNC_COMPLETION:
848c2ecf20Sopenharmony_ci		ret = opal_async_wait_response(token, &msg);
858c2ecf20Sopenharmony_ci		if (ret) {
868c2ecf20Sopenharmony_ci			pr_err("%s: Failed to wait for the async response, %d\n",
878c2ecf20Sopenharmony_ci			       __func__, ret);
888c2ecf20Sopenharmony_ci			goto out_token;
898c2ecf20Sopenharmony_ci		}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		ret = opal_error_code(opal_get_async_rc(msg));
928c2ecf20Sopenharmony_ci		*sensor_data = be64_to_cpu(data);
938c2ecf20Sopenharmony_ci		break;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	case OPAL_SUCCESS:
968c2ecf20Sopenharmony_ci		ret = 0;
978c2ecf20Sopenharmony_ci		*sensor_data = be64_to_cpu(data);
988c2ecf20Sopenharmony_ci		break;
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	case OPAL_WRONG_STATE:
1018c2ecf20Sopenharmony_ci		ret = -EIO;
1028c2ecf20Sopenharmony_ci		break;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	default:
1058c2ecf20Sopenharmony_ci		ret = opal_error_code(ret);
1068c2ecf20Sopenharmony_ci		break;
1078c2ecf20Sopenharmony_ci	}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ciout_token:
1108c2ecf20Sopenharmony_ci	opal_async_release_token(token);
1118c2ecf20Sopenharmony_ci	return ret;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(opal_get_sensor_data_u64);
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ciint __init opal_sensor_init(void)
1168c2ecf20Sopenharmony_ci{
1178c2ecf20Sopenharmony_ci	struct platform_device *pdev;
1188c2ecf20Sopenharmony_ci	struct device_node *sensor;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	sensor = of_find_node_by_path("/ibm,opal/sensors");
1218c2ecf20Sopenharmony_ci	if (!sensor) {
1228c2ecf20Sopenharmony_ci		pr_err("Opal node 'sensors' not found\n");
1238c2ecf20Sopenharmony_ci		return -ENODEV;
1248c2ecf20Sopenharmony_ci	}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	pdev = of_platform_device_create(sensor, "opal-sensor", NULL);
1278c2ecf20Sopenharmony_ci	of_node_put(sensor);
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(pdev);
1308c2ecf20Sopenharmony_ci}
131