1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * PowerNV sensor code
4 *
5 * Copyright (C) 2013 IBM
6 */
7
8 #include <linux/delay.h>
9 #include <linux/of.h>
10 #include <linux/of_platform.h>
11 #include <linux/platform_device.h>
12 #include <asm/opal.h>
13 #include <asm/machdep.h>
14
15 /*
16 * This will return sensor information to driver based on the requested sensor
17 * handle. A handle is an opaque id for the powernv, read by the driver from the
18 * device tree..
19 */
opal_get_sensor_data(u32 sensor_hndl,u32 * sensor_data)20 int opal_get_sensor_data(u32 sensor_hndl, u32 *sensor_data)
21 {
22 int ret, token;
23 struct opal_msg msg;
24 __be32 data;
25
26 token = opal_async_get_token_interruptible();
27 if (token < 0)
28 return token;
29
30 ret = opal_sensor_read(sensor_hndl, token, &data);
31 switch (ret) {
32 case OPAL_ASYNC_COMPLETION:
33 ret = opal_async_wait_response(token, &msg);
34 if (ret) {
35 pr_err("%s: Failed to wait for the async response, %d\n",
36 __func__, ret);
37 goto out;
38 }
39
40 ret = opal_error_code(opal_get_async_rc(msg));
41 *sensor_data = be32_to_cpu(data);
42 break;
43
44 case OPAL_SUCCESS:
45 ret = 0;
46 *sensor_data = be32_to_cpu(data);
47 break;
48
49 case OPAL_WRONG_STATE:
50 ret = -EIO;
51 break;
52
53 default:
54 ret = opal_error_code(ret);
55 break;
56 }
57
58 out:
59 opal_async_release_token(token);
60 return ret;
61 }
62 EXPORT_SYMBOL_GPL(opal_get_sensor_data);
63
opal_get_sensor_data_u64(u32 sensor_hndl,u64 * sensor_data)64 int opal_get_sensor_data_u64(u32 sensor_hndl, u64 *sensor_data)
65 {
66 int ret, token;
67 struct opal_msg msg;
68 __be64 data;
69
70 if (!opal_check_token(OPAL_SENSOR_READ_U64)) {
71 u32 sdata;
72
73 ret = opal_get_sensor_data(sensor_hndl, &sdata);
74 if (!ret)
75 *sensor_data = sdata;
76 return ret;
77 }
78
79 token = opal_async_get_token_interruptible();
80 if (token < 0)
81 return token;
82
83 ret = opal_sensor_read_u64(sensor_hndl, token, &data);
84 switch (ret) {
85 case OPAL_ASYNC_COMPLETION:
86 ret = opal_async_wait_response(token, &msg);
87 if (ret) {
88 pr_err("%s: Failed to wait for the async response, %d\n",
89 __func__, ret);
90 goto out_token;
91 }
92
93 ret = opal_error_code(opal_get_async_rc(msg));
94 *sensor_data = be64_to_cpu(data);
95 break;
96
97 case OPAL_SUCCESS:
98 ret = 0;
99 *sensor_data = be64_to_cpu(data);
100 break;
101
102 case OPAL_WRONG_STATE:
103 ret = -EIO;
104 break;
105
106 default:
107 ret = opal_error_code(ret);
108 break;
109 }
110
111 out_token:
112 opal_async_release_token(token);
113 return ret;
114 }
115 EXPORT_SYMBOL_GPL(opal_get_sensor_data_u64);
116
opal_sensor_init(void)117 int __init opal_sensor_init(void)
118 {
119 struct platform_device *pdev;
120 struct device_node *sensor;
121
122 sensor = of_find_node_by_path("/ibm,opal/sensors");
123 if (!sensor) {
124 pr_err("Opal node 'sensors' not found\n");
125 return -ENODEV;
126 }
127
128 pdev = of_platform_device_create(sensor, "opal-sensor", NULL);
129 of_node_put(sensor);
130
131 return PTR_ERR_OR_ZERO(pdev);
132 }
133