Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 2/8] usb: chipidea: add otg file
From: Peter Chen @ 2013-02-04  3:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359947039-23906-1-git-send-email-peter.chen@freescale.com>

Implement struct usb_otg, In that way, calling otg_set_peripheral
will not be failed at udc.c.

Signed-off-by: Peter Chen <peter.chen@freescale.com>
---
 drivers/usb/chipidea/Makefile |    2 +-
 drivers/usb/chipidea/ci.h     |    2 +
 drivers/usb/chipidea/otg.c    |   60 +++++++++++++++++++++++++++++++++++++++++
 drivers/usb/chipidea/otg.h    |    6 ++++
 4 files changed, 69 insertions(+), 1 deletions(-)
 create mode 100644 drivers/usb/chipidea/otg.c
 create mode 100644 drivers/usb/chipidea/otg.h

diff --git a/drivers/usb/chipidea/Makefile b/drivers/usb/chipidea/Makefile
index d92ca32..11f513c 100644
--- a/drivers/usb/chipidea/Makefile
+++ b/drivers/usb/chipidea/Makefile
@@ -2,7 +2,7 @@ ccflags-$(CONFIG_USB_CHIPIDEA_DEBUG) := -DDEBUG
 
 obj-$(CONFIG_USB_CHIPIDEA)		+= ci_hdrc.o
 
-ci_hdrc-y				:= core.o
+ci_hdrc-y				:= core.o otg.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_UDC)	+= udc.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_HOST)	+= host.o
 ci_hdrc-$(CONFIG_USB_CHIPIDEA_DEBUG)	+= debug.o
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index d738603..697e369 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -129,6 +129,7 @@ struct hw_bank {
  * @vbus_active: is VBUS active
  * @transceiver: pointer to USB PHY, if any
  * @hcd: pointer to usb_hcd for ehci host driver
+ * @otg: for otg support
  */
 struct ci13xxx {
 	struct device			*dev;
@@ -164,6 +165,7 @@ struct ci13xxx {
 	bool				global_phy;
 	struct usb_phy			*transceiver;
 	struct usb_hcd			*hcd;
+	struct usb_otg      		otg;
 };
 
 static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
new file mode 100644
index 0000000..7dea3b3
--- /dev/null
+++ b/drivers/usb/chipidea/otg.c
@@ -0,0 +1,60 @@
+/*
+ * otg.c - ChipIdea USB IP core OTG driver
+ *
+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
+ *
+ * Author: Peter Chen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/chipidea.h>
+
+#include "ci.h"
+#include "udc.h"
+#include "bits.h"
+#include "host.h"
+#include "debug.h"
+
+static int ci_otg_set_peripheral(struct usb_otg *otg,
+		struct usb_gadget *periph)
+{
+	otg->gadget = periph;
+
+	return 0;
+}
+
+static int ci_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
+{
+	otg->host = host;
+
+	return 0;
+}
+
+/**
+ * ci_hdrc_otg_init - initialize device related bits
+ * ci: the controller
+ *
+ * This function create otg struct, if the device can switch between
+ * device and host.
+ */
+int ci_hdrc_otg_init(struct ci13xxx *ci)
+{
+	/* Useless at current */
+	ci->otg.set_peripheral = ci_otg_set_peripheral;
+	ci->otg.set_host = ci_otg_set_host;
+	if (!IS_ERR_OR_NULL(ci->transceiver))
+		ci->transceiver->otg = &ci->otg;
+
+	return 0;
+}
diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h
new file mode 100644
index 0000000..b4c6b3e
--- /dev/null
+++ b/drivers/usb/chipidea/otg.h
@@ -0,0 +1,6 @@
+#ifndef __DRIVERS_USB_CHIPIDEA_OTG_H
+#define __DRIVERS_USB_CHIPIDEA_OTG_H
+
+int ci_hdrc_otg_init(struct ci13xxx *ci);
+
+#endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH v6 3/8] usb: chipidea: add otg id switch and vbus connect/disconnect detect
From: Peter Chen @ 2013-02-04  3:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359947039-23906-1-git-send-email-peter.chen@freescale.com>

The main design flow is the same with msm otg driver, that is the id and
vbus interrupt are handled at core driver, others are handled by
individual drivers.

- At former design, when switch usb role from device->host, it will call
udc_stop, it will remove the gadget driver, so when switch role
from host->device, it can't add gadget driver any more.
At new design, when role switch occurs, the gadget just calls
usb_gadget_vbus_disconnect/usb_gadget_vbus_connect as well as
reset controller, it will not free any device/gadget structure

- Add vbus connect and disconnect to core interrupt handler, it can
notify udc driver by calling usb_gadget_vbus_disconnect
/usb_gadget_vbus_connect.

Signed-off-by: Peter Chen <peter.chen@freescale.com>
---
 drivers/usb/chipidea/bits.h |   10 +++
 drivers/usb/chipidea/ci.h   |    6 ++
 drivers/usb/chipidea/core.c |  182 +++++++++++++++++++++++++++++++++++++++----
 drivers/usb/chipidea/otg.c  |   28 ++++---
 drivers/usb/chipidea/otg.h  |    3 +
 drivers/usb/chipidea/udc.c  |    2 +
 6 files changed, 206 insertions(+), 25 deletions(-)

diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
index 050de85..ba9c6ef 100644
--- a/drivers/usb/chipidea/bits.h
+++ b/drivers/usb/chipidea/bits.h
@@ -65,11 +65,21 @@
 #define OTGSC_ASVIS	      BIT(18)
 #define OTGSC_BSVIS	      BIT(19)
 #define OTGSC_BSEIS	      BIT(20)
+#define OTGSC_1MSIS	      BIT(21)
+#define OTGSC_DPIS	      BIT(22)
 #define OTGSC_IDIE	      BIT(24)
 #define OTGSC_AVVIE	      BIT(25)
 #define OTGSC_ASVIE	      BIT(26)
 #define OTGSC_BSVIE	      BIT(27)
 #define OTGSC_BSEIE	      BIT(28)
+#define OTGSC_1MSIE	      BIT(29)
+#define OTGSC_DPIE	      BIT(30)
+#define OTGSC_INT_EN_BITS	(OTGSC_IDIE | OTGSC_AVVIE | OTGSC_ASVIE \
+				| OTGSC_BSVIE | OTGSC_BSEIE | OTGSC_1MSIE \
+				| OTGSC_DPIE)
+#define OTGSC_INT_STATUS_BITS	(OTGSC_IDIS | OTGSC_AVVIS | OTGSC_ASVIS	\
+				| OTGSC_BSVIS | OTGSC_BSEIS | OTGSC_1MSIS \
+				| OTGSC_DPIS)
 
 /* USBMODE */
 #define USBMODE_CM            (0x03UL <<  0)
diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 697e369..325d790 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -130,6 +130,7 @@ struct hw_bank {
  * @transceiver: pointer to USB PHY, if any
  * @hcd: pointer to usb_hcd for ehci host driver
  * @otg: for otg support
+ * @events: events for otg, and handled@ci_role_work
  */
 struct ci13xxx {
 	struct device			*dev;
@@ -140,6 +141,7 @@ struct ci13xxx {
 	enum ci_role			role;
 	bool				is_otg;
 	struct work_struct		work;
+	struct delayed_work		dwork;
 	struct workqueue_struct		*wq;
 
 	struct dma_pool			*qh_pool;
@@ -166,6 +168,8 @@ struct ci13xxx {
 	struct usb_phy			*transceiver;
 	struct usb_hcd			*hcd;
 	struct usb_otg      		otg;
+	bool				id_event;
+	bool				b_sess_valid_event;
 };
 
 static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
@@ -314,4 +318,6 @@ int hw_port_test_set(struct ci13xxx *ci, u8 mode);
 
 u8 hw_port_test_get(struct ci13xxx *ci);
 
+void ci_handle_vbus_change(struct ci13xxx *ci);
+
 #endif	/* __DRIVERS_USB_CHIPIDEA_CI_H */
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 57cae1f..8857b2c 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -73,6 +73,7 @@
 #include "bits.h"
 #include "host.h"
 #include "debug.h"
+#include "otg.h"
 
 /* Controller register map */
 static uintptr_t ci_regs_nolpm[] = {
@@ -199,6 +200,14 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
 	if (ci->hw_ep_max > ENDPT_MAX)
 		return -ENODEV;
 
+	/* Disable all interrupts bits */
+	hw_write(ci, OP_USBINTR, 0xffffffff, 0);
+	ci_disable_otg_interrupt(ci, OTGSC_INT_EN_BITS);
+
+	/* Clear all interrupts status bits*/
+	hw_write(ci, OP_USBSTS, 0xffffffff, 0xffffffff);
+	ci_clear_otg_interrupt(ci, OTGSC_INT_STATUS_BITS);
+
 	dev_dbg(ci->dev, "ChipIdea HDRC found, lpm: %d; cap: %p op: %p\n",
 		ci->hw_bank.lpm, ci->hw_bank.cap, ci->hw_bank.op);
 
@@ -265,24 +274,132 @@ static enum ci_role ci_otg_role(struct ci13xxx *ci)
 }
 
 /**
- * ci_role_work - perform role changing based on ID pin
- * @work: work struct
+ * hw_wait_reg: wait the register value
+ *
+ * Sometimes, it needs to wait register value before going on.
+ * Eg, when switch to device mode, the vbus value should be lower
+ * than OTGSC_BSV before connects to host.
+ *
+ * @ci: the controller
+ * @reg: register index
+ * @mask: mast bit
+ * @value: the bit value to wait
+ * @timeout: timeout to indicate an error
+ *
+ * This function returns an error code if timeout
  */
-static void ci_role_work(struct work_struct *work)
+static int hw_wait_reg(struct ci13xxx *ci, enum ci13xxx_regs reg, u32 mask,
+				u32 value, unsigned long timeout)
+{
+	unsigned long elapse = jiffies + timeout;
+
+	while (hw_read(ci, reg, mask) != value) {
+		if (time_after(jiffies, elapse)) {
+			dev_err(ci->dev, "timeout waiting for %08x in %d\n",
+					mask, reg);
+			return -ETIMEDOUT;
+		}
+		msleep(20);
+	}
+
+	return 0;
+}
+
+/* 
+ * Since there are some capacitances at vbus, the vbus may not
+ * change very quickly when we stop/start internal 5v.
+ * Below is a vbus stable timeout value, the routine will quit
+ * if the vbus gets the required value, we can think there are some
+ * problems for hardware if the vbus can't get the required value
+ * within 5 seconds.
+ */
+#define CI_VBUS_STABLE_TIMEOUT 500
+static void ci_handle_id_switch(struct ci13xxx *ci)
 {
-	struct ci13xxx *ci = container_of(work, struct ci13xxx, work);
 	enum ci_role role = ci_otg_role(ci);
 
 	if (role != ci->role) {
 		dev_dbg(ci->dev, "switching from %s to %s\n",
 			ci_role(ci)->name, ci->roles[role]->name);
 
-		ci_role_stop(ci);
-		ci_role_start(ci, role);
-		enable_irq(ci->irq);
+		/* 1. Finish the current role */
+		if (ci->role == CI_ROLE_GADGET) {
+			usb_gadget_vbus_disconnect(&ci->gadget);
+			/* host doesn't care B_SESSION_VALID event */
+			ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
+			ci_disable_otg_interrupt(ci, OTGSC_BSVIE);
+			ci->role = CI_ROLE_END;
+			/* reset controller */
+			hw_device_reset(ci, USBMODE_CM_IDLE);
+		} else if (ci->role == CI_ROLE_HOST) {
+			ci_role_stop(ci);
+			/* reset controller */
+			hw_device_reset(ci, USBMODE_CM_IDLE);
+		}
+
+		/* 2. Turn on/off vbus according to coming role */
+		if (ci_otg_role(ci) == CI_ROLE_GADGET) {
+			otg_set_vbus(&ci->otg, false);
+			/* wait vbus lower than OTGSC_BSV */
+			hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
+					CI_VBUS_STABLE_TIMEOUT);
+		} else if (ci_otg_role(ci) == CI_ROLE_HOST) {
+			otg_set_vbus(&ci->otg, true);
+			/* wait vbus higher than OTGSC_AVV */
+			hw_wait_reg(ci, OP_OTGSC, OTGSC_AVV, OTGSC_AVV,
+					CI_VBUS_STABLE_TIMEOUT);
+		}
+
+		/* 3. Begin the new role */
+		if (ci_otg_role(ci) == CI_ROLE_GADGET) {
+			ci->role = role;
+			ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
+			ci_enable_otg_interrupt(ci, OTGSC_BSVIE);
+		} else if (ci_otg_role(ci) == CI_ROLE_HOST) {
+			ci_role_start(ci, role);
+		}
 	}
 }
 
+void ci_handle_vbus_change(struct ci13xxx *ci)
+{
+	u32 otgsc = hw_read(ci, OP_OTGSC, ~0);
+
+	if (otgsc & OTGSC_BSV)
+		usb_gadget_vbus_connect(&ci->gadget);
+	else
+		usb_gadget_vbus_disconnect(&ci->gadget);
+}
+
+/**
+ * ci_otg_work - perform otg (vbus/id) event handle
+ * @work: work struct
+ */
+static void ci_otg_work(struct work_struct *work)
+{
+	struct ci13xxx *ci = container_of(work, struct ci13xxx, work);
+
+	if (ci->id_event) {
+		ci->id_event = false;
+		ci_handle_id_switch(ci);
+	} else if (ci->b_sess_valid_event) {
+		ci->b_sess_valid_event = false;
+		ci_handle_vbus_change(ci);
+	} else
+		dev_err(ci->dev, "unexpected event occurs at %s\n", __func__);
+
+	enable_irq(ci->irq);
+}
+
+static void ci_delayed_work(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct ci13xxx *ci = container_of(dwork, struct ci13xxx, dwork);
+
+	otg_set_vbus(&ci->otg, true);
+
+}
+
 static ssize_t show_role(struct device *dev, struct device_attribute *attr,
 			 char *buf)
 {
@@ -324,16 +441,34 @@ static irqreturn_t ci_irq(int irq, void *data)
 	if (ci->is_otg)
 		otgsc = hw_read(ci, OP_OTGSC, ~0);
 
-	if (ci->role != CI_ROLE_END)
-		ret = ci_role(ci)->irq(ci);
+	/*
+	 * Handle id change interrupt, it indicates device/host function
+	 * switch.
+	 */
+	if (ci->is_otg && (otgsc & OTGSC_IDIE) && (otgsc & OTGSC_IDIS)) {
+		ci->id_event = true;
+		ci_clear_otg_interrupt(ci, OTGSC_IDIS);
+		disable_irq_nosync(ci->irq);
+		queue_work(ci->wq, &ci->work);
+		return IRQ_HANDLED;
+	}
 
-	if (ci->is_otg && (otgsc & OTGSC_IDIS)) {
-		hw_write(ci, OP_OTGSC, OTGSC_IDIS, OTGSC_IDIS);
+	/*
+	 * Handle vbus change interrupt, it indicates device connection
+	 * and disconnection events.
+	 */
+	if ((otgsc & OTGSC_BSVIE) && (otgsc & OTGSC_BSVIS)) {
+		ci->b_sess_valid_event = true;
+		ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
 		disable_irq_nosync(ci->irq);
 		queue_work(ci->wq, &ci->work);
-		ret = IRQ_HANDLED;
+		return IRQ_HANDLED;
 	}
 
+	/* Handle device/host interrupt */
+	if (ci->role != CI_ROLE_END)
+		ret = ci_role(ci)->irq(ci);
+
 	return ret;
 }
 
@@ -398,6 +533,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 	struct resource	*res;
 	void __iomem	*base;
 	int		ret;
+	u32		otgsc;
 
 	if (!dev->platform_data) {
 		dev_err(dev, "platform data missing\n");
@@ -443,7 +579,8 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 		return -ENODEV;
 	}
 
-	INIT_WORK(&ci->work, ci_role_work);
+	INIT_WORK(&ci->work, ci_otg_work);
+	INIT_DELAYED_WORK(&ci->dwork, ci_delayed_work);
 	ci->wq = create_singlethread_workqueue("ci_otg");
 	if (!ci->wq) {
 		dev_err(dev, "can't create workqueue\n");
@@ -466,7 +603,10 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 	}
 
 	if (ci->roles[CI_ROLE_HOST] && ci->roles[CI_ROLE_GADGET]) {
+		dev_dbg(dev, "support otg\n");
 		ci->is_otg = true;
+		/* if otg is supported, create struct usb_otg */
+		ci_hdrc_otg_init(ci);
 		/* ID pin needs 1ms debouce time, we delay 2ms for safe */
 		mdelay(2);
 		ci->role = ci_otg_role(ci);
@@ -483,6 +623,17 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 		goto rm_wq;
 	}
 
+	otgsc = hw_read(ci, OP_OTGSC, ~0);
+	/*
+	 * if it is device mode:
+	 * - Enable vbus detect
+	 * - If it has already connected to host, notify udc
+	 */
+	if (ci->role == CI_ROLE_GADGET) {
+		ci_enable_otg_interrupt(ci, OTGSC_BSVIE);
+		ci_handle_vbus_change(ci);
+	}
+
 	platform_set_drvdata(pdev, ci);
 	ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->platdata->name,
 			  ci);
@@ -493,8 +644,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 	if (ret)
 		goto rm_attr;
 
-	if (ci->is_otg)
-		hw_write(ci, OP_OTGSC, OTGSC_IDIE, OTGSC_IDIE);
+	/* Handle the situation that usb device at the MicroB to A cable */
+	if (ci->is_otg && !(otgsc & OTGSC_ID))
+		queue_delayed_work(ci->wq, &ci->dwork, msecs_to_jiffies(500));
 
 	return ret;
 
diff --git a/drivers/usb/chipidea/otg.c b/drivers/usb/chipidea/otg.c
index 7dea3b3..2986d91 100644
--- a/drivers/usb/chipidea/otg.c
+++ b/drivers/usb/chipidea/otg.c
@@ -10,21 +10,28 @@
  * published by the Free Software Foundation.
  */
 
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/chipidea.h>
 
 #include "ci.h"
-#include "udc.h"
 #include "bits.h"
-#include "host.h"
-#include "debug.h"
+
+void ci_clear_otg_interrupt(struct ci13xxx *ci, u32 bits)
+{
+	/* Only clear request bits */
+	hw_write(ci, OP_OTGSC, OTGSC_INT_STATUS_BITS, bits);
+}
+
+void ci_enable_otg_interrupt(struct ci13xxx *ci, u32 bits)
+{
+	hw_write(ci, OP_OTGSC, bits, bits);
+}
+
+void ci_disable_otg_interrupt(struct ci13xxx *ci, u32 bits)
+{
+	hw_write(ci, OP_OTGSC, bits, 0);
+}
 
 static int ci_otg_set_peripheral(struct usb_otg *otg,
 		struct usb_gadget *periph)
@@ -55,6 +62,7 @@ int ci_hdrc_otg_init(struct ci13xxx *ci)
 	ci->otg.set_host = ci_otg_set_host;
 	if (!IS_ERR_OR_NULL(ci->transceiver))
 		ci->transceiver->otg = &ci->otg;
+	ci_enable_otg_interrupt(ci, OTGSC_IDIE);
 
 	return 0;
 }
diff --git a/drivers/usb/chipidea/otg.h b/drivers/usb/chipidea/otg.h
index b4c6b3e..fa30428 100644
--- a/drivers/usb/chipidea/otg.h
+++ b/drivers/usb/chipidea/otg.h
@@ -2,5 +2,8 @@
 #define __DRIVERS_USB_CHIPIDEA_OTG_H
 
 int ci_hdrc_otg_init(struct ci13xxx *ci);
+void ci_clear_otg_interrupt(struct ci13xxx *ci, u32 bits);
+void ci_enable_otg_interrupt(struct ci13xxx *ci, u32 bits);
+void ci_disable_otg_interrupt(struct ci13xxx *ci, u32 bits);
 
 #endif /* __DRIVERS_USB_CHIPIDEA_OTG_H */
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index d214448..83e54bb 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1371,6 +1371,7 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
 			pm_runtime_get_sync(&_gadget->dev);
 			hw_device_reset(ci, USBMODE_CM_DC);
 			hw_device_state(ci, ci->ep0out->qh.dma);
+			dev_dbg(ci->dev, "Connected to host\n");
 		} else {
 			hw_device_state(ci, 0);
 			if (ci->platdata->notify_event)
@@ -1378,6 +1379,7 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
 				CI13XXX_CONTROLLER_STOPPED_EVENT);
 			_gadget_stop_activity(&ci->gadget);
 			pm_runtime_put_sync(&_gadget->dev);
