blob: 699914e824543b26cb329dbb8fc20c77f0e7670d [file] [log] [blame]
Wolfram Sang53f8f7c2017-05-23 16:22:23 +02001/*
2 * Linux I2C core ACPI support code
3 *
4 * Copyright (C) 2014 Intel Corp, Author: Lan Tianyu <tianyu.lan@intel.com>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 */
11
12#include <linux/acpi.h>
13#include <linux/device.h>
14#include <linux/err.h>
15#include <linux/i2c.h>
16#include <linux/list.h>
17#include <linux/module.h>
18#include <linux/slab.h>
19
20#include "i2c-core.h"
21
22struct i2c_acpi_handler_data {
23 struct acpi_connection_info info;
24 struct i2c_adapter *adapter;
25};
26
27struct gsb_buffer {
28 u8 status;
29 u8 len;
30 union {
31 u16 wdata;
32 u8 bdata;
33 u8 data[0];
34 };
35} __packed;
36
37struct i2c_acpi_lookup {
38 struct i2c_board_info *info;
39 acpi_handle adapter_handle;
40 acpi_handle device_handle;
41 acpi_handle search_handle;
42 int n;
43 int index;
44 u32 speed;
45 u32 min_speed;
46};
47
Andy Shevchenko0d5102f2018-11-28 13:45:29 +020048/**
49 * i2c_acpi_get_i2c_resource - Gets I2cSerialBus resource if type matches
50 * @ares: ACPI resource
51 * @i2c: Pointer to I2cSerialBus resource will be returned here
52 *
53 * Checks if the given ACPI resource is of type I2cSerialBus.
54 * In this case, returns a pointer to it to the caller.
55 *
56 * Returns true if resource type is of I2cSerialBus, otherwise false.
57 */
58bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares,
59 struct acpi_resource_i2c_serialbus **i2c)
60{
61 struct acpi_resource_i2c_serialbus *sb;
62
63 if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
64 return false;
65
66 sb = &ares->data.i2c_serial_bus;
67 if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
68 return false;
69
70 *i2c = sb;
71 return true;
72}
73EXPORT_SYMBOL_GPL(i2c_acpi_get_i2c_resource);
74
Wolfram Sang53f8f7c2017-05-23 16:22:23 +020075static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data)
76{
77 struct i2c_acpi_lookup *lookup = data;
78 struct i2c_board_info *info = lookup->info;
79 struct acpi_resource_i2c_serialbus *sb;
80 acpi_status status;
81
Andy Shevchenko0d5102f2018-11-28 13:45:29 +020082 if (info->addr || !i2c_acpi_get_i2c_resource(ares, &sb))
Wolfram Sang53f8f7c2017-05-23 16:22:23 +020083 return 1;
84
85 if (lookup->index != -1 && lookup->n++ != lookup->index)
86 return 1;
87
88 status = acpi_get_handle(lookup->device_handle,
89 sb->resource_source.string_ptr,
90 &lookup->adapter_handle);
Andy Shevchenko5f59d6a2018-11-28 13:45:28 +020091 if (ACPI_FAILURE(status))
Wolfram Sang53f8f7c2017-05-23 16:22:23 +020092 return 1;
93
94 info->addr = sb->slave_address;
95 lookup->speed = sb->connection_speed;
96 if (sb->access_mode == ACPI_I2C_10BIT_MODE)
97 info->flags |= I2C_CLIENT_TEN;
98
99 return 1;
100}
101
Hans de Goede3a4991a2017-07-04 15:04:48 +0200102static const struct acpi_device_id i2c_acpi_ignored_device_ids[] = {
103 /*
104 * ACPI video acpi_devices, which are handled by the acpi-video driver
105 * sometimes contain a SERIAL_TYPE_I2C ACPI resource, ignore these.
106 */
107 { ACPI_VIDEO_HID, 0 },
108 {}
109};
110
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200111static int i2c_acpi_do_lookup(struct acpi_device *adev,
112 struct i2c_acpi_lookup *lookup)
113{
114 struct i2c_board_info *info = lookup->info;
115 struct list_head resource_list;
116 int ret;
117
118 if (acpi_bus_get_status(adev) || !adev->status.present ||
119 acpi_device_enumerated(adev))
120 return -EINVAL;
121
Hans de Goede3a4991a2017-07-04 15:04:48 +0200122 if (acpi_match_device_ids(adev, i2c_acpi_ignored_device_ids) == 0)
123 return -ENODEV;
124
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200125 memset(info, 0, sizeof(*info));
126 lookup->device_handle = acpi_device_handle(adev);
127
128 /* Look up for I2cSerialBus resource */
129 INIT_LIST_HEAD(&resource_list);
130 ret = acpi_dev_get_resources(adev, &resource_list,
131 i2c_acpi_fill_info, lookup);
132 acpi_dev_free_resource_list(&resource_list);
133
134 if (ret < 0 || !info->addr)
135 return -EINVAL;
136
137 return 0;
138}
139
Charles Keepaxc2223dd2019-06-27 10:24:07 +0100140static int i2c_acpi_add_resource(struct acpi_resource *ares, void *data)
141{
142 int *irq = data;
143 struct resource r;
144
145 if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r))
146 *irq = i2c_dev_irq_from_resources(&r, 1);
147
148 return 1; /* No need to add resource to the list */
149}
150
Charles Keepax16c9db12019-06-27 10:24:09 +0100151/**
152 * i2c_acpi_get_irq - get device IRQ number from ACPI
153 * @client: Pointer to the I2C client device
154 *
155 * Find the IRQ number used by a specific client device.
156 *
157 * Return: The IRQ number or an error code.
158 */
159int i2c_acpi_get_irq(struct i2c_client *client)
Charles Keepaxa52e3b32019-06-27 10:24:08 +0100160{
Charles Keepax16c9db12019-06-27 10:24:09 +0100161 struct acpi_device *adev = ACPI_COMPANION(&client->dev);
Charles Keepaxa52e3b32019-06-27 10:24:08 +0100162 struct list_head resource_list;
163 int irq = -ENOENT;
164 int ret;
165
166 INIT_LIST_HEAD(&resource_list);
167
168 ret = acpi_dev_get_resources(adev, &resource_list,
169 i2c_acpi_add_resource, &irq);
170 if (ret < 0)
171 return ret;
172
173 acpi_dev_free_resource_list(&resource_list);
174
Charles Keepax8466b612019-06-27 10:24:10 +0100175 if (irq == -ENOENT)
176 irq = acpi_dev_gpio_irq_get(adev, 0);
177
Charles Keepaxa52e3b32019-06-27 10:24:08 +0100178 return irq;
179}
180
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200181static int i2c_acpi_get_info(struct acpi_device *adev,
182 struct i2c_board_info *info,
183 struct i2c_adapter *adapter,
184 acpi_handle *adapter_handle)
185{
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200186 struct i2c_acpi_lookup lookup;
187 int ret;
188
189 memset(&lookup, 0, sizeof(lookup));
190 lookup.info = info;
191 lookup.index = -1;
192
193 ret = i2c_acpi_do_lookup(adev, &lookup);
194 if (ret)
195 return ret;
196
197 if (adapter) {
198 /* The adapter must match the one in I2cSerialBus() connector */
199 if (ACPI_HANDLE(&adapter->dev) != lookup.adapter_handle)
200 return -ENODEV;
201 } else {
202 struct acpi_device *adapter_adev;
203
204 /* The adapter must be present */
205 if (acpi_bus_get_device(lookup.adapter_handle, &adapter_adev))
206 return -ENODEV;
207 if (acpi_bus_get_status(adapter_adev) ||
208 !adapter_adev->status.present)
209 return -ENODEV;
210 }
211
212 info->fwnode = acpi_fwnode_handle(adev);
213 if (adapter_handle)
214 *adapter_handle = lookup.adapter_handle;
215
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200216 acpi_set_modalias(adev, dev_name(&adev->dev), info->type,
217 sizeof(info->type));
218
219 return 0;
220}
221
222static void i2c_acpi_register_device(struct i2c_adapter *adapter,
223 struct acpi_device *adev,
224 struct i2c_board_info *info)
225{
226 adev->power.flags.ignore_parent = true;
227 acpi_device_set_enumerated(adev);
228
229 if (!i2c_new_device(adapter, info)) {
230 adev->power.flags.ignore_parent = false;
231 dev_err(&adapter->dev,
232 "failed to add I2C device %s from ACPI\n",
233 dev_name(&adev->dev));
234 }
235}
236
237static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level,
238 void *data, void **return_value)
239{
240 struct i2c_adapter *adapter = data;
241 struct acpi_device *adev;
242 struct i2c_board_info info;
243
244 if (acpi_bus_get_device(handle, &adev))
245 return AE_OK;
246
247 if (i2c_acpi_get_info(adev, &info, adapter, NULL))
248 return AE_OK;
249
250 i2c_acpi_register_device(adapter, adev, &info);
251
252 return AE_OK;
253}
254
255#define I2C_ACPI_MAX_SCAN_DEPTH 32
256
257/**
258 * i2c_acpi_register_devices - enumerate I2C slave devices behind adapter
259 * @adap: pointer to adapter
260 *
261 * Enumerate all I2C slave devices behind this adapter by walking the ACPI
262 * namespace. When a device is found it will be added to the Linux device
263 * model and bound to the corresponding ACPI handle.
264 */
265void i2c_acpi_register_devices(struct i2c_adapter *adap)
266{
267 acpi_status status;
268
269 if (!has_acpi_companion(&adap->dev))
270 return;
271
272 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
273 I2C_ACPI_MAX_SCAN_DEPTH,
274 i2c_acpi_add_device, NULL,
275 adap, NULL);
276 if (ACPI_FAILURE(status))
277 dev_warn(&adap->dev, "failed to enumerate I2C slaves\n");
278}
279
Andy Shevchenkoc64ffff2017-07-17 17:13:28 +0300280const struct acpi_device_id *
281i2c_acpi_match_device(const struct acpi_device_id *matches,
282 struct i2c_client *client)
283{
284 if (!(client && matches))
285 return NULL;
286
287 return acpi_match_device(matches, &client->dev);
288}
289
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200290static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level,
291 void *data, void **return_value)
292{
293 struct i2c_acpi_lookup *lookup = data;
294 struct acpi_device *adev;
295
296 if (acpi_bus_get_device(handle, &adev))
297 return AE_OK;
298
299 if (i2c_acpi_do_lookup(adev, lookup))
300 return AE_OK;
301
302 if (lookup->search_handle != lookup->adapter_handle)
303 return AE_OK;
304
305 if (lookup->speed <= lookup->min_speed)
306 lookup->min_speed = lookup->speed;
307
308 return AE_OK;
309}
310
311/**
312 * i2c_acpi_find_bus_speed - find I2C bus speed from ACPI
313 * @dev: The device owning the bus
314 *
315 * Find the I2C bus speed by walking the ACPI namespace for all I2C slaves
316 * devices connected to this bus and use the speed of slowest device.
317 *
318 * Returns the speed in Hz or zero
319 */
320u32 i2c_acpi_find_bus_speed(struct device *dev)
321{
322 struct i2c_acpi_lookup lookup;
323 struct i2c_board_info dummy;
324 acpi_status status;
325
326 if (!has_acpi_companion(dev))
327 return 0;
328
329 memset(&lookup, 0, sizeof(lookup));
330 lookup.search_handle = ACPI_HANDLE(dev);
331 lookup.min_speed = UINT_MAX;
332 lookup.info = &dummy;
333 lookup.index = -1;
334
335 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
336 I2C_ACPI_MAX_SCAN_DEPTH,
337 i2c_acpi_lookup_speed, NULL,
338 &lookup, NULL);
339
340 if (ACPI_FAILURE(status)) {
341 dev_warn(dev, "unable to find I2C bus speed from ACPI\n");
342 return 0;
343 }
344
345 return lookup.min_speed != UINT_MAX ? lookup.min_speed : 0;
346}
347EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed);
348
Andy Shevchenkoc64ffff2017-07-17 17:13:28 +0300349static int i2c_acpi_find_match_adapter(struct device *dev, void *data)
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200350{
351 struct i2c_adapter *adapter = i2c_verify_adapter(dev);
352
353 if (!adapter)
354 return 0;
355
356 return ACPI_HANDLE(dev) == (acpi_handle)data;
357}
358
Andy Shevchenkoc64ffff2017-07-17 17:13:28 +0300359static int i2c_acpi_find_match_device(struct device *dev, void *data)
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200360{
361 return ACPI_COMPANION(dev) == data;
362}
363
Ruslan Babayev5213d7e2019-05-28 16:02:32 -0700364struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle)
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200365{
366 struct device *dev;
367
368 dev = bus_find_device(&i2c_bus_type, NULL, handle,
Andy Shevchenkoc64ffff2017-07-17 17:13:28 +0300369 i2c_acpi_find_match_adapter);
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200370 return dev ? i2c_verify_adapter(dev) : NULL;
371}
Ruslan Babayev5213d7e2019-05-28 16:02:32 -0700372EXPORT_SYMBOL_GPL(i2c_acpi_find_adapter_by_handle);
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200373
374static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev)
375{
376 struct device *dev;
377
Andy Shevchenkoc64ffff2017-07-17 17:13:28 +0300378 dev = bus_find_device(&i2c_bus_type, NULL, adev,
379 i2c_acpi_find_match_device);
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200380 return dev ? i2c_verify_client(dev) : NULL;
381}
382
383static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value,
384 void *arg)
385{
386 struct acpi_device *adev = arg;
387 struct i2c_board_info info;
388 acpi_handle adapter_handle;
389 struct i2c_adapter *adapter;
390 struct i2c_client *client;
391
392 switch (value) {
393 case ACPI_RECONFIG_DEVICE_ADD:
394 if (i2c_acpi_get_info(adev, &info, NULL, &adapter_handle))
395 break;
396
397 adapter = i2c_acpi_find_adapter_by_handle(adapter_handle);
398 if (!adapter)
399 break;
400
401 i2c_acpi_register_device(adapter, adev, &info);
402 break;
403 case ACPI_RECONFIG_DEVICE_REMOVE:
404 if (!acpi_device_enumerated(adev))
405 break;
406
407 client = i2c_acpi_find_client_by_adev(adev);
408 if (!client)
409 break;
410
411 i2c_unregister_device(client);
412 put_device(&client->dev);
413 break;
414 }
415
416 return NOTIFY_OK;
417}
418
419struct notifier_block i2c_acpi_notifier = {
420 .notifier_call = i2c_acpi_notify,
421};
422
423/**
424 * i2c_acpi_new_device - Create i2c-client for the Nth I2cSerialBus resource
425 * @dev: Device owning the ACPI resources to get the client from
426 * @index: Index of ACPI resource to get
427 * @info: describes the I2C device; note this is modified (addr gets set)
428 * Context: can sleep
429 *
430 * By default the i2c subsys creates an i2c-client for the first I2cSerialBus
431 * resource of an acpi_device, but some acpi_devices have multiple I2cSerialBus
432 * resources, in that case this function can be used to create an i2c-client
433 * for other I2cSerialBus resources in the Current Resource Settings table.
434 *
435 * Also see i2c_new_device, which this function calls to create the i2c-client.
436 *
Andy Shevchenko2dea6452018-11-28 13:45:25 +0200437 * Returns a pointer to the new i2c-client, or error pointer in case of failure.
438 * Specifically, -EPROBE_DEFER is returned if the adapter is not found.
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200439 */
440struct i2c_client *i2c_acpi_new_device(struct device *dev, int index,
441 struct i2c_board_info *info)
442{
443 struct i2c_acpi_lookup lookup;
444 struct i2c_adapter *adapter;
Andy Shevchenko2dea6452018-11-28 13:45:25 +0200445 struct i2c_client *client;
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200446 struct acpi_device *adev;
447 LIST_HEAD(resource_list);
448 int ret;
449
450 adev = ACPI_COMPANION(dev);
451 if (!adev)
Andy Shevchenko2dea6452018-11-28 13:45:25 +0200452 return ERR_PTR(-EINVAL);
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200453
454 memset(&lookup, 0, sizeof(lookup));
455 lookup.info = info;
456 lookup.device_handle = acpi_device_handle(adev);
457 lookup.index = index;
458
459 ret = acpi_dev_get_resources(adev, &resource_list,
460 i2c_acpi_fill_info, &lookup);
Andy Shevchenko2dea6452018-11-28 13:45:25 +0200461 if (ret < 0)
462 return ERR_PTR(ret);
463
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200464 acpi_dev_free_resource_list(&resource_list);
465
Andy Shevchenko2dea6452018-11-28 13:45:25 +0200466 if (!info->addr)
467 return ERR_PTR(-EADDRNOTAVAIL);
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200468
469 adapter = i2c_acpi_find_adapter_by_handle(lookup.adapter_handle);
470 if (!adapter)
Andy Shevchenko2dea6452018-11-28 13:45:25 +0200471 return ERR_PTR(-EPROBE_DEFER);
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200472
Andy Shevchenko2dea6452018-11-28 13:45:25 +0200473 client = i2c_new_device(adapter, info);
474 if (!client)
475 return ERR_PTR(-ENODEV);
476
477 return client;
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200478}
479EXPORT_SYMBOL_GPL(i2c_acpi_new_device);
480
481#ifdef CONFIG_ACPI_I2C_OPREGION
482static int acpi_gsb_i2c_read_bytes(struct i2c_client *client,
483 u8 cmd, u8 *data, u8 data_len)
484{
485
486 struct i2c_msg msgs[2];
487 int ret;
488 u8 *buffer;
489
490 buffer = kzalloc(data_len, GFP_KERNEL);
491 if (!buffer)
492 return AE_NO_MEMORY;
493
494 msgs[0].addr = client->addr;
495 msgs[0].flags = client->flags;
496 msgs[0].len = 1;
497 msgs[0].buf = &cmd;
498
499 msgs[1].addr = client->addr;
500 msgs[1].flags = client->flags | I2C_M_RD;
501 msgs[1].len = data_len;
502 msgs[1].buf = buffer;
503
504 ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
Hans de Goede7781eda2018-04-22 19:58:00 +0200505 if (ret < 0) {
506 /* Getting a NACK is unfortunately normal with some DSTDs */
507 if (ret == -EREMOTEIO)
508 dev_dbg(&client->adapter->dev, "i2c read %d bytes from client@%#x starting at reg %#x failed, error: %d\n",
509 data_len, client->addr, cmd, ret);
510 else
511 dev_err(&client->adapter->dev, "i2c read %d bytes from client@%#x starting at reg %#x failed, error: %d\n",
512 data_len, client->addr, cmd, ret);
Hans de Goede0a304462018-08-12 12:53:21 +0200513 /* 2 transfers must have completed successfully */
514 } else if (ret == 2) {
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200515 memcpy(data, buffer, data_len);
Hans de Goede0a304462018-08-12 12:53:21 +0200516 ret = 0;
517 } else {
518 ret = -EIO;
Hans de Goede7781eda2018-04-22 19:58:00 +0200519 }
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200520
521 kfree(buffer);
522 return ret;
523}
524
525static int acpi_gsb_i2c_write_bytes(struct i2c_client *client,
526 u8 cmd, u8 *data, u8 data_len)
527{
528
529 struct i2c_msg msgs[1];
530 u8 *buffer;
531 int ret = AE_OK;
532
533 buffer = kzalloc(data_len + 1, GFP_KERNEL);
534 if (!buffer)
535 return AE_NO_MEMORY;
536
537 buffer[0] = cmd;
538 memcpy(buffer + 1, data, data_len);
539
540 msgs[0].addr = client->addr;
541 msgs[0].flags = client->flags;
542 msgs[0].len = data_len + 1;
543 msgs[0].buf = buffer;
544
545 ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200546
547 kfree(buffer);
Hans de Goedec463a152018-08-12 12:53:20 +0200548
549 if (ret < 0) {
550 dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret);
551 return ret;
552 }
553
554 /* 1 transfer must have completed successfully */
555 return (ret == 1) ? 0 : -EIO;
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200556}
557
558static acpi_status
559i2c_acpi_space_handler(u32 function, acpi_physical_address command,
560 u32 bits, u64 *value64,
561 void *handler_context, void *region_context)
562{
563 struct gsb_buffer *gsb = (struct gsb_buffer *)value64;
564 struct i2c_acpi_handler_data *data = handler_context;
565 struct acpi_connection_info *info = &data->info;
566 struct acpi_resource_i2c_serialbus *sb;
567 struct i2c_adapter *adapter = data->adapter;
568 struct i2c_client *client;
569 struct acpi_resource *ares;
570 u32 accessor_type = function >> 16;
571 u8 action = function & ACPI_IO_MASK;
572 acpi_status ret;
573 int status;
574
575 ret = acpi_buffer_to_resource(info->connection, info->length, &ares);
576 if (ACPI_FAILURE(ret))
577 return ret;
578
579 client = kzalloc(sizeof(*client), GFP_KERNEL);
580 if (!client) {
581 ret = AE_NO_MEMORY;
582 goto err;
583 }
584
Andy Shevchenko0d5102f2018-11-28 13:45:29 +0200585 if (!value64 || !i2c_acpi_get_i2c_resource(ares, &sb)) {
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200586 ret = AE_BAD_PARAMETER;
587 goto err;
588 }
589
590 client->adapter = adapter;
591 client->addr = sb->slave_address;
592
593 if (sb->access_mode == ACPI_I2C_10BIT_MODE)
594 client->flags |= I2C_CLIENT_TEN;
595
596 switch (accessor_type) {
597 case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV:
598 if (action == ACPI_READ) {
599 status = i2c_smbus_read_byte(client);
600 if (status >= 0) {
601 gsb->bdata = status;
602 status = 0;
603 }
604 } else {
605 status = i2c_smbus_write_byte(client, gsb->bdata);
606 }
607 break;
608
609 case ACPI_GSB_ACCESS_ATTRIB_BYTE:
610 if (action == ACPI_READ) {
611 status = i2c_smbus_read_byte_data(client, command);
612 if (status >= 0) {
613 gsb->bdata = status;
614 status = 0;
615 }
616 } else {
617 status = i2c_smbus_write_byte_data(client, command,
618 gsb->bdata);
619 }
620 break;
621
622 case ACPI_GSB_ACCESS_ATTRIB_WORD:
623 if (action == ACPI_READ) {
624 status = i2c_smbus_read_word_data(client, command);
625 if (status >= 0) {
626 gsb->wdata = status;
627 status = 0;
628 }
629 } else {
630 status = i2c_smbus_write_word_data(client, command,
631 gsb->wdata);
632 }
633 break;
634
635 case ACPI_GSB_ACCESS_ATTRIB_BLOCK:
636 if (action == ACPI_READ) {
637 status = i2c_smbus_read_block_data(client, command,
638 gsb->data);
639 if (status >= 0) {
640 gsb->len = status;
641 status = 0;
642 }
643 } else {
644 status = i2c_smbus_write_block_data(client, command,
645 gsb->len, gsb->data);
646 }
647 break;
648
649 case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE:
650 if (action == ACPI_READ) {
651 status = acpi_gsb_i2c_read_bytes(client, command,
652 gsb->data, info->access_length);
Wolfram Sang53f8f7c2017-05-23 16:22:23 +0200653 } else {
654 status = acpi_gsb_i2c_write_bytes(client, command,
655 gsb->data, info->access_length);
656 }
657 break;
658
659 default:
660 dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n",
661 accessor_type, client->addr);
662 ret = AE_BAD_PARAMETER;
663 goto err;
664 }
665
666 gsb->status = status;
667
668 err:
669 kfree(client);
670 ACPI_FREE(ares);
671 return ret;
672}
673
674
675int i2c_acpi_install_space_handler(struct i2c_adapter *adapter)
676{
677 acpi_handle handle;
678 struct i2c_acpi_handler_data *data;
679 acpi_status status;
680
681 if (!adapter->dev.parent)
682 return -ENODEV;
683
684 handle = ACPI_HANDLE(adapter->dev.parent);
685
686 if (!handle)
687 return -ENODEV;
688
689 data = kzalloc(sizeof(struct i2c_acpi_handler_data),
690 GFP_KERNEL);
691 if (!data)
692 return -ENOMEM;
693
694 data->adapter = adapter;
695 status = acpi_bus_attach_private_data(handle, (void *)data);
696 if (ACPI_FAILURE(status)) {
697 kfree(data);
698 return -ENOMEM;
699 }
700
701 status = acpi_install_address_space_handler(handle,
702 ACPI_ADR_SPACE_GSBUS,
703 &i2c_acpi_space_handler,
704 NULL,
705 data);
706 if (ACPI_FAILURE(status)) {
707 dev_err(&adapter->dev, "Error installing i2c space handler\n");
708 acpi_bus_detach_private_data(handle);
709 kfree(data);
710 return -ENOMEM;
711 }
712
713 acpi_walk_dep_device_list(handle);
714 return 0;
715}
716
717void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter)
718{
719 acpi_handle handle;
720 struct i2c_acpi_handler_data *data;
721 acpi_status status;
722
723 if (!adapter->dev.parent)
724 return;
725
726 handle = ACPI_HANDLE(adapter->dev.parent);
727
728 if (!handle)
729 return;
730
731 acpi_remove_address_space_handler(handle,
732 ACPI_ADR_SPACE_GSBUS,
733 &i2c_acpi_space_handler);
734
735 status = acpi_bus_get_private_data(handle, (void **)&data);
736 if (ACPI_SUCCESS(status))
737 kfree(data);
738
739 acpi_bus_detach_private_data(handle);
740}
741#endif /* CONFIG_ACPI_I2C_OPREGION */