Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] ARM: hw_breakpoint: ensure debug logic is powered up on v7 cores
From: Will Deacon @ 2011-02-25 10:13 UTC (permalink / raw)
  To: linux-arm-kernel

ARMv7 allows the debug core logic to be powered down and provides the
DBGPRSR register so that software can power-up and check the status of
the logic.

This patch ensures that the debug logic is powered up on ARMv7 cores
before we attempt to access the extended debug registers.

Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 arch/arm/kernel/hw_breakpoint.c |   26 +++++++++++++++++++++++---
 1 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
index d600bd3..44b84fe 100644
--- a/arch/arm/kernel/hw_breakpoint.c
+++ b/arch/arm/kernel/hw_breakpoint.c
@@ -836,9 +836,11 @@ static int hw_breakpoint_pending(unsigned long addr, unsigned int fsr,
 /*
  * One-time initialisation.
  */
-static void reset_ctrl_regs(void *unused)
+static void reset_ctrl_regs(void *info)
 {
-	int i;
+	int i, cpu = smp_processor_id();
+	u32 dbg_power;
+	cpumask_t *cpumask = info;
 
 	/*
 	 * v7 debug contains save and restore registers so that debug state
@@ -850,6 +852,17 @@ static void reset_ctrl_regs(void *unused)
 	 */
 	if (debug_arch >= ARM_DEBUG_ARCH_V7_ECP14) {
 		/*
+		 * Ensure sticky power-down is clear (i.e. debug logic is
+		 * powered up).
+		 */
+		asm volatile("mrc p14, 0, %0, c1, c5, 4" : "=r" (dbg_power));
+		if ((dbg_power & 0x1) == 0) {
+			pr_warning("CPU %d debug is powered down!\n", cpu);
+			cpumask_or(cpumask, cpumask, cpumask_of(cpu));
+			return;
+		}
+
+		/*
 		 * Unconditionally clear the lock by writing a value
 		 * other than 0xC5ACCE55 to the access register.
 		 */
@@ -887,6 +900,7 @@ static struct notifier_block __cpuinitdata dbg_reset_nb = {
 static int __init arch_hw_breakpoint_init(void)
 {
 	u32 dscr;
+	cpumask_t cpumask = { CPU_BITS_NONE };
 
 	debug_arch = get_debug_arch();
 
@@ -911,7 +925,13 @@ static int __init arch_hw_breakpoint_init(void)
 	 * Reset the breakpoint resources. We assume that a halting
 	 * debugger will leave the world in a nice state for us.
 	 */
-	on_each_cpu(reset_ctrl_regs, NULL, 1);
+	on_each_cpu(reset_ctrl_regs, &cpumask, 1);
+	if (!cpumask_empty(&cpumask)) {
+		core_num_brps = 0;
+		core_num_reserved_brps = 0;
+		core_num_wrps = 0;
+		return 0;
+	}
 
 	ARM_DBG_READ(c1, 0, dscr);
 	if (dscr & ARM_DSCR_HDBGEN) {
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH] davinci: da850/omap-l138: Add Carrier Link OK check in Davinci RX Handler
From: Hegde, Vinay @ 2011-02-25  9:56 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds an additional check in the Davinci EMAC RX Handler,
which tests the __LINK_STATE_NOCARRIER flag along with the
__LINK_STATE_START flag as part EMAC shutting down procedure.

This avoids
WARNING: at drivers/net/davinci_emac.c:1040 emac_rx_handler+0xf8/0x120()
during rtcwake used to suspend the target for a specified duration.

Signed-off-by: Hegde, Vinay <vinay.hegde@ti.com>
---
 drivers/net/davinci_emac.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
index 2a628d1..7018bfe 100644
--- a/drivers/net/davinci_emac.c
+++ b/drivers/net/davinci_emac.c
@@ -1008,7 +1008,7 @@ static void emac_rx_handler(void *token, int len, int status)
 	int			ret;
 
 	/* free and bail if we are shutting down */
-	if (unlikely(!netif_running(ndev))) {
+	if (unlikely(!netif_running(ndev) || !netif_carrier_ok(ndev))) {
 		dev_kfree_skb_any(skb);
 		return;
 	}
-- 
1.7.1

^ permalink raw reply related

* [PATCH v5 1/2] PRUSS UIO driver support
From: Thomas Gleixner @ 2011-02-25  9:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1298623530-10294-2-git-send-email-pratheesh@ti.com>

On Fri, 25 Feb 2011, Pratheesh Gangadhar wrote:
> +static irqreturn_t pruss_handler(int irq, struct uio_info *dev_info)
> +{
> +	void __iomem *base = dev_info->mem[0].internal_addr;
> +	void __iomem *intren_reg = base + PINTC_HIER;
> +	void __iomem *intrstat_reg = base + PINTC_HIPIR + ((irq - 1) << 2);
> +	int val = ioread32(intren_reg), intr_mask = (1 << (irq - 1));
> +
> +	/* Is interrupt enabled and active ? */
> +	if (!(val & intr_mask) && (ioread32(intrstat_reg) & HIPIR_NOPEND))
> +		return IRQ_NONE;
> +
> +	/* Disable interrupt */
> +	iowrite32((val & ~intr_mask), intren_reg);
> +	return IRQ_HANDLED;
> +}

Hmm, just noticed, that you fiddle with the interrupt enable register
here totally unprotected. So on a SMP system you might haandle two
different interrupts at the same time. That wants locking.

And even on UP, you have a problem as you reenable that thing from
user space which requires a read modify write. Racy as hell.

Please look at the other UIO drivers which have the same problem.
Sorry for not noticing earlier!

Thanks,

	tglx

^ permalink raw reply

* [PATCH] ARM: mxs: Initial support for Ka-Ro TX28
From: Uwe Kleine-König @ 2011-02-25  9:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1298581480-15585-1-git-send-email-u.kleine-koenig@pengutronix.de>

Hello,

as requested by Sascha I squashed the following patch in:

diff --git a/arch/arm/mach-mxs/mach-tx28.c b/arch/arm/mach-mxs/mach-tx28.c
index 540d6ea..b609b84 100644
--- a/arch/arm/mach-mxs/mach-tx28.c
+++ b/arch/arm/mach-mxs/mach-tx28.c
@@ -130,7 +130,6 @@ static const struct gpio_led_platform_data tx28_stk5v3_led_data __initconst = {
 };
 
 static struct spi_board_info tx28_spi_board_info[] = {
-#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
 	{
 		.modalias = "spidev",
 		.max_speed_hz = 20000000,
@@ -139,7 +138,6 @@ static struct spi_board_info tx28_spi_board_info[] = {
 		.controller_data = (void *)SPI_GPIO_NO_CHIPSELECT,
 		.mode = SPI_MODE_0,
 	},
-#endif
 };
 
 static void __init tx28_stk5v3_init(void)

The branch in my public repository is updated.

Thanks
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

^ permalink raw reply related

* [PATCH 2/5] ARM: Samsung: cleanup S5P gpio interrupt code
From: Marek Szyprowski @ 2011-02-25  9:00 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <01f201cbd342$8e6001f0$ab2005d0$%kim@samsung.com>

Hello,

On Wednesday, February 23, 2011 11:15 AM Kukjin Kim wrote:

> Marek Szyprowski wrote:
> >
> > This patch performs a global cleanup in s5p gpio interrupt support code.
> > The code is prepared for upcoming support for gpio interrupts on S5PC210
> > platform, which has 2 gpio banks (regions) instead of one (like on
> > S5PC110 and S5PC100).
> >
> > Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
> > Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
> > ---
> >  arch/arm/plat-s5p/irq-gpioint.c |  106
> +++++++++++++++++--------------------
> > --
> >  1 files changed, 46 insertions(+), 60 deletions(-)
> >
> > diff --git a/arch/arm/plat-s5p/irq-gpioint.c b/arch/arm/plat-s5p/irq-
> > gpioint.c
> > index 3b6bf89..af10328 100644
> > --- a/arch/arm/plat-s5p/irq-gpioint.c
> > +++ b/arch/arm/plat-s5p/irq-gpioint.c
> > @@ -22,77 +22,64 @@
> >  #include <plat/gpio-core.h>
> >  #include <plat/gpio-cfg.h>
> >
> > -#define S5P_GPIOREG(x)			(S5P_VA_GPIO + (x))
> > +#define GPIO_BASE(chip)		(((unsigned long)(chip)->base) &
> > ~(SZ_4K - 1))
> >
> 
> Need SZ_4K here instead of 0xFFFFF000?

No problem, I can change it to 0xFFFFF000

> 
> > -#define GPIOINT_CON_OFFSET		0x700
> > -#define GPIOINT_MASK_OFFSET		0x900
> > -#define GPIOINT_PEND_OFFSET		0xA00
> > +#define CON_OFFSET		0x700
> > +#define MASK_OFFSET		0x900
> > +#define PEND_OFFSET		0xA00
> 
> I don't know why need to change above definitions...

I've shortened them to make the code the uses them to fit 80 characters
per line... They are just a local defines that imho don't need to be
prefixed with GPIOINT_

> > +#define REG_OFFSET(x)		((x) << 2)
> >
> Actually, this is used instead of "group << 2" in this file.
> So how about "GPIOINT_REG_OFFSET(x)" like others?

Ok.

> >  static void s5p_gpioint_ack(struct irq_data *data)
> >  {
> > +	struct s3c_gpio_chip *chip = irq_data_get_irq_data(data);
> >  	int group, offset, pend_offset;
> >  	unsigned int value;
> >
> > -	group = s5p_gpioint_get_group(data);
> > +	group = chip->group;
> >  	offset = s5p_gpioint_get_offset(data);
> > -	pend_offset = group << 2;
> > +	pend_offset = REG_OFFSET(group);
> >
> > -	value = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset);
> > -	value |= 1 << offset;
> > -	__raw_writel(value, S5P_GPIOREG(GPIOINT_PEND_OFFSET) + pend_offset);
> > +	value = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET + pend_offset);
> > +	value |= BIT(offset);
> 
> No need inclusion <linux/bitops.h>?

It has been included indirectly, because the code compiled fine.

snip

> >  static void s5p_gpioint_handler(unsigned int irq, struct irq_desc *desc)
> >  {
> > -	int group, offset, pend_offset, mask_offset;
> > -	int real_irq;
> > +	int group, pend_offset, mask_offset;
> >  	unsigned int pend, mask;
> >
> >  	for (group = 0; group < S5P_GPIOINT_GROUP_MAXNR; group++) {
> > -		pend_offset = group << 2;
> > -		pend = __raw_readl(S5P_GPIOREG(GPIOINT_PEND_OFFSET) +
> > -				pend_offset);
> > +		struct s3c_gpio_chip *chip = irq_chips[group];
> > +		if (!chip)
> > +			continue;
> > +
> > +		pend_offset = REG_OFFSET(group);
> > +		pend = __raw_readl(GPIO_BASE(chip) + PEND_OFFSET +
> > pend_offset);
> >  		if (!pend)
> >  			continue;
> >
> > -		mask_offset = group << 2;
> > -		mask = __raw_readl(S5P_GPIOREG(GPIOINT_MASK_OFFSET) +
> > -				mask_offset);
> > +		mask_offset = REG_OFFSET(group);
> > +		mask = __raw_readl(GPIO_BASE(chip) + MASK_OFFSET +
> > mask_offset);
> >  		pend &= ~mask;
> >
> > -		for (offset = 0; offset < 8; offset++) {
> > -			if (pend & (1 << offset)) {
> > -				struct s3c_gpio_chip *chip =
> irq_chips[group];
> > -				if (chip) {
> > -					real_irq = chip->irq_base + offset;
> > -					generic_handle_irq(real_irq);
> > -				}
> > -			}
> > +		while (pend) {
> > +			int offset = fls(pend) - 1;
> 
> __ffs?

I don't see much difference between ffs and fls here...

> And hmm...do we really need while loop here?

Yes, because more than one gpio pin in a group can issue an interrupt at the
same time. The previous version used for() loop here.

> 
> > +			int real_irq = chip->irq_base + offset;
> > +			generic_handle_irq(real_irq);
> > +			pend &= ~BIT(offset);
> >  		}
> >  	}
> >  }
> > @@ -202,7 +188,7 @@ static __init int s5p_gpioint_add(struct s3c_gpio_chip
> > *chip)
> >  	for (i = 0; i < chip->chip.ngpio; i++) {
> >  		irq = chip->irq_base + i;
> >  		set_irq_chip(irq, &s5p_gpioint);
> > -		set_irq_data(irq, &chip->chip);
> > +		set_irq_data(irq, chip);
> 
> ?

This simplifies all the functions that use get_irq_data. Now they get s3c_gpio_chip
directly and don't need to extract it with contrainer_of().

Best regards
--
Marek Szyprowski
Samsung Poland R&D Center

^ permalink raw reply

* mxs: name##_set_rate broken
From: Shawn Guo @ 2011-02-25  8:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110224165700.GY22310@pengutronix.de>

Hi Uwe,

On Thu, Feb 24, 2011 at 05:57:00PM +0100, Uwe Kleine-K?nig wrote:
> Hello Shawn,
> 
> for the lcdif clock get_rate looks as follows:
> 
> 	read div from HW_CLKCTRL_DIS_LCDIF.DIV
> 	return clk_get_rate(clk->parent) / div
> 
> with clk->parent being ref_pix_clk on our system.
> 
> ref_pix_clk's rate depends on HW_CLKCTRL_FRAC1.PIXFRAC.
> 
> The set_rate function for lcdif does:
> 
> 	parent_rate = clk_get_rate(clk->parent);
> 	based on that calculate frac and div such that 
> 	  parent_rate * 18 / frac / div is near the requested rate.
>         HW_CLKCTRL_FRAC1.PIXFRAC is updated with frac
> 	HW_CLKCTRL_DIS_LCDIF.DIV is updated with div
> 
> For this calculation to be correct the parent_rate needs to be
> initialized not with the clock rate of lcdif's parent (i.e. ref_pix) but
> that of its grandparent (i.e. ref_pix' parent == pll0_clk)
> 
Yes, this is bug.  I hesitated to go this way when implementing the
function, because it's not generic that the set_rate function needs
to play parent's rate.  It becomes even worse if the parent has other
children clocks.  But we have to go this way to get the rate close to
the desired one.  For particular example, we have specific cpu rate
for different set points per data sheet, which is not reachable
without playing ref_cpu_clk.

> I think the else branch to if (clk->parent == &ref_xtal_clk) of
> name##_set_rate is broken for all clocks, but Sascha and I didn't
> verified that.  Our local fix is:
> 
> diff --git a/arch/arm/mach-mxs/clock-mx28.c b/arch/arm/mach-mxs/clock-mx28.c
> index febd787..7a26edd 100644
> --- a/arch/arm/mach-mxs/clock-mx28.c
> +++ b/arch/arm/mach-mxs/clock-mx28.c
> @@ -295,11 +295,11 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)		\
>  	unsigned long diff, parent_rate, calc_rate;			\
>  	int i;								\
>  									\
> -	parent_rate = clk_get_rate(clk->parent);			\
>  	div_max = BM_CLKCTRL_##dr##_DIV >> BP_CLKCTRL_##dr##_DIV;	\
>  	bm_busy = BM_CLKCTRL_##dr##_BUSY;				\
>  									\
>  	if (clk->parent == &ref_xtal_clk) {				\
> +		parent_rate = clk_get_rate(clk->parent);		\
>  		div = DIV_ROUND_UP(parent_rate, rate);			\
>  		if (clk == &cpu_clk) {					\
>  			div_max = BM_CLKCTRL_CPU_DIV_XTAL >>		\
> @@ -309,6 +309,7 @@ static int name##_set_rate(struct clk *clk, unsigned long rate)		\
>  		if (div == 0 || div > div_max)				\
>  			return -EINVAL;					\
>  	} else {							\
> +		parent_rate = clk_get_rate(&pll0_clk);			\
>  		rate >>= PARENT_RATE_SHIFT;				\
>  		parent_rate >>= PARENT_RATE_SHIFT;			\
>  		diff = parent_rate;					\
> 
> that seems to work.  (Actually using the grandparent instead of a hard
> coded &pll0_clk would be better.)
> 
> Can you please have a look, too and maybe even come up with a better
> fix?
> 
The fix looks good to me.

> IMHO it's time that Jeremy's clk patches get merged to resolve the
> uglinesses here.  (One thing that comes to mind is that the result of

Yes, agree.  But I'm not able to start working on this immediately,
because I have other priority to take care for my next time slot.
Do you want to take this on?  Feel free to ...

> if (clk->parent == &ref_xtal_clk) doesn't change during runtime, so
> it would be better to use two different implementations.  (That
> statement still needs a careful verification though.))
> 

-- 
Regards,
Shawn

^ permalink raw reply

* [PATCH v5 2/2] Defines DA850/AM18xx/OMAPL1-38 SOC resources used by PRUSS UIO driver
From: Pratheesh Gangadhar @ 2011-02-25  8:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1298623530-10294-2-git-send-email-pratheesh@ti.com>

This patch defines PRUSS, ECAP clocks, memory and IRQ resources
used by PRUSS UIO driver in DA850/AM18xx/OMAPL1-38 devices. UIO
driver exports 64K I/O region of PRUSS, 128KB L3 RAM and 256KB
DDR buffer to user space. PRUSS has 8 host event interrupt lines
mapped to IRQ_DA8XX_EVTOUT0..7 of ARM9 INTC.These in conjunction
with shared memory can be used to implement IPC between ARM9 and
PRUSS.

Signed-off-by: Pratheesh Gangadhar <pratheesh@ti.com>
---
 arch/arm/mach-davinci/board-da850-evm.c    |    4 ++
 arch/arm/mach-davinci/da850.c              |   35 +++++++++++++
 arch/arm/mach-davinci/devices-da8xx.c      |   73 ++++++++++++++++++++++++++++
 arch/arm/mach-davinci/include/mach/da8xx.h |    3 +
 4 files changed, 115 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index 11f986b..bd85aa3 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -1077,6 +1077,10 @@ static __init void da850_evm_init(void)
 		pr_warning("da850_evm_init: i2c0 registration failed: %d\n",
 				ret);
 
+	ret = da8xx_register_pruss();
+	if (ret)
+		pr_warning("da850_evm_init: pruss registration failed: %d\n",
+				ret);
 
 	ret = da8xx_register_watchdog();
 	if (ret)
diff --git a/arch/arm/mach-davinci/da850.c b/arch/arm/mach-davinci/da850.c
index 3443d97..0096d4f 100644
--- a/arch/arm/mach-davinci/da850.c
+++ b/arch/arm/mach-davinci/da850.c
@@ -238,6 +238,13 @@ static struct clk tptc2_clk = {
 	.flags		= ALWAYS_ENABLED,
 };
 
+static struct clk pruss_clk = {
+	.name		= "pruss",
+	.parent		= &pll0_sysclk2,
+	.lpsc		= DA8XX_LPSC0_DMAX,
+	.flags		= ALWAYS_ENABLED,
+};
+
 static struct clk uart0_clk = {
 	.name		= "uart0",
 	.parent		= &pll0_sysclk2,
@@ -359,6 +366,30 @@ static struct clk usb20_clk = {
 	.gpsc		= 1,
 };
 
+static struct clk ecap0_clk = {
+	.name		= "ecap0",
+	.parent		= &pll0_sysclk2,
+	.lpsc		= DA8XX_LPSC1_ECAP,
+	.flags		= DA850_CLK_ASYNC3,
+	.gpsc		= 1,
+};
+
+static struct clk ecap1_clk = {
+	.name		= "ecap1",
+	.parent		= &pll0_sysclk2,
+	.lpsc		= DA8XX_LPSC1_ECAP,
+	.flags		= DA850_CLK_ASYNC3,
+	.gpsc		= 1,
+};
+
+static struct clk ecap2_clk = {
+	.name		= "ecap2",
+	.parent		= &pll0_sysclk2,
+	.lpsc		= DA8XX_LPSC1_ECAP,
+	.flags		= DA850_CLK_ASYNC3,
+	.gpsc		= 1,
+};
+
 static struct clk_lookup da850_clks[] = {
 	CLK(NULL,		"ref",		&ref_clk),
 	CLK(NULL,		"pll0",		&pll0_clk),
@@ -386,6 +417,7 @@ static struct clk_lookup da850_clks[] = {
 	CLK(NULL,		"tptc1",	&tptc1_clk),
 	CLK(NULL,		"tpcc1",	&tpcc1_clk),
 	CLK(NULL,		"tptc2",	&tptc2_clk),
+	CLK(NULL,		"pruss",	&pruss_clk),
 	CLK(NULL,		"uart0",	&uart0_clk),
 	CLK(NULL,		"uart1",	&uart1_clk),
 	CLK(NULL,		"uart2",	&uart2_clk),
@@ -403,6 +435,9 @@ static struct clk_lookup da850_clks[] = {
 	CLK(NULL,		"aemif",	&aemif_clk),
 	CLK(NULL,		"usb11",	&usb11_clk),
 	CLK(NULL,		"usb20",	&usb20_clk),
+	CLK(NULL,		"ecap0",	&ecap0_clk),
+	CLK(NULL,		"ecap1",	&ecap1_clk),
+	CLK(NULL,		"ecap2",	&ecap2_clk),
 	CLK(NULL,		NULL,		NULL),
 };
 
diff --git a/arch/arm/mach-davinci/devices-da8xx.c b/arch/arm/mach-davinci/devices-da8xx.c
index beda8a4..4ea3d1f 100644
--- a/arch/arm/mach-davinci/devices-da8xx.c
+++ b/arch/arm/mach-davinci/devices-da8xx.c
@@ -725,3 +725,76 @@ int __init da8xx_register_cpuidle(void)
 
 	return platform_device_register(&da8xx_cpuidle_device);
 }
+static struct resource pruss_resources[] = {
+	[0] = {
+		.start  = DA8XX_PRUSS_BASE,
+		.end    = DA8XX_PRUSS_BASE + SZ_64K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {
+		.start  = DA8XX_L3RAM_BASE,
+		.end    = DA8XX_L3RAM_BASE + SZ_128K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+	[2] = {
+		.start  = 0,
+		.end    = SZ_256K - 1,
+		.flags  = IORESOURCE_MEM,
+	},
+
+	[3] = {
+		.start  = IRQ_DA8XX_EVTOUT0,
+		.end    = IRQ_DA8XX_EVTOUT0,
+		.flags  = IORESOURCE_IRQ,
+	},
+	[4] = {
+		.start  = IRQ_DA8XX_EVTOUT1,
+		.end    = IRQ_DA8XX_EVTOUT1,
+		.flags  = IORESOURCE_IRQ,
+	},
+	[5] = {
+		.start  = IRQ_DA8XX_EVTOUT2,
+		.end    = IRQ_DA8XX_EVTOUT2,
+		.flags  = IORESOURCE_IRQ,
+	},
+	[6] = {
+		.start  = IRQ_DA8XX_EVTOUT3,
+		.end    = IRQ_DA8XX_EVTOUT3,
+		.flags  = IORESOURCE_IRQ,
+	},
+	[7] = {
+		.start  = IRQ_DA8XX_EVTOUT4,
+		.end    = IRQ_DA8XX_EVTOUT4,
+		.flags  = IORESOURCE_IRQ,
+	},
+	[8] = {
+		.start  = IRQ_DA8XX_EVTOUT5,
+		.end    = IRQ_DA8XX_EVTOUT5,
+		.flags  = IORESOURCE_IRQ,
+	},
+	[9] = {
+		.start  = IRQ_DA8XX_EVTOUT6,
+		.end    = IRQ_DA8XX_EVTOUT6,
+		.flags  = IORESOURCE_IRQ,
+	},
+	[10] = {
+		.start  = IRQ_DA8XX_EVTOUT7,
+		.end    = IRQ_DA8XX_EVTOUT7,
+		.flags  = IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device pruss_device = {
+	.name			= "pruss",
+	.id			= 0,
+	.num_resources		= ARRAY_SIZE(pruss_resources),
+	.resource		= pruss_resources,
+	.dev	 =	{
+		.coherent_dma_mask = 0xffffffff,
+	}
+};
+
+int __init da8xx_register_pruss()
+{
+	return platform_device_register(&pruss_device);
+}
diff --git a/arch/arm/mach-davinci/include/mach/da8xx.h b/arch/arm/mach-davinci/include/mach/da8xx.h
index cfcb223..3ed6ee0 100644
--- a/arch/arm/mach-davinci/include/mach/da8xx.h
+++ b/arch/arm/mach-davinci/include/mach/da8xx.h
@@ -60,6 +60,7 @@ extern unsigned int da850_max_speed;
 #define DA8XX_PLL0_BASE		0x01c11000
 #define DA8XX_TIMER64P0_BASE	0x01c20000
 #define DA8XX_TIMER64P1_BASE	0x01c21000
+#define DA8XX_PRUSS_BASE	0x01c30000
 #define DA8XX_GPIO_BASE		0x01e26000
 #define DA8XX_PSC1_BASE		0x01e27000
 #define DA8XX_LCD_CNTRL_BASE	0x01e13000
@@ -68,6 +69,7 @@ extern unsigned int da850_max_speed;
 #define DA8XX_AEMIF_CS2_BASE	0x60000000
 #define DA8XX_AEMIF_CS3_BASE	0x62000000
 #define DA8XX_AEMIF_CTL_BASE	0x68000000
+#define DA8XX_L3RAM_BASE	0x80000000
 #define DA8XX_DDR2_CTL_BASE	0xb0000000
 #define DA8XX_ARM_RAM_BASE	0xffff0000
 
@@ -90,6 +92,7 @@ int da850_register_cpufreq(char *async_clk);
 int da8xx_register_cpuidle(void);
 void __iomem * __init da8xx_get_mem_ctlr(void);
 int da850_register_pm(struct platform_device *pdev);
+int da8xx_register_pruss(void);
 
 extern struct platform_device da8xx_serial_device;
 extern struct emac_platform_data da8xx_emac_pdata;
-- 
1.6.0.6

^ permalink raw reply related

* [PATCH v5 1/2] PRUSS UIO driver support
From: Pratheesh Gangadhar @ 2011-02-25  8:45 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1298623530-10294-1-git-send-email-pratheesh@ti.com>

This patch implements PRUSS (Programmable Real-time Unit Sub System)
UIO driver which exports SOC resources associated with PRUSS like
I/O, memories and IRQs to user space. PRUSS is dual 32-bit RISC
processors which is efficient in performing embedded tasks that
require manipulation of packed memory mapped data structures and
efficient in handling system events that have tight real time
constraints. This driver is currently supported on Texas Instruments
DA850, AM18xx and OMAPL1-38 devices.
For example, PRUSS runs firmware for real-time critical industrial
communication data link layer and communicates with application stack
running in user space via shared memory and IRQs.

Signed-off-by: Pratheesh Gangadhar <pratheesh@ti.com>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
---
 drivers/uio/Kconfig     |   17 ++++
 drivers/uio/Makefile    |    1 +
 drivers/uio/uio_pruss.c |  217 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 235 insertions(+), 0 deletions(-)
 create mode 100644 drivers/uio/uio_pruss.c

diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index bb44079..6f3ea9b 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -94,4 +94,21 @@ config UIO_NETX
 	  To compile this driver as a module, choose M here; the module
 	  will be called uio_netx.
 
+config UIO_PRUSS
+	tristate "Texas Instruments PRUSS driver"
+	depends on ARCH_DAVINCI_DA850
+	help
+	  PRUSS driver for OMAPL138/DA850/AM18XX devices
+	  PRUSS driver requires user space components, examples and user space
+	  driver is available from below SVN repo - you may use anonymous login
+
+	  https://gforge.ti.com/gf/project/pru_sw/
+
+	  More info on API is available at below wiki
+
+	  http://processors.wiki.ti.com/index.php/PRU_Linux_Application_Loader
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called uio_pruss.
+
 endif
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index 18fd818..d4dd9a5 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_UIO_AEC)	+= uio_aec.o
 obj-$(CONFIG_UIO_SERCOS3)	+= uio_sercos3.o
 obj-$(CONFIG_UIO_PCI_GENERIC)	+= uio_pci_generic.o
 obj-$(CONFIG_UIO_NETX)	+= uio_netx.o
+obj-$(CONFIG_UIO_PRUSS)         += uio_pruss.o
diff --git a/drivers/uio/uio_pruss.c b/drivers/uio/uio_pruss.c
new file mode 100644
index 0000000..d17d3aa
--- /dev/null
+++ b/drivers/uio/uio_pruss.c
@@ -0,0 +1,217 @@
+/*
+ * Programmable Real-Time Unit Sub System (PRUSS) UIO driver (uio_pruss)
+ *
+ * This driver exports PRUSS host event out interrupts and PRUSS, L3 RAM,
+ * and DDR RAM to user space for applications interacting with PRUSS firmware
+ *
+ * Copyright (C) 2010-11 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/uio_driver.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
+#define DRV_NAME "pruss"
+#define DRV_VERSION "0.50"
+
+/*
+ * Host event IRQ numbers from PRUSS - PRUSS can generate upto 8 interrupt
+ * events to AINTC of ARM host processor - which can be used for IPC b/w PRUSS
+ * firmware and user space application, async notification from PRU firmware
+ * to user space application
+ * 3	PRU_EVTOUT0
+ * 4	PRU_EVTOUT1
+ * 5	PRU_EVTOUT2
+ * 6	PRU_EVTOUT3
+ * 7	PRU_EVTOUT4
+ * 8	PRU_EVTOUT5
+ * 9	PRU_EVTOUT6
+ * 10	PRU_EVTOUT7
+*/
+
+#define MAX_PRUSS_EVT			8
+
+#define	PINTC_HIPIR			0x4900
+#define	HIPIR_NOPEND			0x80000000
+#define	PINTC_HIER			0x5500
+
+static struct clk *pruss_clk;
+static struct uio_info *info;
+static dma_addr_t ddr_paddr;
+static void *ddr_vaddr, *prussio_vaddr;
+
+static irqreturn_t pruss_handler(int irq, struct uio_info *dev_info)
+{
+	void __iomem *base = dev_info->mem[0].internal_addr;
+	void __iomem *intren_reg = base + PINTC_HIER;
+	void __iomem *intrstat_reg = base + PINTC_HIPIR + ((irq - 1) << 2);
+	int val = ioread32(intren_reg), intr_mask = (1 << (irq - 1));
+
+	/* Is interrupt enabled and active ? */
+	if (!(val & intr_mask) && (ioread32(intrstat_reg) & HIPIR_NOPEND))
+		return IRQ_NONE;
+
+	/* Disable interrupt */
+	iowrite32((val & ~intr_mask), intren_reg);
+	return IRQ_HANDLED;
+}
+
+static void pruss_cleanup(struct platform_device *dev, struct uio_info *info)
+{
+	struct uio_info *p = info;
+	int cnt;
+
+	for (cnt = 0; cnt < MAX_PRUSS_EVT; cnt++, p++) {
+		uio_unregister_device(p);
+		kfree(p->name);
+	}
+	iounmap(prussio_vaddr);
+	if (ddr_vaddr) {
+		dma_free_coherent(&dev->dev, info->mem[2].size,
+			info->mem[2].internal_addr, info->mem[2].addr);
+	}
+	kfree(info);
+	clk_put(pruss_clk);
+}
+
+static int __devinit pruss_probe(struct platform_device *dev)
+{
+	struct uio_info *p;
+	int ret = -ENODEV, cnt = 0, len;
+	struct resource *regs_prussio, *regs_l3ram, *regs_ddr;
+
+	info = kzalloc(sizeof(struct uio_info) * MAX_PRUSS_EVT, GFP_KERNEL);
+	if (!info)
+		return -ENOMEM;
+	/* Power on PRU in case its not done as part of boot-loader */
+	pruss_clk = clk_get(&dev->dev, "pruss");
+	if (IS_ERR(pruss_clk)) {
+		dev_err(&dev->dev, "Failed to get clock\n");
+		kfree(info);
+		ret = PTR_ERR(pruss_clk);
+		return ret;
+	} else {
+		clk_enable(pruss_clk);
+	}
+
+	regs_prussio = platform_get_resource(dev, IORESOURCE_MEM, 0);
+	if (!regs_prussio) {
+		dev_err(&dev->dev, "No PRUSS I/O resource specified\n");
+		goto out_free;
+	}
+
+	regs_l3ram = platform_get_resource(dev, IORESOURCE_MEM, 1);
+	if (!regs_l3ram) {
+		dev_err(&dev->dev, "No L3 RAM resource specified\n");
+		goto out_free;
+	}
+
+	regs_ddr = platform_get_resource(dev, IORESOURCE_MEM, 2);
+	if (!regs_ddr) {
+		dev_err(&dev->dev, "No External RAM resource specified\n");
+		goto out_free;
+	}
+
+	if (!regs_prussio->start || !regs_l3ram->start) {
+		dev_err(&dev->dev, "Invalid memory resource\n");
+		goto out_free;
+	}
+	len = resource_size(regs_ddr);
+	ddr_vaddr = dma_alloc_coherent(&dev->dev, len, &ddr_paddr,
+				GFP_KERNEL | GFP_DMA);
+	if (!ddr_vaddr) {
+		dev_err(&dev->dev, "Could not allocate external memory\n");
+		goto out_free;
+	}
+	len = resource_size(regs_prussio);
+	prussio_vaddr = ioremap(regs_prussio->start, len);
+	if (!prussio_vaddr) {
+		dev_err(&dev->dev, "Can't remap PRUSS I/O  address range\n");
+		goto out_free;
+	}
+
+	for (cnt = 0, p = info; cnt < MAX_PRUSS_EVT; cnt++, p++) {
+		p->mem[0].internal_addr = prussio_vaddr;
+		p->mem[0].addr = regs_prussio->start;
+		p->mem[0].size = resource_size(regs_prussio);
+		p->mem[0].memtype = UIO_MEM_PHYS;
+
+		p->mem[1].addr = regs_l3ram->start;
+		p->mem[1].size = resource_size(regs_l3ram);
+		p->mem[1].memtype = UIO_MEM_PHYS;
+
+		p->mem[2].internal_addr = ddr_vaddr;
+		p->mem[2].addr = ddr_paddr;
+		p->mem[2].size = resource_size(regs_ddr);
+		p->mem[2].memtype = UIO_MEM_PHYS;
+
+		p->name = kasprintf(GFP_KERNEL, "pruss_evt%d", cnt);
+		p->version = "0.50";
+
+		/* Register PRUSS IRQ lines */
+		p->irq = IRQ_DA8XX_EVTOUT0 + cnt;
+		p->handler = pruss_handler;
+
+		ret = uio_register_device(&dev->dev, p);
+
+		if (ret < 0)
+			goto out_free;
+	}
+
+	platform_set_drvdata(dev, info);
+	return 0;
+
+out_free:
+	pruss_cleanup(dev, info);
+	return ret;
+}
+
+static int __devexit pruss_remove(struct platform_device *dev)
+{
+	struct uio_info *info = platform_get_drvdata(dev);
+
+	pruss_cleanup(dev, info);
+	platform_set_drvdata(dev, NULL);
+	return 0;
+}
+
+static struct platform_driver pruss_driver = {
+	.probe = pruss_probe,
+	.remove = __devexit_p(pruss_remove),
+	.driver = {
+		   .name = DRV_NAME,
+		   .owner = THIS_MODULE,
+		   },
+};
+
+static int __init pruss_init_module(void)
+{
+	return platform_driver_register(&pruss_driver);
+}
+
+module_init(pruss_init_module);
+
+static void __exit pruss_exit_module(void)
+{
+	platform_driver_unregister(&pruss_driver);
+}
+
+module_exit(pruss_exit_module);
+
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DRV_VERSION);
+MODULE_AUTHOR("Amit Chatterjee <amit.chatterjee@ti.com>");
+MODULE_AUTHOR("Pratheesh Gangadhar <pratheesh@ti.com>");
-- 
1.6.0.6

^ permalink raw reply related

* [PATCH v5 0/2] Add PRUSS UIO driver support
From: Pratheesh Gangadhar @ 2011-02-25  8:45 UTC (permalink / raw)
  To: linux-arm-kernel

This patch series add support for PRUSS (Programmable Real-time Unit Sub
System) UIO driver in Texas Instruments DA850, AM18xx and OMAPL1-38 processors.
PRUSS is programmable RISC core which can be used to implement Soft IPs
(eg:- DMA, CAN, UART,SmartCard) and Industrial communications data link layers
(eg:- PROFIBUS). UIO driver exposes PRUSS resources like memory and interrupts 
to user space application.PRUSS UIO application API can be used to control PRUs
 in PRUSS, setup PRU INTC, load firmware to PRUs and implement IPC between Host
 processor and PRUs. More information on PRUSS and UIO linux user space API 
available in the links below

http://processors.wiki.ti.com/index.php/Programmable_Realtime_Unit_Subsystem
http://processors.wiki.ti.com/index.php/PRU_Linux_Application_Loader
http://processors.wiki.ti.com/index.php/PRU_Linux_Application_Loader_API_Guide

Pratheesh Gangadhar (2):
  PRUSS UIO driver support
  Defines DA850/AM18xx/OMAPL1-38 SOC resources used by PRUSS UIO driver

 arch/arm/mach-davinci/board-da850-evm.c    |    4 +
 arch/arm/mach-davinci/da850.c              |   35 +++++
 arch/arm/mach-davinci/devices-da8xx.c      |   73 ++++++++++
 arch/arm/mach-davinci/include/mach/da8xx.h |    3 +
 drivers/uio/Kconfig                        |   17 +++
 drivers/uio/Makefile                       |    1 +
 drivers/uio/uio_pruss.c                    |  217 ++++++++++++++++++++++++++++
 7 files changed, 350 insertions(+), 0 deletions(-)
 create mode 100644 drivers/uio/uio_pruss.c

^ permalink raw reply

* [PATCH] ARM: EXYNOS4: Adds Samsung NURI board support
From: Minkyu Kang @ 2011-02-25  8:43 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds Samsung NURI board support.

Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
---
This patch is base on next-exynos4 branch at kgene tree.

 arch/arm/configs/exynos4_defconfig |    1 +
 arch/arm/mach-exynos4/Kconfig      |   15 +++
 arch/arm/mach-exynos4/Makefile     |    1 +
 arch/arm/mach-exynos4/mach-nuri.c  |  233 ++++++++++++++++++++++++++++++++++++
 4 files changed, 250 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-exynos4/mach-nuri.c

diff --git a/arch/arm/configs/exynos4_defconfig b/arch/arm/configs/exynos4_defconfig
index 2ffba24..fd92324 100644
--- a/arch/arm/configs/exynos4_defconfig
+++ b/arch/arm/configs/exynos4_defconfig
@@ -9,6 +9,7 @@ CONFIG_S3C_LOWLEVEL_UART_PORT=1
 CONFIG_MACH_SMDKC210=y
 CONFIG_MACH_SMDKV310=y
 CONFIG_MACH_UNIVERSAL_C210=y
+CONFIG_MACH_NURI=y
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_SMP=y
diff --git a/arch/arm/mach-exynos4/Kconfig b/arch/arm/mach-exynos4/Kconfig
index ad03840..5bf00b9 100644
--- a/arch/arm/mach-exynos4/Kconfig
+++ b/arch/arm/mach-exynos4/Kconfig
@@ -123,6 +123,21 @@ config MACH_UNIVERSAL_C210
 	  Machine support for Samsung Mobile Universal S5PC210 Reference
 	  Board.
 
+config MACH_NURI
+	bool "Mobile NURI Board"
+	select CPU_EXYNOS4210
+	select S3C_DEV_WDT
+	select S3C_DEV_HSMMC
+	select S3C_DEV_HSMMC2
+	select S3C_DEV_HSMMC3
+	select S3C_DEV_I2C1
+	select S3C_DEV_I2C5
+	select EXYNOS4_SETUP_I2C1
+	select EXYNOS4_SETUP_I2C5
+	select EXYNOS4_SETUP_SDHCI
+	help
+	  Machine support for Samsung Mobile NURI Board.
+
 endmenu
 
 comment "Configuration for HSMMC bus width"
diff --git a/arch/arm/mach-exynos4/Makefile b/arch/arm/mach-exynos4/Makefile
index 0558235..fa9e814 100644
--- a/arch/arm/mach-exynos4/Makefile
+++ b/arch/arm/mach-exynos4/Makefile
@@ -25,6 +25,7 @@ obj-$(CONFIG_HOTPLUG_CPU)	+= hotplug.o
 obj-$(CONFIG_MACH_SMDKC210)		+= mach-smdkc210.o
 obj-$(CONFIG_MACH_SMDKV310)		+= mach-smdkv310.o
 obj-$(CONFIG_MACH_UNIVERSAL_C210)	+= mach-universal_c210.o
+obj-$(CONFIG_MACH_NURI)			+= mach-nuri.o
 
 # device support
 
diff --git a/arch/arm/mach-exynos4/mach-nuri.c b/arch/arm/mach-exynos4/mach-nuri.c
new file mode 100644
index 0000000..28010bd
--- /dev/null
+++ b/arch/arm/mach-exynos4/mach-nuri.c
@@ -0,0 +1,233 @@
+/*
+ * linux/arch/arm/mach-exynos4/mach-nuri.c
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *
+ * 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/serial_core.h>
+#include <linux/input.h>
+#include <linux/i2c.h>
+#include <linux/gpio_keys.h>
+#include <linux/gpio.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/fixed.h>
+#include <linux/mmc/host.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach-types.h>
+
+#include <plat/regs-serial.h>
+#include <plat/exynos4.h>
+#include <plat/cpu.h>
+#include <plat/devs.h>
+#include <plat/sdhci.h>
+
+#include <mach/map.h>
+
+/* Following are default values for UCON, ULCON and UFCON UART registers */
+#define NURI_UCON_DEFAULT	(S3C2410_UCON_TXILEVEL |	\
+				 S3C2410_UCON_RXILEVEL |	\
+				 S3C2410_UCON_TXIRQMODE |	\
+				 S3C2410_UCON_RXIRQMODE |	\
+				 S3C2410_UCON_RXFIFO_TOI |	\
+				 S3C2443_UCON_RXERR_IRQEN)
+
+#define NURI_ULCON_DEFAULT	S3C2410_LCON_CS8
+
+#define NURI_UFCON_DEFAULT	(S3C2410_UFCON_FIFOMODE |	\
+				 S5PV210_UFCON_TXTRIG256 |	\
+				 S5PV210_UFCON_RXTRIG256)
+
+enum fixed_regulator_id {
+	FIXED_REG_ID_MMC = 0,
+};
+
+static struct s3c2410_uartcfg nuri_uartcfgs[] __initdata = {
+	{
+		.hwport		= 0,
+		.ucon		= NURI_UCON_DEFAULT,
+		.ulcon		= NURI_ULCON_DEFAULT,
+		.ufcon		= NURI_UFCON_DEFAULT,
+	},
+	{
+		.hwport		= 1,
+		.ucon		= NURI_UCON_DEFAULT,
+		.ulcon		= NURI_ULCON_DEFAULT,
+		.ufcon		= NURI_UFCON_DEFAULT,
+	},
+	{
+		.hwport		= 2,
+		.ucon		= NURI_UCON_DEFAULT,
+		.ulcon		= NURI_ULCON_DEFAULT,
+		.ufcon		= NURI_UFCON_DEFAULT,
+	},
+	{
+		.hwport		= 3,
+		.ucon		= NURI_UCON_DEFAULT,
+		.ulcon		= NURI_ULCON_DEFAULT,
+		.ufcon		= NURI_UFCON_DEFAULT,
+	},
+};
+
+/* eMMC */
+static struct s3c_sdhci_platdata nuri_hsmmc0_data __initdata = {
+	.max_width		= 8,
+	.host_caps		= (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA |
+			   MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+			   MMC_CAP_DISABLE | MMC_CAP_ERASE),
+	.cd_type		= S3C_SDHCI_CD_PERMANENT,
+	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
+};
+
+static struct regulator_consumer_supply emmc_supplies[] = {
+	REGULATOR_SUPPLY("vmmc", "s3c-sdhci.0"),
+	REGULATOR_SUPPLY("vmmc", "dw_mmc"),
+};
+
+static struct regulator_init_data emmc_fixed_voltage_init_data = {
+	.constraints		= {
+		.name		= "VMEM_VDD_2.8V",
+		.valid_ops_mask	= REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies	= ARRAY_SIZE(emmc_supplies),
+	.consumer_supplies	= emmc_supplies,
+};
+
+static struct fixed_voltage_config emmc_fixed_voltage_config = {
+	.supply_name		= "MASSMEMORY_EN (inverted)",
+	.microvolts		= 2800000,
+	.gpio			= EXYNOS4_GPL1(1),
+	.enable_high		= false,
+	.init_data		= &emmc_fixed_voltage_init_data,
+};
+
+static struct platform_device emmc_fixed_voltage = {
+	.name			= "reg-fixed-voltage",
+	.id			= FIXED_REG_ID_MMC,
+	.dev			= {
+		.platform_data	= &emmc_fixed_voltage_config,
+	},
+};
+
+/* SD */
+static struct s3c_sdhci_platdata nuri_hsmmc2_data __initdata = {
+	.max_width		= 4,
+	.host_caps		= MMC_CAP_4_BIT_DATA |
+				MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
+				MMC_CAP_DISABLE,
+	.ext_cd_gpio		= EXYNOS4_GPX3(3),	/* XEINT_27 */
+	.ext_cd_gpio_invert	= 1,
+	.cd_type		= S3C_SDHCI_CD_GPIO,
+	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
+};
+
+/* WLAN */
+static struct s3c_sdhci_platdata nuri_hsmmc3_data __initdata = {
+	.max_width		= 4,
+	.host_caps		= MMC_CAP_4_BIT_DATA |
+				MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED,
+	.cd_type		= S3C_SDHCI_CD_EXTERNAL,
+	.clk_type		= S3C_SDHCI_CLK_DIV_EXTERNAL,
+};
+
+static void __init nuri_sdhci_init(void)
+{
+	s3c_sdhci0_set_platdata(&nuri_hsmmc0_data);
+	s3c_sdhci2_set_platdata(&nuri_hsmmc2_data);
+	s3c_sdhci3_set_platdata(&nuri_hsmmc3_data);
+}
+
+/* GPIO KEYS */
+static struct gpio_keys_button nuri_gpio_keys_tables[] = {
+	{
+		.code			= KEY_VOLUMEUP,
+		.gpio			= EXYNOS4_GPX2(0),	/* XEINT16 */
+		.desc			= "gpio-keys: KEY_VOLUMEUP",
+		.type			= EV_KEY,
+		.active_low		= 1,
+		.debounce_interval	= 1,
+	}, {
+		.code			= KEY_VOLUMEDOWN,
+		.gpio			= EXYNOS4_GPX2(1),	/* XEINT17 */
+		.desc			= "gpio-keys: KEY_VOLUMEDOWN",
+		.type			= EV_KEY,
+		.active_low		= 1,
+		.debounce_interval	= 1,
+	}, {
+		.code			= KEY_POWER,
+		.gpio			= EXYNOS4_GPX2(7),	/* XEINT23 */
+		.desc			= "gpio-keys: KEY_POWER",
+		.type			= EV_KEY,
+		.active_low		= 1,
+		.wakeup			= 1,
+		.debounce_interval	= 1,
+	},
+};
+
+static struct gpio_keys_platform_data nuri_gpio_keys_data = {
+	.buttons		= nuri_gpio_keys_tables,
+	.nbuttons		= ARRAY_SIZE(nuri_gpio_keys_tables),
+};
+
+static struct platform_device nuri_gpio_keys = {
+	.name			= "gpio-keys",
+	.dev			= {
+		.platform_data	= &nuri_gpio_keys_data,
+	},
+};
+
+/* I2C1 */
+static struct i2c_board_info i2c1_devs[] __initdata = {
+	/* Gyro, To be updated */
+};
+
+/* GPIO I2C 5 (PMIC) */
+static struct i2c_board_info i2c5_devs[] __initdata = {
+	/* max8997, To be updated */
+};
+
+static struct platform_device *nuri_devices[] __initdata = {
+	/* Samsung Platform Devices */
+	&emmc_fixed_voltage,
+	&s3c_device_hsmmc0,
+	&s3c_device_hsmmc2,
+	&s3c_device_hsmmc3,
+#ifdef CONFIG_S3C2410_WATCHDOG
+	&s3c_device_wdt,
+#endif
+
+	/* NURI Devices */
+	&nuri_gpio_keys,
+};
+
+static void __init nuri_map_io(void)
+{
+	s5p_init_io(NULL, 0, S5P_VA_CHIPID);
+	s3c24xx_init_clocks(24000000);
+	s3c24xx_init_uarts(nuri_uartcfgs, ARRAY_SIZE(nuri_uartcfgs));
+}
+
+static void __init nuri_machine_init(void)
+{
+	nuri_sdhci_init();
+
+	i2c_register_board_info(1, i2c1_devs, ARRAY_SIZE(i2c1_devs));
+	i2c_register_board_info(5, i2c5_devs, ARRAY_SIZE(i2c5_devs));
+
+	/* Last */
+	platform_add_devices(nuri_devices, ARRAY_SIZE(nuri_devices));
+}
+
+MACHINE_START(NURI, "NURI")
+	/* Maintainer: Kyungmin Park <kyungmin.park@samsung.com> */
+	.boot_params	= S5P_PA_SDRAM + 0x100,
+	.init_irq	= exynos4_init_irq,
+	.map_io		= nuri_map_io,
+	.init_machine	= nuri_machine_init,
+	.timer		= &exynos4_timer,
+MACHINE_END
-- 
1.7.1

^ permalink raw reply related

* [PATCH V11 2/4] ptp: Added a clock that uses the eTSEC found on the MPC85xx.
From: Richard Cochran @ 2011-02-25  7:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110224112731.2d9bf080@schlenkerla>

On Thu, Feb 24, 2011 at 11:27:31AM -0600, Scott Wood wrote:

> My vote, if it goes in a separate node at all, is "fsl,etsec-ptp",

So, that is what the patch does.

> and let the driver use SVR.

What is SVR?

Thanks,
Richard

^ permalink raw reply

* [PATCH v4] dmaengine: mxs-dma: add dma support for i.MX23/28
From: Shawn Guo @ 2011-02-25  7:34 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds dma support for Freescale MXS-based SoC i.MX23/28,
including apbh-dma and apbx-dma.

* apbh-dma and apbx-dma are supported in the driver as two mxs-dma
  instances.

* apbh-dma is different between mx23 and mx28, hardware version
  register is used to differentiate.

* mxs-dma supports pio function besides data transfer.  The driver
  uses dma_data_direction DMA_NONE to identify the pio mode, and
  steals sgl and sg_len to get pio words and numbers from clients.

* mxs dmaengine has some very specific features, like sense function
  and the special NAND support (nand_lock, nand_wait4ready).  These
  are too specific to implemented in generic dmaengine driver.

* The driver refers to imx-sdma and only a single descriptor is
  statically assigned to each channel.

Signed-off-by: Shawn Guo <shawn.guo@freescale.com>
---
 arch/arm/mach-mxs/include/mach/dma.h |   26 ++
 drivers/dma/Kconfig                  |    8 +
 drivers/dma/Makefile                 |    1 +
 drivers/dma/mxs-dma.c                |  723 ++++++++++++++++++++++++++++++++++
 4 files changed, 758 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-mxs/include/mach/dma.h
 create mode 100644 drivers/dma/mxs-dma.c

diff --git a/arch/arm/mach-mxs/include/mach/dma.h b/arch/arm/mach-mxs/include/mach/dma.h
new file mode 100644
index 0000000..7f4aeea
--- /dev/null
+++ b/arch/arm/mach-mxs/include/mach/dma.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * 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.
+ */
+
+#ifndef __MACH_MXS_DMA_H__
+#define __MACH_MXS_DMA_H__
+
+struct mxs_dma_data {
+	int chan_irq;
+};
+
+static inline int mxs_dma_is_apbh(struct dma_chan *chan)
+{
+	return !strcmp(dev_name(chan->device->dev), "mxs-dma-apbh");
+}
+
+static inline int mxs_dma_is_apbx(struct dma_chan *chan)
+{
+	return !strcmp(dev_name(chan->device->dev), "mxs-dma-apbx");
+}
+
+#endif /* __MACH_MXS_DMA_H__ */
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 1c28816..76f6472 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -227,6 +227,14 @@ config IMX_DMA
 	  Support the i.MX DMA engine. This engine is integrated into
 	  Freescale i.MX1/21/27 chips.
 
+config MXS_DMA
+	bool "MXS DMA support"
+	depends on SOC_IMX23 || SOC_IMX28
+	select DMA_ENGINE
+	help
+	  Support the MXS DMA engine. This engine including APBH-DMA
+	  and APBX-DMA is integrated into Freescale i.MX23/28 chips.
+
 config DMA_ENGINE
 	bool
 
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 64b21f5..802b557 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o
 obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/
 obj-$(CONFIG_IMX_SDMA) += imx-sdma.o
 obj-$(CONFIG_IMX_DMA) += imx-dma.o
+obj-$(CONFIG_MXS_DMA) += mxs-dma.o
 obj-$(CONFIG_TIMB_DMA) += timb_dma.o
 obj-$(CONFIG_STE_DMA40) += ste_dma40.o ste_dma40_ll.o
 obj-$(CONFIG_PL330_DMA) += pl330.o
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
new file mode 100644
index 0000000..94fcc6d
--- /dev/null
+++ b/drivers/dma/mxs-dma.c
@@ -0,0 +1,723 @@
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Refer to drivers/dma/imx-sdma.c
+ *
+ * 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/types.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/semaphore.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/dmaengine.h>
+#include <linux/delay.h>
+
+#include <asm/irq.h>
+#include <mach/mxs.h>
+#include <mach/dma.h>
+#include <mach/common.h>
+
+/*
+ * NOTE: The term "PIO" throughout the mxs-dma implementation means
+ * PIO mode of mxs apbh-dma and apbx-dma.  With this working mode,
+ * dma can program the controller registers of peripheral devices.
+ */
+
+#define MXS_DMA_APBH		0
+#define MXS_DMA_APBX		1
+#define dma_is_apbh()		(mxs_dma->dev_id == MXS_DMA_APBH)
+
+#define APBH_VERSION_LATEST	3
+#define apbh_is_old()		(mxs_dma->version < APBH_VERSION_LATEST)
+
+#define HW_APBHX_CTRL0				0x000
+#define BM_APBH_CTRL0_APB_BURST8_EN		(1 << 29)
+#define BM_APBH_CTRL0_APB_BURST_EN		(1 << 28)
+#define BP_APBH_CTRL0_CLKGATE_CHANNEL		8
+#define BP_APBH_CTRL0_RESET_CHANNEL		16
+#define HW_APBHX_CTRL1				0x010
+#define HW_APBHX_CTRL2				0x020
+#define HW_APBHX_CHANNEL_CTRL			0x030
+#define BP_APBHX_CHANNEL_CTRL_RESET_CHANNEL	16
+#define HW_APBH_VERSION				(cpu_is_mx23() ? 0x3f0 : 0x800)
+#define HW_APBX_VERSION				0x800
+#define BP_APBHX_VERSION_MAJOR			24
+#define HW_APBHX_CHn_NXTCMDAR(n) \
+	(((dma_is_apbh() && apbh_is_old()) ? 0x050 : 0x110) + (n) * 0x70)
+#define HW_APBHX_CHn_SEMA(n) \
+	(((dma_is_apbh() && apbh_is_old()) ? 0x080 : 0x140) + (n) * 0x70)
+
+/*
+ * ccw bits definitions
+ *
+ * COMMAND:		0..1	(2)
+ * CHAIN:		2	(1)
+ * IRQ:			3	(1)
+ * NAND_LOCK:		4	(1) - not implemented
+ * NAND_WAIT4READY:	5	(1) - not implemented
+ * DEC_SEM:		6	(1)
+ * WAIT4END:		7	(1)
+ * HALT_ON_TERMINATE:	8	(1)
+ * TERMINATE_FLUSH:	9	(1)
+ * RESERVED:		10..11	(2)
+ * PIO_NUM:		12..15	(4)
+ */
+#define BP_CCW_COMMAND		0
+#define BM_CCW_COMMAND		(3 << 0)
+#define CCW_CHAIN		(1 << 2)
+#define CCW_IRQ			(1 << 3)
+#define CCW_DEC_SEM		(1 << 6)
+#define CCW_WAIT4END		(1 << 7)
+#define CCW_HALT_ON_TERM	(1 << 8)
+#define CCW_TERM_FLUSH		(1 << 9)
+#define BP_CCW_PIO_NUM		12
+#define BM_CCW_PIO_NUM		(0xf << 12)
+
+#define BF_CCW(value, field)	(((value) << BP_CCW_##field) & BM_CCW_##field)
+
+#define MXS_DMA_CMD_NO_XFER	0
+#define MXS_DMA_CMD_WRITE	1
+#define MXS_DMA_CMD_READ	2
+#define MXS_DMA_CMD_DMA_SENSE	3	/* not implemented */
+
+struct mxs_dma_ccw {
+	u32		next;
+	u16		bits;
+	u16		xfer_bytes;
+#define MAX_XFER_BYTES	0xff00
+	u32		bufaddr;
+#define MXS_PIO_WORDS	16
+	u32		pio_words[MXS_PIO_WORDS];
+};
+
+#define NUM_CCW	(int)(PAGE_SIZE / sizeof(struct mxs_dma_ccw))
+
+struct mxs_dma_chan {
+	struct mxs_dma_engine		*mxs_dma;
+	struct dma_chan			chan;
+	struct dma_async_tx_descriptor	desc;
+	struct tasklet_struct		tasklet;
+	int				chan_irq;
+	struct mxs_dma_ccw		*ccw;
+	dma_addr_t			ccw_phys;
+	dma_cookie_t			last_completed;
+	enum dma_status			status;
+	unsigned int			flags;
+#define MXS_DMA_SG_LOOP			(1 << 0)
+};
+
+#define MXS_DMA_CHANNELS		16
+#define MXS_DMA_CHANNELS_MASK		0xffff
+
+struct mxs_dma_engine {
+	int				dev_id;
+	unsigned int			version;
+	void __iomem			*base;
+	struct clk			*clk;
+	struct dma_device		dma_device;
+	struct device_dma_parameters	dma_parms;
+	struct mxs_dma_chan		mxs_chans[MXS_DMA_CHANNELS];
+};
+
+static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan)
+{
+	struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+	int chan_id = mxs_chan->chan.chan_id;
+
+	if (dma_is_apbh() && apbh_is_old())
+		writel(1 << (chan_id + BP_APBH_CTRL0_RESET_CHANNEL),
+			mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+	else
+		writel(1 << (chan_id + BP_APBHX_CHANNEL_CTRL_RESET_CHANNEL),
+			mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_SET_ADDR);
+}
+
+static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan)
+{
+	struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+	int chan_id = mxs_chan->chan.chan_id;
+
+	/* set cmd_addr up */
+	writel(mxs_chan->ccw_phys,
+		mxs_dma->base + HW_APBHX_CHn_NXTCMDAR(chan_id));
+
+	/* enable apbh channel clock */
+	if (dma_is_apbh()) {
+		if (apbh_is_old())
+			writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL),
+				mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR);
+		else
+			writel(1 << chan_id,
+				mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR);
+	}
+
+	/* write 1 to SEMA to kick off the channel */
+	writel(1, mxs_dma->base + HW_APBHX_CHn_SEMA(chan_id));
+}
+
+static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan)
+{
+	struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+	int chan_id = mxs_chan->chan.chan_id;
+
+	/* disable apbh channel clock */
+	if (dma_is_apbh()) {
+		if (apbh_is_old())
+			writel(1 << (chan_id + BP_APBH_CTRL0_CLKGATE_CHANNEL),
+				mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+		else
+			writel(1 << chan_id,
+				mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+	}
+
+	mxs_chan->status = DMA_SUCCESS;
+}
+
+static void mxs_dma_pause_chan(struct mxs_dma_chan *mxs_chan)
+{
+	struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+	int chan_id = mxs_chan->chan.chan_id;
+
+	/* freeze the channel */
+	if (dma_is_apbh() && apbh_is_old())
+		writel(1 << chan_id,
+			mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+	else
+		writel(1 << chan_id,
+			mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_SET_ADDR);
+
+	mxs_chan->status = DMA_PAUSED;
+}
+
+static void mxs_dma_resume_chan(struct mxs_dma_chan *mxs_chan)
+{
+	struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+	int chan_id = mxs_chan->chan.chan_id;
+
+	/* unfreeze the channel */
+	if (dma_is_apbh() && apbh_is_old())
+		writel(1 << chan_id,
+			mxs_dma->base + HW_APBHX_CTRL0 + MXS_CLR_ADDR);
+	else
+		writel(1 << chan_id,
+			mxs_dma->base + HW_APBHX_CHANNEL_CTRL + MXS_CLR_ADDR);
+
+	mxs_chan->status = DMA_IN_PROGRESS;
+}
+
+static dma_cookie_t mxs_dma_assign_cookie(struct mxs_dma_chan *mxs_chan)
+{
+	dma_cookie_t cookie = mxs_chan->chan.cookie;
+
+	if (++cookie < 0)
+		cookie = 1;
+
+	mxs_chan->chan.cookie = cookie;
+	mxs_chan->desc.cookie = cookie;
+
+	return cookie;
+}
+
+static struct mxs_dma_chan *to_mxs_dma_chan(struct dma_chan *chan)
+{
+	return container_of(chan, struct mxs_dma_chan, chan);
+}
+
+static dma_cookie_t mxs_dma_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+	struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(tx->chan);
+
+	mxs_dma_enable_chan(mxs_chan);
+
+	return mxs_dma_assign_cookie(mxs_chan);
+}
+
+static void mxs_dma_tasklet(unsigned long data)
+{
+	struct mxs_dma_chan *mxs_chan = (struct mxs_dma_chan *) data;
+
+        if (mxs_chan->desc.callback)
+                mxs_chan->desc.callback(mxs_chan->desc.callback_param);
+}
+
+static irqreturn_t mxs_dma_int_handler(int irq, void *dev_id)
+{
+	struct mxs_dma_engine *mxs_dma = dev_id;
+	u32 stat1, stat2;
+
+	/* completion status */
+	stat1 = readl(mxs_dma->base + HW_APBHX_CTRL1);
+	stat1 &= MXS_DMA_CHANNELS_MASK;
+	writel(stat1, mxs_dma->base + HW_APBHX_CTRL1 + MXS_CLR_ADDR);
+
+	/* error status */
+	stat2 = readl(mxs_dma->base + HW_APBHX_CTRL2);
+	writel(stat2, mxs_dma->base + HW_APBHX_CTRL2 + MXS_CLR_ADDR);
+
+	/*
+	 * When both completion and error of termination bits set at the
+	 * same time, we do not take it as an error.  IOW, it only becomes
+	 * an error we need to handler here in case of ether it's (1) an bus
+	 * error or (2) a termination error with no completion.
+	 */
+	stat2 = ((stat2 >> MXS_DMA_CHANNELS) & stat2) | /* (1) */
+		(~(stat2 >> MXS_DMA_CHANNELS) & stat2 & ~stat1); /* (2) */
+
+	/* combine error and completion status for checking */
+	stat1 = (stat2 << MXS_DMA_CHANNELS) | stat1;
+	while (stat1) {
+		int channel = fls(stat1) - 1;
+		struct mxs_dma_chan *mxs_chan =
+			&mxs_dma->mxs_chans[channel % MXS_DMA_CHANNELS];
+
+		if (channel >= MXS_DMA_CHANNELS) {
+			dev_dbg(mxs_dma->dma_device.dev,
+				"%s: error in channel %d\n", __func__,
+				channel - MXS_DMA_CHANNELS);
+			mxs_chan->status = DMA_ERROR;
+			mxs_dma_reset_chan(mxs_chan);
+		} else {
+			if (mxs_chan->flags & MXS_DMA_SG_LOOP)
+				mxs_chan->status = DMA_IN_PROGRESS;
+			else
+				mxs_chan->status = DMA_SUCCESS;
+		}
+
+		stat1 &= ~(1 << channel);
+
+		if (mxs_chan->status == DMA_SUCCESS)
+			mxs_chan->last_completed = mxs_chan->desc.cookie;
+
+		/* schedule tasklet on this channel */
+		tasklet_schedule(&mxs_chan->tasklet);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+	struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+	struct mxs_dma_data *data = chan->private;
+	struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+	int ret;
+
+	if (!data)
+		return -EINVAL;
+
+	mxs_chan->chan_irq = data->chan_irq;
+
+	mxs_chan->ccw = dma_alloc_coherent(mxs_dma->dma_device.dev, PAGE_SIZE,
+				&mxs_chan->ccw_phys, GFP_KERNEL);
+	if (!mxs_chan->ccw) {
+		ret = -ENOMEM;
+		goto err_alloc;
+	}
+
+	memset(mxs_chan->ccw, 0, PAGE_SIZE);
+
+	ret = request_irq(mxs_chan->chan_irq, mxs_dma_int_handler,
+				0, "mxs-dma", mxs_dma);
+	if (ret)
+		goto err_irq;
+
+	ret = clk_enable(mxs_dma->clk);
+	if (ret)
+		goto err_clk;
+
+	mxs_dma_reset_chan(mxs_chan);
+
+	dma_async_tx_descriptor_init(&mxs_chan->desc, chan);
+	mxs_chan->desc.tx_submit = mxs_dma_tx_submit;
+
+	/* the descriptor is ready */
+	async_tx_ack(&mxs_chan->desc);
+
+	return 0;
+
+err_clk:
+	free_irq(mxs_chan->chan_irq, mxs_dma);
+err_irq:
+	dma_free_coherent(mxs_dma->dma_device.dev, PAGE_SIZE,
+			mxs_chan->ccw, mxs_chan->ccw_phys);
+err_alloc:
+	return ret;
+}
+
+static void mxs_dma_free_chan_resources(struct dma_chan *chan)
+{
+	struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+	struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+
+	mxs_dma_disable_chan(mxs_chan);
+
+	free_irq(mxs_chan->chan_irq, mxs_dma);
+
+	dma_free_coherent(mxs_dma->dma_device.dev, PAGE_SIZE,
+			mxs_chan->ccw, mxs_chan->ccw_phys);
+
+	clk_disable(mxs_dma->clk);
+}
+
+static struct dma_async_tx_descriptor *mxs_dma_prep_slave_sg(
+		struct dma_chan *chan, struct scatterlist *sgl,
+		unsigned int sg_len, enum dma_data_direction direction,
+		unsigned long append)
+{
+	struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+	struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+	struct mxs_dma_ccw *ccw;
+	struct scatterlist *sg;
+	int i, j;
+	u32 *pio;
+	static int idx = 0;
+
+	if (mxs_chan->status == DMA_IN_PROGRESS && !append)
+		return NULL;
+
+	if (sg_len + (append ? idx : 0) > NUM_CCW) {
+		dev_err(mxs_dma->dma_device.dev,
+				"maximum number of sg exceeded: %d > %d\n",
+				sg_len, NUM_CCW);
+		goto err_out;
+	}
+
+	mxs_chan->status = DMA_IN_PROGRESS;
+	mxs_chan->flags = 0;
+
+	/*
+	 * If the sg is prepared with append flag set, the sg
+	 * will be appended to the last prepared sg.
+	 */
+	if (append) {
+		BUG_ON(idx < 1);
+		ccw = &mxs_chan->ccw[idx - 1];
+		ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * idx;
+		ccw->bits |= CCW_CHAIN;
+		ccw->bits &= ~CCW_IRQ;
+		ccw->bits &= ~CCW_DEC_SEM;
+		ccw->bits &= ~CCW_WAIT4END;
+	} else {
+		idx = 0;
+	}
+
+	if (direction == DMA_NONE) {
+		ccw = &mxs_chan->ccw[idx++];
+		pio = (u32 *) sgl;
+
+		for (j = 0; j < sg_len;)
+			ccw->pio_words[j++] = *pio++;
+
+		ccw->bits = 0;
+		ccw->bits |= CCW_IRQ;
+		ccw->bits |= CCW_DEC_SEM;
+		ccw->bits |= CCW_WAIT4END;
+		ccw->bits |= CCW_HALT_ON_TERM;
+		ccw->bits |= CCW_TERM_FLUSH;
+		ccw->bits |= BF_CCW(sg_len, PIO_NUM);
+		ccw->bits |= BF_CCW(MXS_DMA_CMD_NO_XFER, COMMAND);
+	} else {
+		for_each_sg(sgl, sg, sg_len, i) {
+			if (sg->length > MAX_XFER_BYTES) {
+				dev_err(mxs_dma->dma_device.dev, "maximum bytes for sg entry exceeded: %d > %d\n",
+						sg->length, MAX_XFER_BYTES);
+				goto err_out;
+			}
+
+			ccw = &mxs_chan->ccw[idx++];
+
+			ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * idx;
+			ccw->bufaddr = sg->dma_address;
+			ccw->xfer_bytes = sg->length;
+
+			ccw->bits = 0;
+			ccw->bits |= CCW_CHAIN;
+			ccw->bits |= CCW_HALT_ON_TERM;
+			ccw->bits |= CCW_TERM_FLUSH;
+			ccw->bits |= BF_CCW(direction == DMA_FROM_DEVICE ?
+					MXS_DMA_CMD_WRITE : MXS_DMA_CMD_READ,
+					COMMAND);
+
+			if (i + 1 == sg_len) {
+				ccw->bits &= ~CCW_CHAIN;
+				ccw->bits |= CCW_IRQ;
+				ccw->bits |= CCW_DEC_SEM;
+				ccw->bits |= CCW_WAIT4END;
+			}
+		}
+	}
+
+	return &mxs_chan->desc;
+
+err_out:
+	mxs_chan->status = DMA_ERROR;
+	return NULL;
+}
+
+static struct dma_async_tx_descriptor *mxs_dma_prep_dma_cyclic(
+		struct dma_chan *chan, dma_addr_t dma_addr, size_t buf_len,
+		size_t period_len, enum dma_data_direction direction)
+{
+	struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+	struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
+	int num_periods = buf_len / period_len;
+	int i = 0, buf = 0;
+
+	if (mxs_chan->status == DMA_IN_PROGRESS)
+		return NULL;
+
+	mxs_chan->status = DMA_IN_PROGRESS;
+	mxs_chan->flags |= MXS_DMA_SG_LOOP;
+
+	if (num_periods > NUM_CCW) {
+		dev_err(mxs_dma->dma_device.dev,
+				"maximum number of sg exceeded: %d > %d\n",
+				num_periods, NUM_CCW);
+		goto err_out;
+	}
+
+	if (period_len > MAX_XFER_BYTES) {
+		dev_err(mxs_dma->dma_device.dev,
+				"maximum period size exceeded: %d > %d\n",
+				period_len, MAX_XFER_BYTES);
+		goto err_out;
+	}
+
+	while (buf < buf_len) {
+		struct mxs_dma_ccw *ccw = &mxs_chan->ccw[i];
+
+		if (i + 1 == num_periods)
+			ccw->next = mxs_chan->ccw_phys;
+		else
+			ccw->next = mxs_chan->ccw_phys + sizeof(*ccw) * (i + 1);
+
+		ccw->bufaddr = dma_addr;
+		ccw->xfer_bytes = period_len;
+
+		ccw->bits = 0;
+		ccw->bits |= CCW_CHAIN;
+		ccw->bits |= CCW_IRQ;
+		ccw->bits |= CCW_HALT_ON_TERM;
+		ccw->bits |= CCW_TERM_FLUSH;
+		ccw->bits |= BF_CCW(direction == DMA_FROM_DEVICE ?
+				MXS_DMA_CMD_WRITE : MXS_DMA_CMD_READ, COMMAND);
+
+		dma_addr += period_len;
+		buf += period_len;
+
+		i++;
+	}
+
+	return &mxs_chan->desc;
+
+err_out:
+	mxs_chan->status = DMA_ERROR;
+	return NULL;
+}
+
+static int mxs_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+		unsigned long arg)
+{
+	struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+	int ret = 0;
+
+	switch (cmd) {
+	case DMA_TERMINATE_ALL:
+		mxs_dma_disable_chan(mxs_chan);
+		break;
+	case DMA_PAUSE:
+		mxs_dma_pause_chan(mxs_chan);
+		break;
+	case DMA_RESUME:
+		mxs_dma_resume_chan(mxs_chan);
+		break;
+	default:
+		ret = -ENOSYS;
+	}
+
+	return ret;
+}
+
+static enum dma_status mxs_dma_tx_status(struct dma_chan *chan,
+			dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+	struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+	dma_cookie_t last_used;
+
+	last_used = chan->cookie;
+	dma_set_tx_state(txstate, mxs_chan->last_completed, last_used, 0);
+
+	return mxs_chan->status;
+}
+
+static void mxs_dma_issue_pending(struct dma_chan *chan)
+{
+	/*
+	 * Nothing to do. We only have a single descriptor.
+	 */
+}
+
+static int __init mxs_dma_init(struct mxs_dma_engine *mxs_dma)
+{
+	int ret;
+
+	ret = clk_enable(mxs_dma->clk);
+	if (ret)
+		goto err_out;
+
+	ret = mxs_reset_block(mxs_dma->base);
+	if (ret)
+		goto err_out;
+
+	/* only major version matters */
+	mxs_dma->version = readl(mxs_dma->base +
+				((mxs_dma->dev_id == MXS_DMA_APBX) ?
+				HW_APBX_VERSION : HW_APBH_VERSION)) >>
+				BP_APBHX_VERSION_MAJOR;
+
+	/* enable apbh burst */
+	if (dma_is_apbh()) {
+		writel(BM_APBH_CTRL0_APB_BURST_EN,
+			mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+		writel(BM_APBH_CTRL0_APB_BURST8_EN,
+			mxs_dma->base + HW_APBHX_CTRL0 + MXS_SET_ADDR);
+	}
+
+	/* enable irq for all the channels */
+	writel(MXS_DMA_CHANNELS_MASK << MXS_DMA_CHANNELS,
+		mxs_dma->base + HW_APBHX_CTRL1 + MXS_SET_ADDR);
+
+	clk_disable(mxs_dma->clk);
+
+	return 0;
+
+err_out:
+	return ret;
+}
+
+static int __init mxs_dma_probe(struct platform_device *pdev)
+{
+	const struct platform_device_id *id_entry =
+				platform_get_device_id(pdev);
+	struct mxs_dma_engine *mxs_dma;
+	struct resource *iores;
+	int ret, i;
+
+	mxs_dma = kzalloc(sizeof(*mxs_dma), GFP_KERNEL);
+	if (!mxs_dma)
+		return -ENOMEM;
+
+	mxs_dma->dev_id = id_entry->driver_data;
+
+	iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	if (!request_mem_region(iores->start, resource_size(iores),
+				pdev->name)) {
+		ret = -EBUSY;
+		goto err_request_region;
+	}
+
+	mxs_dma->base = ioremap(iores->start, resource_size(iores));
+	if (!mxs_dma->base) {
+		ret = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	mxs_dma->clk = clk_get(&pdev->dev, NULL);
+	if (IS_ERR(mxs_dma->clk)) {
+		ret = PTR_ERR(mxs_dma->clk);
+		goto err_clk;
+	}
+
+	dma_cap_set(DMA_SLAVE, mxs_dma->dma_device.cap_mask);
+	dma_cap_set(DMA_CYCLIC, mxs_dma->dma_device.cap_mask);
+
+	INIT_LIST_HEAD(&mxs_dma->dma_device.channels);
+
+	/* Initialize channel parameters */
+	for (i = 0; i < MXS_DMA_CHANNELS; i++) {
+		struct mxs_dma_chan *mxs_chan = &mxs_dma->mxs_chans[i];
+
+		mxs_chan->mxs_dma = mxs_dma;
+		mxs_chan->chan.device = &mxs_dma->dma_device;
+
+		tasklet_init(&mxs_chan->tasklet, mxs_dma_tasklet,
+			     (unsigned long) mxs_chan);
+
+
+		/* Add the channel to mxs_chan list */
+		list_add_tail(&mxs_chan->chan.device_node, &mxs_dma->dma_device.channels);
+	}
+
+	ret = mxs_dma_init(mxs_dma);
+	if (ret)
+		goto err_init;
+
+	mxs_dma->dma_device.dev = &pdev->dev;
+
+	/* mxs_dma gets 65535 bytes maximum sg size */
+	mxs_dma->dma_device.dev->dma_parms = &mxs_dma->dma_parms;
+	dma_set_max_seg_size(mxs_dma->dma_device.dev, MAX_XFER_BYTES);
+
+	mxs_dma->dma_device.device_alloc_chan_resources = mxs_dma_alloc_chan_resources;
+	mxs_dma->dma_device.device_free_chan_resources = mxs_dma_free_chan_resources;
+	mxs_dma->dma_device.device_tx_status = mxs_dma_tx_status;
+	mxs_dma->dma_device.device_prep_slave_sg = mxs_dma_prep_slave_sg;
+	mxs_dma->dma_device.device_prep_dma_cyclic = mxs_dma_prep_dma_cyclic;
+	mxs_dma->dma_device.device_control = mxs_dma_control;
+	mxs_dma->dma_device.device_issue_pending = mxs_dma_issue_pending;
+
+	ret = dma_async_device_register(&mxs_dma->dma_device);
+	if (ret) {
+		dev_err(mxs_dma->dma_device.dev, "unable to register\n");
+		goto err_init;
+	}
+
+	dev_info(mxs_dma->dma_device.dev, "initialized\n");
+
+	return 0;
+
+err_init:
+	clk_put(mxs_dma->clk);
+err_clk:
+	iounmap(mxs_dma->base);
+err_ioremap:
+	release_mem_region(iores->start, resource_size(iores));
+err_request_region:
+	kfree(mxs_dma);
+	return ret;
+}
+
+static struct platform_device_id mxs_dma_type[] = {
+	{
+		.name = "mxs-dma-apbh",
+		.driver_data = MXS_DMA_APBH,
+	}, {
+		.name = "mxs-dma-apbx",
+		.driver_data = MXS_DMA_APBX,
+	}
+};
+
+static struct platform_driver mxs_dma_driver = {
+	.driver		= {
+		.name	= "mxs-dma",
+	},
+	.id_table	= mxs_dma_type,
+};
+
+static int __init mxs_dma_module_init(void)
+{
+	return platform_driver_probe(&mxs_dma_driver, mxs_dma_probe);
+}
+subsys_initcall(mxs_dma_module_init);
-- 
1.7.1

^ permalink raw reply related

* [PATCH 2/4] msm: iommu: Rework clock logic and add IOMMU bus clock control
From: Trilok Soni @ 2011-02-25  7:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1298599242-21971-2-git-send-email-stepanm@codeaurora.org>

Hi Steve,

> 
>  /**
> diff --git a/arch/arm/mach-msm/iommu_dev.c b/arch/arm/mach-msm/iommu_dev.c
> index b83c73b..69acd1e 100644
> --- a/arch/arm/mach-msm/iommu_dev.c
> +++ b/arch/arm/mach-msm/iommu_dev.c
> @@ -1,4 +1,4 @@
> -/* Copyright (c) 2010, Code Aurora Forum. All rights reserved.
> +/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
>   *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License version 2 and
> @@ -29,6 +29,7 @@
> 
>  #include <mach/iommu_hw-8xxx.h>
>  #include <mach/iommu.h>
> +#include <mach/clk.h>
> 
>  struct iommu_ctx_iter_data {
>  	/* input */
> @@ -130,117 +131,134 @@ static int msm_iommu_probe(struct platform_device *pdev)
>  {
>  	struct resource *r, *r2;
>  	struct clk *iommu_clk;
> +	struct clk *iommu_pclk;
>  	struct msm_iommu_drvdata *drvdata;
>  	struct msm_iommu_dev *iommu_dev = pdev->dev.platform_data;

const please.

> +	iommu_pclk = clk_get(NULL, "smmu_pclk");
> +	if (IS_ERR(iommu_pclk)) {
> +		ret = -ENODEV;
> +		goto fail;
> +	}

I am not a big fan of this when you have the "device" around. You should just do

iommu_pclk = clk_get(&pdev->dev, NULL);

...error logic...

iommu_clk = clk_get(&pdev->dev, "iommu_clk");

...error logic...


> +
> +	ret = clk_enable(iommu_pclk);
> +	if (ret)
> +		goto fail_enable;
> +
> +	iommu_clk = clk_get(&pdev->dev, "iommu_clk");
> +
> +	if (!IS_ERR(iommu_clk))	{
> +		if (clk_get_rate(iommu_clk) == 0)
> +			clk_set_min_rate(iommu_clk, 1);
> +
> +		ret = clk_enable(iommu_clk);
> +		if (ret) {
>  			clk_put(iommu_clk);
> +			goto fail_pclk;
>  		}
> +	} else
> +		iommu_clk = NULL;
> 
> -		r = platform_get_resource_byname(pdev, IORESOURCE_MEM,
> -						 "physbase");
> -		if (!r) {
> -			ret = -ENODEV;
> -			goto fail;
> -		}
> +	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "physbase");
> 
> -		len = r->end - r->start + 1;
> +	if (!r) {
> +		ret = -ENODEV;
> +		goto fail_clk;
> +	}
> 
> -		r2 = request_mem_region(r->start, len, r->name);
> -		if (!r2) {
> -			pr_err("Could not request memory region: "
> -			"start=%p, len=%d\n", (void *) r->start, len);
> -			ret = -EBUSY;
> -			goto fail;
> -		}
> +	len = r->end - r->start + 1;


resource_size please.


---Trilok Soni


-- 
Sent by a consultant of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply

* [PATCH] PM: OPP: opp_find_freq_exact documentation fix
From: Nishanth Menon @ 2011-02-25  7:14 UTC (permalink / raw)
  To: linux-arm-kernel

opp_find_freq_exact documentation has is_available instead
of available. This also fixes warning with the kernel-doc:
scripts/kernel-doc drivers/base/power/opp.c >/dev/null
Warning(drivers/base/power/opp.c:246): No description found for parameter 'available'
Warning(drivers/base/power/opp.c:246): Excess function parameter 'is_available' description in 'opp_find_freq_exact'

Signed-off-by: Nishanth Menon <nm@ti.com>
---
 drivers/base/power/opp.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index 2bb9b4c..56a6899 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -222,7 +222,7 @@ int opp_get_opp_count(struct device *dev)
  * opp_find_freq_exact() - search for an exact frequency
  * @dev:		device for which we do this operation
  * @freq:		frequency to search for
- * @is_available:	true/false - match for available opp
+ * @available:		true/false - match for available opp
  *
  * Searches for exact match in the opp list and returns pointer to the matching
  * opp if found, else returns ERR_PTR in case of error and should be handled
-- 
1.7.1

^ permalink raw reply related

* [TRIVIAL/PATCH] ARM: hw_breakpoint: Fix newlines in WARN messages
From: Lothar Waßmann @ 2011-02-25  6:38 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1298573739-25144-1-git-send-email-sboyd@codeaurora.org>

Hi,

Stephen Boyd writes:
> These warnings are missing newlines and spaces causing confusing
> looking output when they trigger.
> 
> Cc: Will Deacon <will.deacon@arm.com>
> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> ---
>  arch/arm/kernel/hw_breakpoint.c |   13 +++++++------
>  1 files changed, 7 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm/kernel/hw_breakpoint.c b/arch/arm/kernel/hw_breakpoint.c
> index d600bd3..5aab00e 100644
> --- a/arch/arm/kernel/hw_breakpoint.c
> +++ b/arch/arm/kernel/hw_breakpoint.c
> @@ -238,8 +238,8 @@ static int enable_monitor_mode(void)
>  	ARM_DBG_READ(c1, 0, dscr);
>  
>  	/* Ensure that halting mode is disabled. */
> -	if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN, "halting debug mode enabled."
> -				"Unable to access hardware resources.")) {
> +	if (WARN_ONCE(dscr & ARM_DSCR_HDBGEN, "halting debug mode enabled. "
> +				"Unable to access hardware resources.\n")) {
>
I'd prefer the message text not to be line wrapped, even if it
violates the general line length rule, because that makes it easier to
grep for the message in the source code.


Lothar Wa?mann
-- 
___________________________________________________________

Ka-Ro electronics GmbH | Pascalstra?e 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Gesch?ftsf?hrer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996

www.karo-electronics.de | info at karo-electronics.de
___________________________________________________________

^ permalink raw reply

* [PATCH] omap4: Fix ULPI PHY init for ES1.0 SDP (Re: 4430SDP boot failure)
From: Santosh Shilimkar @ 2011-02-25  5:33 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110224173840.GC20560@atomide.com>

> -----Original Message-----
> From: linux-omap-owner at vger.kernel.org [mailto:linux-omap-
> owner at vger.kernel.org] On Behalf Of Tony Lindgren
> Sent: Thursday, February 24, 2011 11:09 PM
> To: Santosh Shilimkar
> Cc: Anand Gadiyar; Russell King - ARM Linux; linux-arm-
> kernel at lists.infradead.org; linux-omap at vger.kernel.org; Keshava
> Munegowda; Felipe Balbi
> Subject: Re: [PATCH] omap4: Fix ULPI PHY init for ES1.0 SDP (Re:
> 4430SDP boot failure)
>
> * Santosh Shilimkar <santosh.shilimkar@ti.com> [110212 00:45]:
> > Tony,
> > > -----Original Message-----
> > > From: Santosh Shilimkar [mailto:santosh.shilimkar at ti.com]
> > > Sent: Thursday, February 03, 2011 2:13 PM
> > > To: Tony Lindgren
> > > Cc: Anand Gadiyar; Russell King - ARM Linux; linux-arm-
> > > kernel at lists.infradead.org; linux-omap at vger.kernel.org; Keshava
> > > Munegowda; Felipe Balbi
> > > Subject: RE: [PATCH] omap4: Fix ULPI PHY init for ES1.0 SDP (Re:
> > > 4430SDP boot failure)
> > >
> > > > -----Original Message-----
> > > > From: Tony Lindgren [mailto:tony at atomide.com]
> > > > Sent: Thursday, February 03, 2011 1:19 AM
> > > > To: Santosh Shilimkar
> > > > Cc: Anand Gadiyar; Russell King - ARM Linux; linux-arm-
> > > > kernel at lists.infradead.org; linux-omap at vger.kernel.org;
> Keshava
> > > > Munegowda; Felipe Balbi
> > > > Subject: Re: [PATCH] omap4: Fix ULPI PHY init for ES1.0 SDP
> (Re:
> > > > 4430SDP boot failure)
> > > >
> > > > * Santosh Shilimkar <santosh.shilimkar@ti.com> [110201 22:04]:
> > > > > >
> > > > > > It's a ES1.0 blaze, with the patch below it reboots early
> > > > > > during the boot. I also have to disable omap_l2_cache_init
> > > > > > on this board to get it to boot.
> > > > > >
> > > > > Do you still get this problem with 'omap_l2_cache_init' ?
> > > > > As reported earlier, we don't see this issue on ES1.0
> > > > > SDP.
> > > >
> > > > Yeah I do, it rarely makes it to the userspace. Works reliably
> > > > if I disable omap_l2_cache_init.
> > > >
> > > Ok. I shall try few experiments and try to reproduce it
> >
> > Not sure if it's the same issue but I managed to reproduce the
> > issue on ES2.0 itself. And after some experiments, it boiled
> > down to the V6 and V7 issue. By disabling OMAP2 from the build,
> > everything was fine again.
>
> Was this with linux-omap master branch or mainline?
>
> The V6 vs V7 issues should be sorted out with Russell's patches that
> we also have now in linux-omap master branch.
>
This was with mainline.
Then I applied RMK's series and things were OK.

^ permalink raw reply

* [PATCH 0/3] OMAP2+: voltage: first pass at cleanup/reorganization
From: Rajendra Nayak @ 2011-02-25  5:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <alpine.DEB.2.00.1102242201410.6198@utopia.booyaka.com>

Hi Paul,

> -----Original Message-----
> From: Paul Walmsley [mailto:paul at pwsan.com]
> Sent: Friday, February 25, 2011 10:33 AM
> To: Rajendra Nayak
> Cc: linux-omap at vger.kernel.org; linux-arm-kernel at lists.infradead.org;
Kevin Hilman; Nishanth Menon; Benoit Cousson;
> Mike Turquette
> Subject: RE: [PATCH 0/3] OMAP2+: voltage: first pass at
cleanup/reorganization
>
> Hi Rajendra,
>
> On Thu, 24 Feb 2011, Rajendra Nayak wrote:
>
> > I found these abort on my 4430SDP. The below changes I found
> > are needed for it to bootup..
> > I tested the 'integration-2.6.39' branch of
> > git://git.pwsan.com/linux-integration and the patch is
> > based on this branch.
>
> Thanks very much for the patch, this looks right.  Do you mind if I fold
> it into the "OMAP2+: voltage: reorganize, split code from data" patch
and
> credit you appropriately in the patch description?  (That way, there
won't
> be any gaps between patches where OMAP4 won't work.)

I agree it makes sense to fold these changes into the original patch.
Please go ahead.
Thanks,
Rajendra

>
>
> - Paul

^ permalink raw reply

* [PATCH] mtd: nand: fix one typo in the comments
From: Jason Liu @ 2011-02-25  5:06 UTC (permalink / raw)
  To: linux-arm-kernel

In the function nand_do_write_oob, the comments
has one typo, this patch fix it.

- /* Do not allow reads past end of device */
+ /* Do not allow write past end of device */
if (unlikely(to >= mtd->size ||
	     ops->ooboffs + ops->ooblen >
		((mtd->size >> chip->page_shift) -
		 (to >> chip->page_shift)) * len)) {
	DEBUG(MTD_DEBUG_LEVEL0, "%s: Attempt write beyond "
			"end of device\n", __func__);
	return -EINVAL;
}

Signed-off-by: Jason Liu <r64343@freescale.com>
---
 drivers/mtd/nand/nand_base.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index a9c6ce7..da76040 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2377,7 +2377,7 @@ static int nand_do_write_oob(struct mtd_info *mtd, loff_t to,
 		return -EINVAL;
 	}
 
-	/* Do not allow reads past end of device */
+	/* Do not allow write past end of device */
 	if (unlikely(to >= mtd->size ||
 		     ops->ooboffs + ops->ooblen >
 			((mtd->size >> chip->page_shift) -
-- 
1.7.0.4

^ permalink raw reply related

* [PATCH 0/3] OMAP2+: voltage: first pass at cleanup/reorganization
From: Paul Walmsley @ 2011-02-25  5:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <553cd99ec29ee91e4a4b324d0f4a0be7@mail.gmail.com>

Hi Rajendra,

On Thu, 24 Feb 2011, Rajendra Nayak wrote:

> I found these abort on my 4430SDP. The below changes I found
> are needed for it to bootup..
> I tested the 'integration-2.6.39' branch of
> git://git.pwsan.com/linux-integration and the patch is
> based on this branch.

Thanks very much for the patch, this looks right.  Do you mind if I fold 
it into the "OMAP2+: voltage: reorganize, split code from data" patch and 
credit you appropriately in the patch description?  (That way, there won't 
be any gaps between patches where OMAP4 won't work.)


- Paul

^ permalink raw reply

* [PATCH v2] drivers: ld9040 amoled driver support
From: Donghwa Lee @ 2011-02-25  4:57 UTC (permalink / raw)
  To: linux-arm-kernel

This patch is ld9040 amoled panel driver.
I modify first patch and remove unneeded code.

Signed-off-by: Donghwa Lee <dh09.lee@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
---
 drivers/video/backlight/Kconfig        |    8 +
 drivers/video/backlight/Makefile       |    1 +
 drivers/video/backlight/ld9040.c       |  820 ++++++++++++++++++++++++++++++++
 drivers/video/backlight/ld9040_gamma.h |  201 ++++++++
 4 files changed, 1030 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/backlight/ld9040.c
 create mode 100644 drivers/video/backlight/ld9040_gamma.h

diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index e54a337..39a4cd2 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -109,6 +109,14 @@ config LCD_S6E63M0
 	  If you have an S6E63M0 LCD Panel, say Y to enable its
 	  LCD control driver.
 
+config LCD_LD9040
+	tristate "LD9040 AMOLED LCD Driver"
+	depends on SPI && BACKLIGHT_CLASS_DEVICE
+	default n
+	help
+	  If you have an LD9040 Panel, say Y to enable its
+	  control driver.
+
 endif # LCD_CLASS_DEVICE
 
 #
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
index 44c0f81..457996c 100644
--- a/drivers/video/backlight/Makefile
+++ b/drivers/video/backlight/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_LCD_VGG2432A4)	   += vgg2432a4.o
 obj-$(CONFIG_LCD_TDO24M)	   += tdo24m.o
 obj-$(CONFIG_LCD_TOSA)		   += tosa_lcd.o
 obj-$(CONFIG_LCD_S6E63M0)	+= s6e63m0.o
+obj-$(CONFIG_LCD_LD9040)	+= ld9040.o
 
 obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
 obj-$(CONFIG_BACKLIGHT_ATMEL_PWM)    += atmel-pwm-bl.o
diff --git a/drivers/video/backlight/ld9040.c b/drivers/video/backlight/ld9040.c
new file mode 100644
index 0000000..fbd4b19
--- /dev/null
+++ b/drivers/video/backlight/ld9040.c
@@ -0,0 +1,820 @@
+/*
+ * ld9040 AMOLED LCD panel driver.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ * Author: Donghwa Lee  <dh09.lee@samsung.com>
+ * Derived from drivers/video/backlight/s6e63m0.c
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <linux/wait.h>
+#include <linux/fb.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/lcd.h>
+#include <linux/backlight.h>
+
+#include "ld9040_gamma.h"
+
+#define SLEEPMSEC		0x1000
+#define ENDDEF			0x2000
+#define	DEFMASK			0xFF00
+#define COMMAND_ONLY		0xFE
+#define DATA_ONLY		0xFF
+
+#define MIN_BRIGHTNESS		0
+#define MAX_BRIGHTNESS		24
+#define power_is_on(pwr)	((pwr) <= FB_BLANK_NORMAL)
+
+struct ld9040 {
+	struct device			*dev;
+	struct spi_device		*spi;
+	unsigned int			power;
+	unsigned int			current_brightness;
+
+	struct lcd_device		*ld;
+	struct backlight_device		*bd;
+	struct lcd_platform_data	*lcd_pd;
+};
+
+static const unsigned short seq_swreset[] = {
+	0x01, COMMAND_ONLY,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_user_setting[] = {
+	0xF0, 0x5A,
+
+	DATA_ONLY, 0x5A,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_elvss_on[] = {
+	0xB1, 0x0D,
+
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x16,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_gtcon[] = {
+	0xF7, 0x09,
+
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_panel_condition[] = {
+	0xF8, 0x05,
+
+	DATA_ONLY, 0x65,
+	DATA_ONLY, 0x96,
+	DATA_ONLY, 0x71,
+	DATA_ONLY, 0x7D,
+	DATA_ONLY, 0x19,
+	DATA_ONLY, 0x3B,
+	DATA_ONLY, 0x0D,
+	DATA_ONLY, 0x19,
+	DATA_ONLY, 0x7E,
+	DATA_ONLY, 0x0D,
+	DATA_ONLY, 0xE2,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x7E,
+	DATA_ONLY, 0x7D,
+	DATA_ONLY, 0x07,
+	DATA_ONLY, 0x07,
+	DATA_ONLY, 0x20,
+	DATA_ONLY, 0x20,
+	DATA_ONLY, 0x20,
+	DATA_ONLY, 0x02,
+	DATA_ONLY, 0x02,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_gamma_set1[] = {
+	0xF9, 0x00,
+
+	DATA_ONLY, 0xA7,
+	DATA_ONLY, 0xB4,
+	DATA_ONLY, 0xAE,
+	DATA_ONLY, 0xBF,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x91,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0xB2,
+	DATA_ONLY, 0xB4,
+	DATA_ONLY, 0xAA,
+	DATA_ONLY, 0xBB,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0xAC,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0xB3,
+	DATA_ONLY, 0xB1,
+	DATA_ONLY, 0xAA,
+	DATA_ONLY, 0xBC,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0xB3,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_gamma_ctrl[] = {
+	0xFB, 0x02,
+
+	DATA_ONLY, 0x5A,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_gamma_start[] = {
+	0xF9, COMMAND_ONLY,
+
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_apon[] = {
+	0xF3, 0x00,
+
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x0A,
+	DATA_ONLY, 0x02,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_display_ctrl[] = {
+	0xF2, 0x02,
+
+	DATA_ONLY, 0x08,
+	DATA_ONLY, 0x08,
+	DATA_ONLY, 0x10,
+	DATA_ONLY, 0x10,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_manual_pwr[] = {
+	0xB0, 0x04,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_pwr_ctrl[] = {
+	0xF4, 0x0A,
+
+	DATA_ONLY, 0x87,
+	DATA_ONLY, 0x25,
+	DATA_ONLY, 0x6A,
+	DATA_ONLY, 0x44,
+	DATA_ONLY, 0x02,
+	DATA_ONLY, 0x88,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_sleep_out[] = {
+	0x11, COMMAND_ONLY,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_sleep_in[] = {
+	0x10, COMMAND_ONLY,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_display_on[] = {
+	0x29, COMMAND_ONLY,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_display_off[] = {
+	0x28, COMMAND_ONLY,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_vci1_1st_en[] = {
+	0xF3, 0x10,
+
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x02,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_vl1_en[] = {
+	0xF3, 0x11,
+
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x02,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_vl2_en[] = {
+	0xF3, 0x13,
+
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x02,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_vci1_2nd_en[] = {
+	0xF3, 0x33,
+
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x02,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_vl3_en[] = {
+	0xF3, 0x37,
+
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x02,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_vreg1_amp_en[] = {
+	0xF3, 0x37,
+
+	DATA_ONLY, 0x01,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x02,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_vgh_amp_en[] = {
+	0xF3, 0x37,
+
+	DATA_ONLY, 0x11,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x02,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_vgl_amp_en[] = {
+	0xF3, 0x37,
+
+	DATA_ONLY, 0x31,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x02,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_vmos_amp_en[] = {
+	0xF3, 0x37,
+
+	DATA_ONLY, 0xB1,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x03,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_vint_amp_en[] = {
+	0xF3, 0x37,
+
+	DATA_ONLY, 0xF1,
+	/* DATA_ONLY, 0x71,	VMOS/VBL/VBH not used */
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x03,
+	/* DATA_ONLY, 0x02,	VMOS/VBL/VBH not used */
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_vbh_amp_en[] = {
+	0xF3, 0x37,
+
+	DATA_ONLY, 0xF9,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x03,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_vbl_amp_en[] = {
+	0xF3, 0x37,
+
+	DATA_ONLY, 0xFD,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x03,
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_gam_amp_en[] = {
+	0xF3, 0x37,
+
+	DATA_ONLY, 0xFF,
+	/* DATA_ONLY, 0x73,	VMOS/VBL/VBH not used */
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x03,
+	/* DATA_ONLY, 0x02,	VMOS/VBL/VBH not used */
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_sd_amp_en[] = {
+	0xF3, 0x37,
+
+	DATA_ONLY, 0xFF,
+	/* DATA_ONLY, 0x73,	VMOS/VBL/VBH not used */
+	DATA_ONLY, 0x80,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x03,
+	/* DATA_ONLY, 0x02,	VMOS/VBL/VBH not used */
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_gls_en[] = {
+	0xF3, 0x37,
+
+	DATA_ONLY, 0xFF,
+	/* DATA_ONLY, 0x73,	VMOS/VBL/VBH not used */
+	DATA_ONLY, 0x81,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x03,
+	/* DATA_ONLY, 0x02,	VMOS/VBL/VBH not used */
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_els_en[] = {
+	0xF3, 0x37,
+
+	DATA_ONLY, 0xFF,
+	/* DATA_ONLY, 0x73,	VMOS/VBL/VBH not used */
+	DATA_ONLY, 0x83,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x03,
+	/* DATA_ONLY, 0x02,	VMOS/VBL/VBH not used */
+	ENDDEF, 0x00
+};
+
+static const unsigned short seq_el_on[] = {
+	0xF3, 0x37,
+
+	DATA_ONLY, 0xFF,
+	/* DATA_ONLY, 0x73,	VMOS/VBL/VBH not used */
+	DATA_ONLY, 0x87,
+	DATA_ONLY, 0x00,
+	DATA_ONLY, 0x03,
+	/* DATA_ONLY, 0x02,	VMOS/VBL/VBH not used */
+	ENDDEF, 0x00
+};
+
+static int ld9040_spi_write_byte(struct ld9040 *lcd, int addr, int data)
+{
+	u16 buf[1];
+	struct spi_message msg;
+
+	struct spi_transfer xfer = {
+		.len		= 2,
+		.tx_buf		= buf,
+	};
+
+	buf[0] = (addr << 8) | data;
+
+	spi_message_init(&msg);
+	spi_message_add_tail(&xfer, &msg);
+
+	return spi_sync(lcd->spi, &msg);
+}
+
+static int ld9040_spi_write(struct ld9040 *lcd, unsigned char address,
+	unsigned char command)
+{
+	int ret = 0;
+
+	if (address != DATA_ONLY)
+		ret = ld9040_spi_write_byte(lcd, 0x0, address);
+	if (command != COMMAND_ONLY)
+		ret = ld9040_spi_write_byte(lcd, 0x1, command);
+
+	return ret;
+}
+
+static int ld9040_panel_send_sequence(struct ld9040 *lcd,
+	const unsigned short *wbuf)
+{
+	int ret = 0, i = 0;
+
+	while ((wbuf[i] & DEFMASK) != ENDDEF) {
+		if ((wbuf[i] & DEFMASK) != SLEEPMSEC) {
+			ret = ld9040_spi_write(lcd, wbuf[i], wbuf[i+1]);
+			if (ret)
+				break;
+		} else
+			udelay(wbuf[i+1]*1000);
+		i += 2;
+	}
+
+	return ret;
+}
+
+static int _ld9040_gamma_ctl(struct ld9040 *lcd, const unsigned int *gamma)
+{
+	unsigned int i = 0;
+	int ret = 0;
+
+	/* start gamma table updating. */
+	ret = ld9040_panel_send_sequence(lcd, seq_gamma_start);
+	if (ret) {
+		dev_err(lcd->dev, "failed to disable gamma table updating.\n");
+		goto gamma_err;
+	}
+
+	for (i = 0 ; i < GAMMA_TABLE_COUNT; i++) {
+		ret = ld9040_spi_write(lcd, DATA_ONLY, gamma[i]);
+		if (ret) {
+			dev_err(lcd->dev, "failed to set gamma table.\n");
+			goto gamma_err;
+		}
+	}
+
+	/* update gamma table. */
+	ret = ld9040_panel_send_sequence(lcd, seq_gamma_ctrl);
+	if (ret)
+		dev_err(lcd->dev, "failed to update gamma table.\n");
+
+gamma_err:
+	return ret;
+}
+
+static int ld9040_gamma_ctl(struct ld9040 *lcd, int gamma)
+{
+	int ret = 0;
+
+	ret = _ld9040_gamma_ctl(lcd, gamma_table.gamma_22_table[gamma]);
+
+	return ret;
+}
+
+
+static int ld9040_ldi_init(struct ld9040 *lcd)
+{
+	int ret, i;
+	static const unsigned short *init_seq[] = {
+		seq_user_setting,
+		seq_panel_condition,
+		seq_display_ctrl,
+		seq_manual_pwr,
+		seq_elvss_on,
+		seq_gtcon,
+		seq_gamma_set1,
+		seq_gamma_ctrl,
+		seq_sleep_out,
+	};
+
+	for (i = 0; i < ARRAY_SIZE(init_seq); i++) {
+		ret = ld9040_panel_send_sequence(lcd, init_seq[i]);
+		/* workaround: minimum delay time for transferring CMD */
+		udelay(300);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+static int ld9040_ldi_enable(struct ld9040 *lcd)
+{
+	int ret = 0;
+
+	ret = ld9040_panel_send_sequence(lcd, seq_display_on);
+
+	return ret;
+}
+
+static int ld9040_ldi_disable(struct ld9040 *lcd)
+{
+	int ret;
+
+	ret = ld9040_panel_send_sequence(lcd, seq_display_off);
+	ret = ld9040_panel_send_sequence(lcd, seq_sleep_in);
+
+	return ret;
+}
+
+static int ld9040_power_on(struct ld9040 *lcd)
+{
+	int ret = 0;
+	struct lcd_platform_data *pd = NULL;
+	pd = lcd->lcd_pd;
+	if (!pd) {
+		dev_err(lcd->dev, "platform data is NULL.\n");
+		return -EFAULT;
+	}
+
+	if (!pd->power_on) {
+		dev_err(lcd->dev, "power_on is NULL.\n");
+		return -EFAULT;
+	} else {
+		pd->power_on(lcd->ld, 1);
+		mdelay(pd->power_on_delay);
+	}
+
+	if (!pd->reset) {
+		dev_err(lcd->dev, "reset is NULL.\n");
+		return -EFAULT;
+	} else {
+		pd->reset(lcd->ld);
+		mdelay(pd->reset_delay);
+	}
+
+	ret = ld9040_ldi_init(lcd);
+	if (ret) {
+		dev_err(lcd->dev, "failed to initialize ldi.\n");
+		return ret;
+	}
+
+	ret = ld9040_ldi_enable(lcd);
+	if (ret) {
+		dev_err(lcd->dev, "failed to enable ldi.\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int ld9040_power_off(struct ld9040 *lcd)
+{
+	int ret = 0;
+	struct lcd_platform_data *pd = NULL;
+
+	pd = lcd->lcd_pd;
+	if (!pd) {
+		dev_err(lcd->dev, "platform data is NULL.\n");
+		return -EFAULT;
+	}
+
+	ret = ld9040_ldi_disable(lcd);
+	if (ret) {
+		dev_err(lcd->dev, "lcd setting failed.\n");
+		return -EIO;
+	}
+
+	mdelay(pd->power_off_delay);
+
+	if (!pd->power_on) {
+		dev_err(lcd->dev, "power_on is NULL.\n");
+		return -EFAULT;
+	} else
+		pd->power_on(lcd->ld, 0);
+
+	return 0;
+}
+
+static int ld9040_power(struct ld9040 *lcd, int power)
+{
+	int ret = 0;
+
+	if (power_is_on(power) && !power_is_on(lcd->power))
+		ret = ld9040_power_on(lcd);
+	else if (!power_is_on(power) && power_is_on(lcd->power))
+		ret = ld9040_power_off(lcd);
+
+	if (!ret)
+		lcd->power = power;
+
+	return ret;
+}
+
+static int ld9040_set_power(struct lcd_device *ld, int power)
+{
+	struct ld9040 *lcd = lcd_get_data(ld);
+
+	if (power != FB_BLANK_UNBLANK && power != FB_BLANK_POWERDOWN &&
+		power != FB_BLANK_NORMAL) {
+		dev_err(lcd->dev, "power value should be 0, 1 or 4.\n");
+		return -EINVAL;
+	}
+
+	return ld9040_power(lcd, power);
+}
+
+static int ld9040_get_power(struct lcd_device *ld)
+{
+	struct ld9040 *lcd = lcd_get_data(ld);
+
+	return lcd->power;
+}
+
+static int ld9040_get_brightness(struct backlight_device *bd)
+{
+	return bd->props.brightness;
+}
+
+static int ld9040_set_brightness(struct backlight_device *bd)
+{
+	int ret = 0, brightness = bd->props.brightness;
+	struct ld9040 *lcd = bl_get_data(bd);
+
+	if (brightness < MIN_BRIGHTNESS ||
+		brightness > bd->props.max_brightness) {
+		dev_err(&bd->dev, "lcd brightness should be %d to %d.\n",
+			MIN_BRIGHTNESS, MAX_BRIGHTNESS);
+		return -EINVAL;
+	}
+
+	ret = ld9040_gamma_ctl(lcd, bd->props.brightness);
+	if (ret) {
+		dev_err(&bd->dev, "lcd brightness setting failed.\n");
+		return -EIO;
+	}
+
+	return ret;
+}
+
+static struct lcd_ops ld9040_lcd_ops = {
+	.set_power = ld9040_set_power,
+	.get_power = ld9040_get_power,
+};
+
+static const struct backlight_ops ld9040_backlight_ops  = {
+	.get_brightness = ld9040_get_brightness,
+	.update_status = ld9040_set_brightness,
+};
+
+
+static int ld9040_probe(struct spi_device *spi)
+{
+	int ret = 0;
+	struct ld9040 *lcd = NULL;
+	struct lcd_device *ld = NULL;
+	struct backlight_device *bd = NULL;
+
+	lcd = kzalloc(sizeof(struct ld9040), GFP_KERNEL);
+	if (!lcd)
+		return -ENOMEM;
+
+	/* ld9040 lcd panel uses 3-wire 9bits SPI Mode. */
+	spi->bits_per_word = 9;
+
+	ret = spi_setup(spi);
+	if (ret < 0) {
+		dev_err(&spi->dev, "spi setup failed.\n");
+		goto out_free_lcd;
+	}
+
+	lcd->spi = spi;
+	lcd->dev = &spi->dev;
+
+	lcd->lcd_pd = spi->dev.platform_data;
+	if (!lcd->lcd_pd) {
+		dev_err(&spi->dev, "platform data is NULL.\n");
+		goto out_free_lcd;
+	}
+
+	ld = lcd_device_register("ld9040", &spi->dev, lcd, &ld9040_lcd_ops);
+	if (IS_ERR(ld)) {
+		ret = PTR_ERR(ld);
+		goto out_free_lcd;
+	}
+
+	lcd->ld = ld;
+
+	bd = backlight_device_register("ld9040-bl", &spi->dev,
+		lcd, &ld9040_backlight_ops, NULL);
+	if (IS_ERR(ld)) {
+		ret = PTR_ERR(ld);
+		goto out_free_lcd;
+	}
+
+	bd->props.max_brightness = MAX_BRIGHTNESS;
+	bd->props.brightness = MAX_BRIGHTNESS;
+	lcd->bd = bd;
+
+	/*
+	 * if lcd panel was on from bootloader like u-boot then
+	 * do not lcd on.
+	 */
+	if (!lcd->lcd_pd->lcd_enabled) {
+		/*
+		 * if lcd panel was off from bootloader then
+		 * current lcd status is powerdown and then
+		 * it enables lcd panel.
+		 */
+		lcd->power = FB_BLANK_POWERDOWN;
+
+		ld9040_power(lcd, FB_BLANK_UNBLANK);
+	} else
+		lcd->power = FB_BLANK_UNBLANK;
+
+	dev_set_drvdata(&spi->dev, lcd);
+
+	dev_info(&spi->dev, "ld9040 panel driver has been probed.\n");
+	return 0;
+
+out_free_lcd:
+	kfree(lcd);
+	return ret;
+}
+
+static int __devexit ld9040_remove(struct spi_device *spi)
+{
+	struct ld9040 *lcd = dev_get_drvdata(&spi->dev);
+
+	ld9040_power(lcd, FB_BLANK_POWERDOWN);
+	lcd_device_unregister(lcd->ld);
+	kfree(lcd);
+
+	return 0;
+}
+
+#if defined(CONFIG_PM)
+static int ld9040_suspend(struct spi_device *spi, pm_message_t mesg)
+{
+	int ret = 0;
+	struct ld9040 *lcd = dev_get_drvdata(&spi->dev);
+
+	dev_dbg(&spi->dev, "lcd->power = %d\n", lcd->power);
+
+	/*
+	 * when lcd panel is suspend, lcd panel becomes off
+	 * regardless of status.
+	 */
+	ret = ld9040_power(lcd, FB_BLANK_POWERDOWN);
+
+	return ret;
+}
+
+static int ld9040_resume(struct spi_device *spi)
+{
+	int ret = 0;
+	struct ld9040 *lcd = dev_get_drvdata(&spi->dev);
+
+	lcd->power = FB_BLANK_POWERDOWN;
+
+	ret = ld9040_power(lcd, FB_BLANK_UNBLANK);
+
+	return ret;
+}
+#else
+#define ld9040_suspend		NULL
+#define ld9040_resume		NULL
+#endif
+
+/* Power down all displays on reboot, poweroff or halt. */
+static void ld9040_shutdown(struct spi_device *spi)
+{
+	struct ld9040 *lcd = dev_get_drvdata(&spi->dev);
+
+	ld9040_power(lcd, FB_BLANK_POWERDOWN);
+}
+
+static struct spi_driver ld9040_driver = {
+	.driver = {
+		.name	= "ld9040",
+		.bus	= &spi_bus_type,
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ld9040_probe,
+	.remove		= __devexit_p(ld9040_remove),
+	.shutdown	= ld9040_shutdown,
+	.suspend	= ld9040_suspend,
+	.resume		= ld9040_resume,
+};
+
+static int __init ld9040_init(void)
+{
+	return spi_register_driver(&ld9040_driver);
+}
+
+static void __exit ld9040_exit(void)
+{
+	spi_unregister_driver(&ld9040_driver);
+}
+
+module_init(ld9040_init);
+module_exit(ld9040_exit);
+
+MODULE_AUTHOR("Donghwa Lee <dh09.lee@samsung.com>");
+MODULE_DESCRIPTION("ld9040 LCD Driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/video/backlight/ld9040_gamma.h b/drivers/video/backlight/ld9040_gamma.h
new file mode 100644
index 0000000..167fca4
--- /dev/null
+++ b/drivers/video/backlight/ld9040_gamma.h
@@ -0,0 +1,201 @@
+/* 
+ * Gamma level definitions.
+ *
+ * Copyright (c) 2011 Samsung Electronics
+ * InKi Dae <inki.dae@samsung.com>
+ * Donghwa Lee <dh09.lee@samsung.com>
+ *
+ * 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.
+*/
+
+#ifndef _LD9040_BRIGHTNESS_H
+#define _LD9040_BRIGHTNESS_H
+
+#define MAX_GAMMA_LEVEL		25
+#define GAMMA_TABLE_COUNT	21
+
+/* gamma value: 2.2 */
+static const unsigned int ld9040_22_300[] = {
+	0x00, 0xa7, 0xb4, 0xae, 0xbf, 0x00, 0x91,
+	0x00, 0xb2, 0xb4, 0xaa, 0xbb, 0x00, 0xac,
+	0x00, 0xb3, 0xb1, 0xaa, 0xbc, 0x00, 0xb3
+};
+
+static const unsigned int ld9040_22_290[] = {
+	0x00, 0xa9, 0xb7, 0xae, 0xbd, 0x00, 0x89,
+	0x00, 0xb7, 0xb6, 0xa8, 0xba, 0x00, 0xa4,
+	0x00, 0xb1, 0xb4, 0xaa, 0xbb, 0x00, 0xaa
+};
+
+static const unsigned int ld9040_22_280[] = {
+	0x00, 0xa9, 0xb6, 0xad, 0xbf, 0x00, 0x86,
+	0x00, 0xb8, 0xb5, 0xa8, 0xbc, 0x00, 0xa0,
+	0x00, 0xb3, 0xb3, 0xa9, 0xbc, 0x00, 0xa7
+};
+
+static const unsigned int ld9040_22_270[] = {
+	0x00, 0xa8, 0xb8, 0xae, 0xbe, 0x00, 0x84,
+	0x00, 0xb9, 0xb7, 0xa8, 0xbc, 0x00, 0x9d,
+	0x00, 0xb2, 0xb5, 0xaa, 0xbc, 0x00, 0xa4
+
+};
+static const unsigned int ld9040_22_260[] = {
+	0x00, 0xa4, 0xb8, 0xb0, 0xbf, 0x00, 0x80,
+	0x00, 0xb8, 0xb6, 0xaa, 0xbc, 0x00, 0x9a,
+	0x00, 0xb0, 0xb5, 0xab, 0xbd, 0x00, 0xa0
+};
+
+static const unsigned int ld9040_22_250[] = {
+	0x00, 0xa4, 0xb9, 0xaf, 0xc1, 0x00, 0x7d,
+	0x00, 0xb9, 0xb6, 0xaa, 0xbb, 0x00, 0x97,
+	0x00, 0xb1, 0xb5, 0xaa, 0xbf, 0x00, 0x9d
+};
+
+static const unsigned int ld9040_22_240[] = {
+	0x00, 0xa2, 0xb9, 0xaf, 0xc2, 0x00, 0x7a,
+	0x00, 0xb9, 0xb7, 0xaa, 0xbd, 0x00, 0x94,
+	0x00, 0xb0, 0xb5, 0xab, 0xbf, 0x00, 0x9a
+};
+
+static const unsigned int ld9040_22_230[] = {
+	0x00, 0xa0, 0xb9, 0xaf, 0xc3, 0x00, 0x77,
+	0x00, 0xb9, 0xb7, 0xab, 0xbe, 0x00, 0x90,
+	0x00, 0xb0, 0xb6, 0xab, 0xbf, 0x00, 0x97
+};
+
+static const unsigned int ld9040_22_220[] = {
+	0x00, 0x9e, 0xba, 0xb0, 0xc2, 0x00, 0x75,
+	0x00, 0xb9, 0xb8, 0xab, 0xbe, 0x00, 0x8e,
+	0x00, 0xb0, 0xb6, 0xac, 0xbf, 0x00, 0x94
+};
+
+static const unsigned int ld9040_22_210[] = {
+	0x00, 0x9c, 0xb9, 0xb0, 0xc4, 0x00, 0x72,
+	0x00, 0xb8, 0xb8, 0xac, 0xbf, 0x00, 0x8a,
+	0x00, 0xb0, 0xb6, 0xac, 0xc0, 0x00, 0x91
+};
+
+static const unsigned int ld9040_22_200[] = {
+	0x00, 0x9a, 0xba, 0xb1, 0xc4, 0x00, 0x6f,
+	0x00, 0xb8, 0xb8, 0xad, 0xc0, 0x00, 0x86,
+	0x00, 0xb0, 0xb7, 0xad, 0xc0, 0x00, 0x8d
+};
+
+static const unsigned int ld9040_22_190[] = {
+	0x00, 0x97, 0xba, 0xb2, 0xc5, 0x00, 0x6c,
+	0x00, 0xb8, 0xb8, 0xae, 0xc1, 0x00, 0x82,
+	0x00, 0xb0, 0xb6, 0xae, 0xc2, 0x00, 0x89
+};
+
+static const unsigned int ld9040_22_180[] = {
+	0x00, 0x93, 0xba, 0xb3, 0xc5, 0x00, 0x69,
+	0x00, 0xb8, 0xb9, 0xae, 0xc1, 0x00, 0x7f,
+	0x00, 0xb0, 0xb6, 0xae, 0xc3, 0x00, 0x85
+};
+
+static const unsigned int ld9040_22_170[] = {
+	0x00, 0x8b, 0xb9, 0xb3, 0xc7, 0x00, 0x65,
+	0x00, 0xb7, 0xb8, 0xaf, 0xc3, 0x00, 0x7a,
+	0x00, 0x80, 0xb6, 0xae, 0xc4, 0x00, 0x81
+};
+
+static const unsigned int ld9040_22_160[] = {
+	0x00, 0x89, 0xba, 0xb3, 0xc8, 0x00, 0x62,
+	0x00, 0xb6, 0xba, 0xaf, 0xc3, 0x00, 0x76,
+	0x00, 0xaf, 0xb7, 0xae, 0xc4, 0x00, 0x7e
+};
+
+static const unsigned int ld9040_22_150[] = {
+	0x00, 0x82, 0xba, 0xb4, 0xc7, 0x00, 0x5f,
+	0x00, 0xb5, 0xba, 0xb0, 0xc3, 0x00, 0x72,
+	0x00, 0xae, 0xb8, 0xb0, 0xc3, 0x00, 0x7a
+};
+
+static const unsigned int ld9040_22_140[] = {
+	0x00, 0x7b, 0xbb, 0xb4, 0xc8, 0x00, 0x5b,
+	0x00, 0xb5, 0xba, 0xb1, 0xc4, 0x00, 0x6e,
+	0x00, 0xae, 0xb9, 0xb0, 0xc5, 0x00, 0x75
+};
+
+static const unsigned int ld9040_22_130[] = {
+	0x00, 0x71, 0xbb, 0xb5, 0xc8, 0x00, 0x57,
+	0x00, 0xb5, 0xbb, 0xb0, 0xc5, 0x00, 0x6a,
+	0x00, 0xae, 0xb9, 0xb1, 0xc6, 0x00, 0x70
+};
+
+static const unsigned int ld9040_22_120[] = {
+	0x00, 0x47, 0xba, 0xb6, 0xca, 0x00, 0x53,
+	0x00, 0xb5, 0xbb, 0xb3, 0xc6, 0x00, 0x65,
+	0x00, 0xae, 0xb8, 0xb3, 0xc7, 0x00, 0x6c
+};
+
+static const unsigned int ld9040_22_110[] = {
+	0x00, 0x13, 0xbb, 0xb7, 0xca, 0x00, 0x4f,
+	0x00, 0xb4, 0xbb, 0xb3, 0xc7, 0x00, 0x60,
+	0x00, 0xad, 0xb8, 0xb4, 0xc7, 0x00, 0x67
+};
+
+static const unsigned int ld9040_22_100[] = {
+	0x00, 0x13, 0xba, 0xb8, 0xcb, 0x00, 0x4b,
+	0x00, 0xb3, 0xbc, 0xb4, 0xc7, 0x00, 0x5c,
+	0x00, 0xac, 0xb8, 0xb4, 0xc8, 0x00, 0x62
+};
+
+static const unsigned int ld9040_22_90[] = {
+	0x00, 0x13, 0xb9, 0xb8, 0xcd, 0x00, 0x46,
+	0x00, 0xb1, 0xbc, 0xb5, 0xc8, 0x00, 0x56,
+	0x00, 0xaa, 0xb8, 0xb4, 0xc9, 0x00, 0x5d
+};
+
+static const unsigned int ld9040_22_80[] = {
+	0x00, 0x13, 0xba, 0xb9, 0xcd, 0x00, 0x41,
+	0x00, 0xb0, 0xbe, 0xb5, 0xc9, 0x00, 0x51,
+	0x00, 0xa9, 0xb9, 0xb5, 0xca, 0x00, 0x57
+};
+
+static const unsigned int ld9040_22_70[] = {
+	0x00, 0x13, 0xb9, 0xb9, 0xd0, 0x00, 0x3c,
+	0x00, 0xaf, 0xbf, 0xb6, 0xcb, 0x00, 0x4b,
+	0x00, 0xa8, 0xb9, 0xb5, 0xcc, 0x00, 0x52
+};
+
+static const unsigned int ld9040_22_50[] = {
+	0x00, 0x13, 0xb2, 0xba, 0xd2, 0x00, 0x30,
+	0x00, 0xaf, 0xc0, 0xb8, 0xcd, 0x00, 0x3d,
+	0x00, 0xa8, 0xb8, 0xb7, 0xcd, 0x00, 0x44
+};
+
+struct ld9040_gamma {
+	unsigned int *gamma_22_table[MAX_GAMMA_LEVEL];
+} gamma_table = {
+	.gamma_22_table[0] = (unsigned int *)&ld9040_22_50,
+	.gamma_22_table[1] = (unsigned int *)&ld9040_22_70,
+	.gamma_22_table[2] = (unsigned int *)&ld9040_22_80,
+	.gamma_22_table[3] = (unsigned int *)&ld9040_22_90,
+	.gamma_22_table[4] = (unsigned int *)&ld9040_22_100,
+	.gamma_22_table[5] = (unsigned int *)&ld9040_22_110,
+	.gamma_22_table[6] = (unsigned int *)&ld9040_22_120,
+	.gamma_22_table[7] = (unsigned int *)&ld9040_22_130,
+	.gamma_22_table[8] = (unsigned int *)&ld9040_22_140,
+	.gamma_22_table[9] = (unsigned int *)&ld9040_22_150,
+	.gamma_22_table[10] = (unsigned int *)&ld9040_22_160,
+	.gamma_22_table[11] = (unsigned int *)&ld9040_22_170,
+	.gamma_22_table[12] = (unsigned int *)&ld9040_22_180,
+	.gamma_22_table[13] = (unsigned int *)&ld9040_22_190,
+	.gamma_22_table[14] = (unsigned int *)&ld9040_22_200,
+	.gamma_22_table[15] = (unsigned int *)&ld9040_22_210,
+	.gamma_22_table[16] = (unsigned int *)&ld9040_22_220,
+	.gamma_22_table[17] = (unsigned int *)&ld9040_22_230,
+	.gamma_22_table[18] = (unsigned int *)&ld9040_22_240,
+	.gamma_22_table[19] = (unsigned int *)&ld9040_22_250,
+	.gamma_22_table[20] = (unsigned int *)&ld9040_22_260,
+	.gamma_22_table[21] = (unsigned int *)&ld9040_22_270,
+	.gamma_22_table[22] = (unsigned int *)&ld9040_22_280,
+	.gamma_22_table[23] = (unsigned int *)&ld9040_22_290,
+	.gamma_22_table[24] = (unsigned int *)&ld9040_22_300,
+};
+
+#endif
+
-- 
1.6.0.4

^ permalink raw reply related

* [PATCH v2 2/2] msm: add single-wire serial bus interface (SSBI) driver
From: David Brown @ 2011-02-25  4:06 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110225035857.GA9985@suse.de>

On Thu, Feb 24 2011, Greg KH wrote:

> On Thu, Feb 24, 2011 at 07:54:21PM -0800, David Brown wrote:
>> On Thu, Feb 24 2011, Greg KH wrote:
>> 
>> > drivers/ssbi?  What's keeping this from later moving off of the msm
>> > chips to run on others?  USB started out only on one processor, as did a
>> > lot of other bus-specific drivers, before the hardware became present on
>> > other architectures.  So no need to bury it under a msm specific
>> > location.
>> 
>> Not sure if anything is stopping it from moving off of MSM chips, but it
>> doesn't seem very likely.  There are too many similar interfaces that
>> are standard that others would be likely to use.  For the most part, it
>> is the bus to communicate between the MSM and it's specialized
>> peripherals.
>> 
>> We can still put it there, but it will likely be the only driver ever in
>> the directory.
>
> Ah, so it's just one driver?  Then how about drivers/platform/msm/ ?

I like it.  It keeps drivers from getting cluttered.  Plus x86 is
getting lonely in there.

Ken, in addition to addressing the comments made so far and any others
that come in, let's put this under drivers/platform/msm.

Thanks,
David

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply

* [PATCH v2 2/2] msm: add single-wire serial bus interface (SSBI) driver
From: Greg KH @ 2011-02-25  3:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <8yavd08bwgi.fsf@huya.qualcomm.com>

On Thu, Feb 24, 2011 at 07:54:21PM -0800, David Brown wrote:
> On Thu, Feb 24 2011, Greg KH wrote:
> 
> > drivers/ssbi?  What's keeping this from later moving off of the msm
> > chips to run on others?  USB started out only on one processor, as did a
> > lot of other bus-specific drivers, before the hardware became present on
> > other architectures.  So no need to bury it under a msm specific
> > location.
> 
> Not sure if anything is stopping it from moving off of MSM chips, but it
> doesn't seem very likely.  There are too many similar interfaces that
> are standard that others would be likely to use.  For the most part, it
> is the bus to communicate between the MSM and it's specialized
> peripherals.
> 
> We can still put it there, but it will likely be the only driver ever in
> the directory.

Ah, so it's just one driver?  Then how about drivers/platform/msm/ ?

thanks,

greg k-h

^ permalink raw reply

* [PATCH v2 2/2] msm: add single-wire serial bus interface (SSBI) driver
From: David Brown @ 2011-02-25  3:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20110225032856.GA8475@suse.de>

On Thu, Feb 24 2011, Greg KH wrote:

> drivers/ssbi?  What's keeping this from later moving off of the msm
> chips to run on others?  USB started out only on one processor, as did a
> lot of other bus-specific drivers, before the hardware became present on
> other architectures.  So no need to bury it under a msm specific
> location.

Not sure if anything is stopping it from moving off of MSM chips, but it
doesn't seem very likely.  There are too many similar interfaces that
are standard that others would be likely to use.  For the most part, it
is the bus to communicate between the MSM and it's specialized
peripherals.

We can still put it there, but it will likely be the only driver ever in
the directory.

David

-- 
Sent by an employee of the Qualcomm Innovation Center, Inc.
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.

^ permalink raw reply

* Question about free_pgd_slow ?
From: rocky @ 2011-02-25  3:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,all

free_pgd_slow in arch/arm/mm/pgd.c  free the 4 pages at pgd level,
while could I ask a question about why free the page by pointed by pgd index 0 ?

cannot figure it out, any tips ?

thanks


rocky




       

^ permalink raw reply

* [PATCH v2 2/2] msm: add single-wire serial bus interface (SSBI) driver
From: Greg KH @ 2011-02-25  3:28 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <8ya8vx4dcky.fsf@huya.qualcomm.com>

On Thu, Feb 24, 2011 at 07:20:45PM -0800, David Brown wrote:
> On Thu, Feb 24 2011, Dima Zavin wrote:
> 
> > On that note, should we have a "drivers/arm/msm" instead of just
> > "drivers/msm"? Other non-msm arm sub-arches probably have the same
> > problem and polluting drivers/ top-level for every arm-subarch maybe
> > undesirable.
> 
> I'm moving linux-kernel to the 'to' field, and adding Greg KH to CC.
> 
> This is about a new driver (ssbi) for the MSM chips, and where the
> driver for this should go.  The driver is specific to MSM chips (as far
> as I know, the bus is only supported there).  There are likely to be
> future msm-specific drivers, so the suggestion was to put this under
> drivers/msm, or possibly drivers/arm/msm.
> 
> Anyone other suggestions, or preferences for the location?

drivers/ssbi?  What's keeping this from later moving off of the msm
chips to run on others?  USB started out only on one processor, as did a
lot of other bus-specific drivers, before the hardware became present on
other architectures.  So no need to bury it under a msm specific
location.

Hope this helps,

greg k-h

^ 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