+			dev_dbg(ci->dev, "Disconnected from host\n");
 		}
 	}
 
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH v6 4/8] usb: chipidea: consolidate kinds of APIs for both roles
From: Peter Chen @ 2013-02-04  3:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359947039-23906-1-git-send-email-peter.chen@freescale.com>

- Create/destroy the gadget at udc's init and destory function
- start/stop API are used at otg id switch and probe routine
- Defer some gadget operations at ci's delayed work queue

Signed-off-by: Peter Chen <peter.chen@freescale.com>
---
 drivers/usb/chipidea/ci.h   |    1 -
 drivers/usb/chipidea/core.c |   78 +++++++++++++++++--------------------------
 drivers/usb/chipidea/host.c |    6 +++
 drivers/usb/chipidea/host.h |    4 ++-
 drivers/usb/chipidea/udc.c  |   37 +++++++++++++++-----
 drivers/usb/chipidea/udc.h  |    4 ++-
 6 files changed, 71 insertions(+), 59 deletions(-)

diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 325d790..3ebe87a 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -205,7 +205,6 @@ static inline void ci_role_stop(struct ci13xxx *ci)
 
 	ci->roles[role]->stop(ci);
 }
-
 /******************************************************************************
  * REGISTERS
  *****************************************************************************/
diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
index 8857b2c..dd1fd87 100644
--- a/drivers/usb/chipidea/core.c
+++ b/drivers/usb/chipidea/core.c
@@ -323,27 +323,16 @@ static void ci_handle_id_switch(struct ci13xxx *ci)
 			ci_role(ci)->name, ci->roles[role]->name);
 
 		/* 1. Finish the current role */
-		if (ci->role == CI_ROLE_GADGET) {
-			usb_gadget_vbus_disconnect(&ci->gadget);
-			/* host doesn't care B_SESSION_VALID event */
-			ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
-			ci_disable_otg_interrupt(ci, OTGSC_BSVIE);
-			ci->role = CI_ROLE_END;
-			/* reset controller */
-			hw_device_reset(ci, USBMODE_CM_IDLE);
-		} else if (ci->role == CI_ROLE_HOST) {
-			ci_role_stop(ci);
-			/* reset controller */
-			hw_device_reset(ci, USBMODE_CM_IDLE);
-		}
+		ci_role_stop(ci);
+		hw_device_reset(ci, USBMODE_CM_IDLE);
 
 		/* 2. Turn on/off vbus according to coming role */
-		if (ci_otg_role(ci) == CI_ROLE_GADGET) {
+		if (role == CI_ROLE_GADGET) {
 			otg_set_vbus(&ci->otg, false);
 			/* wait vbus lower than OTGSC_BSV */
 			hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
 					CI_VBUS_STABLE_TIMEOUT);
-		} else if (ci_otg_role(ci) == CI_ROLE_HOST) {
+		} else if (role == CI_ROLE_HOST) {
 			otg_set_vbus(&ci->otg, true);
 			/* wait vbus higher than OTGSC_AVV */
 			hw_wait_reg(ci, OP_OTGSC, OTGSC_AVV, OTGSC_AVV,
@@ -351,13 +340,7 @@ static void ci_handle_id_switch(struct ci13xxx *ci)
 		}
 
 		/* 3. Begin the new role */
-		if (ci_otg_role(ci) == CI_ROLE_GADGET) {
-			ci->role = role;
-			ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
-			ci_enable_otg_interrupt(ci, OTGSC_BSVIE);
-		} else if (ci_otg_role(ci) == CI_ROLE_HOST) {
-			ci_role_start(ci, role);
-		}
+		ci_role_start(ci, role);
 	}
 }
 
@@ -396,8 +379,24 @@ static void ci_delayed_work(struct work_struct *work)
 	struct delayed_work *dwork = to_delayed_work(work);
 	struct ci13xxx *ci = container_of(dwork, struct ci13xxx, dwork);
 
-	otg_set_vbus(&ci->otg, true);
+	if (ci->role == CI_ROLE_GADGET) {
+		/*
+		 * if it is device mode:
+		 * - Enable vbus detect
+		 * - If it has already connected to host, notify udc
+		 */
+		ci_enable_otg_interrupt(ci, OTGSC_BSVIE);
+		ci_handle_vbus_change(ci);
+	} else if (ci->is_otg && (ci->role == CI_ROLE_HOST)) {
+		/* USB Device at the MicroB to A cable */
+		otg_set_vbus(&ci->otg, true);
+	}
+}
 
+static inline void ci_role_destroy(struct ci13xxx *ci)
+{
+	ci_hdrc_gadget_destroy(ci);
+	ci_hdrc_host_destroy(ci);
 }
 
 static ssize_t show_role(struct device *dev, struct device_attribute *attr,
@@ -594,7 +593,7 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 
 	ret = ci_hdrc_gadget_init(ci);
 	if (ret)
-		dev_info(dev, "doesn't support gadget\n");
+		dev_info(dev, "doesn't support gadget, ret=%d\n", ret);
 
 	if (!ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]) {
 		dev_err(dev, "no supported roles\n");
@@ -616,23 +615,9 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 			: CI_ROLE_GADGET;
 	}
 
-	ret = ci_role_start(ci, ci->role);
-	if (ret) {
-		dev_err(dev, "can't start %s role\n", ci_role(ci)->name);
-		ret = -ENODEV;
-		goto rm_wq;
-	}
+	ci_role_start(ci, ci->role);
 
 	otgsc = hw_read(ci, OP_OTGSC, ~0);
-	/*
-	 * if it is device mode:
-	 * - Enable vbus detect
-	 * - If it has already connected to host, notify udc
-	 */
-	if (ci->role == CI_ROLE_GADGET) {
-		ci_enable_otg_interrupt(ci, OTGSC_BSVIE);
-		ci_handle_vbus_change(ci);
-	}
 
 	platform_set_drvdata(pdev, ci);
 	ret = request_irq(ci->irq, ci_irq, IRQF_SHARED, ci->platdata->name,
@@ -642,18 +627,17 @@ static int ci_hdrc_probe(struct platform_device *pdev)
 
 	ret = device_create_file(dev, &dev_attr_role);
 	if (ret)
-		goto rm_attr;
+		goto free_irq;
 
-	/* Handle the situation that usb device at the MicroB to A cable */
-	if (ci->is_otg && !(otgsc & OTGSC_ID))
-		queue_delayed_work(ci->wq, &ci->dwork, msecs_to_jiffies(500));
+	/* Defer some operations */
+	queue_delayed_work(ci->wq, &ci->dwork, msecs_to_jiffies(200));
 
 	return ret;
 
-rm_attr:
-	device_remove_file(dev, &dev_attr_role);
+free_irq:
+	free_irq(ci->irq, ci);
 stop:
-	ci_role_stop(ci);
+	ci_role_destroy(ci);
 rm_wq:
 	flush_workqueue(ci->wq);
 	destroy_workqueue(ci->wq);
@@ -669,7 +653,7 @@ static int ci_hdrc_remove(struct platform_device *pdev)
 	destroy_workqueue(ci->wq);
 	device_remove_file(ci->dev, &dev_attr_role);
 	free_irq(ci->irq, ci);
-	ci_role_stop(ci);
+	ci_role_destroy(ci);
 
 	return 0;
 }
diff --git a/drivers/usb/chipidea/host.c b/drivers/usb/chipidea/host.c
index 8e9d312..ead3158 100644
--- a/drivers/usb/chipidea/host.c
+++ b/drivers/usb/chipidea/host.c
@@ -105,3 +105,9 @@ int ci_hdrc_host_init(struct ci13xxx *ci)
 
 	return 0;
 }
+
+void ci_hdrc_host_destroy(struct ci13xxx *ci)
+{
+	if (ci->role == CI_ROLE_HOST)
+		host_stop(ci);
+}
diff --git a/drivers/usb/chipidea/host.h b/drivers/usb/chipidea/host.h
index 761fb1f..5fd03a4 100644
--- a/drivers/usb/chipidea/host.h
+++ b/drivers/usb/chipidea/host.h
@@ -4,13 +4,15 @@
 #ifdef CONFIG_USB_CHIPIDEA_HOST
 
 int ci_hdrc_host_init(struct ci13xxx *ci);
-
+void ci_hdrc_host_destroy(struct ci13xxx *ci);
 #else
 
 static inline int ci_hdrc_host_init(struct ci13xxx *ci)
 {
 	return -ENXIO;
 }
+static void ci_hdrc_host_destroy(struct ci13xxx *ci)
+{}
 
 #endif
 
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 83e54bb..e82dae4 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -31,6 +31,7 @@
 
 #include "ci.h"
 #include "udc.h"
+#include "otg.h"
 #include "bits.h"
 #include "debug.h"
 
@@ -1743,7 +1744,12 @@ static int udc_start(struct ci13xxx *ci)
 	if (!IS_ERR_OR_NULL(ci->transceiver)) {
 		retval = otg_set_peripheral(ci->transceiver->otg,
 						&ci->gadget);
-		if (retval)
+		/* 
+		 * If we implement all USB functions using chipidea drivers,
+		 * it doesn't need to call above API, meanwhile, if we only
+		 * use gadget function, calling above API is useless.
+		 */
+		if (retval && retval != -ENOTSUPP)
 			goto remove_dbg;
 	}
 
@@ -1780,12 +1786,27 @@ free_qh_pool:
 	return retval;
 }
 
+static int udc_id_switch_for_device(struct ci13xxx *ci)
+{
+	ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
+	ci_enable_otg_interrupt(ci, OTGSC_BSVIE);
+
+	return 0;
+}
+
+static void udc_id_switch_for_host(struct ci13xxx *ci)
+{
+	/* host doesn't care B_SESSION_VALID event */
+	ci_clear_otg_interrupt(ci, OTGSC_BSVIS);
+	ci_disable_otg_interrupt(ci, OTGSC_BSVIE);
+}
+
 /**
- * udc_remove: parent remove must call this to remove UDC
+ * ci_hdrc_gadget_destroy: parent remove must call this to remove UDC
  *
  * No interrupts active, the IRQ has been released
  */
-static void udc_stop(struct ci13xxx *ci)
+void ci_hdrc_gadget_destroy(struct ci13xxx *ci)
 {
 	if (ci == NULL)
 		return;
@@ -1804,15 +1825,13 @@ static void udc_stop(struct ci13xxx *ci)
 	}
 	dbg_remove_files(&ci->gadget.dev);
 	device_unregister(&ci->gadget.dev);
-	/* my kobject is dynamic, I swear! */
-	memset(&ci->gadget, 0, sizeof(ci->gadget));
 }
 
 /**
  * ci_hdrc_gadget_init - initialize device related bits
  * ci: the controller
  *
- * This function enables the gadget role, if the device is "device capable".
+ * This function initializes gadget, if the device is "device capable".
  */
 int ci_hdrc_gadget_init(struct ci13xxx *ci)
 {
@@ -1825,11 +1844,11 @@ int ci_hdrc_gadget_init(struct ci13xxx *ci)
 	if (!rdrv)
 		return -ENOMEM;
 
-	rdrv->start	= udc_start;
-	rdrv->stop	= udc_stop;
+	rdrv->start	= udc_id_switch_for_device;
+	rdrv->stop	= udc_id_switch_for_host;
 	rdrv->irq	= udc_irq;
 	rdrv->name	= "gadget";
 	ci->roles[CI_ROLE_GADGET] = rdrv;
 
-	return 0;
+	return udc_start(ci);
 }
diff --git a/drivers/usb/chipidea/udc.h b/drivers/usb/chipidea/udc.h
index 4ff2384..6c42d49 100644
--- a/drivers/usb/chipidea/udc.h
+++ b/drivers/usb/chipidea/udc.h
@@ -80,6 +80,7 @@ struct ci13xxx_req {
 #ifdef CONFIG_USB_CHIPIDEA_UDC
 
 int ci_hdrc_gadget_init(struct ci13xxx *ci);
+void ci_hdrc_gadget_destroy(struct ci13xxx *ci);
 
 #else
 
@@ -87,7 +88,8 @@ static inline int ci_hdrc_gadget_init(struct ci13xxx *ci)
 {
 	return -ENXIO;
 }
-
+static void ci_hdrc_gadget_destroy(struct ci13xxx *ci)
+{}
 #endif
 
 #endif /* __DRIVERS_USB_CHIPIDEA_UDC_H */
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH v6 5/8] usb: chipidea: udc: add pullup/pulldown dp at hw_device_state
From: Peter Chen @ 2013-02-04  3:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359947039-23906-1-git-send-email-peter.chen@freescale.com>

- During the connect/disconnect host, we need to pullup
and pulldown dp
- Make sure the dp is not pullup until the vbus is on when
flag CI13XXX_PULLUP_ON_VBUS is set
- Using hw_device_state when set run/stop bit

Signed-off-by: Peter Chen <peter.chen@freescale.com>
---
 drivers/usb/chipidea/udc.c |   10 ++++++++--
 1 files changed, 8 insertions(+), 2 deletions(-)

diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index e82dae4..597ae64 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -91,8 +91,10 @@ static int hw_device_state(struct ci13xxx *ci, u32 dma)
 		/* interrupt, error, port change, reset, sleep/suspend */
 		hw_write(ci, OP_USBINTR, ~0,
 			     USBi_UI|USBi_UEI|USBi_PCI|USBi_URI|USBi_SLI);
+		hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
 	} else {
 		hw_write(ci, OP_USBINTR, ~0, 0);
+		hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
 	}
 	return 0;
 }
@@ -1424,10 +1426,14 @@ static int ci13xxx_pullup(struct usb_gadget *_gadget, int is_on)
 {
 	struct ci13xxx *ci = container_of(_gadget, struct ci13xxx, gadget);
 
+	if ((ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) &&
+			!ci->vbus_active)
+		return -ENOTSUPP;
+
 	if (is_on)
-		hw_write(ci, OP_USBCMD, USBCMD_RS, USBCMD_RS);
+		hw_device_state(ci, ci->ep0out->qh.dma);
 	else
-		hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
+		hw_device_state(ci, 0);
 
 	return 0;
 }
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH v6 6/8] usb: chipidea: udc: retire the flag CI13_PULLUP_ON_VBUS
From: Peter Chen @ 2013-02-04  3:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359947039-23906-1-git-send-email-peter.chen@freescale.com>

(change CI13XXX to CI13 to avoid junk email check)
Now, we have handled vbus session in core driver when the
vbus interrupt occurs, so our pullup operations are all
according to vbus.
Of cource, the software can still call .pullup when device connects
to host if it wants to connect/disconnect with host.

Signed-off-by: Peter Chen <peter.chen@freescale.com>
---
 drivers/usb/chipidea/ci13xxx_imx.c |    1 -
 drivers/usb/chipidea/ci13xxx_msm.c |    1 -
 drivers/usb/chipidea/udc.c         |   23 ++++++++---------------
 include/linux/usb/chipidea.h       |    1 -
 4 files changed, 8 insertions(+), 18 deletions(-)

diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci13xxx_imx.c
index 8c29122..3b91ff4 100644
--- a/drivers/usb/chipidea/ci13xxx_imx.c
+++ b/drivers/usb/chipidea/ci13xxx_imx.c
@@ -88,7 +88,6 @@ EXPORT_SYMBOL_GPL(usbmisc_get_init_data);
 static struct ci13xxx_platform_data ci13xxx_imx_platdata  = {
 	.name			= "ci13xxx_imx",
 	.flags			= CI13XXX_REQUIRE_TRANSCEIVER |
-				  CI13XXX_PULLUP_ON_VBUS |
 				  CI13XXX_DISABLE_STREAMING,
 	.capoffset		= DEF_CAPOFFSET,
 };
