I2C/ACPI: Add i2c ACPI operation region support
[firefly-linux-kernel-4.4.55.git] / drivers / i2c / i2c-acpi.c
1 /*
2  * I2C ACPI code
3  *
4  * Copyright (C) 2014 Intel Corp
5  *
6  * Author: Lan Tianyu <tianyu.lan@intel.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15  * for more details.
16  */
17 #define pr_fmt(fmt) "I2C/ACPI : " fmt
18
19 #include <linux/kernel.h>
20 #include <linux/errno.h>
21 #include <linux/err.h>
22 #include <linux/i2c.h>
23 #include <linux/acpi.h>
24
25 struct acpi_i2c_handler_data {
26         struct acpi_connection_info info;
27         struct i2c_adapter *adapter;
28 };
29
30 struct gsb_buffer {
31         u8      status;
32         u8      len;
33         union {
34                 u16     wdata;
35                 u8      bdata;
36                 u8      data[0];
37         };
38 } __packed;
39
40 static int acpi_gsb_i2c_read_bytes(struct i2c_client *client,
41                 u8 cmd, u8 *data, u8 data_len)
42 {
43
44         struct i2c_msg msgs[2];
45         int ret;
46         u8 *buffer;
47
48         buffer = kzalloc(data_len, GFP_KERNEL);
49         if (!buffer)
50                 return AE_NO_MEMORY;
51
52         msgs[0].addr = client->addr;
53         msgs[0].flags = client->flags;
54         msgs[0].len = 1;
55         msgs[0].buf = &cmd;
56
57         msgs[1].addr = client->addr;
58         msgs[1].flags = client->flags | I2C_M_RD;
59         msgs[1].len = data_len;
60         msgs[1].buf = buffer;
61
62         ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
63         if (ret < 0)
64                 dev_err(&client->adapter->dev, "i2c read failed\n");
65         else
66                 memcpy(data, buffer, data_len);
67
68         kfree(buffer);
69         return ret;
70 }
71
72 static int acpi_gsb_i2c_write_bytes(struct i2c_client *client,
73                 u8 cmd, u8 *data, u8 data_len)
74 {
75
76         struct i2c_msg msgs[1];
77         u8 *buffer;
78         int ret = AE_OK;
79
80         buffer = kzalloc(data_len + 1, GFP_KERNEL);
81         if (!buffer)
82                 return AE_NO_MEMORY;
83
84         buffer[0] = cmd;
85         memcpy(buffer + 1, data, data_len);
86
87         msgs[0].addr = client->addr;
88         msgs[0].flags = client->flags;
89         msgs[0].len = data_len + 1;
90         msgs[0].buf = buffer;
91
92         ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
93         if (ret < 0)
94                 dev_err(&client->adapter->dev, "i2c write failed\n");
95
96         kfree(buffer);
97         return ret;
98 }
99
100 static acpi_status
101 acpi_i2c_space_handler(u32 function, acpi_physical_address command,
102                         u32 bits, u64 *value64,
103                         void *handler_context, void *region_context)
104 {
105         struct gsb_buffer *gsb = (struct gsb_buffer *)value64;
106         struct acpi_i2c_handler_data *data = handler_context;
107         struct acpi_connection_info *info = &data->info;
108         struct acpi_resource_i2c_serialbus *sb;
109         struct i2c_adapter *adapter = data->adapter;
110         struct i2c_client client;
111         struct acpi_resource *ares;
112         u32 accessor_type = function >> 16;
113         u8 action = function & ACPI_IO_MASK;
114         acpi_status ret = AE_OK;
115         int status;
116
117         ret = acpi_buffer_to_resource(info->connection, info->length, &ares);
118         if (ACPI_FAILURE(ret))
119                 return ret;
120
121         if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) {
122                 ret = AE_BAD_PARAMETER;
123                 goto err;
124         }
125
126         sb = &ares->data.i2c_serial_bus;
127         if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) {
128                 ret = AE_BAD_PARAMETER;
129                 goto err;
130         }
131
132         memset(&client, 0, sizeof(client));
133         client.adapter = adapter;
134         client.addr = sb->slave_address;
135         client.flags = 0;
136
137         if (sb->access_mode == ACPI_I2C_10BIT_MODE)
138                 client.flags |= I2C_CLIENT_TEN;
139
140         switch (accessor_type) {
141         case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV:
142                 if (action == ACPI_READ) {
143                         status = i2c_smbus_read_byte(&client);
144                         if (status >= 0) {
145                                 gsb->bdata = status;
146                                 status = 0;
147                         }
148                 } else {
149                         status = i2c_smbus_write_byte(&client, gsb->bdata);
150                 }
151                 break;
152
153         case ACPI_GSB_ACCESS_ATTRIB_BYTE:
154                 if (action == ACPI_READ) {
155                         status = i2c_smbus_read_byte_data(&client, command);
156                         if (status >= 0) {
157                                 gsb->bdata = status;
158                                 status = 0;
159                         }
160                 } else {
161                         status = i2c_smbus_write_byte_data(&client, command,
162                                         gsb->bdata);
163                 }
164                 break;
165
166         case ACPI_GSB_ACCESS_ATTRIB_WORD:
167                 if (action == ACPI_READ) {
168                         status = i2c_smbus_read_word_data(&client, command);
169                         if (status >= 0) {
170                                 gsb->wdata = status;
171                                 status = 0;
172                         }
173                 } else {
174                         status = i2c_smbus_write_word_data(&client, command,
175                                         gsb->wdata);
176                 }
177                 break;
178
179         case ACPI_GSB_ACCESS_ATTRIB_BLOCK:
180                 if (action == ACPI_READ) {
181                         status = i2c_smbus_read_block_data(&client, command,
182                                         gsb->data);
183                         if (status >= 0) {
184                                 gsb->len = status;
185                                 status = 0;
186                         }
187                 } else {
188                         status = i2c_smbus_write_block_data(&client, command,
189                                         gsb->len, gsb->data);
190                 }
191                 break;
192
193         case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE:
194                 if (action == ACPI_READ) {
195                         status = acpi_gsb_i2c_read_bytes(&client, command,
196                                         gsb->data, info->access_length);
197                         if (status > 0)
198                                 status = 0;
199                 } else {
200                         status = acpi_gsb_i2c_write_bytes(&client, command,
201                                         gsb->data, info->access_length);
202                 }
203                 break;
204
205         default:
206                 pr_info("protocol(0x%02x) is not supported.\n", accessor_type);
207                 ret = AE_BAD_PARAMETER;
208                 goto err;
209         }
210
211         gsb->status = status;
212
213  err:
214         ACPI_FREE(ares);
215         return ret;
216 }
217
218
219 int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
220 {
221         acpi_handle handle = ACPI_HANDLE(adapter->dev.parent);
222         struct acpi_i2c_handler_data *data;
223         acpi_status status;
224
225         if (!handle)
226                 return -ENODEV;
227
228         data = kzalloc(sizeof(struct acpi_i2c_handler_data),
229                             GFP_KERNEL);
230         if (!data)
231                 return -ENOMEM;
232
233         data->adapter = adapter;
234         status = acpi_bus_attach_private_data(handle, (void *)data);
235         if (ACPI_FAILURE(status)) {
236                 kfree(data);
237                 return -ENOMEM;
238         }
239
240         status = acpi_install_address_space_handler(handle,
241                                 ACPI_ADR_SPACE_GSBUS,
242                                 &acpi_i2c_space_handler,
243                                 NULL,
244                                 data);
245         if (ACPI_FAILURE(status)) {
246                 dev_err(&adapter->dev, "Error installing i2c space handler\n");
247                 acpi_bus_detach_private_data(handle);
248                 kfree(data);
249                 return -ENOMEM;
250         }
251
252         return 0;
253 }
254
255 void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter)
256 {
257         acpi_handle handle = ACPI_HANDLE(adapter->dev.parent);
258         struct acpi_i2c_handler_data *data;
259         acpi_status status;
260
261         if (!handle)
262                 return;
263
264         acpi_remove_address_space_handler(handle,
265                                 ACPI_ADR_SPACE_GSBUS,
266                                 &acpi_i2c_space_handler);
267
268         status = acpi_bus_get_private_data(handle, (void **)&data);
269         if (ACPI_SUCCESS(status))
270                 kfree(data);
271
272         acpi_bus_detach_private_data(handle);
273 }