Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
26285 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* AMD MP2 1.1 communication interfaces
4
*
5
* Copyright (c) 2022, Advanced Micro Devices, Inc.
6
* All Rights Reserved.
7
*
8
* Author: Basavaraj Natikar <[email protected]>
9
*/
10
#include <linux/amd-pmf-io.h>
11
#include <linux/io-64-nonatomic-lo-hi.h>
12
#include <linux/iopoll.h>
13
14
#include "amd_sfh_interface.h"
15
16
static struct amd_mp2_dev *emp2;
17
18
static int amd_sfh_wait_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id)
19
{
20
struct sfh_cmd_response cmd_resp;
21
22
/* Get response with status within a max of 10000 ms timeout */
23
if (!readl_poll_timeout(mp2->mmio + amd_get_p2c_val(mp2, 0), cmd_resp.resp,
24
(cmd_resp.response.response == 0 &&
25
cmd_resp.response.cmd_id == cmd_id && (sid == 0xff ||
26
cmd_resp.response.sensor_id == sid)), 500, 10000000))
27
return cmd_resp.response.response;
28
29
return -1;
30
}
31
32
static void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info)
33
{
34
struct sfh_cmd_base cmd_base;
35
36
cmd_base.ul = 0;
37
cmd_base.cmd.cmd_id = ENABLE_SENSOR;
38
cmd_base.cmd.intr_disable = 0;
39
cmd_base.cmd.sub_cmd_value = 1;
40
cmd_base.cmd.sensor_id = info.sensor_idx;
41
42
writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));
43
}
44
45
static void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx)
46
{
47
struct sfh_cmd_base cmd_base;
48
49
cmd_base.ul = 0;
50
cmd_base.cmd.cmd_id = DISABLE_SENSOR;
51
cmd_base.cmd.intr_disable = 0;
52
cmd_base.cmd.sub_cmd_value = 1;
53
cmd_base.cmd.sensor_id = sensor_idx;
54
55
writeq(0x0, privdata->mmio + amd_get_c2p_val(privdata, 1));
56
writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));
57
}
58
59
static void amd_stop_all_sensor(struct amd_mp2_dev *privdata)
60
{
61
struct sfh_cmd_base cmd_base;
62
63
cmd_base.ul = 0;
64
cmd_base.cmd.cmd_id = DISABLE_SENSOR;
65
cmd_base.cmd.intr_disable = 0;
66
/* 0xf indicates all sensors */
67
cmd_base.cmd.sensor_id = 0xf;
68
69
writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));
70
}
71
72
static struct amd_mp2_ops amd_sfh_ops = {
73
.start = amd_start_sensor,
74
.stop = amd_stop_sensor,
75
.stop_all = amd_stop_all_sensor,
76
.response = amd_sfh_wait_response,
77
};
78
79
void sfh_deinit_emp2(void)
80
{
81
emp2 = NULL;
82
}
83
84
void sfh_interface_init(struct amd_mp2_dev *mp2)
85
{
86
mp2->mp2_ops = &amd_sfh_ops;
87
emp2 = mp2;
88
}
89
90
static int amd_sfh_mode_info(u32 *platform_type, u32 *laptop_placement)
91
{
92
struct sfh_op_mode mode;
93
94
if (!platform_type || !laptop_placement)
95
return -EINVAL;
96
97
if (!emp2 || !emp2->dev_en.is_sra_present)
98
return -ENODEV;
99
100
mode.val = readl(emp2->mmio + amd_get_c2p_val(emp2, 3));
101
102
*platform_type = mode.op_mode.devicemode;
103
104
if (mode.op_mode.ontablestate == 1) {
105
*laptop_placement = ON_TABLE;
106
} else if (mode.op_mode.ontablestate == 2) {
107
*laptop_placement = ON_LAP_MOTION;
108
} else if (mode.op_mode.inbagstate == 1) {
109
*laptop_placement = IN_BAG;
110
} else if (mode.op_mode.outbagstate == 1) {
111
*laptop_placement = OUT_OF_BAG;
112
} else if (mode.op_mode.ontablestate == 0 || mode.op_mode.inbagstate == 0 ||
113
mode.op_mode.outbagstate == 0) {
114
*laptop_placement = LP_UNKNOWN;
115
pr_warn_once("Unknown laptop placement\n");
116
} else if (mode.op_mode.ontablestate == 3 || mode.op_mode.inbagstate == 3 ||
117
mode.op_mode.outbagstate == 3) {
118
*laptop_placement = LP_UNDEFINED;
119
pr_warn_once("Undefined laptop placement\n");
120
}
121
122
return 0;
123
}
124
125
static int amd_sfh_hpd_info(u8 *user_present)
126
{
127
struct hpd_status hpdstatus;
128
129
if (!user_present)
130
return -EINVAL;
131
132
if (!emp2 || !emp2->dev_en.is_hpd_present || !emp2->dev_en.is_hpd_enabled)
133
return -ENODEV;
134
135
hpdstatus.val = readl(emp2->mmio + amd_get_c2p_val(emp2, 4));
136
*user_present = hpdstatus.shpd.presence;
137
138
return 0;
139
}
140
141
static int amd_sfh_als_info(u32 *ambient_light)
142
{
143
struct sfh_als_data als_data;
144
void __iomem *sensoraddr;
145
146
if (!ambient_light)
147
return -EINVAL;
148
149
if (!emp2 || !emp2->dev_en.is_als_present)
150
return -ENODEV;
151
152
sensoraddr = emp2->vsbase +
153
(ALS_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) +
154
OFFSET_SENSOR_DATA_DEFAULT;
155
memcpy_fromio(&als_data, sensoraddr, sizeof(struct sfh_als_data));
156
*ambient_light = amd_sfh_float_to_int(als_data.lux);
157
158
return 0;
159
}
160
161
int amd_get_sfh_info(struct amd_sfh_info *sfh_info, enum sfh_message_type op)
162
{
163
if (sfh_info) {
164
switch (op) {
165
case MT_HPD:
166
return amd_sfh_hpd_info(&sfh_info->user_present);
167
case MT_ALS:
168
return amd_sfh_als_info(&sfh_info->ambient_light);
169
case MT_SRA:
170
return amd_sfh_mode_info(&sfh_info->platform_type,
171
&sfh_info->laptop_placement);
172
}
173
}
174
return -EINVAL;
175
}
176
EXPORT_SYMBOL_GPL(amd_get_sfh_info);
177
178