diff --git a/drivers/usb/chipidea/ci13xxx_msm.c b/drivers/usb/chipidea/ci13xxx_msm.c
index 7d16681..5755ee8 100644
--- a/drivers/usb/chipidea/ci13xxx_msm.c
+++ b/drivers/usb/chipidea/ci13xxx_msm.c
@@ -49,7 +49,6 @@ static struct ci13xxx_platform_data ci13xxx_msm_platdata = {
 	.name			= "ci13xxx_msm",
 	.flags			= CI13XXX_REGS_SHARED |
 				  CI13XXX_REQUIRE_TRANSCEIVER |
-				  CI13XXX_PULLUP_ON_VBUS |
 				  CI13XXX_DISABLE_STREAMING,
 
 	.notify_event		= ci13xxx_msm_notify_event,
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 597ae64..b57b735 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1360,9 +1360,6 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
 	unsigned long flags;
 	int gadget_ready = 0;
 
-	if (!(ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS))
-		return -EOPNOTSUPP;
-
 	spin_lock_irqsave(&ci->lock, flags);
 	ci->vbus_active = is_active;
 	if (ci->driver)
@@ -1426,8 +1423,7 @@ static int ci13xxx_pullup(struct usb_gadget *_gadget, int is_on)
 {
 	struct ci13xxx *ci = container_of(_gadget, struct ci13xxx, gadget);
 
-	if ((ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) &&
-			!ci->vbus_active)
+	if (!ci->vbus_active)
 		return -ENOTSUPP;
 
 	if (is_on)
@@ -1551,14 +1547,12 @@ static int ci13xxx_start(struct usb_gadget *gadget,
 
 	ci->driver = driver;
 	pm_runtime_get_sync(&ci->gadget.dev);
-	if (ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) {
-		if (ci->vbus_active) {
-			if (ci->platdata->flags & CI13XXX_REGS_SHARED)
-				hw_device_reset(ci, USBMODE_CM_DC);
-		} else {
-			pm_runtime_put_sync(&ci->gadget.dev);
-			goto done;
-		}
+	if (ci->vbus_active) {
+		if (ci->platdata->flags & CI13XXX_REGS_SHARED)
+			hw_device_reset(ci, USBMODE_CM_DC);
+	} else {
+		pm_runtime_put_sync(&ci->gadget.dev);
+		goto done;
 	}
 
 	retval = hw_device_state(ci, ci->ep0out->qh.dma);
@@ -1581,8 +1575,7 @@ static int ci13xxx_stop(struct usb_gadget *gadget,
 
 	spin_lock_irqsave(&ci->lock, flags);
 
-	if (!(ci->platdata->flags & CI13XXX_PULLUP_ON_VBUS) ||
-			ci->vbus_active) {
+	if (ci->vbus_active) {
 		hw_device_state(ci, 0);
 		if (ci->platdata->notify_event)
 			ci->platdata->notify_event(ci,
diff --git a/include/linux/usb/chipidea.h b/include/linux/usb/chipidea.h
index 544825d..37821b3 100644
--- a/include/linux/usb/chipidea.h
+++ b/include/linux/usb/chipidea.h
@@ -17,7 +17,6 @@ struct ci13xxx_platform_data {
 	unsigned long	 flags;
 #define CI13XXX_REGS_SHARED		BIT(0)
 #define CI13XXX_REQUIRE_TRANSCEIVER	BIT(1)
-#define CI13XXX_PULLUP_ON_VBUS		BIT(2)
 #define CI13XXX_DISABLE_STREAMING	BIT(3)
 
 #define CI13XXX_CONTROLLER_RESET_EVENT		0
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH v6 7/8] usb: chipidea: imx: add internal vbus regulator control
From: Peter Chen @ 2013-02-04  3:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359947039-23906-1-git-send-email-peter.chen@freescale.com>

- For host, the vbus should always be on.
- For otg, the vbus is off defaultly, the vbus needs to be
turned on/off when usb role switches.

Signed-off-by: Peter Chen <peter.chen@freescale.com>
---
 drivers/usb/chipidea/ci.h          |    2 +
 drivers/usb/chipidea/ci13xxx_imx.c |   80 ++++++++++++++++++++++++++++--------
 2 files changed, 64 insertions(+), 18 deletions(-)

diff --git a/drivers/usb/chipidea/ci.h b/drivers/usb/chipidea/ci.h
index 3ebe87a..bd78078 100644
--- a/drivers/usb/chipidea/ci.h
+++ b/drivers/usb/chipidea/ci.h
@@ -131,6 +131,7 @@ struct hw_bank {
  * @hcd: pointer to usb_hcd for ehci host driver
  * @otg: for otg support
  * @events: events for otg, and handled at ci_role_work
+ * @reg_vbus: used to control internal vbus regulator
  */
 struct ci13xxx {
 	struct device			*dev;
@@ -170,6 +171,7 @@ struct ci13xxx {
 	struct usb_otg      		otg;
 	bool				id_event;
 	bool				b_sess_valid_event;
+	struct regulator		*reg_vbus;
 };
 
 static inline struct ci_role_driver *ci_role(struct ci13xxx *ci)
diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci13xxx_imx.c
index 3b91ff4..4c9df98 100644
--- a/drivers/usb/chipidea/ci13xxx_imx.c
+++ b/drivers/usb/chipidea/ci13xxx_imx.c
@@ -88,14 +88,47 @@ EXPORT_SYMBOL_GPL(usbmisc_get_init_data);
 static struct ci13xxx_platform_data ci13xxx_imx_platdata  = {
 	.name			= "ci13xxx_imx",
 	.flags			= CI13XXX_REQUIRE_TRANSCEIVER |
-				  CI13XXX_DISABLE_STREAMING,
+				  CI13XXX_DISABLE_STREAMING |
+				  CI13XXX_REGS_SHARED,
 	.capoffset		= DEF_CAPOFFSET,
 };
 
+static int ci13xxx_otg_set_vbus(struct usb_otg *otg, bool enabled)
+{
+	struct ci13xxx	*ci = container_of(otg, struct ci13xxx, otg);
+	struct regulator *reg_vbus = ci->reg_vbus;
+	int ret;
+
+	WARN_ON(!reg_vbus);
+
+	if (reg_vbus) {
+		if (enabled) {
+			ret = regulator_enable(reg_vbus);
+			if (ret) {
+				dev_err(ci->dev,
+				"Failed to enable vbus regulator, ret=%d\n",
+				ret);
+				return ret;
+			}
+		} else {
+			ret = regulator_disable(reg_vbus);
+			if (ret) {
+				dev_err(ci->dev,
+				"Failed to disable vbus regulator, ret=%d\n",
+				ret);
+				return ret;
+			}
+		}
+	}
+
+	return 0;
+}
+
 static int ci13xxx_imx_probe(struct platform_device *pdev)
 {
 	struct ci13xxx_imx_data *data;
 	struct platform_device *plat_ci, *phy_pdev;
+	struct ci13xxx	*ci;
 	struct device_node *phy_np;
 	struct resource *res;
 	struct regulator *reg_vbus;
@@ -152,20 +185,11 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
 		}
 	}
 
-	/* we only support host now, so enable vbus here */
 	reg_vbus = devm_regulator_get(&pdev->dev, "vbus");
-	if (!IS_ERR(reg_vbus)) {
-		ret = regulator_enable(reg_vbus);
-		if (ret) {
-			dev_err(&pdev->dev,
-				"Failed to enable vbus regulator, err=%d\n",
-				ret);
-			goto put_np;
-		}
+	if (!IS_ERR(reg_vbus))
 		data->reg_vbus = reg_vbus;
-	} else {
+	else
 		reg_vbus = NULL;
-	}
 
 	ci13xxx_imx_platdata.phy = data->phy;
 
@@ -175,7 +199,7 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
 		if (!pdev->dev.dma_mask) {
 			ret = -ENOMEM;
 			dev_err(&pdev->dev, "Failed to alloc dma_mask!\n");
-			goto err;
+			goto put_np;
 		}
 		*pdev->dev.dma_mask = DMA_BIT_MASK(32);
 		dma_set_coherent_mask(&pdev->dev, *pdev->dev.dma_mask);
@@ -186,7 +210,7 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
 		if (ret) {
 			dev_err(&pdev->dev,
 				"usbmisc init failed, ret=%d\n", ret);
-			goto err;
+			goto put_np;
 		}
 	}
 
@@ -198,24 +222,44 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
 		dev_err(&pdev->dev,
 			"Can't register ci_hdrc platform device, err=%d\n",
 			ret);
-		goto err;
+		goto put_np;
 	}
 
 	data->ci_pdev = plat_ci;
 	platform_set_drvdata(pdev, data);
 
+	ci = platform_get_drvdata(plat_ci);
+	/*
+	 * Internal vbus on/off policy
+	 * - Always on for host only function
+	 * - Always off for gadget only function
+	 * - call otg.set_vbus to control on/off according usb role
+	 */
+
+	if (ci->roles[CI_ROLE_HOST] && !ci->roles[CI_ROLE_GADGET]
+			&& reg_vbus) {
+		ret = regulator_enable(reg_vbus);
+		if (ret) {
+			dev_err(&pdev->dev,
+				"Failed to enable vbus regulator, ret=%d\n",
+				ret);
+			goto put_np;
+		}
+	} else if (ci->is_otg) {
+		ci->otg.set_vbus = ci13xxx_otg_set_vbus;
+		ci->reg_vbus = data->reg_vbus;
+	}
+
 	pm_runtime_no_callbacks(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 
 	return 0;
 
-err:
-	if (reg_vbus)
-		regulator_disable(reg_vbus);
 put_np:
 	if (phy_np)
 		of_node_put(phy_np);
 	clk_disable_unprepare(data->clk);
+
 	return ret;
 }
 
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH v6 8/8] usb: chipidea: udc: fix the oops when plugs in usb cable after rmmod gadget
From: Peter Chen @ 2013-02-04  3:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359947039-23906-1-git-send-email-peter.chen@freescale.com>

When we rmmod gadget, we should call ci13xxx_stop unconditionally,
as ci->driver needs to be cleared. Otherwise, we plug in usb cable
again, it will think gadget is there, in fact, it is removed.
Below is the oops this patch fixes.

root at freescale ~$ ci_hdrc ci_hdrc.0: Connected to host
Unable to handle kernel paging request at virtual address 7f01171c
pgd = 80004000
[7f01171c] *pgd=4fa1e811, *pte=00000000, *ppte=00000000
Internal error: Oops: 7 [#1] SMP ARM
Modules linked in: f_acm libcomposite u_serial [last unloaded: g_serial]
CPU: 0    Not tainted  (3.8.0-rc5+ #221)
	PC is at _gadget_stop_activity+0xbc/0x128
	LR is at ep_fifo_flush+0x68/0xa0
	pc : [<803634cc>]    lr : [<80363938>]    psr: 20000193
	sp : 806c7dc8  ip : 00000000  fp : 806c7de4
	r10: 00000000  r9 : 80710ea4  r8 : 00000000
	r7 : bf834094  r6 : bf834098  r5 : bf834010  r4 : bf8340a0
	r3 : 7f011708  r2 : 01940194  r1 : a0000193  r0 : bf834014
	Flags: nzCv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
	Control: 10c53c7d  Table: 4f06404a  DAC: 00000017
	Process swapper/0 (pid: 0, stack limit = 0x806c6238)
	Stack: (0x806c7dc8 to 0x806c8000)
	7dc0:                   bf834010 bf809950 bf834010 0000004b 806c7e44 806c7de8
	7de0: 80365400 8036341c 0000ec1c 00000000 0000ec1c 00000040 fff5ede0 bf834014
	7e00: 000a1220 00000000 0000002e ffffd958 806c7e3c 806c7e20 8004e870 bf834010
	7e20: bf809950 0000004b 0000004b 00000000 80710ea4 00000000 806c7e5c 806c7e48
	7e40: 80362888 80365154 bfb35180 bf809950 806c7e9c 806c7e60 8008111c 803627f4
	7e60: 00989680 00000000 bf809900 bf809964 812df8c0 bf809900 bf809950 806c3f2c
	7e80: 0000004b 00000000 412fc09a 00000000 806c7eb4 806c7ea0 80081368 800810b8
	7ea0: bf809900 bf809950 806c7ecc 806c7eb8 800843c8 8008130c 0000004b 806cf748
	7ec0: 806c7ee4 806c7ed0 80081088 8008432c 806c6000 806cf748 806c7f0c 806c7ee8
	7ee0: 8000fa44 8008105c f400010c 806ce974 806c7f30 f4000110 806d29e8 412fc09a
	7f00: 806c7f2c 806c7f10 80008584 8000f9f4 8000fbd0 60000013 ffffffff 806c7f64
	7f20: 806c7f84 806c7f30 8000eac0 80008554 00000000 00000000 0000000f 8001aea0
	7f40: 806c6000 80712a48 804f0040 00000000 806d29e8 412fc09a 00000000 806c7f84
	7f60: 806c7f88 806c7f78 8000fbcc 8000fbd0 60000013 ffffffff 806c7fac 806c7f88
	7f80: 8001015c 8000fb9c 806cf5b0 80712980 806a4528 8fffffff 1000406a 412fc09a
	7fa0: 806c7fbc 806c7fb0 804e5334 800100ac 806c7ff4 806c7fc0 80668940 804e52d4
	7fc0: ffffffff ffffffff 806684bc 00000000 00000000 806a4528 10c53c7d 806ce94c
	7fe0: 806a4524 806d29dc 00000000 806c7ff8 10008078 806686b0 00000000 00000000
	Backtrace:
	[<80363410>] (_gadget_stop_activity+0x0/0x128) from [<80365400>] (udc_irq+0x2b8/0xf38)
	 r7:0000004b r6:bf834010 r5:bf809950 r4:bf834010
	 [<80365148>] (udc_irq+0x0/0xf38) from [<80362888>] (ci_irq+0xa0/0xf4)
	[<803627e8>] (ci_irq+0x0/0xf4) from [<8008111c>] (handle_irq_event_percpu+0x70/0x254)
	 r5:bf809950 r4:bfb35180
	 [<800810ac>] (handle_irq_event_percpu+0x0/0x254) from [<80081368>] (handle_irq_event+0x68/0x88)
	[<80081300>] (handle_irq_event+0x0/0x88) from [<800843c8>] (handle_fasteoi_irq+0xa8/0x178)
	 r5:bf809950 r4:bf809900
	 [<80084320>] (handle_fasteoi_irq+0x0/0x178) from [<80081088>] (generic_handle_irq+0x38/0x40)
	 r5:806cf748 r4:0000004b
	 [<80081050>] (generic_handle_irq+0x0/0x40) from [<8000fa44>] (handle_IRQ+0x5c/0xbc)
	 r5:806cf748 r4:806c6000
	 [<8000f9e8>] (handle_IRQ+0x0/0xbc) from [<80008584>] (gic_handle_irq+0x3c/0x70)
	 r9:412fc09a r8:806d29e8 r7:f4000110 r6:806c7f30 r5:806ce974
	 r4:f400010c
	 [<80008548>] (gic_handle_irq+0x0/0x70) from [<8000eac0>] (__irq_svc+0x40/0x54)
	Exception stack(0x806c7f30 to 0x806c7f78)
	7f20:                                     00000000 00000000 0000000f 8001aea0
	7f40: 806c6000 80712a48 804f0040 00000000 806d29e8 412fc09a 00000000 806c7f84
	7f60: 806c7f88 806c7f78 8000fbcc 8000fbd0 60000013 ffffffff
	 r7:806c7f64 r6:ffffffff r5:60000013 r4:8000fbd0
	 [<8000fb90>] (default_idle+0x0/0x4c) from [<8001015c>] (cpu_idle+0xbc/0xf8)
	[<800100a0>] (cpu_idle+0x0/0xf8) from [<804e5334>] (rest_init+0x6c/0x84)
	 r9:412fc09a r8:1000406a r7:8fffffff r6:806a4528 r5:80712980
	 r4:806cf5b0
	 [<804e52c8>] (rest_init+0x0/0x84) from [<80668940>] (start_kernel+0x29c/0x2ec)
	[<806686a4>] (start_kernel+0x0/0x2ec) from [<10008078>] (0x10008078)
	Code: e12fff33 e5953200 e3530000 0a000002 (e5933014)
	---[ end trace aade28ad434062bd ]---
	Kernel panic - not syncing: 0xbf8bdfa8)
	df60: 00000000 00000000 0000000f 8001aea0 bf8bc000 80712a48 804f0040 00000000
	df80: 806d29e8 412fc09a 00000000 bf8bdfb4 bf8bdfb8 bf8bdfa8 8000fbcc 8000fbd0
	dfa0: 60000013 ffffffff
	 r7:bf8bdf94 r6:ffffffff r5:60000013 r4:8000fbd0
	 [<8000fb90>] (default_idle+0x0/0x4c) from [<8001015c>] (cpu_idle+0xbc/0xf8)
	[<800100a0>] (cpu_idle+0x0/0xf8) from [<804e7930>] (secondary_start_kernel+0x120/0x148)
	 r9:412fc09a r8:1000406a r7:80712d20 r6:10c03c7d r5:00000002
	 r4:806e2008
	 [<804e7810>] (secondary_start_kernel+0x0/0x148) from [<104e7148>] (0x104e7148)
	 r5:0000001f r4:4f8a806a
	 CPU3: stopping
	 Backtrace:
	 [<800132e8>] (dump_backtrace+0x0/0x114) from [<804ea684>] (dump_stack+0x20/0x24)
	 r7:00000000 r6:806c3f2c r5:806cf748 r4:80712d18
	 [<804ea664>] (dump_stack+0x0/0x24) from [<80014adc>] (handle_IPI+0x140/0x18c)
	[<8001499c>] (handle_IPI+0x0/0x18c) from [<800085b0>] (gic_handle_irq+0x68/0x70)
	 r9:412fc09a r8:806d29e8 r7:f4000110 r6:bf8bff60 r5:806ce974
	 r4:f400010c
	 [<80008548>] (gic_handle_irq+0x0/0x70) from [<8000eac0>] (__irq_svc+0x40/0x54)
	Exception stack(0xbf8bff60 to 0xbf8bffa8)
	ff60: 00000000 00000000 0000000f 8001aea0 bf8be000 80712a48 804f0040 00000000
	ff80: 806d29e8 412fc09a 00000000 bf8bffb4 bf8bffb8 bf8bffa8 8000fbcc 8000fbd0
	ffa0: 60000013 ffffffff
	 r7:bf8bff94 r6:ffffffff r5:60000013 r4:8000fbd0
	 [<8000fb90>] (default_idle+0x0/0x4c) from [<8001015c>] (cpu_idle+0xbc/0xf8)
	[<800100a0>] (cpu_idle+0x0/0xf8) from [<804e7930>] (secondary_start_kernel+0x120/0x148)
	 r9:412fc09a r8:1000406a r7:80712d20 r6:10c03c7d r5:00000003
	 r4:806e2008
	 [<804e7810>] (secondary_start_kernel+0x0/0x148) from [<104e7148>] (0x104e7148)
	 r5:0000001f r4:4f8a806a
	 CPU1: stopping
	 Backtrace:
	 [<800132e8>] (dump_backtrace+0x0/0x114) from [<804ea684>] (dump_stack+0x20/0x24)
	 r7:00000000 r6:806c3f2c r5:806cf748 r4:80712d18
	 [<804ea664>] (dump_stack+0x0/0x24) from [<80014adc>] (handle_IPI+0x140/0x18c)
	[<8001499c>] (handle_IPI+0x0/0x18c) from [<800085b0>] (gic_handle_irq+0x68/0x70)
	 r9:412fc09a r8:806d29e8 r7:f4000110 r6:bf8bbf60 r5:806ce974
	 r4:f400010c
	 [<80008548>] (gic_handle_irq+0x0/0x70) from [<8000eac0>] (__irq_svc+0x40/0x54)
	Exception stack(0xbf8bbf60 to 0xbf8bbfa8)
	bf60: 00000000 00000000 0000000f 8001aea0 bf8ba000 80712a48 804f0040 00000000
	bf80: 806d29e8 412fc09a 00000000 bf8bbfb4 bf8bbfb8 bf8bbfa8 8000fbcc 8000fbd0
	bfa0: 60000013 ffffffff
	 r7:bf8bbf94 r6:ffffffff r5:60000013 r4:8000fbd0
	 [<8000fb90>] (default_idle+0x0/0x4c) from [<8001015c>] (cpu_idle+0xbc/0xf8)
	[<800100a0>] (cpu_idle+0x0/0xf8) from [<804e7930>] (secondary_start_kernel+0x120/0x148)
	 r9:412fc09a r8:1000406a r7:80712d20 r6:10c03c7d r5:00000001
	 r4:806e2008

Signed-off-by: Peter Chen <peter.chen@freescale.com>
---
 drivers/usb/chipidea/udc.c |   20 +++++++++-----------
 1 files changed, 9 insertions(+), 11 deletions(-)

diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index b57b735..e738883 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -1575,17 +1575,15 @@ static int ci13xxx_stop(struct usb_gadget *gadget,
 
 	spin_lock_irqsave(&ci->lock, flags);
 
-	if (ci->vbus_active) {
-		hw_device_state(ci, 0);
-		if (ci->platdata->notify_event)
-			ci->platdata->notify_event(ci,
-			CI13XXX_CONTROLLER_STOPPED_EVENT);
-		ci->driver = NULL;
-		spin_unlock_irqrestore(&ci->lock, flags);
-		_gadget_stop_activity(&ci->gadget);
-		spin_lock_irqsave(&ci->lock, flags);
-		pm_runtime_put(&ci->gadget.dev);
-	}
+	hw_device_state(ci, 0);
+	if (ci->platdata->notify_event)
+		ci->platdata->notify_event(ci,
+		CI13XXX_CONTROLLER_STOPPED_EVENT);
+	ci->driver = NULL;
+	spin_unlock_irqrestore(&ci->lock, flags);
+	_gadget_stop_activity(&ci->gadget);
+	spin_lock_irqsave(&ci->lock, flags);
+	pm_runtime_put(&ci->gadget.dev);
 
 	spin_unlock_irqrestore(&ci->lock, flags);
 
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH V2 3/6] ARM: davinci: da850: add DT node for I2C0
From: Vishwanathrao Badarkhe, Manish @ 2013-02-04  3:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <510E5CC1.8050801@ti.com>

On Sun, Feb 03, 2013 at 18:19:05, Nori, Sekhar wrote:
> 
> 
> On 1/29/2013 1:08 PM, Vishwanathrao Badarkhe, Manish wrote:
> > Add I2C0 device tree node information to da850-evm.
> > Also, add I2C0 pin muxing information in da850-evm.
> > 
> > Signed-off-by: Vishwanathrao Badarkhe, Manish <manishv.b@ti.com>
> > ---
> > Changes since V1:
> >  - Updated i2c0 node names in dts and dtsi file.
> >  - Removed interrupt parent from i2c0 node.
> >  - Handled i2c0 pin mux inside i2c0 node.
> > 
> > :100644 100644 433027f... c9ed683... M	arch/arm/boot/dts/da850-evm.dts
> > :100644 100644 5e0eb5c... 245ab9a... M	arch/arm/boot/dts/da850.dtsi
> >  arch/arm/boot/dts/da850-evm.dts |    5 +++++
> >  arch/arm/boot/dts/da850.dtsi    |   15 +++++++++++++++
> >  2 files changed, 20 insertions(+), 0 deletions(-)
> > 
> > diff --git a/arch/arm/boot/dts/da850-evm.dts 
> > b/arch/arm/boot/dts/da850-evm.dts index 433027f..c9ed683 100644
> > --- a/arch/arm/boot/dts/da850-evm.dts
> > +++ b/arch/arm/boot/dts/da850-evm.dts
> > @@ -27,6 +27,11 @@
> >  		serial2: serial at 1d0d000 {
> >  			status = "okay";
> >  		};
> > +		i2c0: i2c0 at 1c22000 {
> 
> This should be:
> 
> i2c0: i2c at 1c22000
> 
> inline with what has been done in rest of this file.

Ok, I will update this name everywhere.

> 
> > +			status = "okay";
> > +			pinctrl-names = "default";
> > +			pinctrl-0 = <&i2c0_pins>;
> > +		};
> >  	};
> >  	nand_cs3 at 62000000 {
> >  		status = "okay";
> > diff --git a/arch/arm/boot/dts/da850.dtsi 
> > b/arch/arm/boot/dts/da850.dtsi index 5e0eb5c..245ab9a 100644
> > --- a/arch/arm/boot/dts/da850.dtsi
> > +++ b/arch/arm/boot/dts/da850.dtsi
> > @@ -56,6 +56,12 @@
> >  					0x30 0x01100000  0x0ff00000
> >  				>;
> >  			};
> > +			i2c0_pins: pinmux_i2c0_pins {
> > +				pinctrl-single,bits = <
> > +					/* I2C0_SDA,I2C0_SCL */
> > +					0x10 0x00002200 0x0000ff00
> > +				>;
> > +			};
> >  		};
> >  		serial0: serial at 1c42000 {
> >  			compatible = "ns16550a";
> > @@ -81,6 +87,15 @@
> >  			interrupts = <61>;
> >  			status = "disabled";
> >  		};
> > +		i2c0: i2c0 at 1c22000 {
> > +			compatible = "ti,davinci-i2c";
> > +			reg = <0x22000 0x1000>;
> > +			clock-frequency = <100000>;
> 
> The clock frequency is board specific. This should come from da850-evm.dts.

Ok, I will add this board specific information in da850-evm.dts.

> 
> Also, I think you can merge the auxdata addition with this patch. Can you post the i2c0 support separate from this series, so it can be taken independently? Looks like other patches have some dependencies/acks needed.

Sure, I will merge auxdata addition with this patch and post this patch independently from this series.

> 
> Thanks,
> Sekhar
> 


Regards, 
Manish

^ permalink raw reply

* [PATCH 2/2] ARM: imx: set CKO1 parent clock source in imx6q sabresd
From: Zhang Quan-B13634 @ 2013-02-04  3:13 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130203104636.GB26233@S2101-09.ap.freescale.net>

Hi Shawn,
Please see the feedback inline


Best Regards
Gary


>  -----Original Message-----
>  From: Shawn Guo [mailto:shawn.guo at linaro.org]
>  Sent: Sunday, February 03, 2013 18:47
>  To: Zhang Quan-B13634
>  Cc: kernel at pengutronix.de; linux at arm.linux.org.uk; linux-arm-
>  kernel at lists.infradead.org
>  Subject: Re: [PATCH 2/2] ARM: imx: set CKO1 parent clock source in imx6q
>  sabresd
>  
>  On Fri, Feb 01, 2013 at 02:46:57PM +0800, Gary Zhang wrote:
>  > in imx6q sabresd board, set ahb as CKO1 parent clock sourrce
>  >
>  > Signed-off-by: Gary Zhang <b13634@freescale.com>
>  > ---
>  >  arch/arm/mach-imx/mach-imx6q.c |   15 ++++++++++++---
>  >  1 files changed, 12 insertions(+), 3 deletions(-)
>  >
>  > diff --git a/arch/arm/mach-imx/mach-imx6q.c
>  > b/arch/arm/mach-imx/mach-imx6q.c index 4eb1b3a..860e272 100644
>  > --- a/arch/arm/mach-imx/mach-imx6q.c
>  > +++ b/arch/arm/mach-imx/mach-imx6q.c
>  > @@ -119,7 +119,7 @@ static int ksz9021rn_phy_fixup(struct phy_device *phydev)
>  >  	return 0;
>  >  }
>  >
>  > -static void __init imx6q_sabrelite_cko1_setup(void)
>  > +static void __init cko1_setup(unsigned long freq)
>  >  {
>  >  	struct clk *cko1_sel, *ahb, *cko1;
>  >  	unsigned long rate;
>  > @@ -132,8 +132,10 @@ static void __init imx6q_sabrelite_cko1_setup(void)
>  >  		goto put_clk;
>  >  	}
>  >  	clk_set_parent(cko1_sel, ahb);
>  > -	rate = clk_round_rate(cko1, 16000000);
>  > +	rate = clk_round_rate(cko1, freq);
>  >  	clk_set_rate(cko1, rate);
>  > +
>  > +	return;
>  
>  Why does this "return" needs to be added here?
[Gary-b13634] because the codes below may be ignored when execute 'return' ,
Saving cpu consumption.
>  
>  Shawn
>  
>  >  put_clk:
>  >  	if (!IS_ERR(cko1_sel))
>  >  		clk_put(cko1_sel);
>  > @@ -148,7 +150,12 @@ static void __init imx6q_sabrelite_init(void)
>  >  	if (IS_BUILTIN(CONFIG_PHYLIB))
>  >  		phy_register_fixup_for_uid(PHY_ID_KSZ9021, MICREL_PHY_ID_MASK,
>  >  				ksz9021rn_phy_fixup);
>  > -	imx6q_sabrelite_cko1_setup();
>  > +	cko1_setup(16000000);
>  > +}
>  > +
>  > +static void __init imx6q_sabresd_init(void) {
>  > +	cko1_setup(24000000);
>  >  }
>  >
>  >  static void __init imx6q_1588_init(void) @@ -193,6 +200,8 @@ static
>  > void __init imx6q_init_machine(void)  {
>  >  	if (of_machine_is_compatible("fsl,imx6q-sabrelite"))
>  >  		imx6q_sabrelite_init();
>  > +	else if (of_machine_is_compatible("fsl,imx6q-sabresd"))
>  > +		imx6q_sabresd_init();
>  >
>  >  	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
>  >
>  > --
>  > 1.7.0.4
>  >
>  >

^ permalink raw reply

* [PATCH v3 2/4] ARM: Kirkwood: Add support thermal sensor for 88F6282 and 88F6283
From: Zhang Rui @ 2013-02-04  3:14 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1359815749-27705-3-git-send-email-andrew@lunn.ch>

On Sat, 2013-02-02 at 15:35 +0100, Andrew Lunn wrote:
> From: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
> 
> Kirkwood 88F6282 and 88F6283 have a thermal sensor.
> This patch adds a DT node and enables the driver in the kernel config.
> 
> Signed-off-by: Nobuhiro Iwamatsu <iwamatsu@nigauri.org>
> Signed-off-by: Andrew Lunn <andrew@lunn.ch>

I can take this one but I need ACK from ARM experts first.

thanks,
rui
> ---
>  arch/arm/boot/dts/kirkwood-6282.dtsi |    6 ++++++
>  arch/arm/configs/kirkwood_defconfig  |    2 ++
>  2 files changed, 8 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/kirkwood-6282.dtsi b/arch/arm/boot/dts/kirkwood-6282.dtsi
> index 4ccea21..bd168b6 100644
> --- a/arch/arm/boot/dts/kirkwood-6282.dtsi
> +++ b/arch/arm/boot/dts/kirkwood-6282.dtsi
> @@ -32,6 +32,12 @@
>  			};
>  		};
>  
> +		thermal at 10078 {
> +			compatible = "marvell,kirkwood-thermal";
> +			reg = <0x10078 0x4>;
> +			status = "okay";
> +		};
> +
>  		i2c at 11100 {
>  			compatible = "marvell,mv64xxx-i2c";
>  			reg = <0x11100 0x20>;
> diff --git a/arch/arm/configs/kirkwood_defconfig b/arch/arm/configs/kirkwood_defconfig
> index 93f3794..3d8667f 100644
> --- a/arch/arm/configs/kirkwood_defconfig
> +++ b/arch/arm/configs/kirkwood_defconfig
> @@ -118,6 +118,8 @@ CONFIG_SPI=y
>  CONFIG_SPI_ORION=y
>  CONFIG_GPIO_SYSFS=y
>  # CONFIG_HWMON is not set
> +CONFIG_THERMAL=y
> +CONFIG_KIRKWOOD_THERMAL=y
>  CONFIG_WATCHDOG=y
>  CONFIG_ORION_WATCHDOG=y
>  CONFIG_HID_DRAGONRISE=y

^ permalink raw reply

* [PATCH 4/9] USB: chipidea: add PTW and PTS handling
From: Peter Chen @ 2013-02-04  3:16 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <874nhwmc41.fsf@ashishki-desk.ger.corp.intel.com>

On Fri, Feb 01, 2013 at 02:50:54PM +0200, Alexander Shishkin wrote:
> Michael Grzeschik <mgr@pengutronix.de> writes:
> 
> > On Fri, Feb 01, 2013 at 08:52:07AM +0100, Sascha Hauer wrote:
> >> From: Michael Grzeschik <m.grzeschik@pengutronix.de>
> >> 
> >> This patch makes it possible to configure the PTW and PTS bits inside
> >> the portsc register for host and device mode before the driver starts
> >> and the phy can be addressed as hardware implementation is designed.
> >> 
> >> Signed-off-by: Michael Grzeschik <m.grzeschik@pengutronix.de>
> >> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
> >> Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
> >> ---
> >>  .../devicetree/bindings/usb/ci13xxx-imx.txt        |    5 +++
> >>  drivers/usb/chipidea/bits.h                        |   14 ++++++-
> >>  drivers/usb/chipidea/ci13xxx_imx.c                 |    3 ++
> >>  drivers/usb/chipidea/core.c                        |   39 ++++++++++++++++++++
> >>  include/linux/usb/chipidea.h                       |    1 +
> >>  5 files changed, 61 insertions(+), 1 deletion(-)
> >> 
> >> diff --git a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt
> >> index 5778b9c..dd42ccd 100644
> >> --- a/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt
> >> +++ b/Documentation/devicetree/bindings/usb/ci13xxx-imx.txt
> >> @@ -5,6 +5,11 @@ Required properties:
> >>  - reg: Should contain registers location and length
> >>  - interrupts: Should contain controller interrupt
> >>  
> >> +Recommended properies:
> >> +- phy_type: the type of the phy connected to the core. Should be one
> >> +  of "utmi", "utmi_wide", "ulpi", "serial" or "hsic". Without this
> >> +  property the PORTSC register won't be touched
> >> +
> >>  Optional properties:
> >>  - fsl,usbphy: phandler of usb phy that connects to the only one port
> >>  - fsl,usbmisc: phandler of non-core register device, with one argument
> >> diff --git a/drivers/usb/chipidea/bits.h b/drivers/usb/chipidea/bits.h
> >> index 050de85..d8ffc2f 100644
> >> --- a/drivers/usb/chipidea/bits.h
> >> +++ b/drivers/usb/chipidea/bits.h
> >> @@ -48,10 +48,22 @@
> >>  #define PORTSC_SUSP           BIT(7)
> >>  #define PORTSC_HSP            BIT(9)
> >>  #define PORTSC_PTC            (0x0FUL << 16)
> >> +/* PTS and PTW for non lpm version only */
> >> +#define PORTSC_PTS(d)         ((((d) & 0x3) << 30) | (((d) & 0x4) ? BIT(25) : 0))
> >> +#define PORTSC_PTW            BIT(28)
> >>  
> >>  /* DEVLC */
> >>  #define DEVLC_PSPD            (0x03UL << 25)
> >> -#define    DEVLC_PSPD_HS      (0x02UL << 25)
> >> +#define DEVLC_PSPD_HS         (0x02UL << 25)
> >> +#define DEVLC_PTW             BIT(27)
> >> +#define DEVLC_STS             BIT(28)
> >> +#define DEVLC_PTS(d)          (((d) & 0x7) << 29)
> >> +
> >> +/* Encoding for DEVLC_PTS and PORTSC_PTS */
> >> +#define PTS_UTMI              0
> >> +#define PTS_ULPI              2
> >> +#define PTS_SERIAL            3
> >> +#define PTS_HSIC              4
> >>  
> >>  /* OTGSC */
> >>  #define OTGSC_IDPU	      BIT(5)
> >> diff --git a/drivers/usb/chipidea/ci13xxx_imx.c b/drivers/usb/chipidea/ci13xxx_imx.c
> >> index 69024e0..ebc1148 100644
> >> --- a/drivers/usb/chipidea/ci13xxx_imx.c
> >> +++ b/drivers/usb/chipidea/ci13xxx_imx.c
> >> @@ -21,6 +21,7 @@
> >>  #include <linux/clk.h>
> >>  #include <linux/regulator/consumer.h>
> >>  #include <linux/pinctrl/consumer.h>
> >> +#include <linux/usb/of.h>
> >>  
> >>  #include "ci.h"
> >>  #include "ci13xxx_imx.h"
> >> @@ -112,6 +113,8 @@ static int ci13xxx_imx_probe(struct platform_device *pdev)
> >>  		       CI13XXX_PULLUP_ON_VBUS |
> >>  		       CI13XXX_DISABLE_STREAMING;
> >>  
> >> +	pdata->phy_mode = of_usb_get_phy_mode(pdev->dev.of_node);
> >> +
> >>  	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> >>  	if (!data) {
> >>  		dev_err(&pdev->dev, "Failed to allocate CI13xxx-IMX data!\n");
> >> diff --git a/drivers/usb/chipidea/core.c b/drivers/usb/chipidea/core.c
> >> index 57cae1f..a3ec29d 100644
> >> --- a/drivers/usb/chipidea/core.c
> >> +++ b/drivers/usb/chipidea/core.c
> >> @@ -67,6 +67,8 @@
> >>  #include <linux/usb/gadget.h>
> >>  #include <linux/usb/otg.h>
> >>  #include <linux/usb/chipidea.h>
> >> +#include <linux/usb/of.h>
> >> +#include <linux/phy.h>
> >>  
> >>  #include "ci.h"
> >>  #include "udc.h"
> >> @@ -211,6 +213,41 @@ static int hw_device_init(struct ci13xxx *ci, void __iomem *base)
> >>  	return 0;
> >>  }
> >>  
> >> +static void hw_phymode_configure(struct ci13xxx *ci)
> >> +{
> >> +	u32 portsc, lpm;
> >> +
> >> +	switch (ci->platdata->phy_mode) {
> >> +	case USBPHY_INTERFACE_MODE_UTMI:
> >> +		portsc = PORTSC_PTS(PTS_UTMI);
> >> +		lpm = DEVLC_PTS(PTS_UTMI);
> >> +		break;
> >> +	case USBPHY_INTERFACE_MODE_UTMIW:
> >> +		portsc = PORTSC_PTS(PTS_UTMI) | PORTSC_PTW;
> >> +		lpm = DEVLC_PTS(PTS_UTMI) | DEVLC_PTW;
> >> +		break;
> >> +	case USBPHY_INTERFACE_MODE_ULPI:
> >> +		portsc = PORTSC_PTS(PTS_ULPI);
> >> +		lpm = DEVLC_PTS(PTS_ULPI);
> >> +		break;
> >> +	case USBPHY_INTERFACE_MODE_SERIAL:
> >> +		portsc = PORTSC_PTS(PTS_SERIAL);
> >> +		lpm = DEVLC_PTS(PTS_SERIAL);
> >> +		break;
> >> +	case USBPHY_INTERFACE_MODE_HSIC:
> >> +		portsc = PORTSC_PTS(PTS_HSIC);
> >> +		lpm = DEVLC_PTS(PTS_HSIC);
> >> +		break;
> >> +	default:
> >> +		return;
> >> +	}
> >> +
> >> +	if (ci->hw_bank.lpm)
> >> +		hw_write(ci, OP_PORTSC, DEVLC_PTS(7) | DEVLC_PTW, lpm);
> >                              ^^^^^^^^^
> >
> > This is probably supposed to be OP_DEVLC.
> 
> Looks like that. I'd like to test this code on an LPM device first.
> Can somebody with an imx test give a Tested-by?

Sascha, would you like add above changes and change "int" to 
"enum usb_dr_mode" for your [PATCH 5/9] USB chipidea: 
introduce dual role mode pdata flags.
Then send v4 patch, I can help to test it before
this Tuesday (There will be 9 days Chinese New Year holiday).

> 
> Regards,
> --
> Alex
> 

-- 

Best Regards,
Peter Chen

^ permalink raw reply

* [PATCH v3 15/15] ARM: vexpress/dcscb: probe via device tree
From: Nicolas Pitre @ 2013-02-04  4:39 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130131105436.GA2091@linaro.org>

On Thu, 31 Jan 2013, Dave Martin wrote:

> On Wed, Jan 30, 2013 at 12:43:29PM -0500, Nicolas Pitre wrote:
> > On Wed, 30 Jan 2013, Achin Gupta wrote:
> > 
> > > On Tue, Jan 29, 2013 at 9:41 PM, Nicolas Pitre <nicolas.pitre@linaro.org> wrote:
> > > > On Tue, 29 Jan 2013, Rob Herring wrote:
> > > >
> > > >> On 01/29/2013 01:51 AM, Nicolas Pitre wrote:
> > > >> > +   node = of_find_compatible_node(NULL, NULL, "arm,dcscb");
> > > >>
> > > >> This needs binding documentation and should be a more specific name. Not
> > > >> knowing what dcscb is, I don't have a suggestion.
> 
> The name is 100% specific.  The real problem seems to be that it's also
> very cryptic, and undocumented.

OK, here's my attempt at documenting it, folded with the latest fixes in 
the patch that introduced DCSCB support.  ACK?

---------- >8
From: Nicolas Pitre <nicolas.pitre@linaro.org>
Date: Wed, 2 May 2012 20:56:52 -0400
Subject: [PATCH] ARM: vexpress: introduce DCSCB support

This adds basic CPU and cluster reset controls on RTSM for the
A15x4-A7x4 model configuration using the Dual Cluster System
Configuration Block (DCSCB).

The cache coherency interconnect (CCI) is not handled yet.

Signed-off-by: Nicolas Pitre <nico@linaro.org>
---
 .../devicetree/bindings/arm/rtsm-dcscb.txt         |  19 +++
 arch/arm/mach-vexpress/Kconfig                     |   8 +
 arch/arm/mach-vexpress/Makefile                    |   1 +
 arch/arm/mach-vexpress/dcscb.c                     | 162 +++++++++++++++++++++
 4 files changed, 190 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/rtsm-dcscb.txt b/Documentation/devicetree/bindings/arm/rtsm-dcscb.txt
new file mode 100644
index 0000000000..3b8fbf3c00
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/rtsm-dcscb.txt
@@ -0,0 +1,19 @@
+ARM Dual Cluster System Configuration Block
+-------------------------------------------
+
+The Dual Cluster System Configuration Block (DCSCB) provides basic
+functionality for controlling clocks, resets and configuration pins in
+the Dual Cluster System implemented by the Real-Time System Model (RTSM).
+
+Required properties:
+
+- compatible : should be "arm,rtsm,dcscb"
+
+- reg : physical base address and the size of the registers window
+
+Example:
+
+	dcscb at 60000000 {
+		compatible = "arm,rtsm,dcscb";
+		reg = <0x60000000 0x1000>;
+	};
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index 52d315b792..f3f92b120a 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -52,4 +52,12 @@ config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
 config ARCH_VEXPRESS_CA9X4
 	bool "Versatile Express Cortex-A9x4 tile"
 
+config ARCH_VEXPRESS_DCSCB
+	bool "Dual Cluster System Control Block (DCSCB) support"
+	depends on CLUSTER_PM
+	help
+	  Support for the Dual Cluster System Configuration Block (DCSCB).
+	  This is needed to provide CPU and cluster power management
+	  on RTSM.
+
 endmenu
diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile
index 80b64971fb..2253644054 100644
--- a/arch/arm/mach-vexpress/Makefile
+++ b/arch/arm/mach-vexpress/Makefile
@@ -6,5 +6,6 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
 
 obj-y					:= v2m.o reset.o
 obj-$(CONFIG_ARCH_VEXPRESS_CA9X4)	+= ct-ca9x4.o
+obj-$(CONFIG_ARCH_VEXPRESS_DCSCB)	+= dcscb.o
 obj-$(CONFIG_SMP)			+= platsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)		+= hotplug.o
diff --git a/arch/arm/mach-vexpress/dcscb.c b/arch/arm/mach-vexpress/dcscb.c
new file mode 100644
index 0000000000..07e835cb72
--- /dev/null
+++ b/arch/arm/mach-vexpress/dcscb.c
@@ -0,0 +1,162 @@
+/*
+ * arch/arm/mach-vexpress/dcscb.c - Dual Cluster System Configuration Block
+ *
+ * Created by:	Nicolas Pitre, May 2012
+ * Copyright:	(C) 2012-2013  Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/of_address.h>
+#include <linux/vexpress.h>
+
+#include <asm/mcpm_entry.h>
+#include <asm/proc-fns.h>
+#include <asm/cacheflush.h>
+#include <asm/cputype.h>
+#include <asm/cp15.h>
+
+
+#define RST_HOLD0	0x0
+#define RST_HOLD1	0x4
+#define SYS_SWRESET	0x8
+#define RST_STAT0	0xc
+#define RST_STAT1	0x10
+#define EAG_CFG_R	0x20
+#define EAG_CFG_W	0x24
+#define KFC_CFG_R	0x28
+#define KFC_CFG_W	0x2c
+#define DCS_CFG_R	0x30
+
+/*
+ * We can't use regular spinlocks. In the switcher case, it is possible
+ * for an outbound CPU to call power_down() after its inbound counterpart
+ * is already live using the same logical CPU number which trips lockdep
+ * debugging.
+ */
+static arch_spinlock_t dcscb_lock = __ARCH_SPIN_LOCK_UNLOCKED;
+
+static void __iomem *dcscb_base;
+
+static int dcscb_power_up(unsigned int cpu, unsigned int cluster)
+{
+	unsigned int rst_hold, cpumask = (1 << cpu);
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	if (cpu >= 4 || cluster >= 2)
+		return -EINVAL;
+
+	/*
+	 * Since this is called with IRQs enabled, and no arch_spin_lock_irq
+	 * variant exists, we need to disable IRQs manually here.
+	 */
+	local_irq_disable();
+	arch_spin_lock(&dcscb_lock);
+
+	rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4);
+	if (rst_hold & (1 << 8)) {
+		/* remove cluster reset and add individual CPU's reset */
+		rst_hold &= ~(1 << 8);
+		rst_hold |= 0xf;
+	}
+	rst_hold &= ~(cpumask | (cpumask << 4));
+	writel(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4);
+
+	arch_spin_unlock(&dcscb_lock);
+	local_irq_enable();
+
+	return 0;
+}
+
+static void dcscb_power_down(void)
+{
+	unsigned int mpidr, cpu, cluster, rst_hold, cpumask, last_man;
+
+	mpidr = read_cpuid_mpidr();
+	cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+	cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+	cpumask = (1 << cpu);
+
+	pr_debug("%s: cpu %u cluster %u\n", __func__, cpu, cluster);
+	BUG_ON(cpu >= 4 || cluster >= 2);
+
+	arch_spin_lock(&dcscb_lock);
+	rst_hold = readl_relaxed(dcscb_base + RST_HOLD0 + cluster * 4);
+	rst_hold |= cpumask;
+	if (((rst_hold | (rst_hold >> 4)) & 0xf) == 0xf)
+		rst_hold |= (1 << 8);
+	writel(rst_hold, dcscb_base + RST_HOLD0 + cluster * 4);
+	arch_spin_unlock(&dcscb_lock);
+	last_man = (rst_hold & (1 << 8));
+
+	/*
+	 * Now let's clean our L1 cache and shut ourself down.
+	 * If we're the last CPU in this cluster then clean L2 too.
+	 */
+
+	/*
+	 * A15/A7 can hit in the cache with SCTLR.C=0, so we don't need
+	 * a preliminary flush here for those CPUs.  At least, that's
+	 * the theory -- without the extra flush, Linux explodes on
+	 * RTSM (maybe not needed anymore, to be investigated)..
+	 */
+	flush_cache_louis();
+	set_cr(get_cr() & ~CR_C);
+
+	if (!last_man) {
+		flush_cache_louis();
+	} else {
+		flush_cache_all();
+		outer_flush_all();
+	}
+
+	/* Disable local coherency by clearing the ACTLR "SMP" bit: */
+	set_auxcr(get_auxcr() & ~(1 << 6));
+
+	/* Now we are prepared for power-down, do it: */
+	dsb();
+	wfi();
+
+	/* Not dead@this point?  Let our caller cope. */
+}
+
+static const struct mcpm_platform_ops dcscb_power_ops = {
+	.power_up	= dcscb_power_up,
+	.power_down	= dcscb_power_down,
+};
+
+static int __init dcscb_init(void)
+{
+	struct device_node *node;
+	int ret;
+
+	node = of_find_compatible_node(NULL, NULL, "arm,rtsm,dcscb");
+	if (!node)
+		return -ENODEV;
+	dcscb_base= of_iomap(node, 0);
+	if (!dcscb_base)
+		return -EADDRNOTAVAIL;
+
+	ret = mcpm_platform_register(&dcscb_power_ops);
+	if (ret) {
+		iounmap(dcscb_base);
+		return ret;
+	}
+
+	/*
+	 * Future entries into the kernel can now go
+	 * through the cluster entry vectors.
+	 */
+	vexpress_flags_set(virt_to_phys(mcpm_entry_point));
+
+	return 0;
+}
+
+early_initcall(dcscb_init);

^ permalink raw reply related

* [PATCH v4] ARM: LPAE: Fix mapping in alloc_init_pte for unaligned addresses
From: R Sricharan @ 2013-02-04  4:40 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130201174246.GJ5151@arm.com>

Hi Catalin,

[ snip..]
>
> diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
> index 9f06102..47154f3 100644
> --- a/arch/arm/mm/mmu.c
> +++ b/arch/arm/mm/mmu.c
> @@ -581,34 +581,36 @@ static void __init alloc_init_section(pud_t *pud, unsigned long addr,
>   				      const struct mem_type *type)
>   {
>   	pmd_t *pmd = pmd_offset(pud, addr);
> +	unsigned long next;
>
> -	/*
> -	 * Try a section mapping - end, addr and phys must all be aligned
> -	 * to a section boundary.  Note that PMDs refer to the individual
> -	 * L1 entries, whereas PGDs refer to a group of L1 entries making
> -	 * up one logical pointer to an L2 table.
> -	 */
> -	if (type->prot_sect && ((addr | end | phys) & ~SECTION_MASK) == 0) {
> -		pmd_t *p = pmd;
> +	do {
> +		next = pmd_addr_end(addr, end);
> +
> +		/*
> +		 * Try a section mapping - next, addr and phys must all be
> +		 * aligned to a section boundary.  Note that PMDs refer to the
> +		 * individual L1 entries, whereas PGDs refer to a group of L1
> +		 * entries making up one logical pointer to an L2 table.
> +		 */
> +		if (((addr | next | phys) & ~SECTION_MASK) == 0) {
> +			pmd_t *p = pmd;
>
    There is a  need to do page mappings even when all the addresses
    are aligned. This was added with CMA, which required the initial
    mappings to be set with 2 level tables.

>   #ifndef CONFIG_ARM_LPAE
> -		if (addr & SECTION_SIZE)
> -			pmd++;
> +			if (addr & SECTION_SIZE)
> +				pmd++;
>   #endif
> +			do {
> +				*pmd = __pmd(phys | type->prot_sect);
> +				phys += SECTION_SIZE;
> +			} while (pmd++, addr += SECTION_SIZE, addr != next);
>
> -		do {
> -			*pmd = __pmd(phys | type->prot_sect);
> -			phys += SECTION_SIZE;
> -		} while (pmd++, addr += SECTION_SIZE, addr != end);
> -
> -		flush_pmd_entry(p);
> -	} else {
> -		/*
> -		 * No need to loop; pte's aren't interested in the
> -		 * individual L1 entries.
> -		 */
> -		alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type);
> -	}
> +			flush_pmd_entry(p);
> +		} else {
> +			alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys), type);
> +			phys += next - addr;
> +			pmd++;
> +		}
> +	} while (addr = next, addr != end);
>   }
>
>   static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
>
  I did a similar kind of patch in my V1 [1].
  I should be using PMD_MASK instead of SECTION_MASK there, and
  updated it in the next version.

  [1] https://patchwork.kernel.org/patch/1272991/


Regards,
  Sricharan

^ permalink raw reply

* [PATCH v4] ARM: LPAE: Fix mapping in alloc_init_pte for unaligned addresses
From: R Sricharan @ 2013-02-04  4:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <510F3BA8.8070700@ti.com>

On Monday 04 February 2013 10:10 AM, R Sricharan wrote:
> Hi Catalin,
>
> [ snip..]
>>
>> diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
>> index 9f06102..47154f3 100644
>> --- a/arch/arm/mm/mmu.c
>> +++ b/arch/arm/mm/mmu.c
>> @@ -581,34 +581,36 @@ static void __init alloc_init_section(pud_t
>> *pud, unsigned long addr,
>>                         const struct mem_type *type)
>>   {
>>       pmd_t *pmd = pmd_offset(pud, addr);
>> +    unsigned long next;
>>
>> -    /*
>> -     * Try a section mapping - end, addr and phys must all be aligned
>> -     * to a section boundary.  Note that PMDs refer to the individual
>> -     * L1 entries, whereas PGDs refer to a group of L1 entries making
>> -     * up one logical pointer to an L2 table.
>> -     */
>> -    if (type->prot_sect && ((addr | end | phys) & ~SECTION_MASK) == 0) {
>> -        pmd_t *p = pmd;
>> +    do {
>> +        next = pmd_addr_end(addr, end);
>> +
>> +        /*
>> +         * Try a section mapping - next, addr and phys must all be
>> +         * aligned to a section boundary.  Note that PMDs refer to the
>> +         * individual L1 entries, whereas PGDs refer to a group of L1
>> +         * entries making up one logical pointer to an L2 table.
>> +         */
>> +        if (((addr | next | phys) & ~SECTION_MASK) == 0) {
>> +            pmd_t *p = pmd;
>>
>     There is a  need to do page mappings even when all the addresses
>     are aligned. This was added with CMA, which required the initial
>     mappings to be set with 2 level tables.
>
    Sorry, i wanted to ask type->prot_sect is removed here and is that
   intentional?
>>   #ifndef CONFIG_ARM_LPAE
>> -        if (addr & SECTION_SIZE)
>> -            pmd++;
>> +            if (addr & SECTION_SIZE)
>> +                pmd++;
>>   #endif
>> +            do {
>> +                *pmd = __pmd(phys | type->prot_sect);
>> +                phys += SECTION_SIZE;
>> +            } while (pmd++, addr += SECTION_SIZE, addr != next);
>>
>> -        do {
>> -            *pmd = __pmd(phys | type->prot_sect);
>> -            phys += SECTION_SIZE;
>> -        } while (pmd++, addr += SECTION_SIZE, addr != end);
>> -
>> -        flush_pmd_entry(p);
>> -    } else {
>> -        /*
>> -         * No need to loop; pte's aren't interested in the
>> -         * individual L1 entries.
>> -         */
>> -        alloc_init_pte(pmd, addr, end, __phys_to_pfn(phys), type);
>> -    }
>> +            flush_pmd_entry(p);
>> +        } else {
>> +            alloc_init_pte(pmd, addr, next, __phys_to_pfn(phys), type);
>> +            phys += next - addr;
>> +            pmd++;
>> +        }
>> +    } while (addr = next, addr != end);
>>   }
>>
>>   static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
>>
   I did a similar kind of patch in my V1 [1].
    I should be using PMD_MASK instead of SECTION_MASK there, and
   updated it in the next version.

    [1] https://patchwork.kernel.org/patch/1272991/


Regards,
   Sricharan

^ permalink raw reply

* [PATCH v2 6/6] ARM: davinci: da850: configure system configuration chip(CFGCHIP3) for emac
From: Prabhakar Lad @ 2013-02-04  5:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <510E5BCF.9080006@ti.com>

Sekhar ,

On Sun, Feb 3, 2013 at 6:15 PM, Sekhar Nori <nsekhar@ti.com> wrote:
> On 1/28/2013 7:17 PM, Prabhakar Lad wrote:
>> From: Lad, Prabhakar <prabhakar.lad@ti.com>
>>
>> The system configuration chip CFGCHIP3, controls the emac module.
>> This patch appropriately configures this register for emac and
>> sets DA850_MII_MDIO_CLKEN_PIN GPIO pin appropriately.
>>
>> Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
>> Cc: linux-arm-kernel at lists.infradead.org
>> Cc: linux-kernel at vger.kernel.org
>> Cc: davinci-linux-open-source at linux.davincidsp.com
>> Cc: netdev at vger.kernel.org
>> Cc: devicetree-discuss at lists.ozlabs.org
>> Cc: Sekhar Nori <nsekhar@ti.com>
>> Cc: Heiko Schocher <hs@denx.de>
>> ---
>>  arch/arm/mach-davinci/da8xx-dt.c |   28 ++++++++++++++++++++++++++++
>>  1 files changed, 28 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/arm/mach-davinci/da8xx-dt.c b/arch/arm/mach-davinci/da8xx-dt.c
>> index e533a0a..4a096e3 100644
>> --- a/arch/arm/mach-davinci/da8xx-dt.c
>> +++ b/arch/arm/mach-davinci/da8xx-dt.c
>> @@ -8,6 +8,7 @@
>>   * published by the Free Software Foundation.
>>   */
>>  #include <linux/io.h>
>> +#include <linux/gpio.h>
>>  #include <linux/of_irq.h>
>>  #include <linux/of_platform.h>
>>  #include <linux/irqdomain.h>
>> @@ -39,6 +40,32 @@ static void __init da8xx_init_irq(void)
>>
>>  #ifdef CONFIG_ARCH_DAVINCI_DA850
>>
>> +static void __init da8xx_config_emac(void)
>> +{
>> +#define DA850_MII_MDIO_CLKEN_PIN     GPIO_TO_PIN(2, 6)
>> +#define DA850_EMAC_MODE_SELECT               BIT(8)
>> +     void __iomem *cfg_chip3_base;
>> +     int ret;
>> +     u32 val;
>> +
>> +     cfg_chip3_base = DA8XX_SYSCFG0_VIRT(DA8XX_CFGCHIP3_REG);
>> +
>> +     val = __raw_readl(cfg_chip3_base);
>> +     val &= ~DA850_EMAC_MODE_SELECT;
>> +     /* configure the CFGCHIP3 register for MII */
>> +     __raw_writel(val, cfg_chip3_base);
>
> Use readl/writel instead.
>
Ok.

>> +     pr_info("EMAC: MII PHY configured\n");
>> +
>> +     ret = gpio_request(DA850_MII_MDIO_CLKEN_PIN, "mdio_clk_en");
>> +     if (ret) {
>> +             pr_warn("Cannot open GPIO %d\n",
>> +                                     DA850_MII_MDIO_CLKEN_PIN);
>> +             return;
>> +     }
>> +     /* Enable/Disable MII MDIO clock */
>> +     gpio_direction_output(DA850_MII_MDIO_CLKEN_PIN, 0);
>> +}
>> +
>>  struct of_dev_auxdata da8xx_auxdata[] __initdata = {
>>       OF_DEV_AUXDATA("ti,davinci_mdio", 0x01e24000, "davinci_mdio.0", NULL),
>>       OF_DEV_AUXDATA("ti,davinci-dm6467-emac", 0x01e20000, "davinci_emac.1",
>> @@ -52,6 +79,7 @@ static void __init da850_init_machine(void)
>>                            da8xx_auxdata, NULL);
>>
>>       da8xx_uart_clk_enable();
>> +     da8xx_config_emac();
>
> There are couple of issues with this implementation.
>
> 1) da8xx_config_emac() is specific to DA850 EVM, but masquerades as
>    generic for da8xx. Looks like you need two functions, one for soc
>    specific configuration and one board specific.
Ok.

> 2) da8xx_config_emac() goes through all the time, whether the
>    particular board has emac module or not. Shouldn't
>    da8xx_config_emac() check if emac is actually enabled in the passed
>    dtb and only the do the configuration?

Ok. Can you give some pointers how we can access the dtb in board files.

> 3) The function assumes mii is used always, you can use the rmii_en dt
>    property to check if rmii/mii is enabled and configure the soc/board
>    accordingly.

Ok.

> 4) If the same function can work both for da850 and da830, then it can
>    be implemented outside of CONFIG_ARCH_DAVINCI_DA850.
>
Ok.

Regards,
--Prabhakar

> Thanks,
> Sekhar

^ permalink raw reply

* [PATCH v2 4/6] ARM: davinci: da850: add DT node for eth0.
From: Prabhakar Lad @ 2013-02-04  5:07 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <510E51FF.8090005@ti.com>

Sekhar ,

On Sun, Feb 3, 2013 at 5:33 PM, Sekhar Nori <nsekhar@ti.com> wrote:
> On 1/28/2013 7:17 PM, Prabhakar Lad wrote:
>> From: Lad, Prabhakar <prabhakar.lad@ti.com>
>>
>> Add eth0 device tree node information and pinmux for mii to da850 by
>> providing interrupt details and local mac address of eth0.
>>
>> Signed-off-by: Lad, Prabhakar <prabhakar.lad@ti.com>
>> Cc: linux-arm-kernel at lists.infradead.org
>> Cc: linux-kernel at vger.kernel.org
>> Cc: davinci-linux-open-source at linux.davincidsp.com
>> Cc: netdev at vger.kernel.org
>> Cc: devicetree-discuss at lists.ozlabs.org
>> Cc: Sekhar Nori <nsekhar@ti.com>
>> Cc: Heiko Schocher <hs@denx.de>
>> ---
>>  arch/arm/boot/dts/da850-evm.dts |    5 +++++
>>  arch/arm/boot/dts/da850.dtsi    |   35 +++++++++++++++++++++++++++++++++++
>>  2 files changed, 40 insertions(+), 0 deletions(-)
>>
>> diff --git a/arch/arm/boot/dts/da850-evm.dts b/arch/arm/boot/dts/da850-evm.dts
>> index a319491..19aa2b3 100644
>> --- a/arch/arm/boot/dts/da850-evm.dts
>> +++ b/arch/arm/boot/dts/da850-evm.dts
>> @@ -30,6 +30,11 @@
>>               mdio: davinci_mdio at 1e24000 {
>>                       status = "okay";
>>               };
>> +             eth0: emac at 1e20000 {
>> +                     status = "okay";
>> +                     pinctrl-names = "default";
>> +                     pinctrl-0 = <&mii_pins>;
>> +             };
>>       };
>>       nand_cs3 at 62000000 {
>>               status = "okay";
>> diff --git a/arch/arm/boot/dts/da850.dtsi b/arch/arm/boot/dts/da850.dtsi
>> index ba28f2d..76905f3 100644
>> --- a/arch/arm/boot/dts/da850.dtsi
>> +++ b/arch/arm/boot/dts/da850.dtsi
>> @@ -56,6 +56,26 @@
>>                                       0x30 0x01100000  0x0ff00000
>>                               >;
>>                       };
>> +                     mii_pins: pinmux_mii_pins {
>> +                             pinctrl-single,bits = <
>> +                                     /*
>> +                                      * MII_TXEN, MII_TXCLK, MII_COL
>> +                                      * MII_TXD_3, MII_TXD_2, MII_TXD_1
>> +                                      * MII_TXD_0
>> +                                      */
>> +                                     0x8 0x88888880 0xfffffff0
>> +                                     /*
>> +                                      * MII_RXER, MII_CRS, MII_RXCLK
>> +                                      * MII_RXDV, MII_RXD_3, MII_RXD_2
>> +                                      * MII_RXD_1, MII_RXD_0
>> +                                      */
>> +                                     0xc 0x88888888 0xffffffff
>> +                                     /* MDIO_CLK, MDIO_D */
>
> You call this mii_pins, but include mdio pins in there as well. Can you
> separate them out? Then some board which uses rmii can simply reuse the
> entry.
>
Ok makes sense.

>> +                                     0x10 0x00222288 0x00ffffff
>> +                                     /* GPIO2_6 */
>> +                                     0x18 0x00000080 0x000000f0
>
> This is SoC specific pin list. Such board specific pins should not make
> it here.
>
Ok, so this should be set up using GPIO API's ?

>> +                             >;
>> +                     };
>>               };
>>               serial0: serial at 1c42000 {
>>                       compatible = "ns16550a";
>> @@ -88,6 +108,21 @@
>>                       reg = <0x224000 0x1000>;
>>                       bus_freq = <2200000>;
>>               };
>> +             eth0: emac at 1e20000 {
>> +                     compatible = "ti,davinci-dm6467-emac";
>> +                     reg = <0x220000 0x4000>;
>> +                     ti,davinci-ctrl-reg-offset = <0x3000>;
>> +                     ti,davinci-ctrl-mod-reg-offset = <0x2000>;
>> +                     ti,davinci-ctrl-ram-offset = <0>;
>> +                     ti,davinci-ctrl-ram-size = <0x2000>;
>> +                     local-mac-address = [ 00 00 00 00 00 00 ];
>> +                     interrupts = <33
>> +                                     34
>> +                                     35
>> +                                     36
>> +                                     >;
>> +                     phy-handle = <&mdio>;
>
> I doubt this is required. This property is to pass a handle to the phy,
> not mdio bus.
>
Ok I'll check on this.

Regards,
--Prabhakar


> Thanks,
> Sekhar

^ permalink raw reply

* [PATCH v5] cpufreq: add imx6q-cpufreq driver
From: Shawn Guo @ 2013-02-04  5:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130204160622.GB5209@ubuntu>

On Mon, Feb 04, 2013 at 11:06:22AM -0500, Anson Huang wrote:
> > +	/*
> > +	 * The setpoints are selected per PLL/PDF frequencies, so we need to
> > +	 * reprogram PLL for frequency scaling.  The procedure of reprogramming
> > +	 * PLL1 is as below.
> > +	 *
> > +	 *  - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
> > +	 *  - Disable pll1_sys_clk and reprogram it
> > +	 *  - Enable pll1_sys_clk and reparent pll1_sw_clk back to it
> > +	 *  - Disable pll2_pfd2_396m_clk
> > +	 */
> > +	clk_prepare_enable(pll2_pfd2_396m_clk);
> > +	clk_set_parent(step_clk, pll2_pfd2_396m_clk);
> > +	clk_set_parent(pll1_sw_clk, step_clk);
> > +	clk_prepare_enable(pll1_sys_clk);
> > +	if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
> > +		clk_disable_unprepare(pll1_sys_clk);
> > +		clk_set_rate(pll1_sys_clk, freqs.new * 1000);
> > +		clk_prepare_enable(pll1_sys_clk);
> > +		clk_set_parent(pll1_sw_clk, pll1_sys_clk);
> > +		clk_disable_unprepare(pll2_pfd2_396m_clk);
> > +	} else {
> > +		/*
> > +		 * Disable pll1_sys_clk if pll2_pfd2_396m_clk is sufficient
> > +		 * to provide the frequency.
> > +		 */
> > +		clk_disable_unprepare(pll1_sys_clk);
> > +	}
> Seems like we will get pll2_pfd2_396m_clk's use count mismatch? As every time cpu freq is changed, pll2_pfd2_396m_clk will be added at the beginning of this code piece, but only decreased when cpu freq > 396M, so everytime cpu freq changed to 396M, this pll2_pfd2_396m_clk will in increased?

