nvec.c 12.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * NVEC: NVIDIA compliant embedded controller interface
 *
 * Copyright (C) 2011 The AC100 Kernel Team <ac100@lists.lauchpad.net>
 *
 * Authors:  Pierre-Hugues Husson <phhusson@free.fr>
 *           Ilya Petrov <ilya.muromec@gmail.com>
 *           Marc Dietrich <marvin24@gmx.de>
 *
 * This file is subject to the terms and conditions of the GNU General Public
 * License.  See the file "COPYING" in the main directory of this archive
 * for more details.
 *
 */

/* #define DEBUG */
17 18

#include <asm/irq.h>
19

20 21
#include <linux/completion.h>
#include <linux/interrupt.h>
22
#include <linux/io.h>
23 24 25 26 27 28 29 30
#include <linux/irq.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/input.h>
#include <linux/workqueue.h>
#include <linux/clk.h>
31

32 33 34 35
#include <linux/semaphore.h>
#include <linux/list.h>
#include <linux/notifier.h>
#include <linux/platform_device.h>
36
#include <linux/mfd/core.h>
37 38 39 40

#include <mach/iomap.h>
#include <mach/clk.h>

41 42
#include "nvec.h"

43 44 45
static const unsigned char EC_DISABLE_EVENT_REPORTING[3] = "\x04\x00\x00";
static const unsigned char EC_ENABLE_EVENT_REPORTING[3]  = "\x04\x00\x01";
static const unsigned char EC_GET_FIRMWARE_VERSION[2]    = "\x07\x15";
46 47 48

static struct nvec_chip *nvec_power_handle;

49 50
static struct mfd_cell nvec_devices[] = {
	{
51 52
		.name = "nvec-kbd",
		.id = 1,
53 54
	},
	{
55 56
		.name = "nvec-mouse",
		.id = 1,
57 58
	},
	{
59 60
		.name = "nvec-power",
		.id = 1,
61 62
	},
	{
63 64
		.name = "nvec-power",
		.id = 2,
65 66 67
	},
};

68
int nvec_register_notifier(struct nvec_chip *nvec, struct notifier_block *nb,
69
			   unsigned int events)
70 71 72 73 74
{
	return atomic_notifier_chain_register(&nvec->notifier_list, nb);
}
EXPORT_SYMBOL_GPL(nvec_register_notifier);

75 76
static int nvec_status_notifier(struct notifier_block *nb,
				unsigned long event_type, void *data)
77 78 79
{
	unsigned char *msg = (unsigned char *)data;

80
	if (event_type != NVEC_CNTL)
81 82
		return NOTIFY_DONE;

83 84 85
	printk(KERN_WARNING "unhandled msg type %ld\n", event_type);
	print_hex_dump(KERN_WARNING, "payload: ", DUMP_PREFIX_NONE, 16, 1,
		msg, msg[1] + 2, true);
86 87 88 89

	return NOTIFY_OK;
}

90 91
void nvec_write_async(struct nvec_chip *nvec, const unsigned char *data,
			short size)
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
{
	struct nvec_msg *msg = kzalloc(sizeof(struct nvec_msg), GFP_NOWAIT);

	msg->data = kzalloc(size, GFP_NOWAIT);
	msg->data[0] = size;
	memcpy(msg->data + 1, data, size);
	msg->size = size + 1;
	msg->pos = 0;
	INIT_LIST_HEAD(&msg->node);

	list_add_tail(&msg->node, &nvec->tx_data);

	gpio_set_value(nvec->gpio, 0);
}
EXPORT_SYMBOL(nvec_write_async);

static void nvec_request_master(struct work_struct *work)
{
	struct nvec_chip *nvec = container_of(work, struct nvec_chip, tx_work);

112
	if (!list_empty(&nvec->tx_data))
113 114 115 116 117
		gpio_set_value(nvec->gpio, 0);
}

static int parse_msg(struct nvec_chip *nvec, struct nvec_msg *msg)
{
118 119 120
	if ((msg->data[0] & 1 << 7) == 0 && msg->data[3]) {
		dev_err(nvec->dev, "ec responded %02x %02x %02x %02x\n",
			msg->data[0], msg->data[1], msg->data[2], msg->data[3]);
121 122 123
		return -EINVAL;
	}

124 125 126 127
	if ((msg->data[0] >> 7) == 1 && (msg->data[0] & 0x0f) == 5)
		print_hex_dump(KERN_WARNING, "ec system event ",
				DUMP_PREFIX_NONE, 16, 1, msg->data,
				msg->data[1] + 2, true);
128

129 130
	atomic_notifier_call_chain(&nvec->notifier_list, msg->data[0] & 0x8f,
				   msg->data);
131 132 133 134

	return 0;
}

