xref: /openbmc/linux/drivers/staging/nvec/nvec.c (revision e7c40851)
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 static void nvec_gpio_set_value(struct nvec_chip *nvec, int value)
118 {
119 	dev_dbg(nvec->dev, "GPIO changed from %u to %u\n",
120 		gpio_get_value(nvec->gpio), value);
121 	gpio_set_value(nvec->gpio, value);
122 }
123 
124 void nvec_write_async(struct nvec_chip *nvec, const unsigned char *data,
125 			short size)
126 {
127 	struct nvec_msg *msg = kzalloc(sizeof(struct nvec_msg), GFP_NOWAIT);
128 
129 	msg->data = kzalloc(size, GFP_NOWAIT);
130 	msg->data[0] = size;
131 	memcpy(msg->data + 1, data, size);
132 	msg->size = size + 1;
133 	msg->pos = 0;
134 	INIT_LIST_HEAD(&msg->node);
135 
136 	list_add_tail(&msg->node, &nvec->tx_data);
137 
138 	gpio_set_value(nvec->gpio, 0);
139 }
140 EXPORT_SYMBOL(nvec_write_async);
141 
142 static void nvec_request_master(struct work_struct *work)
143 {
144 	struct nvec_chip *nvec = container_of(work, struct nvec_chip, tx_work);
145 
146 	if (!list_empty(&nvec->tx_data))
147 		gpio_set_value(nvec->gpio, 0);
148 }
149 
150 static int parse_msg(struct nvec_chip *nvec, struct nvec_msg *msg)
151 {
152 	if ((msg->data[0] & 1 << 7) == 0 && msg->data[3]) {
153 		dev_err(nvec->dev, "ec responded %02x %02x %02x %02x\n",
154 			msg->data[0], msg->data[1], msg->data[2], msg->data[3]);
155 		return -EINVAL;
156 	}
157 
158 	if ((msg->data[0] >> 7) == 1 && (msg->data[0] & 0x0f) == 5)
159 		print_hex_dump(KERN_WARNING, "ec system event ",
160 				DUMP_PREFIX_NONE, 16, 1, msg->data,
161 				msg->data[1] + 2, true);
162 
163 	atomic_notifier_call_chain(&nvec->notifier_list, msg->data[0] & 0x8f,
164 				   msg->data);
165 
166 	return 0;
167 }
168 
169 static struct nvec_msg *nvec_write_sync(struct nvec_chip *nvec,
170 					const unsigned char *data, short size)
171 {
172 	down(&nvec->sync_write_mutex);
173 
174 	nvec->sync_write_pending = (data[1] << 8) + data[0];
175 	nvec_write_async(nvec, data, size);
176 
177 	dev_dbg(nvec->dev, "nvec_sync_write: 0x%04x\n",
178 		nvec->sync_write_pending);
179 	wait_for_completion(&nvec->sync_write);
180 	dev_dbg(nvec->dev, "nvec_sync_write: pong!\n");
181 
182 	up(&nvec->sync_write_mutex);
183 
184 	return nvec->last_sync_msg;
185 }
186 
187 /* RX worker */
188 static void nvec_dispatch(struct work_struct *work)
189 {
190 	struct nvec_chip *nvec = container_of(work, struct nvec_chip, rx_work);
191 	struct nvec_msg *msg;
192 
193 	while (!list_empty(&nvec->rx_data)) {
194 		msg = list_first_entry(&nvec->rx_data, struct nvec_msg, node);
195 		list_del_init(&msg->node);
196 
197 		if (nvec->sync_write_pending ==
198 		    (msg->data[2] << 8) + msg->data[0]) {
199 			dev_dbg(nvec->dev, "sync write completed!\n");
200 			nvec->sync_write_pending = 0;
201 			nvec->last_sync_msg = msg;
202 			complete(&nvec->sync_write);
203 		} else {
204 			parse_msg(nvec, msg);
205 			if ((!msg) || (!msg->data))
206 				dev_warn(nvec->dev,
207 					"attempt access zero pointer\n");
208 			else {
209 				kfree(msg->data);
210 				kfree(msg);
211 			}
212 		}
213 	}
214 }
215 
216 static irqreturn_t nvec_interrupt(int irq, void *dev)
217 {
218 	unsigned long status;
219 	unsigned long received;
220 	unsigned char to_send;
221 	struct nvec_msg *msg;
222 	struct nvec_chip *nvec = (struct nvec_chip *)dev;
223 	void __iomem *base = nvec->base;
224 
225 	status = readl(base + I2C_SL_STATUS);
226 
227 	if (!(status & I2C_SL_IRQ)) {
228 		dev_warn(nvec->dev, "nvec Spurious IRQ\n");
229 		goto handled;
230 	}
231 	if (status & END_TRANS && !(status & RCVD)) {
232 		nvec->state = NVEC_WAIT;
233 		if (nvec->rx->size > 1) {
234 			list_add_tail(&nvec->rx->node, &nvec->rx_data);
235 			schedule_work(&nvec->rx_work);
236 		} else {
237 			kfree(nvec->rx->data);
238 			kfree(nvec->rx);
239 		}
240 		return IRQ_HANDLED;
241 	} else if (status & RNW) {
242 		if (status & RCVD)
243 			udelay(3);
244 
245 		if (status & RCVD)
246 			nvec->state = NVEC_WRITE;
247 
248 		if (list_empty(&nvec->tx_data)) {
249 			dev_err(nvec->dev, "nvec empty tx - sending no-op\n");
250 			to_send = 0x8a;
251 			nvec_write_async(nvec, "\x07\x02", 2);
252 		} else {
253 			msg =
254 			    list_first_entry(&nvec->tx_data, struct nvec_msg,
255 					     node);
256 			if (msg->pos < msg->size) {
257 				to_send = msg->data[msg->pos];
258 				msg->pos++;
259 			} else {
260 				dev_err(nvec->dev, "nvec crap! %d\n",
261 					msg->size);
262 				to_send = 0x01;
263 			}
264 
265 			if (msg->pos >= msg->size) {
266 				list_del_init(&msg->node);
267 				kfree(msg->data);
268 				kfree(msg);
269 				schedule_work(&nvec->tx_work);
270 				nvec->state = NVEC_WAIT;
271 			}
272 		}
273 		writel(to_send, base + I2C_SL_RCVD);
274 
275 		gpio_set_value(nvec->gpio, 1);
276 
277 		dev_dbg(nvec->dev, "nvec sent %x\n", to_send);
278 
279 		goto handled;
280 	} else {
281 		received = readl(base + I2C_SL_RCVD);
282 
283 		if (status & RCVD) {
284 			writel(0, base + I2C_SL_RCVD);
285 			goto handled;
286 		}
287 
288 		if (nvec->state == NVEC_WAIT) {
289 			nvec->state = NVEC_READ;
290 			msg = kzalloc(sizeof(struct nvec_msg), GFP_NOWAIT);
291 			msg->data = kzalloc(32, GFP_NOWAIT);
292 			INIT_LIST_HEAD(&msg->node);
293 			nvec->rx = msg;
294 		} else
295 			msg = nvec->rx;
296 
297 		BUG_ON(msg->pos > 32);
298 
299 		msg->data[msg->pos] = received;
300 		msg->pos++;
301 		msg->size = msg->pos;
302 		dev_dbg(nvec->dev, "Got %02lx from Master (pos: %d)!\n",
303 			received, msg->pos);
304 	}
305 handled:
306 	return IRQ_HANDLED;
307 }
308 
309 static void tegra_init_i2c_slave(struct nvec_chip *nvec)
310 {
311 	u32 val;
312 
313 	clk_enable(nvec->i2c_clk);
314 
315 	tegra_periph_reset_assert(nvec->i2c_clk);
316 	udelay(2);
317 	tegra_periph_reset_deassert(nvec->i2c_clk);
318 
319 	val = I2C_CNFG_NEW_MASTER_SFM | I2C_CNFG_PACKET_MODE_EN |
320 	    (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
321 	writel(val, nvec->base + I2C_CNFG);
322 
323 	clk_set_rate(nvec->i2c_clk, 8 * 80000);
324 
325 	writel(I2C_SL_NEWL, nvec->base + I2C_SL_CNFG);
326 	writel(0x1E, nvec->base + I2C_SL_DELAY_COUNT);
327 
328 	writel(nvec->i2c_addr>>1, nvec->base + I2C_SL_ADDR1);
329 	writel(0, nvec->base + I2C_SL_ADDR2);
330 
331 	enable_irq(nvec->irq);
332 
333 	clk_disable(nvec->i2c_clk);
334 }
335 
336 static void nvec_disable_i2c_slave(struct nvec_chip *nvec)
337 {
338 	disable_irq(nvec->irq);
339 	writel(I2C_SL_NEWL | I2C_SL_NACK, nvec->base + I2C_SL_CNFG);
340 	clk_disable(nvec->i2c_clk);
341 }
342 
343 static void nvec_power_off(void)
344 {
345 	nvec_write_async(nvec_power_handle, EC_DISABLE_EVENT_REPORTING, 3);
346 	nvec_write_async(nvec_power_handle, "\x04\x01", 2);
347 }
348 
349 static int __devinit tegra_nvec_probe(struct platform_device *pdev)
350 {
351 	int err, ret;
352 	struct clk *i2c_clk;
353 	struct nvec_platform_data *pdata = pdev->dev.platform_data;
354 	struct nvec_chip *nvec;
355 	struct nvec_msg *msg;
356 	struct resource *res;
357 	struct resource *iomem;
358 	void __iomem *base;
359 
360 	nvec = kzalloc(sizeof(struct nvec_chip), GFP_KERNEL);
361 	if (nvec == NULL) {
362 		dev_err(&pdev->dev, "failed to reserve memory\n");
363 		return -ENOMEM;
364 	}
365 	platform_set_drvdata(pdev, nvec);
366 	nvec->dev = &pdev->dev;
367 	nvec->gpio = pdata->gpio;
368 	nvec->i2c_addr = pdata->i2c_addr;
369 
370 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
371 	if (!res) {
372 		dev_err(&pdev->dev, "no mem resource?\n");
373 		return -ENODEV;
374 	}
375 
376 	iomem = request_mem_region(res->start, resource_size(res), pdev->name);
377 	if (!iomem) {
378 		dev_err(&pdev->dev, "I2C region already claimed\n");
379 		return -EBUSY;
380 	}
381 
382 	base = ioremap(iomem->start, resource_size(iomem));
383 	if (!base) {
384 		dev_err(&pdev->dev, "Can't ioremap I2C region\n");
385 		return -ENOMEM;
386 	}
387 
388 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
389 	if (!res) {
390 		dev_err(&pdev->dev, "no irq resource?\n");
391 		ret = -ENODEV;
392 		goto err_iounmap;
393 	}
394 
395 	i2c_clk = clk_get_sys("tegra-i2c.2", NULL);
396 	if (IS_ERR(i2c_clk)) {
397 		dev_err(nvec->dev, "failed to get controller clock\n");
398 		goto err_iounmap;
399 	}
400 
401 	nvec->base = base;
402 	nvec->irq = res->start;
403 	nvec->i2c_clk = i2c_clk;
404 
405 	/* Set the gpio to low when we've got something to say */
406 	err = gpio_request(nvec->gpio, "nvec gpio");
407 	if (err < 0)
408 		dev_err(nvec->dev, "couldn't request gpio\n");
409 
410 	ATOMIC_INIT_NOTIFIER_HEAD(&nvec->notifier_list);
411 
412 	init_completion(&nvec->sync_write);
413 	sema_init(&nvec->sync_write_mutex, 1);
414 	INIT_LIST_HEAD(&nvec->tx_data);
415 	INIT_LIST_HEAD(&nvec->rx_data);
416 	INIT_WORK(&nvec->rx_work, nvec_dispatch);
417 	INIT_WORK(&nvec->tx_work, nvec_request_master);
418 
419 	err = request_irq(nvec->irq, nvec_interrupt, 0, "nvec", nvec);
420 	if (err) {
421 		dev_err(nvec->dev, "couldn't request irq\n");
422 		goto failed;
423 	}
424 	disable_irq(nvec->irq);
425 
426 	tegra_init_i2c_slave(nvec);
427 
428 	clk_enable(i2c_clk);
429 
430 	gpio_direction_output(nvec->gpio, 1);
431 	gpio_set_value(nvec->gpio, 1);
432 
433 	/* enable event reporting */
434 	nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING,
435 			 sizeof(EC_ENABLE_EVENT_REPORTING));
436 
437 	nvec->nvec_status_notifier.notifier_call = nvec_status_notifier;
438 	nvec_register_notifier(nvec, &nvec->nvec_status_notifier, 0);
439 
440 	nvec_power_handle = nvec;
441 	pm_power_off = nvec_power_off;
442 
443 	/* Get Firmware Version */
444 	msg = nvec_write_sync(nvec, EC_GET_FIRMWARE_VERSION,
445 			      sizeof(EC_GET_FIRMWARE_VERSION));
446 
447 	dev_warn(nvec->dev, "ec firmware version %02x.%02x.%02x / %02x\n",
448 		 msg->data[4], msg->data[5], msg->data[6], msg->data[7]);
449 
450 	kfree(msg->data);
451 	kfree(msg);
452 
453 	ret = mfd_add_devices(nvec->dev, -1, nvec_devices,
454 			      ARRAY_SIZE(nvec_devices), base, 0);
455 	if (ret)
456 		dev_err(nvec->dev, "error adding subdevices\n");
457 
458 	/* unmute speakers? */
459 	nvec_write_async(nvec, "\x0d\x10\x59\x95", 4);
460 
461 	/* enable lid switch event */
462 	nvec_write_async(nvec, "\x01\x01\x01\x00\x00\x02\x00", 7);
463 
464 	/* enable power button event */
465 	nvec_write_async(nvec, "\x01\x01\x01\x00\x00\x80\x00", 7);
466 
467 	return 0;
468 
469 err_iounmap:
470 	iounmap(base);
471 failed:
472 	kfree(nvec);
473 	return -ENOMEM;
474 }
475 
476 static int __devexit tegra_nvec_remove(struct platform_device *pdev)
477 {
478 	struct nvec_chip *nvec = platform_get_drvdata(pdev);
479 
480 	nvec_write_async(nvec, EC_DISABLE_EVENT_REPORTING, 3);
481 	mfd_remove_devices(nvec->dev);
482 	free_irq(nvec->irq, &nvec_interrupt);
483 	iounmap(nvec->base);
484 	gpio_free(nvec->gpio);
485 	kfree(nvec);
486 
487 	return 0;
488 }
489 
490 #ifdef CONFIG_PM
491 
492 static int tegra_nvec_suspend(struct platform_device *pdev, pm_message_t state)
493 {
494 	struct nvec_chip *nvec = platform_get_drvdata(pdev);
495 
496 	dev_dbg(nvec->dev, "suspending\n");
497 	nvec_write_async(nvec, EC_DISABLE_EVENT_REPORTING, 3);
498 	nvec_write_async(nvec, "\x04\x02", 2);
499 	nvec_disable_i2c_slave(nvec);
500 
501 	return 0;
502 }
503 
504 static int tegra_nvec_resume(struct platform_device *pdev)
505 {
506 	struct nvec_chip *nvec = platform_get_drvdata(pdev);
507 
508 	dev_dbg(nvec->dev, "resuming\n");
509 	tegra_init_i2c_slave(nvec);
510 	nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING, 3);
511 
512 	return 0;
513 }
514 
515 #else
516 #define tegra_nvec_suspend NULL
517 #define tegra_nvec_resume NULL
518 #endif
519 
520 static struct platform_driver nvec_device_driver = {
521 	.probe   = tegra_nvec_probe,
522 	.remove  = __devexit_p(tegra_nvec_remove),
523 	.suspend = tegra_nvec_suspend,
524 	.resume  = tegra_nvec_resume,
525 	.driver  = {
526 		.name = "nvec",
527 		.owner = THIS_MODULE,
528 	}
529 };
530 
531 static int __init tegra_nvec_init(void)
532 {
533 	return platform_driver_register(&nvec_device_driver);
534 }
535 
536 module_init(tegra_nvec_init);
537 
538 MODULE_ALIAS("platform:nvec");
539 MODULE_DESCRIPTION("NVIDIA compliant embedded controller interface");
540 MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>");
541 MODULE_LICENSE("GPL");
542