nvec.c 11.8 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 80
{
	unsigned char *msg = (unsigned char *)data;
	int i;

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

84
	printk(KERN_WARNING "unhandled msg type %ld, payload: ", event_type);
85 86 87 88 89 90 91
	for (i = 0; i < msg[1]; i++)
		printk("%0x ", msg[i+2]);
	printk("\n");

	return NOTIFY_OK;
}

92 93
void nvec_write_async(struct nvec_chip *nvec, const unsigned char *data,
			short size)
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
{
	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);

114
	if (!list_empty(&nvec->tx_data))
115 116 117 118 119 120 121
		gpio_set_value(nvec->gpio, 0);
}

static int parse_msg(struct nvec_chip *nvec, struct nvec_msg *msg)
{
	int i;

122 123 124
	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]);
125 126 127
		return -EINVAL;
	}

128
	if ((msg->data[0] >> 7) == 1 && (msg->data[0] & 0x0f) == 5) {
129
		dev_warn(nvec->dev, "ec system event ");
130
		for (i = 0; i < msg->data[1]; i++)
131 132 133 134
			dev_warn(nvec->dev, "%02x ", msg->data[2+i]);
		dev_warn(nvec->dev, "\n");
	}

135 136
	atomic_notifier_call_chain(&nvec->notifier_list, msg->data[0] & 0x8f,
				   msg->data);
137 138 139 140

	return 0;
}

141 142
static struct nvec_msg *nvec_write_sync(struct nvec_chip *nvec,
					const unsigned char *data, short size)
143 144 145 146 147 148
{
	down(&nvec->sync_write_mutex);

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

149 150
	dev_dbg(nvec->dev, "nvec_sync_write: 0x%04x\n",
		nvec->sync_write_pending);
151 152 153 154 155 156 157 158 159 160 161 162 163 164
	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;

165
	while (!list_empty(&nvec->rx_data)) {
166 167 168
		msg = list_first_entry(&nvec->rx_data, struct nvec_msg, node);
		list_del_init(&msg->node);

169 170
		if (nvec->sync_write_pending ==
		    (msg->data[2] << 8) + msg->data[0]) {
171 172 173 174 175 176
			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);
177 178 179
			if ((!msg) || (!msg->data))
				dev_warn(nvec->dev,
					"attempt access zero pointer\n");
180 181 182 183 184 185 186 187
			else {
				kfree(msg->data);
				kfree(msg);
			}
		}
	}
}

188
static irqreturn_t nvec_interrupt(int irq, void *dev)
189 190 191 192 193 194
{
	unsigned long status;
	unsigned long received;
	unsigned char to_send;
	struct nvec_msg *msg;
	struct nvec_chip *nvec = (struct nvec_chip *)dev;
195
	void __iomem *base = nvec->base;
196

197
	status = readl(base + I2C_SL_STATUS);
198

199
	if (!(status & I2C_SL_IRQ)) {
200 201 202
		dev_warn(nvec->dev, "nvec Spurious IRQ\n");
		goto handled;
	}
203
	if (status & END_TRANS && !(status & RCVD)) {
204
		nvec->state = NVEC_WAIT;
205
		if (nvec->rx->size > 1) {
206 207 208 209 210 211 212
			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;
213 214
	} else if (status & RNW) {
		if (status & RCVD)
215 216
			udelay(3);

217
		if (status & RCVD)
218
			nvec->state = NVEC_WRITE;
219 220

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

237
			if (msg->pos >= msg->size) {
238 239 240 241 242 243 244
				list_del_init(&msg->node);
				kfree(msg->data);
				kfree(msg);
				schedule_work(&nvec->tx_work);
				nvec->state = NVEC_WAIT;
			}
		}
245
		writel(to_send, base + I2C_SL_RCVD);
246 247 248 249 250 251 252

		gpio_set_value(nvec->gpio, 1);

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

		goto handled;
	} else {
253
		received = readl(base + I2C_SL_RCVD);
254 255

		if (status & RCVD) {
256
			writel(0, base + I2C_SL_RCVD);
257 258 259
			goto handled;
		}

260
		if (nvec->state == NVEC_WAIT) {
261 262 263 264 265 266 267 268 269 270 271 272 273
			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;
274 275
		dev_dbg(nvec->dev, "Got %02lx from Master (pos: %d)!\n",
			received, msg->pos);
276 277 278 279 280
	}
handled:
	return IRQ_HANDLED;
}

281
static void tegra_init_i2c_slave(struct nvec_chip *nvec)
282 283 284
{
	u32 val;

285 286 287
	clk_enable(nvec->i2c_clk);

	tegra_periph_reset_assert(nvec->i2c_clk);
288
	udelay(2);
289
	tegra_periph_reset_deassert(nvec->i2c_clk);
290

291 292
	writel(nvec->i2c_addr>>1, nvec->base + I2C_SL_ADDR1);
	writel(0, nvec->base + I2C_SL_ADDR2);
293

294
	writel(0x1E, nvec->base + I2C_SL_DELAY_COUNT);
295 296
	val = I2C_CNFG_NEW_MASTER_SFM | I2C_CNFG_PACKET_MODE_EN |
		(0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
297 298
	writel(val, nvec->base + I2C_CNFG);
	writel(I2C_SL_NEWL, nvec->base + I2C_SL_CNFG);
299

300
	clk_disable(nvec->i2c_clk);
301 302 303 304 305 306 307 308 309 310
}

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)
{
311
	int err, ret;
312 313 314 315
	struct clk *i2c_clk;
	struct nvec_platform_data *pdata = pdev->dev.platform_data;
	struct nvec_chip *nvec;
	struct nvec_msg *msg;
316 317 318
	struct resource *res;
	struct resource *iomem;
	void __iomem *base;
319 320

	nvec = kzalloc(sizeof(struct nvec_chip), GFP_KERNEL);
321
	if (nvec == NULL) {
322 323 324 325 326 327
		dev_err(&pdev->dev, "failed to reserve memory\n");
		return -ENOMEM;
	}
	platform_set_drvdata(pdev, nvec);
	nvec->dev = &pdev->dev;
	nvec->gpio = pdata->gpio;
328 329 330 331 332 333
	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;
334 335
	}

336 337 338 339 340
	iomem = request_mem_region(res->start, resource_size(res), pdev->name);
	if (!iomem) {
		dev_err(&pdev->dev, "I2C region already claimed\n");
		return -EBUSY;
	}
341

342 343 344 345
	base = ioremap(iomem->start, resource_size(iomem));
	if (!base) {
		dev_err(&pdev->dev, "Can't ioremap I2C region\n");
		return -ENOMEM;
346 347
	}

348 349 350 351 352 353
	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
	if (!res) {
		dev_err(&pdev->dev, "no irq resource?\n");
		ret = -ENODEV;
		goto err_iounmap;
	}
354

355 356 357 358
	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;
359 360 361 362 363
	}

	clk_enable(i2c_clk);
	clk_set_rate(i2c_clk, 8*80000);

364 365 366 367
	nvec->base = base;
	nvec->irq = res->start;
	nvec->i2c_clk = i2c_clk;

368 369
	/* Set the gpio to low when we've got something to say */
	err = gpio_request(nvec->gpio, "nvec gpio");
370
	if (err < 0)
371 372 373 374 375 376 377 378 379 380 381
		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);

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

	tegra_init_i2c_slave(nvec);

	gpio_direction_output(nvec->gpio, 1);
	gpio_set_value(nvec->gpio, 1);

393 394
	/* enable event reporting */
	nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING,
395
			 sizeof(EC_ENABLE_EVENT_REPORTING));
396 397 398 399 400 401 402 403 404

	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,
405
			      sizeof(EC_GET_FIRMWARE_VERSION));
406 407

	dev_warn(nvec->dev, "ec firmware version %02x.%02x.%02x / %02x\n",
408
		 msg->data[4], msg->data[5], msg->data[6], msg->data[7]);
409 410 411 412

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

413
	ret = mfd_add_devices(nvec->dev, -1, nvec_devices,
414 415
			      ARRAY_SIZE(nvec_devices), base, 0);
	if (ret)
416 417
		dev_err(nvec->dev, "error adding subdevices\n");

418 419 420 421 422 423 424 425 426 427 428
	/* 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;

429 430
err_iounmap:
	iounmap(base);
431 432 433 434 435 436 437
failed:
	kfree(nvec);
	return -ENOMEM;
}

static int __devexit tegra_nvec_remove(struct platform_device *pdev)
{
438 439 440 441 442 443 444 445 446
	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);

447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
	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);

	return 0;
}

463 464
static int tegra_nvec_resume(struct platform_device *pdev)
{
465 466 467
	struct nvec_chip *nvec = platform_get_drvdata(pdev);

	dev_dbg(nvec->dev, "resuming\n");
468
	tegra_init_i2c_slave(nvec);
469 470 471 472 473 474 475 476 477 478
	nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING, 3);

	return 0;
}

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

479 480 481
static struct platform_driver nvec_device_driver = {
	.probe   = tegra_nvec_probe,
	.remove  = __devexit_p(tegra_nvec_remove),
482
	.suspend = tegra_nvec_suspend,
483 484
	.resume  = tegra_nvec_resume,
	.driver  = {
485 486 487 488 489 490 491 492 493 494 495
		.name = "nvec",
		.owner = THIS_MODULE,
	}
};

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

module_init(tegra_nvec_init);
496

497
MODULE_ALIAS("platform:nvec");
498 499 500
MODULE_DESCRIPTION("NVIDIA compliant embedded controller interface");
MODULE_AUTHOR("Marc Dietrich <marvin24@gmx.de>");
MODULE_LICENSE("GPL");