135 136
static struct nvec_msg *nvec_write_sync(struct nvec_chip *nvec,
					const unsigned char *data, short size)
137 138 139 140 141 142
{
	down(&nvec->sync_write_mutex);

	nvec->sync_write_pending = (data[1] << 8) + data[0];
	nvec_write_async(nvec, data, size);

143 144
	dev_dbg(nvec->dev, "nvec_sync_write: 0x%04x\n",
		nvec->sync_write_pending);
145 146 147 148 149 150 151 152 153 154 155 156 157 158
	wait_for_completion(&nvec->sync_write);
	dev_dbg(nvec->dev, "nvec_sync_write: pong!\n");

	up(&nvec->sync_write_mutex);

	return nvec->last_sync_msg;
}

/* RX worker */
static void nvec_dispatch(struct work_struct *work)
{
	struct nvec_chip *nvec = container_of(work, struct nvec_chip, rx_work);
	struct nvec_msg *msg;

159
	while (!list_empty(&nvec->rx_data)) {
160 161 162
		msg = list_first_entry(&nvec->rx_data, struct nvec_msg, node);
		list_del_init(&msg->node);

163 164
		if (nvec->sync_write_pending ==
		    (msg->data[2] << 8) + msg->data[0]) {
165 166 167 168 169 170
			dev_dbg(nvec->dev, "sync write completed!\n");
			nvec->sync_write_pending = 0;
			nvec->last_sync_msg = msg;
			complete(&nvec->sync_write);
		} else {
			parse_msg(nvec, msg);
171 172 173
			if ((!msg) || (!msg->data))
				dev_warn(nvec->dev,
					"attempt access zero pointer\n");
174 175 176 177 178 179 180 181
			else {
				kfree(msg->data);
				kfree(msg);
			}
		}
	}
}

182
static irqreturn_t nvec_interrupt(int irq, void *dev)
183 184 185 186 187 188
{
	unsigned long status;
	unsigned long received;
	unsigned char to_send;
	struct nvec_msg *msg;
	struct nvec_chip *nvec = (struct nvec_chip *)dev;
189
	void __iomem *base = nvec->base;
190

191
	status = readl(base + I2C_SL_STATUS);
192

193
	if (!(status & I2C_SL_IRQ)) {
194 195 196
		dev_warn(nvec->dev, "nvec Spurious IRQ\n");
		goto handled;
	}
197
	if (status & END_TRANS && !(status & RCVD)) {
198
		nvec->state = NVEC_WAIT;
199
		if (nvec->rx->size > 1) {
200 201 202 203 204 205 206
			list_add_tail(&nvec->rx->node, &nvec->rx_data);
			schedule_work(&nvec->rx_work);
		} else {
			kfree(nvec->rx->data);
			kfree(nvec->rx);
		}
		return IRQ_HANDLED;
207 208
	} else if (status & RNW) {
		if (status & RCVD)
209 210
			udelay(3);

211
		if (status & RCVD)
212
			nvec->state = NVEC_WRITE;
213 214

		if (list_empty(&nvec->tx_data)) {
215 216 217 218
			dev_err(nvec->dev, "nvec empty tx - sending no-op\n");
			to_send = 0x8a;
			nvec_write_async(nvec, "\x07\x02", 2);
		} else {
219 220 221 222
			msg =
			    list_first_entry(&nvec->tx_data, struct nvec_msg,
					     node);
			if (msg->pos < msg->size) {
223 224 225
				to_send = msg->data[msg->pos];
				msg->pos++;
			} else {
226 227
				dev_err(nvec->dev, "nvec crap! %d\n",
					msg->size);
228 229 230
				to_send = 0x01;
			}

231
			if (msg->pos >= msg->size) {
232 233 234 235 236 237 238
				list_del_init(&msg->node);
				kfree(msg->data);
				kfree(msg);
				schedule_work(&nvec->tx_work);
				nvec->state = NVEC_WAIT;
			}
		}
239
		writel(to_send, base + I2C_SL_RCVD);
240 241 242 243 244 245 246

		gpio_set_value(nvec->gpio, 1);

		dev_dbg(nvec->dev, "nvec sent %x\n", to_send);

		goto handled;
	} else {
247
		received = readl(base + I2C_SL_RCVD);
248 249

		if (status & RCVD) {
250
			writel(0, base + I2C_SL_RCVD);
251 252 253
			goto handled;
		}

254
		if (nvec->state == NVEC_WAIT) {
255 256 257 258 259 260 261 262 263 264 265 266 267
			nvec->state = NVEC_READ;
			msg = kzalloc(sizeof(struct nvec_msg), GFP_NOWAIT);
			msg->data = kzalloc(32, GFP_NOWAIT);
			INIT_LIST_HEAD(&msg->node);
			nvec->rx = msg;
		} else
			msg = nvec->rx;

		BUG_ON(msg->pos > 32);

		msg->data[msg->pos] = received;
		msg->pos++;
		msg->size = msg->pos;
268 269
		dev_dbg(nvec->dev, "Got %02lx from Master (pos: %d)!\n",
			received, msg->pos);
270 271 272 273 274
	}
handled:
	return IRQ_HANDLED;
}

275
static void tegra_init_i2c_slave(struct nvec_chip *nvec)
276 277 278
{
	u32 val;

279 280 281
	clk_enable(nvec->i2c_clk);

	tegra_periph_reset_assert(nvec->i2c_clk);
282
	udelay(2);
283
	tegra_periph_reset_deassert(nvec->i2c_clk);
284 285

	val = I2C_CNFG_NEW_MASTER_SFM | I2C_CNFG_PACKET_MODE_EN |
286
	    (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
287
	writel(val, nvec->base + I2C_CNFG);
288 289 290

	clk_set_rate(nvec->i2c_clk, 8 * 80000);

291
	writel(I2C_SL_NEWL, nvec->base + I2C_SL_CNFG);
292 293 294 295
	writel(0x1E, nvec->base + I2C_SL_DELAY_COUNT);

	writel(nvec->i2c_addr>>1, nvec->base + I2C_SL_ADDR1);
	writel(0, nvec->base + I2C_SL_ADDR2);
296

297 298 299 300 301 302 303 304 305
	enable_irq(nvec->irq);

	clk_disable(nvec->i2c_clk);
}

static void nvec_disable_i2c_slave(struct nvec_chip *nvec)
{
	disable_irq(nvec->irq);
	writel(I2C_SL_NEWL | I2C_SL_NACK, nvec->base + I2C_SL_CNFG);
306
	clk_disable(nvec->i2c_clk);
307 308 309 310 311 312 313 314 315 316
}

static void nvec_power_off(void)
{
	nvec_write_async(nvec_power_handle, EC_DISABLE_EVENT_REPORTING, 3);
	nvec_write_async(nvec_power_handle, "\x04\x01", 2);
}

static int __devinit tegra_nvec_probe(struct platform_device *pdev)
{
317
	int err, ret;
318 319 320 321
	struct clk *i2c_clk;
	struct nvec_platform_data *pdata = pdev->dev.platform_data;
	struct nvec_chip *nvec;
	struct nvec_msg *msg;
322 323 324
	struct resource *res;
	struct resource *iomem;
	void __iomem *base;
325 326

	nvec = kzalloc(sizeof(struct nvec_chip), GFP_KERNEL);
327
	if (nvec == NULL) {
328 329 330 331 332 333
		dev_err(&pdev->dev, "failed to reserve memory\n");
		return -ENOMEM;
	}
	platform_set_drvdata(pdev, nvec);
	nvec->dev = &pdev->dev;
	nvec->gpio = pdata->gpio;
334 335 336 337 338 339
	nvec->i2c_addr = pdata->i2c_addr;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(&pdev->dev, "no mem resource?\n");
		return -ENODEV;
340 341
	}

342 343 344 345 346
	iomem = request_mem_region(res->start, resource_size(res), pdev->name);
	if (!iomem) {
		dev_err(&pdev->dev, "I2C region already claimed\n");
		return -EBUSY;
	}
347

348 349 350 351
	base = ioremap(iomem->start, resource_size(iomem));
	if (!base) {
		dev_err(&pdev->dev, "Can't ioremap I2C region\n");
		return -ENOMEM;
352 353
	}

354 355 356 357 358 359
	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (!res) {
		dev_err(&pdev->dev, "no irq resource?\n");
		ret = -ENODEV;
		goto err_iounmap;
	}
360

361 362 363 364
	i2c_clk = clk_get_sys("tegra-i2c.2", NULL);
	if (IS_ERR(i2c_clk)) {
		dev_err(nvec->dev, "failed to get controller clock\n");
		goto err_iounmap;
365 366
	}

367 368 369 370
	nvec->base = base;
	nvec->irq = res->start;
	nvec->i2c_clk = i2c_clk;

371 372
	/* Set the gpio to low when we've got something to say */
	err = gpio_request(nvec->gpio, "nvec gpio");
373
	if (err < 0)
374 375 376 377 378 379 380 381 382 383 384
		dev_err(nvec->dev, "couldn't request gpio\n");

	ATOMIC_INIT_NOTIFIER_HEAD(&nvec->notifier_list);

	init_completion(&nvec->sync_write);
	sema_init(&nvec->sync_write_mutex, 1);
	INIT_LIST_HEAD(&nvec->tx_data);
	INIT_LIST_HEAD(&nvec->rx_data);
	INIT_WORK(&nvec->rx_work, nvec_dispatch);
	INIT_WORK(&nvec->tx_work, nvec_request_master);

385 386 387 388 389
	err = request_irq(nvec->irq, nvec_interrupt, 0, "nvec", nvec);
	if (err) {
		dev_err(nvec->dev, "couldn't request irq\n");
		goto failed;
	}
390
	disable_irq(nvec->irq);
391 392 393

	tegra_init_i2c_slave(nvec);

394 395
	clk_enable(i2c_clk);

396 397 398
	gpio_direction_output(nvec->gpio, 1);
	gpio_set_value(nvec->gpio, 1);

399 400
	/* enable event reporting */
	nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING,
401
			 sizeof(EC_ENABLE_EVENT_REPORTING));
402 403 404 405 406 407 408 409 410

	nvec->nvec_status_notifier.notifier_call = nvec_status_notifier;
	nvec_register_notifier(nvec, &nvec->nvec_status_notifier, 0);

	nvec_power_handle = nvec;
	pm_power_off = nvec_power_off;

	/* Get Firmware Version */
	msg = nvec_write_sync(nvec, EC_GET_FIRMWARE_VERSION,
411
			      sizeof(EC_GET_FIRMWARE_VERSION));
412 413

	dev_warn(nvec->dev, "ec firmware version %02x.%02x.%02x / %02x\n",
414
		 msg->data[4], msg->data[5], msg->data[6], msg->data[7]);
415 416 417 418

	kfree(msg->data);
	kfree(msg);

419
	ret = mfd_add_devices(nvec->dev, -1, nvec_devices,
420 421
			      ARRAY_SIZE(nvec_devices), base, 0);
	if (ret)
422 423
		dev_err(nvec->dev, "error adding subdevices\n");

424 425 426 427 428 429 430 431 432 433 434
	/* unmute speakers? */
	nvec_write_async(nvec, "\x0d\x10\x59\x94", 4);

	/* enable lid switch event */
	nvec_write_async(nvec, "\x01\x01\x01\x00\x00\x02\x00", 7);

	/* enable power button event */
	nvec_write_async(nvec, "\x01\x01\x01\x00\x00\x80\x00", 7);

	return 0;

435 436
err_iounmap:
	iounmap(base);
437 438 439 440 441 442 443
failed:
	kfree(nvec);
	return -ENOMEM;
}

static int __devexit tegra_nvec_remove(struct platform_device *pdev)
{
444 445 446 447 448 449 450 451 452
	struct nvec_chip *nvec = platform_get_drvdata(pdev);

	nvec_write_async(nvec, EC_DISABLE_EVENT_REPORTING, 3);
	mfd_remove_devices(nvec->dev);
	free_irq(nvec->irq, &nvec_interrupt);
	iounmap(nvec->base);
	gpio_free(nvec->gpio);
	kfree(nvec);

453 454 455 456 457 458 459 460 461 462 463 464
	return 0;
}

#ifdef CONFIG_PM

static int tegra_nvec_suspend(struct platform_device *pdev, pm_message_t state)
{
	struct nvec_chip *nvec = platform_get_drvdata(pdev);

	dev_dbg(nvec->dev, "suspending\n");
	nvec_write_async(nvec, EC_DISABLE_EVENT_REPORTING, 3);
	nvec_write_async(nvec, "\x04\x02", 2);
465
	nvec_disable_i2c_slave(nvec);
466 467 468 469

	return 0;
}

470 471
static int tegra_nvec_resume(struct platform_device *pdev)
{
472 473 474
	struct nvec_chip *nvec = platform_get_drvdata(pdev);

	dev_dbg(nvec->dev, "resuming\n");
475
	tegra_init_i2c_slave(nvec);
476 477 478 479 480 481 482 483 484 485
	nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING, 3);

	return 0;
}

#else
#define tegra_nvec_suspend NULL
#define tegra_nvec_resume NULL
#endif

486 487 488
static struct platform_driver nvec_device_driver = {
	.probe   = tegra_nvec_probe,
	.remove  = __devexit_p(tegra_nvec_remove),
489
	.suspend = tegra_nvec_suspend,
490 491
	.resume  = tegra_nvec_resume,
	.driver  = {
492 493 494 495 496 497 498 499 500 501 502
		.name = "nvec",
		.owner = THIS_MODULE,
	}
};

static int __init tegra_nvec_init(void)
{
	return platform_driver_register(&nvec_device_driver);
}

module_init(tegra_nvec_init);
503

504
MODULE_ALIAS("platform:nvec");
505 506 507
MODULE_DESCRIPTION("NVIDIA compliant embedded controller interface");
MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>");
MODULE_LICENSE("GPL");