Ah, good catch.  And pll1_sys_clk has the same problem.  Since it's
been verified by FSL kernel that we do not necessarily need to disable
pll1_sys_clk before reprogramming it, I would choose to rewrite the
code as below to make it cleaner and correct on clock usage.

        /*
         * The setpoints are selected per PLL/PDF frequencies, so we need to
         * reprogram PLL for frequency scaling.  The procedure of reprogramming
         * PLL1 is as below.
         *
         *  - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
         *  - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
         *  - Disable pll2_pfd2_396m_clk
         */
        clk_prepare_enable(pll2_pfd2_396m_clk);
        clk_set_parent(step_clk, pll2_pfd2_396m_clk);
        clk_set_parent(pll1_sw_clk, step_clk);
        if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
                clk_set_rate(pll1_sys_clk, freqs.new * 1000);
                /*
                 * If we are leaving 396 MHz set-point, we need to enable
                 * pll1_sys_clk and disable pll2_pfd2_396m_clk to keep
                 * their use count correct.
                 */
                if (freqs.old * 1000 <= clk_get_rate(pll2_pfd2_396m_clk)) {
                        clk_prepare_enable(pll1_sys_clk);
                        clk_disable_unprepare(pll2_pfd2_396m_clk);
                }
                clk_set_parent(pll1_sw_clk, pll1_sys_clk);
                clk_disable_unprepare(pll2_pfd2_396m_clk);
        } else {
                /*
                 * Disable pll1_sys_clk if pll2_pfd2_396m_clk is sufficient
                 * to provide the frequency.
                 */
                clk_disable_unprepare(pll1_sys_clk);
        }

> > +
> > +	/* Ensure the arm clock divider is what we expect */
> > +	ret = clk_set_rate(arm_clk, freqs.new * 1000);
> > +	if (ret) {
> > +		dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
> > +		regulator_set_voltage_tol(arm_reg, volt_old, 0);
> > +		return ret;
> > +	}
> > +
> > +	/* scaling down?  scale voltage after frequency */
> > +	if (freqs.new < freqs.old) {
> > +		ret = regulator_set_voltage_tol(arm_reg, volt, 0);
> > +		if (ret)
> > +			dev_warn(cpu_dev,
> > +				 "failed to scale vddarm down: %d\n", ret);
> > +
> > +		if (freqs.old == FREQ_1P2_GHZ / 1000) {
> > +			regulator_set_voltage_tol(pu_reg,
> > +					PU_SOC_VOLTAGE_NORMAL, 0);
> > +			regulator_set_voltage_tol(soc_reg,
> > +					PU_SOC_VOLTAGE_NORMAL, 0);
> > +		}
> > +	}
> > +
> > +	for_each_online_cpu(cpu) {
> > +		freqs.cpu = cpu;
> > +		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
> > +	}
> > +
> Should we need to update the percpu loops_per_jiffy variable and global loops_per_jiffy? As the udelay and mdelay will rely on this global loops_per_jiffy? Or the latest kernel has handle it in other place such as cpufreq common driver? I remembered that common cpufreq driver only handle the noSMP case.

No, it's not needed since commit ec971ea (ARM: add cpufreq transiton
notifier to adjust loops_per_jiffy for smp) is in place.

Shawn

^ permalink raw reply

* [PATCH 2/2] ARM: imx: set CKO1 parent clock source in imx6q sabresd
From: Shawn Guo @ 2013-02-04  5:12 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <8D894AC610DA3944965280D4097EAC4603CD2F55@039-SN2MPN1-021.039d.mgd.msft.net>

On Mon, Feb 04, 2013 at 03:13:40AM +0000, Zhang Quan-B13634 wrote:
> >  > -static void __init imx6q_sabrelite_cko1_setup(void)
> >  > +static void __init cko1_setup(unsigned long freq)
> >  >  {
> >  >  	struct clk *cko1_sel, *ahb, *cko1;
> >  >  	unsigned long rate;
> >  > @@ -132,8 +132,10 @@ static void __init imx6q_sabrelite_cko1_setup(void)
> >  >  		goto put_clk;
> >  >  	}
> >  >  	clk_set_parent(cko1_sel, ahb);
> >  > -	rate = clk_round_rate(cko1, 16000000);
> >  > +	rate = clk_round_rate(cko1, freq);
> >  >  	clk_set_rate(cko1, rate);
> >  > +
> >  > +	return;
> >  
> >  Why does this "return" needs to be added here?
> [Gary-b13634] because the codes below may be ignored when execute 'return' ,
> Saving cpu consumption.

But we haven't finished our job.  We need to "put" those clocks before
returning to balance the "get" call.

Shawn

^ permalink raw reply

* [PATCH V2 4/4] DMA: PL330: Modify pl330 filter based on new generic dma dt bindings.
From: Padma Venkat @ 2013-02-04  5:21 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1692358.6BmDsJsb25@wuerfel>

On Sat, Feb 2, 2013 at 8:39 PM, Arnd Bergmann <arnd@arndb.de> wrote:
> On Saturday 02 February 2013 08:00:54 Padma Venkat wrote:
>
>> > The result of this looks good, but I fear that changing the filter function
>> > like this wil break all drivers that currently use the plat-samsung/dma-ops.c
>> > code. For migration purposes, I think the best way is to change
>> > samsung_dmadev_request() to match the new filter_param format.
>> >
>> > After that is done, you can migrate all the drivers using samsung_dma_get_ops
>> > over to the new dma_request_slave_channel interface without breaking
>> > anything when only part of the series is applied.
>> >
>> >         Arnd
>>
>> Please check the below link where I made the dma request compatible to
>> both DT and non-DT
>>
>> http://git.kernel.org/?p=linux/kernel/git/broonie/sound.git;a=commit;h=e7ba5f1d0f6292e1b99c63cc4bb74c70232e9065
>> http://git.kernel.org/?p=linux/kernel/git/broonie/sound.git;a=commit;h=b5be04d35dbb2e00ab27a97bfd26e17019e857ef
>>
>> Please let me know if any changes required.
>>
>
> Those two changes by themselves still look ok, I think but you
> still break the non-DT case in this 4/4 patch by changing the
> pl330_filter function in an incompatible way. You will still
> have to either change the filter_param argument in the
> samsung_dmadev_request() function, or provide separate filter
> functions, one to be used by samsung_dmadev_request and
> one for the pl330_xlate function.

I missed out to delete this part. Thanks for your point. I will send
another patch.

>
> In the long run, I think it would be better to move the slave
> drivers away from the samsung_dma wrappers and use
> dma_request_slave_channel directly, but that is an independent
> discussion.
>
>         Arnd

Regards
Padma

^ permalink raw reply

* [PATCH 1/1] net: fec: fix miss init spinlock
From: David Miller @ 2013-02-04  5:24 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAHrpEqSLx-J-1SYC6OapqidY+U3acnTmNyOj8UrNRZwYZRXCoQ@mail.gmail.com>

From: Frank Li <lznuaa@gmail.com>
Date: Mon, 4 Feb 2013 10:22:23 +0800

> 2013/2/3 David Miller <davem@davemloft.net>:
>> From: Frank Li <Frank.Li@freescale.com>
>> Date: Fri, 1 Feb 2013 16:56:26 +0800
>>
>>> @@ -1607,6 +1607,7 @@ static int fec_enet_init(struct net_device *ndev)
>>>       }
>>>
>>>       spin_lock_init(&fep->hw_lock);
>>> +     spin_lock_init(&fep->tmreg_lock);
>>
>> This breaks the build, tmreg_lock is only present in certain
>> configurations.
> 
> No, FEC have changed to check dramatically instead of static config.
> You can look fec.h.  tmreg_lock is always defined.

Not in the 'net' tree or you don't want this bug fixed there at all?

^ permalink raw reply

* [PATCH v3 13/15] ARM: CCI: ensure powerdown-time data is flushed from cache
From: Santosh Shilimkar @ 2013-02-04  5:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <alpine.LFD.2.02.1302031327450.6300@xanadu.home>

On Sunday 03 February 2013 11:59 PM, Nicolas Pitre wrote:
> On Sun, 3 Feb 2013, Santosh Shilimkar wrote:
>
>> On Sunday 03 February 2013 03:53 AM, Nicolas Pitre wrote:
>>> On Fri, 1 Feb 2013, Santosh Shilimkar wrote:
>>>
>>>> On Tuesday 29 January 2013 01:21 PM, Nicolas Pitre wrote:
>>>>> From: Dave Martin <dave.martin@linaro.org>

[..]

>>>>> This patch adds the appropriate flushing to the CCI driver to ensure
>>>>> that the relevant data is available in RAM ahead of time.
>>>>>
>>>>> Because this creates a dependency on arch-specific cacheflushing
>>>>> functions, this patch also makes ARM_CCI depend on ARM.
>>>>>
>>>> You should do that otherwise to avoid other arch building this
>>>> driver for random builds and breaking their builds.
>>>
>>> Before this patch the driver was buildable on any architecture.  That's
>>> why this dependency is added only in this patch.
>>>
>> I was just trying to counter the reasoning in the changelog which says
>> dependency is added because of arch specific cache flushing function.
>> Meaning even without that ARM dependency should be in place to avoid
>> driver getting build for other archs.
>
> Well, some upstream maintainers' opinion is that you should not put
> artificial dependencies on a specific architecture if a driver is
> buildable on any architecture, even if the built driver is of no use to
> those other architectures.
>
I see. I have seen some complaint about not adding the arch dependency.
Anyways, the patch has the dependency set with ARM and hence its
non-issue.

Regards,
Santosh

^ permalink raw reply

* [PATCH v2 6/6] ARM: davinci: da850: configure system configuration chip(CFGCHIP3) for emac
From: Sekhar Nori @ 2013-02-04  5:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <510E5BCF.9080006@ti.com>

On 2/3/2013 6:15 PM, Sekhar Nori wrote:
> On 1/28/2013 7:17 PM, Prabhakar Lad wrote:
>> From: Lad, Prabhakar <prabhakar.lad@ti.com>

> There are couple of issues with this implementation.
> 
> 1) da8xx_config_emac() is specific to DA850 EVM, but masquerades as
>    generic for da8xx. Looks like you need two functions, one for soc
>    specific configuration and one board specific.
> 2) da8xx_config_emac() goes through all the time, whether the
>    particular board has emac module or not. Shouldn't
>    da8xx_config_emac() check if emac is actually enabled in the passed
>    dtb and only the do the configuration?
> 3) The function assumes mii is used always, you can use the rmii_en dt
>    property to check if rmii/mii is enabled and configure the soc/board
>    accordingly.
> 4) If the same function can work both for da850 and da830, then it can
>    be implemented outside of CONFIG_ARCH_DAVINCI_DA850.

Another thing I forgot to mention:

5) This patch replicates a lot of code form board-da850-evm.c. This
needs to be avoided. May be create function to configure emac in
da850.c. This can then be called in board-da850-evm.c as well as in the
dt case.

Thanks,
Sekhar

^ permalink raw reply

* [PATCH] ARM: MARCO: fix the build issue due to gic-vic-to-irqchip move
From: Barry Song @ 2013-02-04  5:41 UTC (permalink / raw)
  To: linux-arm-kernel

From: Barry Song <Baohua.Song@csr.com>

Fix the issue:
tree:   git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git next/soc
head:   6ed05a2aab3763b58922247543d7079106b254dc
commit: af70fdc947dbe835acc26c6ee9e8e930f38935f8 [4/8] Merge branch 'marco-timer-cleanup-rebase' of
git://gitorious.org/sirfprima2-kernel/sirfprima2-kernel into next/soc
config: make ARCH=arm prima2_defconfig

All error/warnings:

>> arch/arm/mach-prima2/platsmp.c:20:30: fatal error: asm/hardware/gic.h: No such file or directory
   compilation terminated.
--
>> arch/arm/mach-prima2/common.c:15:30: fatal error: asm/hardware/gic.h: No such file or directory
   compilation terminated.

Signed-off-by: Barry Song <Baohua.Song@csr.com>
Cc: Xie ChanglongX <changlongx.xie@intel.com>
---
 arch/arm/mach-prima2/common.c  |   16 ++--------------
 arch/arm/mach-prima2/platsmp.c |    8 +-------
 2 files changed, 3 insertions(+), 21 deletions(-)

diff --git a/arch/arm/mach-prima2/common.c b/arch/arm/mach-prima2/common.c
index 00a6564..2d57aa4 100644
--- a/arch/arm/mach-prima2/common.c
+++ b/arch/arm/mach-prima2/common.c
@@ -8,11 +8,10 @@
 
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/of_irq.h>
+#include <linux/irqchip.h>
 #include <asm/sizes.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
-#include <asm/hardware/gic.h>
 #include <linux/of.h>
 #include <linux/of_platform.h>
 #include "common.h"
@@ -61,16 +60,6 @@ MACHINE_END
 #endif
 
 #ifdef CONFIG_ARCH_MARCO
