]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/staging/nvec/nvec.c
8e97e2d7ac3d193e86ad7a38c5c74610f2f3d21b
[karo-tx-linux.git] / drivers / staging / nvec / nvec.c
1 /*
2  * NVEC: NVIDIA compliant embedded controller interface
3  *
4  * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
5  *
6  * Authors:  Pierre-Hugues Husson <phhusson@free.fr>
7  *           Ilya Petrov <ilya.muromec@gmail.com>
8  *           Marc Dietrich <marvin24@gmx.de>
9  *
10  * This file is subject to the terms and conditions of the GNU General Public
11  * License.  See the file "COPYING" in the main directory of this archive
12  * for more details.
13  *
14  */
15
16 /* #define DEBUG */
17
18 #include <asm/irq.h>
19
20 #include <linux/atomic.h>
21 #include <linux/completion.h>
22 #include <linux/interrupt.h>
23 #include <linux/io.h>
24 #include <linux/irq.h>
25 #include <linux/slab.h>
26 #include <linux/gpio.h>
27 #include <linux/serio.h>
28 #include <linux/delay.h>
29 #include <linux/input.h>
30 #include <linux/workqueue.h>
31 #include <linux/clk.h>
32
33 #include <linux/semaphore.h>
34 #include <linux/list.h>
35 #include <linux/notifier.h>
36 #include <linux/platform_device.h>
37 #include <linux/mfd/core.h>
38
39 #include <mach/iomap.h>
40 #include <mach/clk.h>
41
42 #include "nvec.h"
43
44 static const unsigned char EC_DISABLE_EVENT_REPORTING[3] = "\x04\x00\x00";
45 static const unsigned char EC_ENABLE_EVENT_REPORTING[3]  = "\x04\x00\x01";
46 static const unsigned char EC_GET_FIRMWARE_VERSION[2]    = "\x07\x15";
47
48 static struct nvec_chip *nvec_power_handle;
49
50 static struct mfd_cell nvec_devices[] = {
51         {
52                 .name = "nvec-kbd",
53                 .id = 1,
54         },
55         {
56                 .name = "nvec-mouse",
57                 .id = 1,
58         },
59         {
60                 .name = "nvec-power",
61                 .id = 1,
62         },
63         {
64                 .name = "nvec-power",
65                 .id = 2,
66         },
67         {
68                 .name = "nvec-leds",
69                 .id = 1,
70         },
71 };
72
73 int nvec_register_notifier(struct nvec_chip *nvec, struct notifier_block *nb,
74                            unsigned int events)
75 {
76         return atomic_notifier_chain_register(&nvec->notifier_list, nb);
77 }
78 EXPORT_SYMBOL_GPL(nvec_register_notifier);
79
80 static int nvec_status_notifier(struct notifier_block *nb,
81                                 unsigned long event_type, void *data)
82 {
83         unsigned char *msg = (unsigned char *)data;
84
85         if (event_type != NVEC_CNTL)
86                 return NOTIFY_DONE;
87
88         printk(KERN_WARNING "unhandled msg type %ld\n", event_type);
89         print_hex_dump(KERN_WARNING, "payload: ", DUMP_PREFIX_NONE, 16, 1,
90                 msg, msg[1] + 2, true);
91
92         return NOTIFY_OK;
93 }
94
95 static struct nvec_msg *nvec_msg_alloc(struct nvec_chip *nvec)
96 {
97         int i;
98
99         for (i = 0; i < NVEC_POOL_SIZE; i++) {
100                 if (atomic_xchg(&nvec->msg_pool[i].used, 1) == 0) {
101                         dev_vdbg(nvec->dev, "INFO: Allocate %i\n", i);
102                         return &nvec->msg_pool[i];
103                 }
104         }
105
106         dev_err(nvec->dev, "could not allocate buffer\n");
107
108         return NULL;
109 }
110
111 static void nvec_msg_free(struct nvec_chip *nvec, struct nvec_msg *msg)
112 {
113         dev_vdbg(nvec->dev, "INFO: Free %ti\n", msg - nvec->msg_pool);
114         atomic_set(&msg->used, 0);
115 }
116
117 /**
118  * nvec_msg_is_event - Return %true if @msg is an event
119  * @msg: A message
120  */
121 static bool nvec_msg_is_event(struct nvec_msg *msg)
122 {
123         return msg->data[0] >> 7;
124 }
125
126 /**
127  * nvec_msg_size - Get the size of a message
128  * @msg: The message to get the size for
129  *
130  * This only works for received messages, not for outgoing messages.
131  */
132 static size_t nvec_msg_size(struct nvec_msg *msg)
133 {
134         bool is_event = nvec_msg_is_event(msg);
135         int event_length = (msg->data[0] & 0x60) >> 5;
136
137         /* for variable size, payload size in byte 1 + count (1) + cmd (1) */
138         if (!is_event || event_length == NVEC_VAR_SIZE)
139                 return (msg->pos || msg->size) ? (msg->data[1] + 2) : 0;
140         else if (event_length == NVEC_2BYTES)
141                 return 2;
142         else if (event_length == NVEC_3BYTES)
143                 return 3;
144         else
145                 return 0;
146 }
147
148 static void nvec_gpio_set_value(struct nvec_chip *nvec, int value)
149 {
150         dev_dbg(nvec->dev, "GPIO changed from %u to %u\n",
151                 gpio_get_value(nvec->gpio), value);
152         gpio_set_value(nvec->gpio, value);
153 }
154
155 void nvec_write_async(struct nvec_chip *nvec, const unsigned char *data,
156                         short size)
157 {
158         struct nvec_msg *msg = kzalloc(sizeof(struct nvec_msg), GFP_NOWAIT);
159
160         msg->data = kzalloc(size, GFP_NOWAIT);
161         msg->data[0] = size;
162         memcpy(msg->data + 1, data, size);
163         msg->size = size + 1;
164         msg->pos = 0;
165         INIT_LIST_HEAD(&msg->node);
166
167         list_add_tail(&msg->node, &nvec->tx_data);
168
169         gpio_set_value(nvec->gpio, 0);
170 }
171 EXPORT_SYMBOL(nvec_write_async);
172
173 static void nvec_request_master(struct work_struct *work)
174 {
175         struct nvec_chip *nvec = container_of(work, struct nvec_chip, tx_work);
176
177         if (!list_empty(&nvec->tx_data))
178                 gpio_set_value(nvec->gpio, 0);
179 }
180
181 static int parse_msg(struct nvec_chip *nvec, struct nvec_msg *msg)
182 {
183         if ((msg->data[0] & 1 << 7) == 0 && msg->data[3]) {
184                 dev_err(nvec->dev, "ec responded %02x %02x %02x %02x\n",
185                         msg->data[0], msg->data[1], msg->data[2], msg->data[3]);
186                 return -EINVAL;
187         }
188
189         if ((msg->data[0] >> 7) == 1 && (msg->data[0] & 0x0f) == 5)
190                 print_hex_dump(KERN_WARNING, "ec system event ",
191                                 DUMP_PREFIX_NONE, 16, 1, msg->data,
192                                 msg->data[1] + 2, true);
193
194         atomic_notifier_call_chain(&nvec->notifier_list, msg->data[0] & 0x8f,
195                                    msg->data);
196
197         return 0;
198 }
199
200 static struct nvec_msg *nvec_write_sync(struct nvec_chip *nvec,
201                                         const unsigned char *data, short size)
202 {
203         down(&nvec->sync_write_mutex);
204
205         nvec->sync_write_pending = (data[1] << 8) + data[0];
206         nvec_write_async(nvec, data, size);
207
208         dev_dbg(nvec->dev, "nvec_sync_write: 0x%04x\n",
209                 nvec->sync_write_pending);
210         wait_for_completion(&nvec->sync_write);
211         dev_dbg(nvec->dev, "nvec_sync_write: pong!\n");
212
213         up(&nvec->sync_write_mutex);
214
215         return nvec->last_sync_msg;
216 }
217
218 /* RX worker */
219 static void nvec_dispatch(struct work_struct *work)
220 {
221         struct nvec_chip *nvec = container_of(work, struct nvec_chip, rx_work);
222         struct nvec_msg *msg;
223
224         while (!list_empty(&nvec->rx_data)) {
225                 msg = list_first_entry(&nvec->rx_data, struct nvec_msg, node);
226                 list_del_init(&msg->node);
227
228                 if (nvec->sync_write_pending ==
229                     (msg->data[2] << 8) + msg->data[0]) {
230                         dev_dbg(nvec->dev, "sync write completed!\n");
231                         nvec->sync_write_pending = 0;
232                         nvec->last_sync_msg = msg;
233                         complete(&nvec->sync_write);
234                 } else {
235                         parse_msg(nvec, msg);
236                         if ((!msg) || (!msg->data))
237                                 dev_warn(nvec->dev,
238                                         "attempt access zero pointer\n");
239                         else {
240                                 kfree(msg->data);
241                                 kfree(msg);
242                         }
243                 }
244         }
245 }
246
247 static irqreturn_t nvec_interrupt(int irq, void *dev)
248 {
249         unsigned long status;
250         unsigned long received;
251         unsigned char to_send;
252         struct nvec_msg *msg;
253         struct nvec_chip *nvec = (struct nvec_chip *)dev;
254         void __iomem *base = nvec->base;
255
256         status = readl(base + I2C_SL_STATUS);
257
258         if (!(status & I2C_SL_IRQ)) {
259                 dev_warn(nvec->dev, "nvec Spurious IRQ\n");
260                 goto handled;
261         }
262         if (status & END_TRANS && !(status & RCVD)) {
263                 nvec->state = NVEC_WAIT;
264                 if (nvec->rx->size > 1) {
265                         list_add_tail(&nvec->rx->node, &nvec->rx_data);
266                         schedule_work(&nvec->rx_work);
267                 } else {
268                         kfree(nvec->rx->data);
269                         kfree(nvec->rx);
270                 }
271                 return IRQ_HANDLED;
272         } else if (status & RNW) {
273                 if (status & RCVD)
274                         udelay(3);
275
276                 if (status & RCVD)
277                         nvec->state = NVEC_WRITE;
278
279                 if (list_empty(&nvec->tx_data)) {
280                         dev_err(nvec->dev, "nvec empty tx - sending no-op\n");
281                         to_send = 0x8a;
282                         nvec_write_async(nvec, "\x07\x02", 2);
283                 } else {
284                         msg =
285                             list_first_entry(&nvec->tx_data, struct nvec_msg,
286                                              node);
287                         if (msg->pos < msg->size) {
288                                 to_send = msg->data[msg->pos];
289                                 msg->pos++;
290                         } else {
291                                 dev_err(nvec->dev, "nvec crap! %d\n",
292                                         msg->size);
293                                 to_send = 0x01;
294                         }
295
296                         if (msg->pos >= msg->size) {
297                                 list_del_init(&msg->node);
298                                 kfree(msg->data);
299                                 kfree(msg);
300                                 schedule_work(&nvec->tx_work);
301                                 nvec->state = NVEC_WAIT;
302                         }
303                 }
304                 writel(to_send, base + I2C_SL_RCVD);
305
306                 gpio_set_value(nvec->gpio, 1);
307
308                 dev_dbg(nvec->dev, "nvec sent %x\n", to_send);
309
310                 goto handled;
311         } else {
312                 received = readl(base + I2C_SL_RCVD);
313
314                 if (status & RCVD) {
315                         writel(0, base + I2C_SL_RCVD);
316                         goto handled;
317                 }
318
319                 if (nvec->state == NVEC_WAIT) {
320                         nvec->state = NVEC_READ;
321                         msg = kzalloc(sizeof(struct nvec_msg), GFP_NOWAIT);
322                         msg->data = kzalloc(32, GFP_NOWAIT);
323                         INIT_LIST_HEAD(&msg->node);
324                         nvec->rx = msg;
325                 } else
326                         msg = nvec->rx;
327
328                 BUG_ON(msg->pos > 32);
329
330                 msg->data[msg->pos] = received;
331                 msg->pos++;
332                 msg->size = msg->pos;
333                 dev_dbg(nvec->dev, "Got %02lx from Master (pos: %d)!\n",
334                         received, msg->pos);
335         }
336 handled:
337         return IRQ_HANDLED;
338 }
339
340 static void tegra_init_i2c_slave(struct nvec_chip *nvec)
341 {
342         u32 val;
343
344         clk_enable(nvec->i2c_clk);
345
346         tegra_periph_reset_assert(nvec->i2c_clk);
347         udelay(2);
348         tegra_periph_reset_deassert(nvec->i2c_clk);
349
350         val = I2C_CNFG_NEW_MASTER_SFM | I2C_CNFG_PACKET_MODE_EN |
351             (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
352         writel(val, nvec->base + I2C_CNFG);
353
354         clk_set_rate(nvec->i2c_clk, 8 * 80000);
355
356         writel(I2C_SL_NEWL, nvec->base + I2C_SL_CNFG);
357         writel(0x1E, nvec->base + I2C_SL_DELAY_COUNT);
358
359         writel(nvec->i2c_addr>>1, nvec->base + I2C_SL_ADDR1);
360         writel(0, nvec->base + I2C_SL_ADDR2);
361
362         enable_irq(nvec->irq);
363
364         clk_disable(nvec->i2c_clk);
365 }
366
367 static void nvec_disable_i2c_slave(struct nvec_chip *nvec)
368 {
369         disable_irq(nvec->irq);
370         writel(I2C_SL_NEWL | I2C_SL_NACK, nvec->base + I2C_SL_CNFG);
371         clk_disable(nvec->i2c_clk);
372 }
373
374 static void nvec_power_off(void)
375 {
376         nvec_write_async(nvec_power_handle, EC_DISABLE_EVENT_REPORTING, 3);
377         nvec_write_async(nvec_power_handle, "\x04\x01", 2);
378 }
379
380 static int __devinit tegra_nvec_probe(struct platform_device *pdev)
381 {
382         int err, ret;
383         struct clk *i2c_clk;
384         struct nvec_platform_data *pdata = pdev->dev.platform_data;
385         struct nvec_chip *nvec;
386         struct nvec_msg *msg;
387         struct resource *res;
388         struct resource *iomem;
389         void __iomem *base;
390
391         nvec = kzalloc(sizeof(struct nvec_chip), GFP_KERNEL);
392         if (nvec == NULL) {
393                 dev_err(&pdev->dev, "failed to reserve memory\n");
394                 return -ENOMEM;
395         }
396         platform_set_drvdata(pdev, nvec);
397         nvec->dev = &pdev->dev;
398         nvec->gpio = pdata->gpio;
399         nvec->i2c_addr = pdata->i2c_addr;
400
401         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
402         if (!res) {
403                 dev_err(&pdev->dev, "no mem resource?\n");
404                 return -ENODEV;
405         }
406
407         iomem = request_mem_region(res->start, resource_size(res), pdev->name);
408         if (!iomem) {
409                 dev_err(&pdev->dev, "I2C region already claimed\n");
410                 return -EBUSY;
411         }
412
413         base = ioremap(iomem->start, resource_size(iomem));
414         if (!base) {
415                 dev_err(&pdev->dev, "Can't ioremap I2C region\n");
416                 return -ENOMEM;
417         }
418
419         res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
420         if (!res) {
421                 dev_err(&pdev->dev, "no irq resource?\n");
422                 ret = -ENODEV;
423                 goto err_iounmap;
424         }
425
426         i2c_clk = clk_get_sys("tegra-i2c.2", NULL);
427         if (IS_ERR(i2c_clk)) {
428                 dev_err(nvec->dev, "failed to get controller clock\n");
429                 goto err_iounmap;
430         }
431
432         nvec->base = base;
433         nvec->irq = res->start;
434         nvec->i2c_clk = i2c_clk;
435
436         /* Set the gpio to low when we've got something to say */
437         err = gpio_request(nvec->gpio, "nvec gpio");
438         if (err < 0)
439                 dev_err(nvec->dev, "couldn't request gpio\n");
440
441         ATOMIC_INIT_NOTIFIER_HEAD(&nvec->notifier_list);
442
443         init_completion(&nvec->sync_write);
444         sema_init(&nvec->sync_write_mutex, 1);
445         INIT_LIST_HEAD(&nvec->tx_data);
446         INIT_LIST_HEAD(&nvec->rx_data);
447         INIT_WORK(&nvec->rx_work, nvec_dispatch);
448         INIT_WORK(&nvec->tx_work, nvec_request_master);
449
450         err = request_irq(nvec->irq, nvec_interrupt, 0, "nvec", nvec);
451         if (err) {
452                 dev_err(nvec->dev, "couldn't request irq\n");
453                 goto failed;
454         }
455         disable_irq(nvec->irq);
456
457         tegra_init_i2c_slave(nvec);
458
459         clk_enable(i2c_clk);
460
461         gpio_direction_output(nvec->gpio, 1);
462         gpio_set_value(nvec->gpio, 1);
463
464         /* enable event reporting */
465         nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING,
466                          sizeof(EC_ENABLE_EVENT_REPORTING));
467
468         nvec->nvec_status_notifier.notifier_call = nvec_status_notifier;
469         nvec_register_notifier(nvec, &nvec->nvec_status_notifier, 0);
470
471         nvec_power_handle = nvec;
472         pm_power_off = nvec_power_off;
473
474         /* Get Firmware Version */
475         msg = nvec_write_sync(nvec, EC_GET_FIRMWARE_VERSION,
476                               sizeof(EC_GET_FIRMWARE_VERSION));
477
478         dev_warn(nvec->dev, "ec firmware version %02x.%02x.%02x / %02x\n",
479                  msg->data[4], msg->data[5], msg->data[6], msg->data[7]);
480
481         kfree(msg->data);
482         kfree(msg);
483
484         ret = mfd_add_devices(nvec->dev, -1, nvec_devices,
485                               ARRAY_SIZE(nvec_devices), base, 0);
486         if (ret)
487                 dev_err(nvec->dev, "error adding subdevices\n");
488
489         /* unmute speakers? */
490         nvec_write_async(nvec, "\x0d\x10\x59\x95", 4);
491
492         /* enable lid switch event */
493         nvec_write_async(nvec, "\x01\x01\x01\x00\x00\x02\x00", 7);
494
495         /* enable power button event */
496         nvec_write_async(nvec, "\x01\x01\x01\x00\x00\x80\x00", 7);
497
498         return 0;
499
500 err_iounmap:
501         iounmap(base);
502 failed:
503         kfree(nvec);
504         return -ENOMEM;
505 }
506
507 static int __devexit tegra_nvec_remove(struct platform_device *pdev)
508 {
509         struct nvec_chip *nvec = platform_get_drvdata(pdev);
510
511         nvec_write_async(nvec, EC_DISABLE_EVENT_REPORTING, 3);
512         mfd_remove_devices(nvec->dev);
513         free_irq(nvec->irq, &nvec_interrupt);
514         iounmap(nvec->base);
515         gpio_free(nvec->gpio);
516         kfree(nvec);
517
518         return 0;
519 }
520
521 #ifdef CONFIG_PM
522
523 static int tegra_nvec_suspend(struct platform_device *pdev, pm_message_t state)
524 {
525         struct nvec_chip *nvec = platform_get_drvdata(pdev);
526
527         dev_dbg(nvec->dev, "suspending\n");
528         nvec_write_async(nvec, EC_DISABLE_EVENT_REPORTING, 3);
529         nvec_write_async(nvec, "\x04\x02", 2);
530         nvec_disable_i2c_slave(nvec);
531
532         return 0;
533 }
534
535 static int tegra_nvec_resume(struct platform_device *pdev)
536 {
537         struct nvec_chip *nvec = platform_get_drvdata(pdev);
538
539         dev_dbg(nvec->dev, "resuming\n");
540         tegra_init_i2c_slave(nvec);
541         nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING, 3);
542
543         return 0;
544 }
545
546 #else
547 #define tegra_nvec_suspend NULL
548 #define tegra_nvec_resume NULL
549 #endif
550
551 static struct platform_driver nvec_device_driver = {
552         .probe   = tegra_nvec_probe,
553         .remove  = __devexit_p(tegra_nvec_remove),
554         .suspend = tegra_nvec_suspend,
555         .resume  = tegra_nvec_resume,
556         .driver  = {
557                 .name = "nvec",
558                 .owner = THIS_MODULE,
559         }
560 };
561
562 static int __init tegra_nvec_init(void)
563 {
564         return platform_driver_register(&nvec_device_driver);
565 }
566
567 module_init(tegra_nvec_init);
568
569 MODULE_ALIAS("platform:nvec");
570 MODULE_DESCRIPTION("NVIDIA compliant embedded controller interface");
571 MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>");
572 MODULE_LICENSE("GPL");