]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/input/rmi4/rmi_smbus.c
6bb67baa1b77c7c10865803d796bde3b59841f94
[karo-tx-linux.git] / drivers / input / rmi4 / rmi_smbus.c
1 /*
2  * Copyright (c) 2015 - 2016 Red Hat, Inc
3  * Copyright (c) 2011, 2012 Synaptics Incorporated
4  * Copyright (c) 2011 Unixphere
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 version 2 as published by
8  * the Free Software Foundation.
9  */
10
11 #include <linux/kernel.h>
12 #include <linux/delay.h>
13 #include <linux/i2c.h>
14 #include <linux/interrupt.h>
15 #include <linux/kconfig.h>
16 #include <linux/lockdep.h>
17 #include <linux/module.h>
18 #include <linux/pm.h>
19 #include <linux/rmi.h>
20 #include <linux/slab.h>
21 #include "rmi_driver.h"
22
23 #define SMB_PROTOCOL_VERSION_ADDRESS    0xfd
24 #define SMB_MAX_COUNT                   32
25 #define RMI_SMB2_MAP_SIZE               8 /* 8 entry of 4 bytes each */
26 #define RMI_SMB2_MAP_FLAGS_WE           0x01
27
28 struct mapping_table_entry {
29         __le16 rmiaddr;
30         u8 readcount;
31         u8 flags;
32 };
33
34 struct rmi_smb_xport {
35         struct rmi_transport_dev xport;
36         struct i2c_client *client;
37
38         struct mutex page_mutex;
39         int page;
40         u8 table_index;
41         struct mutex mappingtable_mutex;
42         struct mapping_table_entry mapping_table[RMI_SMB2_MAP_SIZE];
43 };
44
45 static int rmi_smb_get_version(struct rmi_smb_xport *rmi_smb)
46 {
47         struct i2c_client *client = rmi_smb->client;
48         int retval;
49
50         /* Check if for SMBus new version device by reading version byte. */
51         retval = i2c_smbus_read_byte_data(client, SMB_PROTOCOL_VERSION_ADDRESS);
52         if (retval < 0) {
53                 dev_err(&client->dev, "failed to get SMBus version number!\n");
54                 return retval;
55         }
56         return retval + 1;
57 }
58
59 /* SMB block write - wrapper over ic2_smb_write_block */
60 static int smb_block_write(struct rmi_transport_dev *xport,
61                               u8 commandcode, const void *buf, size_t len)
62 {
63         struct rmi_smb_xport *rmi_smb =
64                 container_of(xport, struct rmi_smb_xport, xport);
65         struct i2c_client *client = rmi_smb->client;
66         int retval;
67
68         retval = i2c_smbus_write_block_data(client, commandcode, len, buf);
69
70         rmi_dbg(RMI_DEBUG_XPORT, &client->dev,
71                 "wrote %zd bytes at %#04x: %d (%*ph)\n",
72                 len, commandcode, retval, (int)len, buf);
73
74         return retval;
75 }
76
77 /*
78  * The function to get command code for smbus operations and keeps
79  * records to the driver mapping table
80  */
81 static int rmi_smb_get_command_code(struct rmi_transport_dev *xport,
82                 u16 rmiaddr, int bytecount, bool isread, u8 *commandcode)
83 {
84         struct rmi_smb_xport *rmi_smb =
85                 container_of(xport, struct rmi_smb_xport, xport);
86         int i;
87         int retval;
88         struct mapping_table_entry mapping_data[1];
89
90         mutex_lock(&rmi_smb->mappingtable_mutex);
91         for (i = 0; i < RMI_SMB2_MAP_SIZE; i++) {
92                 struct mapping_table_entry *entry = &rmi_smb->mapping_table[i];
93
94                 if (le16_to_cpu(entry->rmiaddr) == rmiaddr) {
95                         if (isread) {
96                                 if (entry->readcount == bytecount) {
97                                         *commandcode = i;
98                                         retval = 0;
99                                         goto exit;
100                                 }
101                         } else {
102                                 if (entry->flags & RMI_SMB2_MAP_FLAGS_WE) {
103                                         *commandcode = i;
104                                         retval = 0;
105                                         goto exit;
106                                 }
107                         }
108                 }
109         }
110         i = rmi_smb->table_index;
111         rmi_smb->table_index = (i + 1) % RMI_SMB2_MAP_SIZE;
112
113         /* constructs mapping table data entry. 4 bytes each entry */
114         memset(mapping_data, 0, sizeof(mapping_data));
115
116         mapping_data[0].rmiaddr = cpu_to_le16(rmiaddr);
117         mapping_data[0].readcount = bytecount;
118         mapping_data[0].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0;
119
120         retval = smb_block_write(xport, i + 0x80, mapping_data,
121                                  sizeof(mapping_data));
122
123         if (retval < 0) {
124                 /*
125                  * if not written to device mapping table
126                  * clear the driver mapping table records
127                  */
128                 rmi_smb->mapping_table[i].rmiaddr = 0x0000;
129                 rmi_smb->mapping_table[i].readcount = 0;
130                 rmi_smb->mapping_table[i].flags = 0;
131                 goto exit;
132         }
133         /* save to the driver level mapping table */
134         rmi_smb->mapping_table[i].rmiaddr = rmiaddr;
135         rmi_smb->mapping_table[i].readcount = bytecount;
136         rmi_smb->mapping_table[i].flags = !isread ? RMI_SMB2_MAP_FLAGS_WE : 0;
137         *commandcode = i;
138
139 exit:
140         mutex_unlock(&rmi_smb->mappingtable_mutex);
141
142         return retval;
143 }
144
145 static int rmi_smb_write_block(struct rmi_transport_dev *xport, u16 rmiaddr,
146                                 const void *databuff, size_t len)
147 {
148         int retval = 0;
149         u8 commandcode;
150         struct rmi_smb_xport *rmi_smb =
151                 container_of(xport, struct rmi_smb_xport, xport);
152         int cur_len = (int)len;
153
154         mutex_lock(&rmi_smb->page_mutex);
155
156         while (cur_len > 0) {
157                 /*
158                  * break into 32 bytes chunks to write get command code
159                  */
160                 int block_len = min_t(int, len, SMB_MAX_COUNT);
161
162                 retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
163                                                   false, &commandcode);
164                 if (retval < 0)
165                         goto exit;
166
167                 retval = smb_block_write(xport, commandcode,
168                                          databuff, block_len);
169                 if (retval < 0)
170                         goto exit;
171
172                 /* prepare to write next block of bytes */
173                 cur_len -= SMB_MAX_COUNT;
174                 databuff += SMB_MAX_COUNT;
175                 rmiaddr += SMB_MAX_COUNT;
176         }
177 exit:
178         mutex_unlock(&rmi_smb->page_mutex);
179         return retval;
180 }
181
182 /* SMB block read - wrapper over ic2_smb_read_block */
183 static int smb_block_read(struct rmi_transport_dev *xport,
184                              u8 commandcode, void *buf, size_t len)
185 {
186         struct rmi_smb_xport *rmi_smb =
187                 container_of(xport, struct rmi_smb_xport, xport);
188         struct i2c_client *client = rmi_smb->client;
189         int retval;
190
191         retval = i2c_smbus_read_block_data(client, commandcode, buf);
192         if (retval < 0)
193                 return retval;
194
195         return retval;
196 }
197
198 static int rmi_smb_read_block(struct rmi_transport_dev *xport, u16 rmiaddr,
199                               void *databuff, size_t len)
200 {
201         struct rmi_smb_xport *rmi_smb =
202                 container_of(xport, struct rmi_smb_xport, xport);
203         int retval;
204         u8 commandcode;
205         int cur_len = (int)len;
206
207         mutex_lock(&rmi_smb->page_mutex);
208         memset(databuff, 0, len);
209
210         while (cur_len > 0) {
211                 /* break into 32 bytes chunks to write get command code */
212                 int block_len =  min_t(int, cur_len, SMB_MAX_COUNT);
213
214                 retval = rmi_smb_get_command_code(xport, rmiaddr, block_len,
215                                                   true, &commandcode);
216                 if (retval < 0)
217                         goto exit;
218
219                 retval = smb_block_read(xport, commandcode,
220                                         databuff, block_len);
221                 if (retval < 0)
222                         goto exit;
223
224                 /* prepare to read next block of bytes */
225                 cur_len -= SMB_MAX_COUNT;
226                 databuff += SMB_MAX_COUNT;
227                 rmiaddr += SMB_MAX_COUNT;
228         }
229
230         retval = 0;
231
232 exit:
233         mutex_unlock(&rmi_smb->page_mutex);
234         return retval;
235 }
236
237 static void rmi_smb_clear_state(struct rmi_smb_xport *rmi_smb)
238 {
239         /* the mapping table has been flushed, discard the current one */
240         mutex_lock(&rmi_smb->mappingtable_mutex);
241         memset(rmi_smb->mapping_table, 0, sizeof(rmi_smb->mapping_table));
242         mutex_unlock(&rmi_smb->mappingtable_mutex);
243 }
244
245 static int rmi_smb_enable_smbus_mode(struct rmi_smb_xport *rmi_smb)
246 {
247         int retval;
248
249         /* we need to get the smbus version to activate the touchpad */
250         retval = rmi_smb_get_version(rmi_smb);
251         if (retval < 0)
252                 return retval;
253
254         return 0;
255 }
256
257 static int rmi_smb_reset(struct rmi_transport_dev *xport, u16 reset_addr)
258 {
259         struct rmi_smb_xport *rmi_smb =
260                 container_of(xport, struct rmi_smb_xport, xport);
261
262         rmi_smb_clear_state(rmi_smb);
263
264         /*
265          * we do not call the actual reset command, it has to be handled in
266          * PS/2 or there will be races between PS/2 and SMBus.
267          * PS/2 should ensure that a psmouse_reset is called before
268          * intializing the device and after it has been removed to be in a known
269          * state.
270          */
271         return rmi_smb_enable_smbus_mode(rmi_smb);
272 }
273
274 static const struct rmi_transport_ops rmi_smb_ops = {
275         .write_block    = rmi_smb_write_block,
276         .read_block     = rmi_smb_read_block,
277         .reset          = rmi_smb_reset,
278 };
279
280 static int rmi_smb_probe(struct i2c_client *client,
281                          const struct i2c_device_id *id)
282 {
283         struct rmi_device_platform_data *pdata = dev_get_platdata(&client->dev);
284         struct rmi_smb_xport *rmi_smb;
285         int retval;
286         int smbus_version;
287
288         if (!i2c_check_functionality(client->adapter,
289                                      I2C_FUNC_SMBUS_READ_BLOCK_DATA |
290                                      I2C_FUNC_SMBUS_HOST_NOTIFY)) {
291                 dev_err(&client->dev,
292                         "adapter does not support required functionality.\n");
293                 return -ENODEV;
294         }
295
296         if (client->irq <= 0) {
297                 dev_err(&client->dev, "no IRQ provided, giving up.\n");
298                 return client->irq ? client->irq : -ENODEV;
299         }
300
301         rmi_smb = devm_kzalloc(&client->dev, sizeof(struct rmi_smb_xport),
302                                 GFP_KERNEL);
303         if (!rmi_smb)
304                 return -ENOMEM;
305
306         if (!pdata) {
307                 dev_err(&client->dev, "no platform data, aborting\n");
308                 return -ENOMEM;
309         }
310
311         rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Probing %s.\n",
312                 dev_name(&client->dev));
313
314         rmi_smb->client = client;
315         mutex_init(&rmi_smb->page_mutex);
316         mutex_init(&rmi_smb->mappingtable_mutex);
317
318         rmi_smb->xport.dev = &client->dev;
319         rmi_smb->xport.pdata = *pdata;
320         rmi_smb->xport.pdata.irq = client->irq;
321         rmi_smb->xport.proto_name = "smb2";
322         rmi_smb->xport.ops = &rmi_smb_ops;
323
324         retval = rmi_smb_get_version(rmi_smb);
325         if (retval < 0)
326                 return retval;
327
328         smbus_version = retval;
329         rmi_dbg(RMI_DEBUG_XPORT, &client->dev, "Smbus version is %d",
330                 smbus_version);
331
332         if (smbus_version != 2) {
333                 dev_err(&client->dev, "Unrecognized SMB version %d.\n",
334                                 smbus_version);
335                 return -ENODEV;
336         }
337
338         i2c_set_clientdata(client, rmi_smb);
339
340         retval = rmi_register_transport_device(&rmi_smb->xport);
341         if (retval) {
342                 dev_err(&client->dev, "Failed to register transport driver at 0x%.2X.\n",
343                         client->addr);
344                 i2c_set_clientdata(client, NULL);
345                 return retval;
346         }
347
348         dev_info(&client->dev, "registered rmi smb driver at %#04x.\n",
349                         client->addr);
350         return 0;
351
352 }
353
354 static int rmi_smb_remove(struct i2c_client *client)
355 {
356         struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
357
358         rmi_unregister_transport_device(&rmi_smb->xport);
359
360         return 0;
361 }
362
363 static int __maybe_unused rmi_smb_suspend(struct device *dev)
364 {
365         struct i2c_client *client = to_i2c_client(dev);
366         struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
367         int ret;
368
369         ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, true);
370         if (ret)
371                 dev_warn(dev, "Failed to suspend device: %d\n", ret);
372
373         return ret;
374 }
375
376 static int __maybe_unused rmi_smb_runtime_suspend(struct device *dev)
377 {
378         struct i2c_client *client = to_i2c_client(dev);
379         struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
380         int ret;
381
382         ret = rmi_driver_suspend(rmi_smb->xport.rmi_dev, false);
383         if (ret)
384                 dev_warn(dev, "Failed to suspend device: %d\n", ret);
385
386         return ret;
387 }
388
389 static int __maybe_unused rmi_smb_resume(struct device *dev)
390 {
391         struct i2c_client *client = container_of(dev, struct i2c_client, dev);
392         struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
393         struct rmi_device *rmi_dev = rmi_smb->xport.rmi_dev;
394         int ret;
395
396         rmi_smb_reset(&rmi_smb->xport, 0);
397
398         rmi_reset(rmi_dev);
399
400         ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, true);
401         if (ret)
402                 dev_warn(dev, "Failed to resume device: %d\n", ret);
403
404         return 0;
405 }
406
407 static int __maybe_unused rmi_smb_runtime_resume(struct device *dev)
408 {
409         struct i2c_client *client = to_i2c_client(dev);
410         struct rmi_smb_xport *rmi_smb = i2c_get_clientdata(client);
411         int ret;
412
413         ret = rmi_driver_resume(rmi_smb->xport.rmi_dev, false);
414         if (ret)
415                 dev_warn(dev, "Failed to resume device: %d\n", ret);
416
417         return 0;
418 }
419
420 static const struct dev_pm_ops rmi_smb_pm = {
421         SET_SYSTEM_SLEEP_PM_OPS(rmi_smb_suspend, rmi_smb_resume)
422         SET_RUNTIME_PM_OPS(rmi_smb_runtime_suspend, rmi_smb_runtime_resume,
423                            NULL)
424 };
425
426 static const struct i2c_device_id rmi_id[] = {
427         { "rmi4_smbus", 0 },
428         { }
429 };
430 MODULE_DEVICE_TABLE(i2c, rmi_id);
431
432 static struct i2c_driver rmi_smb_driver = {
433         .driver = {
434                 .name   = "rmi4_smbus",
435                 .pm     = &rmi_smb_pm,
436         },
437         .id_table       = rmi_id,
438         .probe          = rmi_smb_probe,
439         .remove         = rmi_smb_remove,
440 };
441
442 module_i2c_driver(rmi_smb_driver);
443
444 MODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>");
445 MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
446 MODULE_DESCRIPTION("RMI4 SMBus driver");
447 MODULE_LICENSE("GPL");