-static const struct of_device_id marco_irq_match[] __initconst = {
-	{ .compatible = "arm,cortex-a9-gic", .data = gic_of_init, },
-	{ /* sentinel */ }
-};
-
-static void __init marco_init_irq(void)
-{
-	of_irq_init(marco_irq_match);
-}
-
 static const char *marco_dt_match[] __initdata = {
 	"sirf,marco",
 	NULL
@@ -80,9 +69,8 @@ DT_MACHINE_START(MARCO_DT, "Generic MARCO (Flattened Device Tree)")
 	/* Maintainer: Barry Song <baohua.song@csr.com> */
 	.smp            = smp_ops(sirfsoc_smp_ops),
 	.map_io         = sirfsoc_map_io,
-	.init_irq	= marco_init_irq,
+	.init_irq	= irqchip_init,
 	.init_time	= sirfsoc_marco_timer_init,
-	.handle_irq     = gic_handle_irq,
 	.init_machine	= sirfsoc_mach_init,
 	.init_late	= sirfsoc_init_late,
 	.dt_compat      = marco_dt_match,
diff --git a/arch/arm/mach-prima2/platsmp.c b/arch/arm/mach-prima2/platsmp.c
index 2395022..4b78831 100644
--- a/arch/arm/mach-prima2/platsmp.c
+++ b/arch/arm/mach-prima2/platsmp.c
@@ -11,13 +11,13 @@
 #include <linux/delay.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
+#include <linux/irqchip/arm-gic.h>
 #include <asm/page.h>
 #include <asm/mach/map.h>
 #include <asm/smp_plat.h>
 #include <asm/smp_scu.h>
 #include <asm/cacheflush.h>
 #include <asm/cputype.h>
-#include <asm/hardware/gic.h>
 #include <mach/map.h>
 
 #include "common.h"
@@ -142,18 +142,12 @@ static int __cpuinit sirfsoc_boot_secondary(unsigned int cpu, struct task_struct
 	return pen_release != -1 ? -ENOSYS : 0;
 }
 
-static void __init sirfsoc_smp_init_cpus(void)
-{
-	set_smp_cross_call(gic_raise_softirq);
-}
-
 static void __init sirfsoc_smp_prepare_cpus(unsigned int max_cpus)
 {
 	scu_enable(scu_base);
 }
 
 struct smp_operations sirfsoc_smp_ops __initdata = {
-        .smp_init_cpus          = sirfsoc_smp_init_cpus,
         .smp_prepare_cpus       = sirfsoc_smp_prepare_cpus,
         .smp_secondary_init     = sirfsoc_secondary_init,
         .smp_boot_secondary     = sirfsoc_boot_secondary,
-- 
1.7.5.4



Member of the CSR plc group of companies. CSR plc registered in England and Wales, registered number 4187346, registered office Churchill House, Cambridge Business Park, Cowley Road, Cambridge, CB4 0WZ, United Kingdom
More information can be found at www.csr.com. Follow CSR on Twitter at http://twitter.com/CSR_PLC and read our blog at www.csr.com/blog

^ permalink raw reply related

* [PATCH v6] cpufreq: add imx6q-cpufreq driver
From: Shawn Guo @ 2013-02-04  5:46 UTC (permalink / raw)
  To: linux-arm-kernel

Add an imx6q-cpufreq driver for Freescale i.MX6Q SoC to handle the
hardware specific frequency and voltage scaling requirements.

The driver supports module build and is instantiated by the platform
device/driver mechanism, so that it will not be instantiated on other
platforms, as IMX is built with multiplatform support.

Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org>
---
Changes since v5:
 * Update clock tranistion code to make keep use count correct

 drivers/cpufreq/Kconfig.arm     |    9 ++
 drivers/cpufreq/Makefile        |    1 +
 drivers/cpufreq/imx6q-cpufreq.c |  336 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 346 insertions(+)
 create mode 100644 drivers/cpufreq/imx6q-cpufreq.c

diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index ffe55b8..c65226c 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -77,6 +77,15 @@ config ARM_EXYNOS5250_CPUFREQ
 	  This adds the CPUFreq driver for Samsung EXYNOS5250
 	  SoC.
 
+config ARM_IMX6Q_CPUFREQ
+	tristate "Freescale i.MX6Q cpufreq support"
+	depends on SOC_IMX6Q
+	depends on REGULATOR_ANATOP
+	help
+	  This adds cpufreq driver support for Freescale i.MX6Q SOC.
+
+	  If in doubt, say N.
+
 config ARM_SPEAR_CPUFREQ
 	bool "SPEAr CPUFreq support"
 	depends on PLAT_SPEAR
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index e2a5da7..93610b2 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ)	+= exynos5250-cpufreq.o
 obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ)	+= omap-cpufreq.o
 obj-$(CONFIG_ARM_SPEAR_CPUFREQ)		+= spear-cpufreq.o
 obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ)	+= highbank-cpufreq.o
+obj-$(CONFIG_ARM_IMX6Q_CPUFREQ)		+= imx6q-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
new file mode 100644
index 0000000..d6b6ef3
--- /dev/null
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -0,0 +1,336 @@
+/*
+ * Copyright (C) 2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/opp.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#define PU_SOC_VOLTAGE_NORMAL	1250000
+#define PU_SOC_VOLTAGE_HIGH	1275000
+#define FREQ_1P2_GHZ		1200000000
+
+static struct regulator *arm_reg;
+static struct regulator *pu_reg;
+static struct regulator *soc_reg;
+
+static struct clk *arm_clk;
+static struct clk *pll1_sys_clk;
+static struct clk *pll1_sw_clk;
+static struct clk *step_clk;
+static struct clk *pll2_pfd2_396m_clk;
+
+static struct device *cpu_dev;
+static struct cpufreq_frequency_table *freq_table;
+static unsigned int transition_latency;
+
+static int imx6q_verify_speed(struct cpufreq_policy *policy)
+{
+	return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static unsigned int imx6q_get_speed(unsigned int cpu)
+{
+	return clk_get_rate(arm_clk) / 1000;
+}
+
+static int imx6q_set_target(struct cpufreq_policy *policy,
+			    unsigned int target_freq, unsigned int relation)
+{
+	struct cpufreq_freqs freqs;
+	struct opp *opp;
+	unsigned long freq_hz, volt, volt_old;
+	unsigned int index, cpu;
+	int ret;
+
+	ret = cpufreq_frequency_table_target(policy, freq_table, target_freq,
+					     relation, &index);
+	if (ret) {
+		dev_err(cpu_dev, "failed to match target frequency %d: %d\n",
+			target_freq, ret);
+		return ret;
+	}
+
+	freqs.new = freq_table[index].frequency;
+	freq_hz = freqs.new * 1000;
+	freqs.old = clk_get_rate(arm_clk) / 1000;
+
+	if (freqs.old == freqs.new)
+		return 0;
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+	}
+
+	rcu_read_lock();
+	opp = opp_find_freq_ceil(cpu_dev, &freq_hz);
+	if (IS_ERR(opp)) {
+		rcu_read_unlock();
+		dev_err(cpu_dev, "failed to find OPP for %ld\n", freq_hz);
+		return PTR_ERR(opp);
+	}
+
+	volt = opp_get_voltage(opp);
+	rcu_read_unlock();
+	volt_old = regulator_get_voltage(arm_reg);
+
+	dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
+		freqs.old / 1000, volt_old / 1000,
+		freqs.new / 1000, volt / 1000);
+
+	/* scaling up?  scale voltage before frequency */
+	if (freqs.new > freqs.old) {
+		ret = regulator_set_voltage_tol(arm_reg, volt, 0);
+		if (ret) {
+			dev_err(cpu_dev,
+				"failed to scale vddarm up: %d\n", ret);
+			return ret;
+		}
+
+		/*
+		 * Need to increase vddpu and vddsoc for safety
+		 * if we are about to run at 1.2 GHz.
+		 */
+		if (freqs.new == FREQ_1P2_GHZ / 1000) {
+			regulator_set_voltage_tol(pu_reg,
+					PU_SOC_VOLTAGE_HIGH, 0);
+			regulator_set_voltage_tol(soc_reg,
+					PU_SOC_VOLTAGE_HIGH, 0);
+		}
+	}
+
+	/*
+	 * The setpoints are selected per PLL/PDF frequencies, so we need to
+	 * reprogram PLL for frequency scaling.  The procedure of reprogramming
+	 * PLL1 is as below.
+	 *
+	 *  - Enable pll2_pfd2_396m_clk and reparent pll1_sw_clk to it
+	 *  - Reprogram pll1_sys_clk and reparent pll1_sw_clk back to it
+	 *  - Disable pll2_pfd2_396m_clk
+	 */
+	clk_prepare_enable(pll2_pfd2_396m_clk);
+	clk_set_parent(step_clk, pll2_pfd2_396m_clk);
+	clk_set_parent(pll1_sw_clk, step_clk);
+	if (freq_hz > clk_get_rate(pll2_pfd2_396m_clk)) {
+		clk_set_rate(pll1_sys_clk, freqs.new * 1000);
+		/*
+		 * If we are leaving 396 MHz set-point, we need to enable
+		 * pll1_sys_clk and disable pll2_pfd2_396m_clk to keep
+		 * their use count correct.
+		 */
+		if (freqs.old * 1000 <= clk_get_rate(pll2_pfd2_396m_clk)) {
+			clk_prepare_enable(pll1_sys_clk);
+			clk_disable_unprepare(pll2_pfd2_396m_clk);
+		}
+		clk_set_parent(pll1_sw_clk, pll1_sys_clk);
+		clk_disable_unprepare(pll2_pfd2_396m_clk);
+	} else {
+		/*
+		 * Disable pll1_sys_clk if pll2_pfd2_396m_clk is sufficient
+		 * to provide the frequency.
+		 */
+		clk_disable_unprepare(pll1_sys_clk);
+	}
+
+	/* Ensure the arm clock divider is what we expect */
+	ret = clk_set_rate(arm_clk, freqs.new * 1000);
+	if (ret) {
+		dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
+		regulator_set_voltage_tol(arm_reg, volt_old, 0);
+		return ret;
+	}
+
+	/* scaling down?  scale voltage after frequency */
+	if (freqs.new < freqs.old) {
+		ret = regulator_set_voltage_tol(arm_reg, volt, 0);
+		if (ret)
+			dev_warn(cpu_dev,
+				 "failed to scale vddarm down: %d\n", ret);
+
+		if (freqs.old == FREQ_1P2_GHZ / 1000) {
+			regulator_set_voltage_tol(pu_reg,
+					PU_SOC_VOLTAGE_NORMAL, 0);
+			regulator_set_voltage_tol(soc_reg,
+					PU_SOC_VOLTAGE_NORMAL, 0);
+		}
+	}
+
+	for_each_online_cpu(cpu) {
+		freqs.cpu = cpu;
+		cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+	}
+
+	return 0;
+}
+
+static int imx6q_cpufreq_init(struct cpufreq_policy *policy)
+{
+	int ret;
+
+	ret = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+	if (ret) {
+		dev_err(cpu_dev, "invalid frequency table: %d\n", ret);
+		return ret;
+	}
+
+	policy->cpuinfo.transition_latency = transition_latency;
+	policy->cur = clk_get_rate(arm_clk) / 1000;
+	cpumask_setall(policy->cpus);
+	cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+	return 0;
+}
+
+static int imx6q_cpufreq_exit(struct cpufreq_policy *policy)
+{
+	cpufreq_frequency_table_put_attr(policy->cpu);
+	return 0;
+}
+
+static struct freq_attr *imx6q_cpufreq_attr[] = {
+	&cpufreq_freq_attr_scaling_available_freqs,
+	NULL,
+};
+
+static struct cpufreq_driver imx6q_cpufreq_driver = {
+	.verify = imx6q_verify_speed,
+	.target = imx6q_set_target,
+	.get = imx6q_get_speed,
+	.init = imx6q_cpufreq_init,
+	.exit = imx6q_cpufreq_exit,
+	.name = "imx6q-cpufreq",
+	.attr = imx6q_cpufreq_attr,
+};
+
+static int imx6q_cpufreq_probe(struct platform_device *pdev)
+{
+	struct device_node *np;
+	struct opp *opp;
+	unsigned long min_volt, max_volt;
+	int num, ret;
+
+	cpu_dev = &pdev->dev;
+
+	np = of_find_node_by_path("/cpus/cpu at 0");
+	if (!np) {
+		dev_err(cpu_dev, "failed to find cpu0 node\n");
+		return -ENOENT;
+	}
+
+	cpu_dev->of_node = np;
+
+	arm_clk = devm_clk_get(cpu_dev, "arm");
+	pll1_sys_clk = devm_clk_get(cpu_dev, "pll1_sys");
+	pll1_sw_clk = devm_clk_get(cpu_dev, "pll1_sw");
+	step_clk = devm_clk_get(cpu_dev, "step");
+	pll2_pfd2_396m_clk = devm_clk_get(cpu_dev, "pll2_pfd2_396m");
+	if (IS_ERR(arm_clk) || IS_ERR(pll1_sys_clk) || IS_ERR(pll1_sw_clk) ||
+	    IS_ERR(step_clk) || IS_ERR(pll2_pfd2_396m_clk)) {
+		dev_err(cpu_dev, "failed to get clocks\n");
+		ret = -ENOENT;
+		goto put_node;
+	}
+
+	arm_reg = devm_regulator_get(cpu_dev, "arm");
+	pu_reg = devm_regulator_get(cpu_dev, "pu");
+	soc_reg = devm_regulator_get(cpu_dev, "soc");
+	if (!arm_reg || !pu_reg || !soc_reg) {
+		dev_err(cpu_dev, "failed to get regulators\n");
+		ret = -ENOENT;
+		goto put_node;
+	}
+
+	/* We expect an OPP table supplied by platform */
+	num = opp_get_opp_count(cpu_dev);
+	if (num < 0) {
+		ret = num;
+		dev_err(cpu_dev, "no OPP table is found: %d\n", ret);
+		goto put_node;
+	}
+
+	ret = opp_init_cpufreq_table(cpu_dev, &freq_table);
+	if (ret) {
+		dev_err(cpu_dev, "failed to init cpufreq table: %d\n", ret);
+		goto put_node;
+	}
+
+	if (of_property_read_u32(np, "clock-latency", &transition_latency))
+		transition_latency = CPUFREQ_ETERNAL;
+
+	/*
+	 * OPP is maintained in order of increasing frequency, and
+	 * freq_table initialised from OPP is therefore sorted in the
+	 * same order.
+	 */
+	rcu_read_lock();
+	opp = opp_find_freq_exact(cpu_dev,
+				  freq_table[0].frequency * 1000, true);
+	min_volt = opp_get_voltage(opp);
+	opp = opp_find_freq_exact(cpu_dev,
+				  freq_table[--num].frequency * 1000, true);
+	max_volt = opp_get_voltage(opp);
+	rcu_read_unlock();
+	ret = regulator_set_voltage_time(arm_reg, min_volt, max_volt);
+	if (ret > 0)
+		transition_latency += ret * 1000;
+
+	/* Count vddpu and vddsoc latency in for 1.2 GHz support */
+	if (freq_table[num].frequency == FREQ_1P2_GHZ / 1000) {
+		ret = regulator_set_voltage_time(pu_reg, PU_SOC_VOLTAGE_NORMAL,
+						 PU_SOC_VOLTAGE_HIGH);
+		if (ret > 0)
+			transition_latency += ret * 1000;
+		ret = regulator_set_voltage_time(soc_reg, PU_SOC_VOLTAGE_NORMAL,
+						 PU_SOC_VOLTAGE_HIGH);
+		if (ret > 0)
+			transition_latency += ret * 1000;
+	}
+
+	ret = cpufreq_register_driver(&imx6q_cpufreq_driver);
+	if (ret) {
+		dev_err(cpu_dev, "failed register driver: %d\n", ret);
+		goto free_freq_table;
+	}
+
+	of_node_put(np);
+	return 0;
+
+free_freq_table:
+	opp_free_cpufreq_table(cpu_dev, &freq_table);
+put_node:
+	of_node_put(np);
+	return ret;
+}
+
+static int imx6q_cpufreq_remove(struct platform_device *pdev)
+{
+	cpufreq_unregister_driver(&imx6q_cpufreq_driver);
+	opp_free_cpufreq_table(cpu_dev, &freq_table);
+
+	return 0;
+}
+
+static struct platform_driver imx6q_cpufreq_platdrv = {
+	.driver = {
+		.name	= "imx6q-cpufreq",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= imx6q_cpufreq_probe,
+	.remove		= imx6q_cpufreq_remove,
+};
+module_platform_driver(imx6q_cpufreq_platdrv);
+
+MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
+MODULE_DESCRIPTION("Freescale i.MX6Q cpufreq driver");
+MODULE_LICENSE("GPL");
-- 
1.7.9.5

^ permalink raw reply related

* [arm-soc:next/soc 4/8] arch/arm/mach-prima2/platsmp.c:20:30: fatal error: asm/hardware/gic.h: No such file or directory
From: Barry Song @ 2013-02-04  5:50 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20130130003908.GA12315@quad.lixom.net>

Hi Olof,

2013/1/30 Olof Johansson <olof@lixom.net>
>
> On Wed, Jan 30, 2013 at 08:29:05AM +0800, Xie ChanglongX wrote:
> >
> > Hi Olof,
> >
> > FYI, kernel build failed on
> >
> > tree:   git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc.git
> > next/soc
> > head:   6ed05a2aab3763b58922247543d7079106b254dc
> > commit: af70fdc947dbe835acc26c6ee9e8e930f38935f8 [4/8] Merge branch
> > 'marco-timer-cleanup-rebase' of
> > git://gitorious.org/sirfprima2-kernel/sirfprima2-kernel into next/soc
> > config: make ARCH=arm prima2_defconfig
>
> Thanks! Yes, this is a known issue as of this morning, I didn't catch it
> before
> I merged in so I asked Barry to follow up with a fix.

done by "[PATCH] ARM: MARCO: fix the build issue due to
gic-vic-to-irqchip move".
i'll not send a pull request for it, would you apply it separately?

>
>
> -Olof

-barry

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox