[PATCH 3/8] staging: nvec: rework the nvec slave init

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Rework the tegra slave controller init to look more like in
tegra-i2c.c. This makes the nvec init reliable. Also add de-init of
the slave to be used during suspend.

Signed-off-by: Marc Dietrich <marvin24@xxxxxx>
---
 drivers/staging/nvec/nvec.c |  207 ++++++++++++++++++++++---------------------
 1 files changed, 105 insertions(+), 102 deletions(-)

diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index 2d99f8a..b2f03bb 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -28,65 +28,68 @@
 #include <linux/input.h>
 #include <linux/workqueue.h>
 #include <linux/clk.h>
-#include <mach/iomap.h>
-#include <mach/clk.h>
+
 #include <linux/semaphore.h>
 #include <linux/list.h>
 #include <linux/notifier.h>
 #include <linux/platform_device.h>
 #include <linux/mfd/core.h>
+
+#include <mach/iomap.h>
+#include <mach/clk.h>
+
 #include "nvec.h"
 
-static unsigned char EC_DISABLE_EVENT_REPORTING[] =	{'\x04','\x00','\x00'};
-static unsigned char EC_ENABLE_EVENT_REPORTING[] =	{'\x04','\x00','\x01'};
-static unsigned char EC_GET_FIRMWARE_VERSION[] =	{'\x07','\x15'};
+static const unsigned char EC_DISABLE_EVENT_REPORTING[] = { '\x04', '\x00', '\x00' };
+static const unsigned char EC_ENABLE_EVENT_REPORTING[]  = { '\x04', '\x00', '\x01' };
+static const unsigned char EC_GET_FIRMWARE_VERSION[]    = { '\x07', '\x15' };
 
 static struct nvec_chip *nvec_power_handle;
 
 static struct mfd_cell nvec_devices[] = {
 	{
-		.name	= "nvec-kbd",
-		.id	= 1,
+		.name = "nvec-kbd",
+		.id = 1,
 	},
 	{
-		.name	= "nvec-mouse",
-		.id	= 1,
+		.name = "nvec-mouse",
+		.id = 1,
 	},
 	{
-		.name	= "nvec-power",
-		.id	= 1,
+		.name = "nvec-power",
+		.id = 1,
 	},
 	{
-		.name	= "nvec-power",
-		.id	= 2,
+		.name = "nvec-power",
+		.id = 2,
 	},
 };
 
 int nvec_register_notifier(struct nvec_chip *nvec, struct notifier_block *nb,
-				unsigned int events)
+			   unsigned int events)
 {
 	return atomic_notifier_chain_register(&nvec->notifier_list, nb);
 }
+
 EXPORT_SYMBOL_GPL(nvec_register_notifier);
 
-static int nvec_status_notifier(struct notifier_block *nb, unsigned long event_type,
-				void *data)
+static int nvec_status_notifier(struct notifier_block *nb,
+				unsigned long event_type, void *data)
 {
 	unsigned char *msg = (unsigned char *)data;
-	int i;
 
-	if(event_type != NVEC_CNTL)
+	if (event_type != NVEC_CNTL)
 		return NOTIFY_DONE;
 
-	printk("unhandled msg type %ld, payload: ", event_type);
-	for (i = 0; i < msg[1]; i++)
-		printk("%0x ", msg[i+2]);
-	printk("\n");
+	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);
 
 	return NOTIFY_OK;
 }
 
-void nvec_write_async(struct nvec_chip *nvec, unsigned char *data, short size)
+void nvec_write_async(struct nvec_chip *nvec, const unsigned char *data,
+			short size)
 {
 	struct nvec_msg *msg = kzalloc(sizeof(struct nvec_msg), GFP_NOWAIT);
 
@@ -101,48 +104,47 @@ void nvec_write_async(struct nvec_chip *nvec, unsigned char *data, short size)
 
 	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);
 
-	if(!list_empty(&nvec->tx_data)) {
+	if (!list_empty(&nvec->tx_data)) {
 		gpio_set_value(nvec->gpio, 0);
 	}
 }
 
 static int parse_msg(struct nvec_chip *nvec, struct nvec_msg *msg)
 {
-	int i;
-
-	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]);
+	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]);
 		return -EINVAL;
 	}
 
-	if ((msg->data[0] >> 7 ) == 1 && (msg->data[0] & 0x0f) == 5)
-	{
-		dev_warn(nvec->dev, "ec system event ");
-		for (i=0; i < msg->data[1]; i++)
-			dev_warn(nvec->dev, "%02x ", msg->data[2+i]);
-		dev_warn(nvec->dev, "\n");
+	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);
 	}
 
-	atomic_notifier_call_chain(&nvec->notifier_list, msg->data[0] & 0x8f, msg->data);
+	atomic_notifier_call_chain(&nvec->notifier_list, msg->data[0] & 0x8f,
+				   msg->data);
 
 	return 0;
 }
 
-static struct nvec_msg *nvec_write_sync(struct nvec_chip *nvec, unsigned char *data, short size)
+static struct nvec_msg *nvec_write_sync(struct nvec_chip *nvec,
+					const unsigned char *data, short size)
 {
 	down(&nvec->sync_write_mutex);
 
 	nvec->sync_write_pending = (data[1] << 8) + data[0];
 	nvec_write_async(nvec, data, size);
 
-	dev_dbg(nvec->dev, "nvec_sync_write: 0x%04x\n", nvec->sync_write_pending);
+	dev_dbg(nvec->dev, "nvec_sync_write: 0x%04x\n",
+		nvec->sync_write_pending);
 	wait_for_completion(&nvec->sync_write);
 	dev_dbg(nvec->dev, "nvec_sync_write: pong!\n");
 
@@ -157,21 +159,21 @@ static void nvec_dispatch(struct work_struct *work)
 	struct nvec_chip *nvec = container_of(work, struct nvec_chip, rx_work);
 	struct nvec_msg *msg;
 
-	while(!list_empty(&nvec->rx_data))
-	{
+	while (!list_empty(&nvec->rx_data)) {
 		msg = list_first_entry(&nvec->rx_data, struct nvec_msg, node);
 		list_del_init(&msg->node);
 
-		if(nvec->sync_write_pending == (msg->data[2] << 8) + msg->data[0])
-		{
+		if (nvec->sync_write_pending ==
+		    (msg->data[2] << 8) + msg->data[0]) {
 			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);
-			if((!msg) || (!msg->data))
-				dev_warn(nvec->dev, "attempt access zero pointer\n");
+			if ((!msg) || (!msg->data))
+				dev_warn(nvec->dev,
+					"attempt access zero pointer\n");
 			else {
 				kfree(msg->data);
 				kfree(msg);
@@ -191,20 +193,13 @@ static irqreturn_t nvec_interrupt(int irq, void *dev)
 
 	status = readl(base + I2C_SL_STATUS);
 
-	if(!(status & I2C_SL_IRQ))
-	{
+	if (!(status & I2C_SL_IRQ)) {
 		dev_warn(nvec->dev, "nvec Spurious IRQ\n");
-		//Yup, handled. ahum.
 		goto handled;
 	}
-	if(status & END_TRANS && !(status & RCVD))
-	{
-		//Reenable IRQ only when even has been sent
-		//printk("Write sequence ended !\n");
-                //parse_msg(nvec);
+	if (status & END_TRANS && !(status & RCVD)) {
 		nvec->state = NVEC_WAIT;
-		if(nvec->rx->size > 1)
-		{
+		if (nvec->rx->size > 1) {
 			list_add_tail(&nvec->rx->node, &nvec->rx_data);
 			schedule_work(&nvec->rx_work);
 		} else {
@@ -212,41 +207,33 @@ static irqreturn_t nvec_interrupt(int irq, void *dev)
 			kfree(nvec->rx);
 		}
 		return IRQ_HANDLED;
-	} else if(status & RNW)
-	{
-		// Work around for AP20 New Slave Hw Bug. Give 1us extra.
-		// nvec/smbus/nvec_i2c_transport.c in NV`s crap for reference
-		if(status & RCVD)
+	} else if (status & RNW) {
+		if (status & RCVD)
 			udelay(3);
 
-		if(status & RCVD)
-		{
+		if (status & RCVD) {
 			nvec->state = NVEC_WRITE;
-			//Master wants something from us. New communication
-//			dev_dbg(nvec->dev, "New read comm!\n");
 		} else {
-			//Master wants something from us from a communication we've already started
-//			dev_dbg(nvec->dev, "Read comm cont !\n");
+/*                      dev_dbg(nvec->dev, "Read comm cont !\n"); */
 		}
-		//if(msg_pos<msg_size) {
-		if(list_empty(&nvec->tx_data))
-		{
+		if (list_empty(&nvec->tx_data)) {
 			dev_err(nvec->dev, "nvec empty tx - sending no-op\n");
 			to_send = 0x8a;
 			nvec_write_async(nvec, "\x07\x02", 2);
-//			to_send = 0x01;
 		} else {
-			msg = list_first_entry(&nvec->tx_data, struct nvec_msg, node);
-			if(msg->pos < msg->size) {
+			msg =
+			    list_first_entry(&nvec->tx_data, struct nvec_msg,
+					     node);
+			if (msg->pos < msg->size) {
 				to_send = msg->data[msg->pos];
 				msg->pos++;
 			} else {
-				dev_err(nvec->dev, "nvec crap! %d\n", msg->size);
+				dev_err(nvec->dev, "nvec crap! %d\n",
+					msg->size);
 				to_send = 0x01;
 			}
 
-			if(msg->pos >= msg->size)
-			{
+			if (msg->pos >= msg->size) {
 				list_del_init(&msg->node);
 				kfree(msg->data);
 				kfree(msg);
@@ -263,14 +250,13 @@ static irqreturn_t nvec_interrupt(int irq, void *dev)
 		goto handled;
 	} else {
 		received = readl(base + I2C_SL_RCVD);
-		//Workaround?
-		if(status & RCVD) {
+
+		if (status & RCVD) {
 			writel(0, base + I2C_SL_RCVD);
 			goto handled;
 		}
 
-		if (nvec->state == NVEC_WAIT)
-		{
+		if (nvec->state == NVEC_WAIT) {
 			nvec->state = NVEC_READ;
 			msg = kzalloc(sizeof(struct nvec_msg), GFP_NOWAIT);
 			msg->data = kzalloc(32, GFP_NOWAIT);
@@ -284,7 +270,8 @@ static irqreturn_t nvec_interrupt(int irq, void *dev)
 		msg->data[msg->pos] = received;
 		msg->pos++;
 		msg->size = msg->pos;
-		dev_dbg(nvec->dev, "Got %02lx from Master (pos: %d)!\n", received, msg->pos);
+		dev_dbg(nvec->dev, "Got %02lx from Master (pos: %d)!\n",
+			received, msg->pos);
 	}
 handled:
 	return IRQ_HANDLED;
@@ -300,18 +287,30 @@ static void tegra_init_i2c_slave(struct nvec_chip *nvec)
 	udelay(2);
 	tegra_periph_reset_deassert(nvec->i2c_clk);
 
-	writel(nvec->i2c_addr>>1, nvec->base + I2C_SL_ADDR1);
-	writel(0, nvec->base + I2C_SL_ADDR2);
-
-	writel(0x1E, nvec->base + I2C_SL_DELAY_COUNT);
 	val = I2C_CNFG_NEW_MASTER_SFM | I2C_CNFG_PACKET_MODE_EN |
-		(0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
+	    (0x2 << I2C_CNFG_DEBOUNCE_CNT_SHIFT);
 	writel(val, nvec->base + I2C_CNFG);
+
+	clk_set_rate(nvec->i2c_clk, 8 * 80000);
+
 	writel(I2C_SL_NEWL, nvec->base + I2C_SL_CNFG);
+	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);
+
+	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);
+	clk_disable(nvec->i2c_clk);
+}
+
 static void nvec_power_off(void)
 {
 	nvec_write_async(nvec_power_handle, EC_DISABLE_EVENT_REPORTING, 3);
@@ -330,7 +329,7 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
 	void __iomem *base;
 
 	nvec = kzalloc(sizeof(struct nvec_chip), GFP_KERNEL);
-	if(nvec == NULL) {
+	if (nvec == NULL) {
 		dev_err(&pdev->dev, "failed to reserve memory\n");
 		return -ENOMEM;
 	}
@@ -370,16 +369,13 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
 		goto err_iounmap;
 	}
 
-	clk_enable(i2c_clk);
-	clk_set_rate(i2c_clk, 8*80000);
-
 	nvec->base = base;
 	nvec->irq = res->start;
 	nvec->i2c_clk = i2c_clk;
 
 	/* Set the gpio to low when we've got something to say */
 	err = gpio_request(nvec->gpio, "nvec gpio");
-	if(err < 0)
+	if (err < 0)
 		dev_err(nvec->dev, "couldn't request gpio\n");
 
 	ATOMIC_INIT_NOTIFIER_HEAD(&nvec->notifier_list);
@@ -396,15 +392,18 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
 		dev_err(nvec->dev, "couldn't request irq\n");
 		goto failed;
 	}
+	disable_irq(nvec->irq);
 
 	tegra_init_i2c_slave(nvec);
 
+	clk_enable(i2c_clk);
+
 	gpio_direction_output(nvec->gpio, 1);
 	gpio_set_value(nvec->gpio, 1);
 
 	/* enable event reporting */
 	nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING,
-				sizeof(EC_ENABLE_EVENT_REPORTING));
+			 sizeof(EC_ENABLE_EVENT_REPORTING));
 
 	nvec->nvec_status_notifier.notifier_call = nvec_status_notifier;
 	nvec_register_notifier(nvec, &nvec->nvec_status_notifier, 0);
@@ -414,17 +413,17 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
 
 	/* Get Firmware Version */
 	msg = nvec_write_sync(nvec, EC_GET_FIRMWARE_VERSION,
-		sizeof(EC_GET_FIRMWARE_VERSION));
+			      sizeof(EC_GET_FIRMWARE_VERSION));
 
 	dev_warn(nvec->dev, "ec firmware version %02x.%02x.%02x / %02x\n",
-			msg->data[4], msg->data[5], msg->data[6], msg->data[7]);
+		 msg->data[4], msg->data[5], msg->data[6], msg->data[7]);
 
 	kfree(msg->data);
 	kfree(msg);
 
 	ret = mfd_add_devices(nvec->dev, -1, nvec_devices,
-			ARRAY_SIZE(nvec_devices), base, 0);
-	if(ret)
+			      ARRAY_SIZE(nvec_devices), base, 0);
+	if (ret)
 		dev_err(nvec->dev, "error adding subdevices\n");
 
 	/* unmute speakers? */
@@ -468,12 +467,13 @@ static int tegra_nvec_suspend(struct platform_device *pdev, pm_message_t state)
 	dev_dbg(nvec->dev, "suspending\n");
 	nvec_write_async(nvec, EC_DISABLE_EVENT_REPORTING, 3);
 	nvec_write_async(nvec, "\x04\x02", 2);
+	nvec_disable_i2c_slave(nvec);
 
 	return 0;
 }
 
-static int tegra_nvec_resume(struct platform_device *pdev) {
-
+static int tegra_nvec_resume(struct platform_device *pdev)
+{
 	struct nvec_chip *nvec = platform_get_drvdata(pdev);
 
 	dev_dbg(nvec->dev, "resuming\n");
@@ -488,13 +488,12 @@ static int tegra_nvec_resume(struct platform_device *pdev) {
 #define tegra_nvec_resume NULL
 #endif
 
-static struct platform_driver nvec_device_driver =
-{
-	.probe = tegra_nvec_probe,
-	.remove = __devexit_p(tegra_nvec_remove),
+static struct platform_driver nvec_device_driver = {
+	.probe   = tegra_nvec_probe,
+	.remove  = __devexit_p(tegra_nvec_remove),
 	.suspend = tegra_nvec_suspend,
-	.resume = tegra_nvec_resume,
-	.driver = {
+	.resume  = tegra_nvec_resume,
+	.driver  = {
 		.name = "nvec",
 		.owner = THIS_MODULE,
 	}
@@ -506,4 +505,8 @@ static int __init tegra_nvec_init(void)
 }
 
 module_init(tegra_nvec_init);
+
 MODULE_ALIAS("platform:nvec");
+MODULE_DESCRIPTION("NVIDIA compliant embedded controller interface");
+MODULE_AUTHOR("Marc Dietrich <marvin24@xxxxxx>");
+MODULE_LICENSE("GPL");
-- 
1.7.4.1

_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/devel


[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux