xref: /OK3568_Linux_fs/kernel/drivers/i2c/busses/i2c-scmi.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * SMBus driver for ACPI SMBus CMI
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2009 Crane Cai <crane.cai@amd.com>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/module.h>
9*4882a593Smuzhiyun #include <linux/slab.h>
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/stddef.h>
12*4882a593Smuzhiyun #include <linux/i2c.h>
13*4882a593Smuzhiyun #include <linux/acpi.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #define ACPI_SMBUS_HC_CLASS		"smbus"
16*4882a593Smuzhiyun #define ACPI_SMBUS_HC_DEVICE_NAME	"cmi"
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun /* SMBUS HID definition as supported by Microsoft Windows */
19*4882a593Smuzhiyun #define ACPI_SMBUS_MS_HID		"SMB0001"
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun ACPI_MODULE_NAME("smbus_cmi");
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun struct smbus_methods_t {
24*4882a593Smuzhiyun 	char *mt_info;
25*4882a593Smuzhiyun 	char *mt_sbr;
26*4882a593Smuzhiyun 	char *mt_sbw;
27*4882a593Smuzhiyun };
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun struct acpi_smbus_cmi {
30*4882a593Smuzhiyun 	acpi_handle handle;
31*4882a593Smuzhiyun 	struct i2c_adapter adapter;
32*4882a593Smuzhiyun 	u8 cap_info:1;
33*4882a593Smuzhiyun 	u8 cap_read:1;
34*4882a593Smuzhiyun 	u8 cap_write:1;
35*4882a593Smuzhiyun 	struct smbus_methods_t *methods;
36*4882a593Smuzhiyun };
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun static const struct smbus_methods_t smbus_methods = {
39*4882a593Smuzhiyun 	.mt_info = "_SBI",
40*4882a593Smuzhiyun 	.mt_sbr  = "_SBR",
41*4882a593Smuzhiyun 	.mt_sbw  = "_SBW",
42*4882a593Smuzhiyun };
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun /* Some IBM BIOSes omit the leading underscore */
45*4882a593Smuzhiyun static const struct smbus_methods_t ibm_smbus_methods = {
46*4882a593Smuzhiyun 	.mt_info = "SBI_",
47*4882a593Smuzhiyun 	.mt_sbr  = "SBR_",
48*4882a593Smuzhiyun 	.mt_sbw  = "SBW_",
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun static const struct acpi_device_id acpi_smbus_cmi_ids[] = {
52*4882a593Smuzhiyun 	{"SMBUS01", (kernel_ulong_t)&smbus_methods},
53*4882a593Smuzhiyun 	{ACPI_SMBUS_IBM_HID, (kernel_ulong_t)&ibm_smbus_methods},
54*4882a593Smuzhiyun 	{ACPI_SMBUS_MS_HID, (kernel_ulong_t)&smbus_methods},
55*4882a593Smuzhiyun 	{"", 0}
56*4882a593Smuzhiyun };
57*4882a593Smuzhiyun MODULE_DEVICE_TABLE(acpi, acpi_smbus_cmi_ids);
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun #define ACPI_SMBUS_STATUS_OK			0x00
60*4882a593Smuzhiyun #define ACPI_SMBUS_STATUS_FAIL			0x07
61*4882a593Smuzhiyun #define ACPI_SMBUS_STATUS_DNAK			0x10
62*4882a593Smuzhiyun #define ACPI_SMBUS_STATUS_DERR			0x11
63*4882a593Smuzhiyun #define ACPI_SMBUS_STATUS_CMD_DENY		0x12
64*4882a593Smuzhiyun #define ACPI_SMBUS_STATUS_UNKNOWN		0x13
65*4882a593Smuzhiyun #define ACPI_SMBUS_STATUS_ACC_DENY		0x17
66*4882a593Smuzhiyun #define ACPI_SMBUS_STATUS_TIMEOUT		0x18
67*4882a593Smuzhiyun #define ACPI_SMBUS_STATUS_NOTSUP		0x19
68*4882a593Smuzhiyun #define ACPI_SMBUS_STATUS_BUSY			0x1a
69*4882a593Smuzhiyun #define ACPI_SMBUS_STATUS_PEC			0x1f
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun #define ACPI_SMBUS_PRTCL_WRITE			0x00
72*4882a593Smuzhiyun #define ACPI_SMBUS_PRTCL_READ			0x01
73*4882a593Smuzhiyun #define ACPI_SMBUS_PRTCL_QUICK			0x02
74*4882a593Smuzhiyun #define ACPI_SMBUS_PRTCL_BYTE			0x04
75*4882a593Smuzhiyun #define ACPI_SMBUS_PRTCL_BYTE_DATA		0x06
76*4882a593Smuzhiyun #define ACPI_SMBUS_PRTCL_WORD_DATA		0x08
77*4882a593Smuzhiyun #define ACPI_SMBUS_PRTCL_BLOCK_DATA		0x0a
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 
80*4882a593Smuzhiyun static int
acpi_smbus_cmi_access(struct i2c_adapter * adap,u16 addr,unsigned short flags,char read_write,u8 command,int size,union i2c_smbus_data * data)81*4882a593Smuzhiyun acpi_smbus_cmi_access(struct i2c_adapter *adap, u16 addr, unsigned short flags,
82*4882a593Smuzhiyun 		   char read_write, u8 command, int size,
83*4882a593Smuzhiyun 		   union i2c_smbus_data *data)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun 	int result = 0;
86*4882a593Smuzhiyun 	struct acpi_smbus_cmi *smbus_cmi = adap->algo_data;
87*4882a593Smuzhiyun 	unsigned char protocol;
88*4882a593Smuzhiyun 	acpi_status status = 0;
89*4882a593Smuzhiyun 	struct acpi_object_list input;
90*4882a593Smuzhiyun 	union acpi_object mt_params[5];
91*4882a593Smuzhiyun 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
92*4882a593Smuzhiyun 	union acpi_object *obj;
93*4882a593Smuzhiyun 	union acpi_object *pkg;
94*4882a593Smuzhiyun 	char *method;
95*4882a593Smuzhiyun 	int len = 0;
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun 	dev_dbg(&adap->dev, "access size: %d %s\n", size,
98*4882a593Smuzhiyun 		(read_write) ? "READ" : "WRITE");
99*4882a593Smuzhiyun 	switch (size) {
100*4882a593Smuzhiyun 	case I2C_SMBUS_QUICK:
101*4882a593Smuzhiyun 		protocol = ACPI_SMBUS_PRTCL_QUICK;
102*4882a593Smuzhiyun 		command = 0;
103*4882a593Smuzhiyun 		if (read_write == I2C_SMBUS_WRITE) {
104*4882a593Smuzhiyun 			mt_params[3].type = ACPI_TYPE_INTEGER;
105*4882a593Smuzhiyun 			mt_params[3].integer.value = 0;
106*4882a593Smuzhiyun 			mt_params[4].type = ACPI_TYPE_INTEGER;
107*4882a593Smuzhiyun 			mt_params[4].integer.value = 0;
108*4882a593Smuzhiyun 		}
109*4882a593Smuzhiyun 		break;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	case I2C_SMBUS_BYTE:
112*4882a593Smuzhiyun 		protocol = ACPI_SMBUS_PRTCL_BYTE;
113*4882a593Smuzhiyun 		if (read_write == I2C_SMBUS_WRITE) {
114*4882a593Smuzhiyun 			mt_params[3].type = ACPI_TYPE_INTEGER;
115*4882a593Smuzhiyun 			mt_params[3].integer.value = 0;
116*4882a593Smuzhiyun 			mt_params[4].type = ACPI_TYPE_INTEGER;
117*4882a593Smuzhiyun 			mt_params[4].integer.value = 0;
118*4882a593Smuzhiyun 		} else {
119*4882a593Smuzhiyun 			command = 0;
120*4882a593Smuzhiyun 		}
121*4882a593Smuzhiyun 		break;
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	case I2C_SMBUS_BYTE_DATA:
124*4882a593Smuzhiyun 		protocol = ACPI_SMBUS_PRTCL_BYTE_DATA;
125*4882a593Smuzhiyun 		if (read_write == I2C_SMBUS_WRITE) {
126*4882a593Smuzhiyun 			mt_params[3].type = ACPI_TYPE_INTEGER;
127*4882a593Smuzhiyun 			mt_params[3].integer.value = 1;
128*4882a593Smuzhiyun 			mt_params[4].type = ACPI_TYPE_INTEGER;
129*4882a593Smuzhiyun 			mt_params[4].integer.value = data->byte;
130*4882a593Smuzhiyun 		}
131*4882a593Smuzhiyun 		break;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	case I2C_SMBUS_WORD_DATA:
134*4882a593Smuzhiyun 		protocol = ACPI_SMBUS_PRTCL_WORD_DATA;
135*4882a593Smuzhiyun 		if (read_write == I2C_SMBUS_WRITE) {
136*4882a593Smuzhiyun 			mt_params[3].type = ACPI_TYPE_INTEGER;
137*4882a593Smuzhiyun 			mt_params[3].integer.value = 2;
138*4882a593Smuzhiyun 			mt_params[4].type = ACPI_TYPE_INTEGER;
139*4882a593Smuzhiyun 			mt_params[4].integer.value = data->word;
140*4882a593Smuzhiyun 		}
141*4882a593Smuzhiyun 		break;
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	case I2C_SMBUS_BLOCK_DATA:
144*4882a593Smuzhiyun 		protocol = ACPI_SMBUS_PRTCL_BLOCK_DATA;
145*4882a593Smuzhiyun 		if (read_write == I2C_SMBUS_WRITE) {
146*4882a593Smuzhiyun 			len = data->block[0];
147*4882a593Smuzhiyun 			if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
148*4882a593Smuzhiyun 				return -EINVAL;
149*4882a593Smuzhiyun 			mt_params[3].type = ACPI_TYPE_INTEGER;
150*4882a593Smuzhiyun 			mt_params[3].integer.value = len;
151*4882a593Smuzhiyun 			mt_params[4].type = ACPI_TYPE_BUFFER;
152*4882a593Smuzhiyun 			mt_params[4].buffer.length = len;
153*4882a593Smuzhiyun 			mt_params[4].buffer.pointer = data->block + 1;
154*4882a593Smuzhiyun 		}
155*4882a593Smuzhiyun 		break;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	default:
158*4882a593Smuzhiyun 		dev_warn(&adap->dev, "Unsupported transaction %d\n", size);
159*4882a593Smuzhiyun 		return -EOPNOTSUPP;
160*4882a593Smuzhiyun 	}
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	if (read_write == I2C_SMBUS_READ) {
163*4882a593Smuzhiyun 		protocol |= ACPI_SMBUS_PRTCL_READ;
164*4882a593Smuzhiyun 		method = smbus_cmi->methods->mt_sbr;
165*4882a593Smuzhiyun 		input.count = 3;
166*4882a593Smuzhiyun 	} else {
167*4882a593Smuzhiyun 		protocol |= ACPI_SMBUS_PRTCL_WRITE;
168*4882a593Smuzhiyun 		method = smbus_cmi->methods->mt_sbw;
169*4882a593Smuzhiyun 		input.count = 5;
170*4882a593Smuzhiyun 	}
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	input.pointer = mt_params;
173*4882a593Smuzhiyun 	mt_params[0].type = ACPI_TYPE_INTEGER;
174*4882a593Smuzhiyun 	mt_params[0].integer.value = protocol;
175*4882a593Smuzhiyun 	mt_params[1].type = ACPI_TYPE_INTEGER;
176*4882a593Smuzhiyun 	mt_params[1].integer.value = addr;
177*4882a593Smuzhiyun 	mt_params[2].type = ACPI_TYPE_INTEGER;
178*4882a593Smuzhiyun 	mt_params[2].integer.value = command;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	status = acpi_evaluate_object(smbus_cmi->handle, method, &input,
181*4882a593Smuzhiyun 				      &buffer);
182*4882a593Smuzhiyun 	if (ACPI_FAILURE(status)) {
183*4882a593Smuzhiyun 		acpi_handle_err(smbus_cmi->handle,
184*4882a593Smuzhiyun 				"Failed to evaluate %s: %i\n", method, status);
185*4882a593Smuzhiyun 		return -EIO;
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	pkg = buffer.pointer;
189*4882a593Smuzhiyun 	if (pkg && pkg->type == ACPI_TYPE_PACKAGE)
190*4882a593Smuzhiyun 		obj = pkg->package.elements;
191*4882a593Smuzhiyun 	else {
192*4882a593Smuzhiyun 		acpi_handle_err(smbus_cmi->handle, "Invalid argument type\n");
193*4882a593Smuzhiyun 		result = -EIO;
194*4882a593Smuzhiyun 		goto out;
195*4882a593Smuzhiyun 	}
196*4882a593Smuzhiyun 	if (obj == NULL || obj->type != ACPI_TYPE_INTEGER) {
197*4882a593Smuzhiyun 		acpi_handle_err(smbus_cmi->handle, "Invalid argument type\n");
198*4882a593Smuzhiyun 		result = -EIO;
199*4882a593Smuzhiyun 		goto out;
200*4882a593Smuzhiyun 	}
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	result = obj->integer.value;
203*4882a593Smuzhiyun 	acpi_handle_debug(smbus_cmi->handle,  "%s return status: %i\n", method,
204*4882a593Smuzhiyun 			  result);
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	switch (result) {
207*4882a593Smuzhiyun 	case ACPI_SMBUS_STATUS_OK:
208*4882a593Smuzhiyun 		result = 0;
209*4882a593Smuzhiyun 		break;
210*4882a593Smuzhiyun 	case ACPI_SMBUS_STATUS_BUSY:
211*4882a593Smuzhiyun 		result = -EBUSY;
212*4882a593Smuzhiyun 		goto out;
213*4882a593Smuzhiyun 	case ACPI_SMBUS_STATUS_TIMEOUT:
214*4882a593Smuzhiyun 		result = -ETIMEDOUT;
215*4882a593Smuzhiyun 		goto out;
216*4882a593Smuzhiyun 	case ACPI_SMBUS_STATUS_DNAK:
217*4882a593Smuzhiyun 		result = -ENXIO;
218*4882a593Smuzhiyun 		goto out;
219*4882a593Smuzhiyun 	default:
220*4882a593Smuzhiyun 		result = -EIO;
221*4882a593Smuzhiyun 		goto out;
222*4882a593Smuzhiyun 	}
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 	if (read_write == I2C_SMBUS_WRITE || size == I2C_SMBUS_QUICK)
225*4882a593Smuzhiyun 		goto out;
226*4882a593Smuzhiyun 
227*4882a593Smuzhiyun 	obj = pkg->package.elements + 1;
228*4882a593Smuzhiyun 	if (obj->type != ACPI_TYPE_INTEGER) {
229*4882a593Smuzhiyun 		acpi_handle_err(smbus_cmi->handle, "Invalid argument type\n");
230*4882a593Smuzhiyun 		result = -EIO;
231*4882a593Smuzhiyun 		goto out;
232*4882a593Smuzhiyun 	}
233*4882a593Smuzhiyun 
234*4882a593Smuzhiyun 	len = obj->integer.value;
235*4882a593Smuzhiyun 	obj = pkg->package.elements + 2;
236*4882a593Smuzhiyun 	switch (size) {
237*4882a593Smuzhiyun 	case I2C_SMBUS_BYTE:
238*4882a593Smuzhiyun 	case I2C_SMBUS_BYTE_DATA:
239*4882a593Smuzhiyun 	case I2C_SMBUS_WORD_DATA:
240*4882a593Smuzhiyun 		if (obj->type != ACPI_TYPE_INTEGER) {
241*4882a593Smuzhiyun 			acpi_handle_err(smbus_cmi->handle,
242*4882a593Smuzhiyun 					"Invalid argument type\n");
243*4882a593Smuzhiyun 			result = -EIO;
244*4882a593Smuzhiyun 			goto out;
245*4882a593Smuzhiyun 		}
246*4882a593Smuzhiyun 		if (len == 2)
247*4882a593Smuzhiyun 			data->word = obj->integer.value;
248*4882a593Smuzhiyun 		else
249*4882a593Smuzhiyun 			data->byte = obj->integer.value;
250*4882a593Smuzhiyun 		break;
251*4882a593Smuzhiyun 	case I2C_SMBUS_BLOCK_DATA:
252*4882a593Smuzhiyun 		if (obj->type != ACPI_TYPE_BUFFER) {
253*4882a593Smuzhiyun 			acpi_handle_err(smbus_cmi->handle,
254*4882a593Smuzhiyun 					"Invalid argument type\n");
255*4882a593Smuzhiyun 			result = -EIO;
256*4882a593Smuzhiyun 			goto out;
257*4882a593Smuzhiyun 		}
258*4882a593Smuzhiyun 		if (len == 0 || len > I2C_SMBUS_BLOCK_MAX)
259*4882a593Smuzhiyun 			return -EPROTO;
260*4882a593Smuzhiyun 		data->block[0] = len;
261*4882a593Smuzhiyun 		memcpy(data->block + 1, obj->buffer.pointer, len);
262*4882a593Smuzhiyun 		break;
263*4882a593Smuzhiyun 	}
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun out:
266*4882a593Smuzhiyun 	kfree(buffer.pointer);
267*4882a593Smuzhiyun 	dev_dbg(&adap->dev, "Transaction status: %i\n", result);
268*4882a593Smuzhiyun 	return result;
269*4882a593Smuzhiyun }
270*4882a593Smuzhiyun 
acpi_smbus_cmi_func(struct i2c_adapter * adapter)271*4882a593Smuzhiyun static u32 acpi_smbus_cmi_func(struct i2c_adapter *adapter)
272*4882a593Smuzhiyun {
273*4882a593Smuzhiyun 	struct acpi_smbus_cmi *smbus_cmi = adapter->algo_data;
274*4882a593Smuzhiyun 	u32 ret;
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	ret = smbus_cmi->cap_read | smbus_cmi->cap_write ?
277*4882a593Smuzhiyun 		I2C_FUNC_SMBUS_QUICK : 0;
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun 	ret |= smbus_cmi->cap_read ?
280*4882a593Smuzhiyun 		(I2C_FUNC_SMBUS_READ_BYTE |
281*4882a593Smuzhiyun 		I2C_FUNC_SMBUS_READ_BYTE_DATA |
282*4882a593Smuzhiyun 		I2C_FUNC_SMBUS_READ_WORD_DATA |
283*4882a593Smuzhiyun 		I2C_FUNC_SMBUS_READ_BLOCK_DATA) : 0;
284*4882a593Smuzhiyun 
285*4882a593Smuzhiyun 	ret |= smbus_cmi->cap_write ?
286*4882a593Smuzhiyun 		(I2C_FUNC_SMBUS_WRITE_BYTE |
287*4882a593Smuzhiyun 		I2C_FUNC_SMBUS_WRITE_BYTE_DATA |
288*4882a593Smuzhiyun 		I2C_FUNC_SMBUS_WRITE_WORD_DATA |
289*4882a593Smuzhiyun 		I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) : 0;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	return ret;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun static const struct i2c_algorithm acpi_smbus_cmi_algorithm = {
295*4882a593Smuzhiyun 	.smbus_xfer = acpi_smbus_cmi_access,
296*4882a593Smuzhiyun 	.functionality = acpi_smbus_cmi_func,
297*4882a593Smuzhiyun };
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 
acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi * smbus_cmi,const char * name)300*4882a593Smuzhiyun static int acpi_smbus_cmi_add_cap(struct acpi_smbus_cmi *smbus_cmi,
301*4882a593Smuzhiyun 				  const char *name)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
304*4882a593Smuzhiyun 	struct acpi_handle *handle = smbus_cmi->handle;
305*4882a593Smuzhiyun 	union acpi_object *obj;
306*4882a593Smuzhiyun 	acpi_status status;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	if (!strcmp(name, smbus_cmi->methods->mt_info)) {
309*4882a593Smuzhiyun 		status = acpi_evaluate_object(smbus_cmi->handle,
310*4882a593Smuzhiyun 					smbus_cmi->methods->mt_info,
311*4882a593Smuzhiyun 					NULL, &buffer);
312*4882a593Smuzhiyun 		if (ACPI_FAILURE(status)) {
313*4882a593Smuzhiyun 			acpi_handle_err(handle, "Failed to evaluate %s: %i\n",
314*4882a593Smuzhiyun 					smbus_cmi->methods->mt_info, status);
315*4882a593Smuzhiyun 			return -EIO;
316*4882a593Smuzhiyun 		}
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 		obj = buffer.pointer;
319*4882a593Smuzhiyun 		if (obj && obj->type == ACPI_TYPE_PACKAGE)
320*4882a593Smuzhiyun 			obj = obj->package.elements;
321*4882a593Smuzhiyun 		else {
322*4882a593Smuzhiyun 			acpi_handle_err(handle, "Invalid argument type\n");
323*4882a593Smuzhiyun 			kfree(buffer.pointer);
324*4882a593Smuzhiyun 			return -EIO;
325*4882a593Smuzhiyun 		}
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 		if (obj->type != ACPI_TYPE_INTEGER) {
328*4882a593Smuzhiyun 			acpi_handle_err(handle, "Invalid argument type\n");
329*4882a593Smuzhiyun 			kfree(buffer.pointer);
330*4882a593Smuzhiyun 			return -EIO;
331*4882a593Smuzhiyun 		} else
332*4882a593Smuzhiyun 			acpi_handle_debug(handle, "SMBus CMI Version %x\n",
333*4882a593Smuzhiyun 					  (int)obj->integer.value);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 		kfree(buffer.pointer);
336*4882a593Smuzhiyun 		smbus_cmi->cap_info = 1;
337*4882a593Smuzhiyun 	} else if (!strcmp(name, smbus_cmi->methods->mt_sbr))
338*4882a593Smuzhiyun 		smbus_cmi->cap_read = 1;
339*4882a593Smuzhiyun 	else if (!strcmp(name, smbus_cmi->methods->mt_sbw))
340*4882a593Smuzhiyun 		smbus_cmi->cap_write = 1;
341*4882a593Smuzhiyun 	else
342*4882a593Smuzhiyun 		acpi_handle_debug(handle, "Unsupported CMI method: %s\n", name);
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	return 0;
345*4882a593Smuzhiyun }
346*4882a593Smuzhiyun 
acpi_smbus_cmi_query_methods(acpi_handle handle,u32 level,void * context,void ** return_value)347*4882a593Smuzhiyun static acpi_status acpi_smbus_cmi_query_methods(acpi_handle handle, u32 level,
348*4882a593Smuzhiyun 			void *context, void **return_value)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun 	char node_name[5];
351*4882a593Smuzhiyun 	struct acpi_buffer buffer = { sizeof(node_name), node_name };
352*4882a593Smuzhiyun 	struct acpi_smbus_cmi *smbus_cmi = context;
353*4882a593Smuzhiyun 	acpi_status status;
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	status = acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	if (ACPI_SUCCESS(status))
358*4882a593Smuzhiyun 		acpi_smbus_cmi_add_cap(smbus_cmi, node_name);
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun 	return AE_OK;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun 
acpi_smbus_cmi_add(struct acpi_device * device)363*4882a593Smuzhiyun static int acpi_smbus_cmi_add(struct acpi_device *device)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun 	struct acpi_smbus_cmi *smbus_cmi;
366*4882a593Smuzhiyun 	const struct acpi_device_id *id;
367*4882a593Smuzhiyun 	int ret;
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun 	smbus_cmi = kzalloc(sizeof(struct acpi_smbus_cmi), GFP_KERNEL);
370*4882a593Smuzhiyun 	if (!smbus_cmi)
371*4882a593Smuzhiyun 		return -ENOMEM;
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 	smbus_cmi->handle = device->handle;
374*4882a593Smuzhiyun 	strcpy(acpi_device_name(device), ACPI_SMBUS_HC_DEVICE_NAME);
375*4882a593Smuzhiyun 	strcpy(acpi_device_class(device), ACPI_SMBUS_HC_CLASS);
376*4882a593Smuzhiyun 	device->driver_data = smbus_cmi;
377*4882a593Smuzhiyun 	smbus_cmi->cap_info = 0;
378*4882a593Smuzhiyun 	smbus_cmi->cap_read = 0;
379*4882a593Smuzhiyun 	smbus_cmi->cap_write = 0;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	for (id = acpi_smbus_cmi_ids; id->id[0]; id++)
382*4882a593Smuzhiyun 		if (!strcmp(id->id, acpi_device_hid(device)))
383*4882a593Smuzhiyun 			smbus_cmi->methods =
384*4882a593Smuzhiyun 				(struct smbus_methods_t *) id->driver_data;
385*4882a593Smuzhiyun 
386*4882a593Smuzhiyun 	acpi_walk_namespace(ACPI_TYPE_METHOD, smbus_cmi->handle, 1,
387*4882a593Smuzhiyun 			    acpi_smbus_cmi_query_methods, NULL, smbus_cmi, NULL);
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	if (smbus_cmi->cap_info == 0) {
390*4882a593Smuzhiyun 		ret = -ENODEV;
391*4882a593Smuzhiyun 		goto err;
392*4882a593Smuzhiyun 	}
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun 	snprintf(smbus_cmi->adapter.name, sizeof(smbus_cmi->adapter.name),
395*4882a593Smuzhiyun 		"SMBus CMI adapter %s",
396*4882a593Smuzhiyun 		acpi_device_name(device));
397*4882a593Smuzhiyun 	smbus_cmi->adapter.owner = THIS_MODULE;
398*4882a593Smuzhiyun 	smbus_cmi->adapter.algo = &acpi_smbus_cmi_algorithm;
399*4882a593Smuzhiyun 	smbus_cmi->adapter.algo_data = smbus_cmi;
400*4882a593Smuzhiyun 	smbus_cmi->adapter.class = I2C_CLASS_HWMON | I2C_CLASS_SPD;
401*4882a593Smuzhiyun 	smbus_cmi->adapter.dev.parent = &device->dev;
402*4882a593Smuzhiyun 
403*4882a593Smuzhiyun 	ret = i2c_add_adapter(&smbus_cmi->adapter);
404*4882a593Smuzhiyun 	if (ret) {
405*4882a593Smuzhiyun 		dev_err(&device->dev, "Couldn't register adapter!\n");
406*4882a593Smuzhiyun 		goto err;
407*4882a593Smuzhiyun 	}
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	return 0;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun err:
412*4882a593Smuzhiyun 	kfree(smbus_cmi);
413*4882a593Smuzhiyun 	device->driver_data = NULL;
414*4882a593Smuzhiyun 	return ret;
415*4882a593Smuzhiyun }
416*4882a593Smuzhiyun 
acpi_smbus_cmi_remove(struct acpi_device * device)417*4882a593Smuzhiyun static int acpi_smbus_cmi_remove(struct acpi_device *device)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun 	struct acpi_smbus_cmi *smbus_cmi = acpi_driver_data(device);
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	i2c_del_adapter(&smbus_cmi->adapter);
422*4882a593Smuzhiyun 	kfree(smbus_cmi);
423*4882a593Smuzhiyun 	device->driver_data = NULL;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 	return 0;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun 
428*4882a593Smuzhiyun static struct acpi_driver acpi_smbus_cmi_driver = {
429*4882a593Smuzhiyun 	.name = ACPI_SMBUS_HC_DEVICE_NAME,
430*4882a593Smuzhiyun 	.class = ACPI_SMBUS_HC_CLASS,
431*4882a593Smuzhiyun 	.ids = acpi_smbus_cmi_ids,
432*4882a593Smuzhiyun 	.ops = {
433*4882a593Smuzhiyun 		.add = acpi_smbus_cmi_add,
434*4882a593Smuzhiyun 		.remove = acpi_smbus_cmi_remove,
435*4882a593Smuzhiyun 	},
436*4882a593Smuzhiyun };
437*4882a593Smuzhiyun module_acpi_driver(acpi_smbus_cmi_driver);
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun MODULE_LICENSE("GPL");
440*4882a593Smuzhiyun MODULE_AUTHOR("Crane Cai <crane.cai@amd.com>");
441*4882a593Smuzhiyun MODULE_DESCRIPTION("ACPI SMBus CMI driver");
442