LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH 6/7] Add mpc512x_find_ips_freq
From: Grant Likely @ 2008-01-08 17:27 UTC (permalink / raw)
  To: John Rigby; +Cc: linuxppc-dev
In-Reply-To: <1199808093-15929-7-git-send-email-jrigby@freescale.com>

Looks good to me; but I'd just merge this one with the earlier patch
that adds 5121 board support.

Cheers,
g.

On 1/8/08, John Rigby <jrigby@freescale.com> wrote:
> Added mpc512x_find_ips_freq needed by the following
> serial driver patch.  It is basically a renamed
> mpc512x_find_ipd_freq from 52xx.
>
> Signed-off-by: John Rigby <jrigby@freescale.com>
> ---
>  arch/powerpc/platforms/512x/mpc5121_ads.c |   28 ++++++++++++++++++++++++++++
>  include/asm-powerpc/mpc512x.h             |   22 ++++++++++++++++++++++
>  2 files changed, 50 insertions(+), 0 deletions(-)
>  create mode 100644 include/asm-powerpc/mpc512x.h
>
> diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
> index a860bf0..2f4cfee 100644
> --- a/arch/powerpc/platforms/512x/mpc5121_ads.c
> +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
> @@ -36,6 +36,34 @@
>  #include <asm/time.h>
>  #include <asm/of_platform.h>
>
> +/**
> + *     mpc512x_find_ips_freq - Find the IPB bus frequency for a device
> + *     @node:  device node
> + *
> + *     Returns IPS bus frequency, or 0 if the bus frequency cannot be found.
> + */
> +unsigned long
> +mpc512x_find_ips_freq(struct device_node *node)
> +{
> +       struct device_node *np;
> +       const unsigned int *p_ips_freq = NULL;
> +
> +       of_node_get(node);
> +       while (node) {
> +               p_ips_freq = of_get_property(node, "bus-frequency", NULL);
> +               if (p_ips_freq)
> +                       break;
> +
> +               np = of_get_parent(node);
> +               of_node_put(node);
> +               node = np;
> +       }
> +       if (node)
> +               of_node_put(node);
> +
> +       return p_ips_freq ? *p_ips_freq : 0;
> +}
> +
>  static void __init mpc5121_ads_setup_arch(void)
>  {
>         if (ppc_md.progress)
> diff --git a/include/asm-powerpc/mpc512x.h b/include/asm-powerpc/mpc512x.h
> new file mode 100644
> index 0000000..c48a165
> --- /dev/null
> +++ b/include/asm-powerpc/mpc512x.h
> @@ -0,0 +1,22 @@
> +/*
> + * Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
> + *
> + * Author: John Rigby, <jrigby@freescale.com>, Friday Apr 13 2007
> + *
> + * Description:
> + * MPC5121 Prototypes and definitions
> + *
> + * This 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.
> + *
> + */
> +
> +#ifndef __ASM_POWERPC_MPC512x_H__
> +#define __ASM_POWERPC_MPC512x_H__
> +
> +extern unsigned long mpc512x_find_ips_freq(struct device_node *node);
> +
> +#endif /* __ASM_POWERPC_MPC512x_H__ */
> +
> --
> 1.5.3.5.726.g41a7a
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>


-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH 3/7] Basic Freescale MPC512x support
From: Olof Johansson @ 2008-01-08 17:40 UTC (permalink / raw)
  To: John Rigby; +Cc: linuxppc-dev
In-Reply-To: <1199808093-15929-4-git-send-email-jrigby@freescale.com>

Hi,


> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> index 66a3d8c..81c3f05 100644
> --- a/arch/powerpc/Kconfig
> +++ b/arch/powerpc/Kconfig
> @@ -470,7 +470,7 @@ config PCI
>  	bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
>  		|| PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
>  		|| PPC_PS3
> -	default y if !40x && !CPM2 && !8xx && !PPC_83xx \
> +	default y if !40x && !CPM2 && !8xx && !PPC_512x && !PPC_83xx \
>  		&& !PPC_85xx && !PPC_86xx

This is getting out of control. Not a comment to this specific patch,
but it's getting silly.

Btw, why no PCI by default on this platform when it seemingly is default
on 5200? I thought they were fairly similar.

> diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
> new file mode 100644
> index 0000000..399d279
> --- /dev/null
> +++ b/arch/powerpc/platforms/512x/Kconfig
> @@ -0,0 +1,20 @@
> +menu "Platform support"
> +	depends on PPC_512x
> +
> +choice
> +	prompt "Machine Type"
> +	default MPC5121_ADS
> +
> +config MPC5121_ADS
> +	bool "Freescale MPC5121E ADS"
> +	select DEFAULT_UIMAGE
> +	help
> +	  This option enables support for the MPC5121E ADS board.
> +
> +endchoice

For new platforms it makes more sense to make it possible to build
multiplatform kernels instead of using 'choice'.

I know some embedded board guys prefer to build a custom kernel for just
their board (since it means extra revenue for them to spin a kernel
for every customer), but it's still convenient to be able to build
multiplatform kernels. Especially since there's some companies out there
with intent to make end-user products with this cpu.

> @@ -0,0 +1,90 @@
> +#include <asm/system.h>
> +#include <asm/atomic.h>
> +#include <asm/machdep.h>
> +#include <asm/ipic.h>
> +#include <asm/prom.h>
> +#include <asm/time.h>
> +#include <asm/of_platform.h>

Stephen will tell you to include linux/of_platform.h instead. :-)

> @@ -229,7 +229,7 @@ config NR_CPUS
>  
>  config NOT_COHERENT_CACHE
>  	bool
> -	depends on 4xx || 8xx || E200
> +	depends on 4xx || 8xx || E200 || PPC_512x
>  	default y

Why do you need this, when 5200 doesn't?


-Olof

^ permalink raw reply

* Re: [PATCH 7/7] Add MPC512x PSC serial driver
From: Grant Likely @ 2008-01-08 17:32 UTC (permalink / raw)
  To: John Rigby; +Cc: linuxppc-dev
In-Reply-To: <1199808093-15929-8-git-send-email-jrigby@freescale.com>

Exactly *how* different is the 5121 PSC from the 5200 PSC?  If it is
really different, then it makes sense to clone.  In fact; I'd
duplicate the mpc52xx_psc.h file also to avoid any crossover.

However, if the differences are manegable, I'd rather see a single
driver that can drive either type of PSC.  In fact, can you post a
diff between this driver and the original PSC driver?

Cheers,
g.

On 1/8/08, John Rigby <jrigby@freescale.com> wrote:
> mpc512x_uart.c is based on mpc52xx_uart.c with
>     names changed
>     arch/ppc support removed
>     512x psc fifo support added
>     shares mpc52xx_psc.h with 52xx driver
>
> Signed-off-by: John Rigby <jrigby@freescale.com>
> ---
>  drivers/serial/Kconfig            |   18 +
>  drivers/serial/Makefile           |    1 +
>  drivers/serial/mpc512x_uart.c     |  969 +++++++++++++++++++++++++++++++++++++
>  include/asm-powerpc/mpc52xx_psc.h |   47 ++
>  4 files changed, 1035 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/serial/mpc512x_uart.c
>
> diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
> index d7e1996..643b84a 100644
> --- a/drivers/serial/Kconfig
> +++ b/drivers/serial/Kconfig
> @@ -1113,6 +1113,24 @@ config SERIAL_SGI_L1_CONSOLE
>                 controller serial port as your console (you want this!),
>                 say Y.  Otherwise, say N.
>
> +config SERIAL_MPC512x
> +       tristate "Freescale MPC512x family PSC serial support"
> +       depends on PPC_512x
> +       select SERIAL_CORE
> +       help
> +         This drivers support the MPC512x PSC serial ports. If you would
> +         like to use them, you must answer Y or M to this option. Not that
> +         for use as console, it must be included in kernel and not as a
> +         module.
> +
> +config SERIAL_MPC512x_CONSOLE
> +       bool "Console on a Freescale MPC512x family PSC serial port"
> +       depends on SERIAL_MPC512x=y
> +       select SERIAL_CORE_CONSOLE
> +       help
> +         Select this options if you'd like to use one of the PSC serial port
> +         of the Freescale MPC52xx family as a console.
> +
>  config SERIAL_MPC52xx
>         tristate "Freescale MPC52xx family PSC serial support"
>         depends on PPC_MPC52xx
> diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
> index af6377d..13e8176 100644
> --- a/drivers/serial/Makefile
> +++ b/drivers/serial/Makefile
> @@ -48,6 +48,7 @@ obj-$(CONFIG_SERIAL_SH_SCI) += sh-sci.o
>  obj-$(CONFIG_SERIAL_SGI_L1_CONSOLE) += sn_console.o
>  obj-$(CONFIG_SERIAL_CPM) += cpm_uart/
>  obj-$(CONFIG_SERIAL_IMX) += imx.o
> +obj-$(CONFIG_SERIAL_MPC512x) += mpc512x_uart.o
>  obj-$(CONFIG_SERIAL_MPC52xx) += mpc52xx_uart.o
>  obj-$(CONFIG_SERIAL_ICOM) += icom.o
>  obj-$(CONFIG_SERIAL_M32R_SIO) += m32r_sio.o
> diff --git a/drivers/serial/mpc512x_uart.c b/drivers/serial/mpc512x_uart.c
> new file mode 100644
> index 0000000..e2ff0b8
> --- /dev/null
> +++ b/drivers/serial/mpc512x_uart.c
> @@ -0,0 +1,969 @@
> +/*
> + * Driver for the PSC of the Freescale MPC512x PSCs configured as UARTs.
> + *
> + * Copyright (C) 2007 Freescale Semiconductor Inc
> + * John Rigby <jrigby@freescale.com>
> + *
> + * Fork of mpc512x_uart.c:
> + *
> + *     Copyright (C) 2006 Secret Lab Technologies Ltd.
> + *                        Grant Likely <grant.likely@secretlab.ca>
> + *     Copyright (C) 2004-2006 Sylvain Munaut <tnt@246tNt.com>
> + *     Copyright (C) 2003 MontaVista, Software, Inc.
> + *                           Dale Farnsworth <dfarnsworth@mvista.com>.
> + *
> + * This file is licensed under the terms of the GNU General Public License
> + * version 2. This program is licensed "as is" without any warranty of any
> + * kind, whether express or implied.
> + */
> +
> +/*
> + * The 512x PSCs are almost identical to those on 52xx.  The most notable
> + * difference is that the FIFOs have been separated out.  This file
> + * still uses the mpc52xx_psc.h which has had the fifo differences added.
> + *
> + * TODO (maybe) abstract out the fifo differences and merge this back
> + * into mpc512x_serial.c
> + */
> +
> +/* OF Platform device Usage :
> + *
> + * This driver is only used for PSCs configured in uart mode.  The device
> + * tree will have a node for each PSC in uart mode w/ device_type = "serial"
> + * and "mpc52xx-psc-uart" in the compatible string
> + *
> + * By default, PSC devices are enumerated in the order they are found.  However
> + * a particular PSC number can be forced by adding 'device_no = <port#>'
> + * to the device node.
> + *
> + * The driver init all necessary registers to place the PSC in uart mode without
> + * DCD. However, the pin multiplexing aren't changed and should be set either
> + * by the bootloader or in the platform init code.
> + */
> +
> +#undef DEBUG
> +
> +#include <linux/device.h>
> +#include <linux/module.h>
> +#include <linux/tty.h>
> +#include <linux/serial.h>
> +#include <linux/sysrq.h>
> +#include <linux/console.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +
> +#include <asm/of_platform.h>
> +#include <asm/mpc52xx_psc.h>
> +#include <asm/mpc512x.h>
> +
> +#if defined(CONFIG_SERIAL_MPC512x_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
> +#define SUPPORT_SYSRQ
> +#endif
> +
> +#include <linux/serial_core.h>
> +
> +/* We've been assigned a range on the "Low-density serial ports" major */
> +#define SERIAL_PSC_MAJOR       204
> +#define SERIAL_PSC_MINOR       148
> +
> +#define ISR_PASS_LIMIT 256     /* Max number of iteration in the interrupt */
> +
> +static struct uart_port mpc512x_uart_ports[MPC52xx_PSC_MAXNUM];
> +
> +/* lookup table for matching device nodes to index numbers */
> +static struct device_node *mpc512x_uart_nodes[MPC52xx_PSC_MAXNUM];
> +
> +static void mpc512x_uart_of_enumerate(void);
> +
> +static unsigned long getuartclk(void *p)
> +{
> +       return mpc512x_find_ips_freq(p);
> +}
> +
> +#define PSC(port) ((struct mpc52xx_psc __iomem *)((port)->membase))
> +#define FIFO(port) ((struct mpc512x_psc_fifo __iomem *)(PSC(port)+1))
> +
> +/* Forward declaration of the interruption handling routine */
> +static irqreturn_t mpc512x_uart_int(int irq, void *dev_id);
> +
> +/* Simple macro to test if a port is console or not. This one is taken
> + * for serial_core.c and maybe should be moved to serial_core.h ? */
> +#ifdef CONFIG_SERIAL_CORE_CONSOLE
> +#define uart_console(port) ((port)->cons && (port)->cons->index == (port)->line)
> +#else
> +#define uart_console(port) (0)
> +#endif
> +
> +static struct of_device_id mpc512x_uart_of_match[] = {
> +       {.type = "serial", .compatible = "mpc512x-psc-uart",},
> +       {},
> +};
> +
> +/* ======================================================================== */
> +/* UART operations                                                          */
> +/* ======================================================================== */
> +
> +static unsigned int mpc512x_uart_tx_empty(struct uart_port *port)
> +{
> +       int status;
> +
> +       status = in_be32(&FIFO(port)->txsr);
> +       return (status & MPC512x_PSC_FIFO_EMPTY) ? TIOCSER_TEMT : 0;
> +}
> +
> +static void mpc512x_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
> +{
> +       /* Not implemented */
> +}
> +
> +static unsigned int mpc512x_uart_get_mctrl(struct uart_port *port)
> +{
> +       /* Not implemented */
> +       return TIOCM_CTS | TIOCM_DSR | TIOCM_CAR;
> +}
> +
> +static void mpc512x_uart_stop_tx(struct uart_port *port)
> +{
> +       /* port->lock taken by caller */
> +       unsigned long tx_fifo_imr;
> +
> +       tx_fifo_imr = in_be32(&FIFO(port)->tximr);
> +       tx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
> +       out_be32(&FIFO(port)->tximr, tx_fifo_imr);
> +}
> +
> +static void mpc512x_uart_start_tx(struct uart_port *port)
> +{
> +       /* port->lock taken by caller */
> +       unsigned long tx_fifo_imr;
> +
> +       tx_fifo_imr = in_be32(&FIFO(port)->tximr);
> +       tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM;
> +       out_be32(&FIFO(port)->tximr, tx_fifo_imr);
> +}
> +
> +static void mpc512x_uart_send_xchar(struct uart_port *port, char ch)
> +{
> +       unsigned long flags;
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       port->x_char = ch;
> +       if (ch) {
> +               /* Make sure tx interrupts are on */
> +               /* Truly necessary ??? They should be anyway */
> +               unsigned long tx_fifo_imr;
> +
> +               tx_fifo_imr = in_be32(&FIFO(port)->tximr);
> +               tx_fifo_imr |= MPC512x_PSC_FIFO_ALARM;
> +               out_be32(&FIFO(port)->tximr, tx_fifo_imr);
> +       }
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static void mpc512x_uart_stop_rx(struct uart_port *port)
> +{
> +       /* port->lock taken by caller */
> +       unsigned long rx_fifo_imr;
> +
> +       rx_fifo_imr = in_be32(&FIFO(port)->rximr);
> +       rx_fifo_imr &= ~MPC512x_PSC_FIFO_ALARM;
> +       out_be32(&FIFO(port)->rximr, rx_fifo_imr);
> +}
> +
> +static void mpc512x_uart_enable_ms(struct uart_port *port)
> +{
> +       /* Not implemented */
> +}
> +
> +static void mpc512x_uart_break_ctl(struct uart_port *port, int ctl)
> +{
> +       unsigned long flags;
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       if (ctl == -1)
> +               out_8(&PSC(port)->command, MPC52xx_PSC_START_BRK);
> +       else
> +               out_8(&PSC(port)->command, MPC52xx_PSC_STOP_BRK);
> +
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static void mpc512x_uart_fifo_init(struct mpc52xx_psc *psc)
> +{
> +       struct mpc512x_psc_fifo *fifo;
> +
> +       /* fifo is right after the psc */
> +       fifo = (struct mpc512x_psc_fifo *)(psc + 1);
> +
> +       out_be32(&fifo->txcmd, MPC512x_PSC_FIFO_RESET_SLICE);
> +       out_be32(&fifo->txcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
> +       out_be32(&fifo->txalarm, 1);
> +       out_be32(&fifo->tximr, 0);
> +
> +       out_be32(&fifo->rxcmd, MPC512x_PSC_FIFO_RESET_SLICE);
> +       out_be32(&fifo->rxcmd, MPC512x_PSC_FIFO_ENABLE_SLICE);
> +       out_be32(&fifo->rxalarm, 1);
> +       out_be32(&fifo->rximr, 0);
> +}
> +
> +static int mpc512x_uart_startup(struct uart_port *port)
> +{
> +       struct mpc52xx_psc __iomem *psc = PSC(port);
> +       int ret;
> +
> +       /* Request IRQ */
> +       ret = request_irq(port->irq, mpc512x_uart_int,
> +                         IRQF_DISABLED | IRQF_SAMPLE_RANDOM,
> +                         "mpc512x_psc_uart", port);
> +       if (ret)
> +               return ret;
> +
> +       /* Reset/activate the port, clear and enable interrupts */
> +       out_8(&psc->command, MPC52xx_PSC_RST_RX);
> +       out_8(&psc->command, MPC52xx_PSC_RST_TX);
> +
> +       out_be32(&psc->sicr, 0);        /* UART mode DCD ignored */
> +
> +       mpc512x_uart_fifo_init(psc);
> +
> +       out_be32(&FIFO(port)->tximr, MPC512x_PSC_FIFO_ALARM);
> +       out_be32(&FIFO(port)->rximr, MPC512x_PSC_FIFO_ALARM);
> +
> +       out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
> +       out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
> +
> +       return 0;
> +}
> +
> +static void mpc512x_uart_shutdown(struct uart_port *port)
> +{
> +       struct mpc52xx_psc __iomem *psc = PSC(port);
> +
> +       /* Shut down the port.  Leave TX active if on a console port */
> +       out_8(&psc->command, MPC52xx_PSC_RST_RX);
> +       if (!uart_console(port))
> +               out_8(&psc->command, MPC52xx_PSC_RST_TX);
> +
> +       out_be32(&FIFO(port)->tximr, 0);
> +       out_be32(&FIFO(port)->rximr, 0);
> +
> +       /* Release interrupt */
> +       free_irq(port->irq, port);
> +}
> +
> +static void
> +mpc512x_uart_set_termios(struct uart_port *port, struct ktermios *new,
> +                        struct ktermios *old)
> +{
> +       struct mpc52xx_psc __iomem *psc = PSC(port);
> +       unsigned long flags;
> +       unsigned char mr1, mr2;
> +       unsigned short ctr;
> +       unsigned int j, baud, quot;
> +       struct mpc512x_psc_fifo *fifo = FIFO(port);
> +
> +       /* Prepare what we're gonna write */
> +       mr1 = 0;
> +
> +       switch (new->c_cflag & CSIZE) {
> +       case CS5:
> +               mr1 |= MPC52xx_PSC_MODE_5_BITS;
> +               break;
> +       case CS6:
> +               mr1 |= MPC52xx_PSC_MODE_6_BITS;
> +               break;
> +       case CS7:
> +               mr1 |= MPC52xx_PSC_MODE_7_BITS;
> +               break;
> +       case CS8:
> +       default:
> +               mr1 |= MPC52xx_PSC_MODE_8_BITS;
> +       }
> +
> +       if (new->c_cflag & PARENB) {
> +               mr1 |= (new->c_cflag & PARODD) ?
> +                   MPC52xx_PSC_MODE_PARODD : MPC52xx_PSC_MODE_PAREVEN;
> +       } else
> +               mr1 |= MPC52xx_PSC_MODE_PARNONE;
> +
> +       mr2 = 0;
> +
> +       if (new->c_cflag & CSTOPB)
> +               mr2 |= MPC52xx_PSC_MODE_TWO_STOP;
> +       else
> +               mr2 |= ((new->c_cflag & CSIZE) == CS5) ?
> +                   MPC52xx_PSC_MODE_ONE_STOP_5_BITS :
> +                   MPC52xx_PSC_MODE_ONE_STOP;
> +
> +       baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16);
> +       quot = uart_get_divisor(port, baud);
> +       ctr = quot & 0xffff;
> +
> +       /* Get the lock */
> +       spin_lock_irqsave(&port->lock, flags);
> +
> +       /* Update the per-port timeout */
> +       uart_update_timeout(port, new->c_cflag, baud);
> +
> +       /* Do our best to flush TX & RX, so we don't loose anything */
> +       /* But we don't wait indefinitly ! */
> +       j = 5000000;            /* Maximum wait */
> +       /* FIXME Can't receive chars since set_termios might be called at early
> +        * boot for the console, all stuff is not yet ready to receive at that
> +        * time and that just makes the kernel oops */
> +       /* while (j-- && mpc512x_uart_int_rx_chars(port)); */
> +       while (!(in_be32(&fifo->txsr) & MPC512x_PSC_FIFO_EMPTY) && --j)
> +               udelay(1);
> +
> +       if (!j)
> +               printk(KERN_ERR "mpc512x_uart.c: "
> +                      "Unable to flush RX & TX fifos in-time in set_termios."
> +                      "Some chars may have been lost.\n");
> +
> +       /* Reset the TX & RX */
> +       out_8(&psc->command, MPC52xx_PSC_RST_RX);
> +       out_8(&psc->command, MPC52xx_PSC_RST_TX);
> +
> +       /* Send new mode settings */
> +       out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
> +       out_8(&psc->mode, mr1);
> +       out_8(&psc->mode, mr2);
> +       out_8(&psc->ctur, ctr >> 8);
> +       out_8(&psc->ctlr, ctr & 0xff);
> +
> +       /* Reenable TX & RX */
> +       out_8(&psc->command, MPC52xx_PSC_TX_ENABLE);
> +       out_8(&psc->command, MPC52xx_PSC_RX_ENABLE);
> +
> +       /* We're all set, release the lock */
> +       spin_unlock_irqrestore(&port->lock, flags);
> +}
> +
> +static const char *mpc512x_uart_type(struct uart_port *port)
> +{
> +       return port->type == PORT_MPC52xx ? "MPC52xx PSC" : NULL;
> +}
> +
> +static void mpc512x_uart_release_port(struct uart_port *port)
> +{
> +       /* remapped by us ? */
> +       if (port->flags & UPF_IOREMAP) {
> +               iounmap(port->membase);
> +               port->membase = NULL;
> +       }
> +
> +       release_mem_region(port->mapbase, sizeof(struct mpc52xx_psc));
> +}
> +
> +static int mpc512x_uart_request_port(struct uart_port *port)
> +{
> +       int err;
> +
> +       if (port->flags & UPF_IOREMAP)  /* Need to remap ? */
> +               port->membase = ioremap(port->mapbase,
> +                                       sizeof(struct mpc52xx_psc));
> +
> +       if (!port->membase)
> +               return -EINVAL;
> +
> +       err = request_mem_region(port->mapbase, sizeof(struct mpc52xx_psc),
> +                                "mpc512x_psc_uart") != NULL ? 0 : -EBUSY;
> +
> +       if (err && (port->flags & UPF_IOREMAP)) {
> +               iounmap(port->membase);
> +               port->membase = NULL;
> +       }
> +
> +       return err;
> +}
> +
> +static void mpc512x_uart_config_port(struct uart_port *port, int flags)
> +{
> +       if ((flags & UART_CONFIG_TYPE) &&
> +           (mpc512x_uart_request_port(port) == 0))
> +               port->type = PORT_MPC52xx;
> +}
> +
> +static int
> +mpc512x_uart_verify_port(struct uart_port *port, struct serial_struct *ser)
> +{
> +       if (ser->type != PORT_UNKNOWN && ser->type != PORT_MPC52xx)
> +               return -EINVAL;
> +
> +       if ((ser->irq != port->irq) ||
> +           (ser->io_type != SERIAL_IO_MEM) ||
> +           (ser->baud_base != port->uartclk) ||
> +           (ser->iomem_base != (void *)port->mapbase) || (ser->hub6 != 0))
> +               return -EINVAL;
> +
> +       return 0;
> +}
> +
> +static struct uart_ops mpc512x_uart_ops = {
> +       .tx_empty = mpc512x_uart_tx_empty,
> +       .set_mctrl = mpc512x_uart_set_mctrl,
> +       .get_mctrl = mpc512x_uart_get_mctrl,
> +       .stop_tx = mpc512x_uart_stop_tx,
> +       .start_tx = mpc512x_uart_start_tx,
> +       .send_xchar = mpc512x_uart_send_xchar,
> +       .stop_rx = mpc512x_uart_stop_rx,
> +       .enable_ms = mpc512x_uart_enable_ms,
> +       .break_ctl = mpc512x_uart_break_ctl,
> +       .startup = mpc512x_uart_startup,
> +       .shutdown = mpc512x_uart_shutdown,
> +       .set_termios = mpc512x_uart_set_termios,
> +/*     .pm             = mpc512x_uart_pm,              Not supported yet */
> +/*     .set_wake       = mpc512x_uart_set_wake,        Not supported yet */
> +       .type = mpc512x_uart_type,
> +       .release_port = mpc512x_uart_release_port,
> +       .request_port = mpc512x_uart_request_port,
> +       .config_port = mpc512x_uart_config_port,
> +       .verify_port = mpc512x_uart_verify_port
> +};
> +
> +/* ======================================================================== */
> +/* Interrupt handling                                                       */
> +/* ======================================================================== */
> +
> +static inline int mpc512x_uart_int_rx_chars(struct uart_port *port)
> +{
> +       struct tty_struct *tty = port->info->tty;
> +       unsigned char ch, flag;
> +       unsigned short status;
> +       unsigned long fifostatus;
> +       struct mpc52xx_psc __iomem *psc = PSC(port);
> +       struct mpc512x_psc_fifo __iomem *fifo = FIFO(port);
> +
> +       /* While we can read, do so ! */
> +       while (1) {
> +               fifostatus = in_be32(&fifo->rxsr);
> +
> +               if (fifostatus & MPC512x_PSC_FIFO_EMPTY)
> +                       break;
> +
> +               status = in_be16(&psc->mpc52xx_psc_status);
> +
> +               /* Get the char */
> +               ch = in_8(&fifo->rxdata_8);
> +
> +               /* Handle sysreq char */
> +#ifdef SUPPORT_SYSRQ
> +               if (uart_handle_sysrq_char(port, ch)) {
> +                       port->sysrq = 0;
> +                       continue;
> +               }
> +#endif
> +
> +               /* Store it */
> +
> +               flag = TTY_NORMAL;
> +               port->icount.rx++;
> +
> +               if (status & (MPC52xx_PSC_SR_PE |
> +                             MPC52xx_PSC_SR_FE | MPC52xx_PSC_SR_RB)) {
> +
> +                       if (status & MPC52xx_PSC_SR_RB) {
> +                               flag = TTY_BREAK;
> +                               uart_handle_break(port);
> +                       } else if (status & MPC52xx_PSC_SR_PE)
> +                               flag = TTY_PARITY;
> +                       else if (status & MPC52xx_PSC_SR_FE)
> +                               flag = TTY_FRAME;
> +
> +                       /* Clear error condition */
> +                       out_8(&PSC(port)->command, MPC52xx_PSC_RST_ERR_STAT);
> +
> +               }
> +               tty_insert_flip_char(tty, ch, flag);
> +               if (status & MPC52xx_PSC_SR_OE) {
> +                       /*
> +                        * Overrun is special, since it's
> +                        * reported immediately, and doesn't
> +                        * affect the current character
> +                        */
> +                       tty_insert_flip_char(tty, 0, TTY_OVERRUN);
> +               }
> +       }
> +
> +       tty_flip_buffer_push(tty);
> +
> +       fifostatus = in_be32(&fifo->rxsr);
> +       return !(fifostatus & MPC512x_PSC_FIFO_EMPTY);
> +}
> +
> +static inline int mpc512x_uart_int_tx_chars(struct uart_port *port)
> +{
> +       struct circ_buf *xmit = &port->info->xmit;
> +       struct mpc512x_psc_fifo *fifo = FIFO(port);
> +
> +       /* Process out of band chars */
> +       if (port->x_char) {
> +               out_8(&fifo->txdata_8, port->x_char);
> +               port->icount.tx++;
> +               port->x_char = 0;
> +               return 1;
> +       }
> +
> +       /* Nothing to do ? */
> +       if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
> +               mpc512x_uart_stop_tx(port);
> +               return 0;
> +       }
> +
> +       /* Send chars */
> +       while (!(in_be32(&fifo->txsr) & MPC512x_PSC_FIFO_FULL)) {
> +               out_8(&fifo->txdata_8, xmit->buf[xmit->tail]);
> +               xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
> +               port->icount.tx++;
> +               if (uart_circ_empty(xmit))
> +                       break;
> +       }
> +
> +       /* Wake up */
> +       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
> +               uart_write_wakeup(port);
> +
> +       /* Maybe we're done after all */
> +       if (uart_circ_empty(xmit)) {
> +               mpc512x_uart_stop_tx(port);
> +               return 0;
> +       }
> +
> +       return 1;
> +}
> +
> +static irqreturn_t mpc512x_uart_int(int irq, void *dev_id)
> +{
> +       struct uart_port *port = dev_id;
> +       unsigned long pass = ISR_PASS_LIMIT;
> +       unsigned int keepgoing;
> +       unsigned long rx_fifo_status;
> +       unsigned long tx_fifo_status;
> +
> +       spin_lock(&port->lock);
> +
> +       /* While we have stuff to do, we continue */
> +       do {
> +               /* If we don't find anything to do, we stop */
> +               keepgoing = 0;
> +
> +               /* clear any pending interrupts */
> +               out_be32(&FIFO(port)->rxisr, in_be32(&FIFO(port)->rxisr));
> +
> +               rx_fifo_status = in_be32(&FIFO(port)->rxsr);
> +               out_be32(&FIFO(port)->rxisr, rx_fifo_status);
> +               rx_fifo_status &= in_be32(&FIFO(port)->rximr);
> +
> +               if (rx_fifo_status & MPC512x_PSC_FIFO_ALARM)
> +                       keepgoing |= mpc512x_uart_int_rx_chars(port);
> +
> +               /* clear any pending interrupts */
> +               out_be32(&FIFO(port)->txisr, in_be32(&FIFO(port)->txisr));
> +
> +               tx_fifo_status = in_be32(&FIFO(port)->txsr);
> +               out_be32(&FIFO(port)->txisr, tx_fifo_status);
> +               tx_fifo_status &= in_be32(&FIFO(port)->tximr);
> +
> +               if (tx_fifo_status & MPC512x_PSC_FIFO_ALARM)
> +                       keepgoing |= mpc512x_uart_int_tx_chars(port);
> +
> +               /* Limit number of iteration */
> +               if (!(--pass))
> +                       keepgoing = 0;
> +
> +       } while (keepgoing);
> +
> +       spin_unlock(&port->lock);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +/* ======================================================================== */
> +/* Console ( if applicable )                                                */
> +/* ======================================================================== */
> +
> +#ifdef CONFIG_SERIAL_MPC512x_CONSOLE
> +
> +static void __init
> +mpc512x_console_get_options(struct uart_port *port,
> +                           int *baud, int *parity, int *bits, int *flow)
> +{
> +       struct mpc52xx_psc __iomem *psc = PSC(port);
> +       unsigned char mr1;
> +
> +       pr_debug("mpc512x_console_get_options(port=%p)\n", port);
> +
> +       /* Read the mode registers */
> +       out_8(&psc->command, MPC52xx_PSC_SEL_MODE_REG_1);
> +       mr1 = in_8(&psc->mode);
> +
> +       /* CT{U,L}R are write-only ! */
> +       *baud = 115200;
> +       /* Parse them */
> +       switch (mr1 & MPC52xx_PSC_MODE_BITS_MASK) {
> +       case MPC52xx_PSC_MODE_5_BITS:
> +               *bits = 5;
> +               break;
> +       case MPC52xx_PSC_MODE_6_BITS:
> +               *bits = 6;
> +               break;
> +       case MPC52xx_PSC_MODE_7_BITS:
> +               *bits = 7;
> +               break;
> +       case MPC52xx_PSC_MODE_8_BITS:
> +       default:
> +               *bits = 8;
> +       }
> +
> +       if (mr1 & MPC52xx_PSC_MODE_PARNONE)
> +               *parity = 'n';
> +       else
> +               *parity = mr1 & MPC52xx_PSC_MODE_PARODD ? 'o' : 'e';
> +}
> +
> +static void
> +mpc512x_console_write(struct console *co, const char *s, unsigned int count)
> +{
> +       struct uart_port *port = &mpc512x_uart_ports[co->index];
> +       unsigned int i, j;
> +       unsigned long rx_fifo_imr, tx_fifo_imr;
> +
> +       /* Disable interrupts */
> +       tx_fifo_imr = in_be32(&FIFO(port)->tximr);
> +       out_be32(&FIFO(port)->tximr, 0);
> +       rx_fifo_imr = in_be32(&FIFO(port)->rximr);
> +       out_be32(&FIFO(port)->rximr, 0);
> +
> +       /* Wait the TX buffer to be empty */
> +       j = 5000000;            /* Maximum wait */
> +       while (!(in_be32(&FIFO(port)->txsr) & MPC512x_PSC_FIFO_EMPTY) && --j)
> +               udelay(1);
> +       /* Write all the chars */
> +       for (i = 0; i < count; i++, s++) {
> +               /* Line return handling */
> +               if (*s == '\n')
> +                       out_8(&FIFO(port)->txdata_8, '\r');
> +
> +               /* Send the char */
> +               out_8(&FIFO(port)->txdata_8, *s);
> +
> +               /* Wait the TX buffer to be empty */
> +               j = 20000;      /* Maximum wait */
> +               while (!(in_be32(&FIFO(port)->txsr) & MPC512x_PSC_FIFO_EMPTY)
> +                      && --j)
> +                       udelay(1);
> +       }
> +
> +       /* Restore interrupt state */
> +       out_be32(&FIFO(port)->tximr, tx_fifo_imr);
> +       out_be32(&FIFO(port)->rximr, rx_fifo_imr);
> +}
> +
> +static int __init mpc512x_console_setup(struct console *co, char *options)
> +{
> +       struct uart_port *port = &mpc512x_uart_ports[co->index];
> +       struct device_node *np = mpc512x_uart_nodes[co->index];
> +       struct resource res;
> +
> +       int baud = 115200;
> +       int bits = 8;
> +       int parity = 'n';
> +       int flow = 'n';
> +
> +       pr_debug("mpc512x_console_setup co=%p, co->index=%i, options=%s\n",
> +                co, co->index, options);
> +
> +       if ((co->index < 0) || (co->index > MPC52xx_PSC_MAXNUM)) {
> +               pr_debug("PSC%x out of range\n", co->index);
> +               return -EINVAL;
> +       }
> +
> +       if (!np) {
> +               pr_debug("PSC%x not found in device tree\n", co->index);
> +               return -EINVAL;
> +       }
> +
> +       pr_debug("Console on ttyPSC%x is %s\n",
> +                co->index, mpc512x_uart_nodes[co->index]->full_name);
> +
> +       /* Fetch register locations */
> +       if (of_address_to_resource(np, 0, &res)) {
> +               pr_debug("Could not get resources for PSC%x\n", co->index);
> +               return -EINVAL;
> +       }
> +
> +       /* Basic port init. Needed since we use some uart_??? func before
> +        * real init for early access */
> +       spin_lock_init(&port->lock);
> +       port->uartclk = getuartclk(np);
> +       port->ops = &mpc512x_uart_ops;
> +       port->mapbase = res.start;
> +       port->membase = ioremap(res.start, sizeof(struct mpc52xx_psc));
> +       port->irq = irq_of_parse_and_map(np, 0);
> +
> +       if (port->membase == NULL)
> +               return -EINVAL;
> +
> +       pr_debug("mpc52xx-psc uart at %p, mapped to %p, irq=%x, freq=%i\n",
> +                (void *)port->mapbase, port->membase, port->irq,
> +                port->uartclk);
> +
> +       /* Setup the port parameters accoding to options */
> +       if (options)
> +               uart_parse_options(options, &baud, &parity, &bits, &flow);
> +       else
> +               mpc512x_console_get_options(port, &baud, &parity, &bits, &flow);
> +
> +       pr_debug("Setting console parameters: %i %i%c1 flow=%c\n",
> +                baud, bits, parity, flow);
> +
> +       return uart_set_options(port, co, baud, parity, bits, flow);
> +}
> +
> +static struct uart_driver mpc512x_uart_driver;
> +
> +static struct console mpc512x_console = {
> +       .name = "ttyPSC",
> +       .write = mpc512x_console_write,
> +       .device = uart_console_device,
> +       .setup = mpc512x_console_setup,
> +       .flags = CON_PRINTBUFFER,
> +       .index = -1,
> +       .data = &mpc512x_uart_driver,
> +};
> +
> +static int __init mpc512x_console_init(void)
> +{
> +       mpc512x_uart_of_enumerate();
> +       register_console(&mpc512x_console);
> +       return 0;
> +}
> +
> +console_initcall(mpc512x_console_init);
> +
> +#define MPC52xx_PSC_CONSOLE &mpc512x_console
> +#else
> +#define MPC52xx_PSC_CONSOLE NULL
> +#endif
> +
> +/* ======================================================================== */
> +/* UART Driver                                                              */
> +/* ======================================================================== */
> +
> +static struct uart_driver mpc512x_uart_driver = {
> +       .owner = THIS_MODULE,
> +       .driver_name = "mpc512x_psc_uart",
> +       .dev_name = "ttyPSC",
> +       .major = SERIAL_PSC_MAJOR,
> +       .minor = SERIAL_PSC_MINOR,
> +       .nr = MPC52xx_PSC_MAXNUM,
> +       .cons = MPC52xx_PSC_CONSOLE,
> +};
> +
> +/* ======================================================================== */
> +/* OF Platform Driver                                                       */
> +/* ======================================================================== */
> +
> +static int __devinit
> +mpc512x_uart_of_probe(struct of_device *op, const struct of_device_id *match)
> +{
> +       int idx = -1;
> +       struct uart_port *port = NULL;
> +       struct resource res;
> +       int ret;
> +
> +       dev_dbg(&op->dev, "mpc512x_uart_probe(op=%p, match=%p)\n", op, match);
> +
> +       /* Check validity & presence */
> +       for (idx = 0; idx < MPC52xx_PSC_MAXNUM; idx++)
> +               if (mpc512x_uart_nodes[idx] == op->node)
> +                       break;
> +       if (idx >= MPC52xx_PSC_MAXNUM)
> +               return -EINVAL;
> +       pr_debug("Found %s assigned to ttyPSC%x\n",
> +                mpc512x_uart_nodes[idx]->full_name, idx);
> +
> +       /* Init the port structure */
> +       port = &mpc512x_uart_ports[idx];
> +
> +       spin_lock_init(&port->lock);
> +       port->uartclk = getuartclk(op->node);
> +       port->fifosize = 512;
> +       port->iotype = UPIO_MEM;
> +       port->flags = UPF_BOOT_AUTOCONF |
> +           (uart_console(port) ? 0 : UPF_IOREMAP);
> +       port->line = idx;
> +       port->ops = &mpc512x_uart_ops;
> +       port->dev = &op->dev;
> +
> +       /* Search for IRQ and mapbase */
> +       if (of_address_to_resource(op->node, 0, &res))
> +               return -EINVAL;
> +
> +       port->mapbase = res.start;
> +       port->irq = irq_of_parse_and_map(op->node, 0);
> +
> +       dev_dbg(&op->dev, "mpc52xx-psc uart at %p, irq=%x, freq=%i\n",
> +               (void *)port->mapbase, port->irq, port->uartclk);
> +
> +       if ((port->irq == NO_IRQ) || !port->mapbase) {
> +               printk(KERN_ERR "Could not allocate resources for PSC\n");
> +               return -EINVAL;
> +       }
> +
> +       /* Add the port to the uart sub-system */
> +       ret = uart_add_one_port(&mpc512x_uart_driver, port);
> +       if (!ret)
> +               dev_set_drvdata(&op->dev, (void *)port);
> +
> +       return ret;
> +}
> +
> +static int mpc512x_uart_of_remove(struct of_device *op)
> +{
> +       struct uart_port *port = dev_get_drvdata(&op->dev);
> +       dev_set_drvdata(&op->dev, NULL);
> +
> +       if (port) {
> +               uart_remove_one_port(&mpc512x_uart_driver, port);
> +               irq_dispose_mapping(port->irq);
> +       }
> +
> +       return 0;
> +}
> +
> +#ifdef CONFIG_PM
> +static int mpc512x_uart_of_suspend(struct of_device *op, pm_message_t state)
> +{
> +       struct uart_port *port = (struct uart_port *)dev_get_drvdata(&op->dev);
> +
> +       if (port)
> +               uart_suspend_port(&mpc512x_uart_driver, port);
> +
> +       return 0;
> +}
> +
> +static int mpc512x_uart_of_resume(struct of_device *op)
> +{
> +       struct uart_port *port = (struct uart_port *)dev_get_drvdata(&op->dev);
> +
> +       if (port)
> +               uart_resume_port(&mpc512x_uart_driver, port);
> +
> +       return 0;
> +}
> +#endif
> +
> +static void mpc512x_uart_of_assign(struct device_node *np, int idx)
> +{
> +       int free_idx = -1;
> +       int i;
> +
> +       /* Find the first free node */
> +       for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
> +               if (mpc512x_uart_nodes[i] == NULL) {
> +                       free_idx = i;
> +                       break;
> +               }
> +       }
> +
> +       if ((idx < 0) || (idx >= MPC52xx_PSC_MAXNUM))
> +               idx = free_idx;
> +
> +       if (idx < 0)
> +               return;         /* No free slot; abort */
> +
> +       /* If the slot is already occupied, then swap slots */
> +       if (mpc512x_uart_nodes[idx] && (free_idx != -1))
> +               mpc512x_uart_nodes[free_idx] = mpc512x_uart_nodes[idx];
> +       mpc512x_uart_nodes[idx] = np;
> +}
> +
> +static void mpc512x_uart_of_enumerate(void)
> +{
> +       static int enum_done;
> +       struct device_node *np;
> +       const unsigned int *devno;
> +       int i;
> +
> +       if (enum_done)
> +               return;
> +
> +       for_each_node_by_type(np, "serial") {
> +               if (!of_match_node(mpc512x_uart_of_match, np))
> +                       continue;
> +
> +               /* Is a particular device number requested? */
> +               devno = of_get_property(np, "port-number", NULL);
> +               mpc512x_uart_of_assign(of_node_get(np), devno ? *devno : -1);
> +       }
> +
> +       enum_done = 1;
> +
> +       for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) {
> +               if (mpc512x_uart_nodes[i])
> +                       pr_debug("%s assigned to ttyPSC%x\n",
> +                                mpc512x_uart_nodes[i]->full_name, i);
> +       }
> +}
> +
> +MODULE_DEVICE_TABLE(of, mpc512x_uart_of_match);
> +
> +static struct of_platform_driver mpc512x_uart_of_driver = {
> +       .owner = THIS_MODULE,
> +       .name = "mpc52xx-psc-uart",
> +       .match_table = mpc512x_uart_of_match,
> +       .probe = mpc512x_uart_of_probe,
> +       .remove = mpc512x_uart_of_remove,
> +#ifdef CONFIG_PM
> +       .suspend = mpc512x_uart_of_suspend,
> +       .resume = mpc512x_uart_of_resume,
> +#endif
> +       .driver = {
> +                  .name = "mpc52xx-psc-uart",
> +                  },
> +};
> +
> +/* ======================================================================== */
> +/* Module                                                                   */
> +/* ======================================================================== */
> +
> +static int __init mpc512x_uart_init(void)
> +{
> +       int ret;
> +
> +       printk(KERN_INFO "Serial: MPC512x PSC UART driver\n");
> +
> +       ret = uart_register_driver(&mpc512x_uart_driver);
> +       if (ret) {
> +               printk(KERN_ERR "%s: uart_register_driver failed (%i)\n",
> +                      __FILE__, ret);
> +               return ret;
> +       }
> +
> +       mpc512x_uart_of_enumerate();
> +
> +       ret = of_register_platform_driver(&mpc512x_uart_of_driver);
> +       if (ret) {
> +               printk(KERN_ERR "%s: of_register_platform_driver failed (%i)\n",
> +                      __FILE__, ret);
> +               uart_unregister_driver(&mpc512x_uart_driver);
> +               return ret;
> +       }
> +       return 0;
> +}
> +
> +static void __exit mpc512x_uart_exit(void)
> +{
> +       of_unregister_platform_driver(&mpc512x_uart_of_driver);
> +       uart_unregister_driver(&mpc512x_uart_driver);
> +}
> +
> +module_init(mpc512x_uart_init);
> +module_exit(mpc512x_uart_exit);
> +
> +MODULE_AUTHOR("John Rigby <jrigby@freescale.com>");
> +MODULE_DESCRIPTION("Freescale MPC512x PSC UART");
> +MODULE_LICENSE("GPL");
> diff --git a/include/asm-powerpc/mpc52xx_psc.h b/include/asm-powerpc/mpc52xx_psc.h
> index bea42b9..6841868 100644
> --- a/include/asm-powerpc/mpc52xx_psc.h
> +++ b/include/asm-powerpc/mpc52xx_psc.h
> @@ -190,5 +190,52 @@ struct mpc52xx_psc_fifo {
>         u16             tflwfptr;       /* PSC + 0x9e */
>  };
>
> +#define MPC512x_PSC_FIFO_RESET_SLICE   0x80
> +#define MPC512x_PSC_FIFO_ENABLE_SLICE  0x01
> +
> +#define MPC512x_PSC_FIFO_EMPTY         0x1
> +#define MPC512x_PSC_FIFO_FULL          0x2
> +#define MPC512x_PSC_FIFO_ALARM         0x4
> +#define MPC512x_PSC_FIFO_URERR         0x8
> +#define MPC512x_PSC_FIFO_ORERR         0x01
> +#define MPC512x_PSC_FIFO_MEMERROR      0x02
> +
> +struct mpc512x_psc_fifo {
> +       u32             reserved1[10];
> +       u32             txcmd;          /* PSC + 0x80 */
> +       u32             txalarm;        /* PSC + 0x84 */
> +       u32             txsr;           /* PSC + 0x88 */
> +       u32             txisr;          /* PSC + 0x8c */
> +       u32             tximr;          /* PSC + 0x90 */
> +       u32             txcnt;          /* PSC + 0x94 */
> +       u32             txptr;          /* PSC + 0x98 */
> +       u32             txsz;           /* PSC + 0x9c */
> +       u32             reserved2[7];
> +       union {
> +               u8      txdata_8;
> +               u16     txdata_16;
> +               u32     txdata_32;
> +       } txdata;                       /* PSC + 0xbc */
> +#define txdata_8 txdata.txdata_8
> +#define txdata_16 txdata.txdata_16
> +#define txdata_32 txdata.txdata_32
> +       u32             rxcmd;          /* PSC + 0xc0 */
> +       u32             rxalarm;        /* PSC + 0xc4 */
> +       u32             rxsr;           /* PSC + 0xc8 */
> +       u32             rxisr;          /* PSC + 0xcc */
> +       u32             rximr;          /* PSC + 0xd0 */
> +       u32             rxcnt;          /* PSC + 0xd4 */
> +       u32             rxptr;          /* PSC + 0xd8 */
> +       u32             rxsz;           /* PSC + 0xdc */
> +       u32             reserved3[7];
> +       union {
> +               u8      rxdata_8;
> +               u16     rxdata_16;
> +               u32     rxdata_32;
> +       } rxdata;                       /* PSC + 0xfc */
> +#define rxdata_8 rxdata.rxdata_8
> +#define rxdata_16 rxdata.rxdata_16
> +#define rxdata_32 rxdata.rxdata_32
> +};
>
>  #endif  /* __ASM_MPC52xx_PSC_H__ */
> --
> 1.5.3.5.726.g41a7a
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@ozlabs.org
> https://ozlabs.org/mailman/listinfo/linuxppc-dev
>


-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* error : array type has incomplete element type
From: Rami @ 2008-01-08 17:02 UTC (permalink / raw)
  To: linuxppc-embedded


[-- Attachment #1.1: Type: text/plain, Size: 2927 bytes --]


 
Hi all,
 
I am trying to compile a kernel for the ppc405 embedded on the virtex 4 and
I am obtaining the compiling errors listed below(at the end of this mail).
 
my compiler is the crosstool latest one. 
 
I tried to compile each the following kernel versions :
2.6.23.8
2.6.17
 
with the following versions of gcc and glibc of the crosscompiler
gcc-4.0.2-glibc-2.3.5
gcc-4.1.0-glibc-2.3.6
gcc-4.1.1-glibc-2.3.6
 
the result is always the same (array type has incomplete element type)
 
moreover I searched all the files and I replaced 
            (struct ocp_def core_ocp[])        with  (struct ocp_def
core_ocp[2]) 
        because my architectur contains only one UART, the result is always
the same (same error).
 
 
any help is appreciated,
 
Rami
 
 
 
 
 
 
 
arch/ppc/syslib/virtex_devices.c:23: error: array type has incomplete
element type

arch/ppc/syslib/virtex_devices.c:25: error: field name not in record or
union initializer

arch/ppc/syslib/virtex_devices.c:25: error: (near initialization for
'core_ocp')

arch/ppc/syslib/virtex_devices.c:26: error: field name not in record or
union initializer

arch/ppc/syslib/virtex_devices.c:26: error: (near initialization for
'core_ocp')

arch/ppc/syslib/virtex_devices.c:27: error: field name not in record or
union initializer

arch/ppc/syslib/virtex_devices.c:27: error: (near initialization for
'core_ocp')

arch/ppc/syslib/virtex_devices.c:28: error: field name not in record or
union initializer

arch/ppc/syslib/virtex_devices.c:28: error: (near initialization for
'core_ocp')

arch/ppc/syslib/virtex_devices.c:29: error: field name not in record or
union initializer

arch/ppc/syslib/virtex_devices.c:29: error: (near initialization for
'core_ocp')

arch/ppc/syslib/virtex_devices.c:30: error: field name not in record or
union initializer

arch/ppc/syslib/virtex_devices.c:30: error: (near initialization for
'core_ocp')

arch/ppc/syslib/virtex_devices.c:30: error: 'OCP_CPM_NA' undeclared here
(not in a function)

arch/ppc/syslib/virtex_devices.c:63: error: field name not in record or
union initializer

arch/ppc/syslib/virtex_devices.c:63: error: (near initialization for
'core_ocp')


 

	

CONFIDENTIALITE : Ce message et les éventuelles pièces attachées sont
confidentiels. Si vous n'êtes pas dans la liste des destinataires, veuillez
informer l'expéditeur immédiatement et ne pas divulguer le contenu à une
tierce personne, ne pas l'utiliser pour quelque raison que ce soit, ne pas
stocker ou copier l'information qu'il contient sur un quelconque support. 

CONFIDENTIALITY : This e-mail and any attachments are confidential and may
be privileged. If you are not a named recipient, please notify the sender
immediately and do not disclose the contents to another person, use it for
any purpose or store or copy the information in any medium. 
	

[-- Attachment #1.2: Type: text/html, Size: 8111 bytes --]

[-- Attachment #2: wt2007bottom_RWE.gif --]
[-- Type: image/gif, Size: 9139 bytes --]

[-- Attachment #3: arbre-logo.gif --]
[-- Type: image/gif, Size: 2808 bytes --]

^ permalink raw reply

* Re: [PATCH 1/3] add default device trees for MPC837x MDS board
From: Scott Wood @ 2008-01-08 17:38 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, Li Yang, paulus
In-Reply-To: <fa686aa40801080758o35dce96ej5db45576769561a5@mail.gmail.com>

On Tue, Jan 08, 2008 at 08:58:17AM -0700, Grant Likely wrote:
> On 1/7/08, Li Yang <leoli@freescale.com> wrote:
> > +       soc@e0000000 {
> > +               #address-cells = <1>;
> > +               #size-cells = <1>;
> > +               device_type = "soc";
> 
> I recommend dropping device_type and adding 'compatible = "fsl,mpc8377-immr";'

I recommend fixing the code that looks for this device_type before
recommending that people drop it. :-)

> > +               wdt@200 {
> > +                       compatible = "mpc83xx_wdt";
> 
> "fsl,mpc8377_wdt", "fsl,mpc83xx_wdt" as per generic names recommended practice.

Speaking of generic names, can we change the node name to "watchdog"?

> > +               /* phy type (ULPI, UTMI, UTMI_WIDE, SERIAL) */
> > +               usb@23000 {
> > +                       compatible = "fsl-usb2-dr";
> > +                       reg = <23000 1000>;
> > +                       #address-cells = <1>;
> > +                       #size-cells = <0>;
> > +                       interrupt-parent = < &ipic >;
> > +                       interrupts = <26 8>;
> > +                       phy_type = "utmi_wide";
> 
> fsl,phy_type please.

Again, code will break.  Can we stop ambushing people submitting board
support with complaints against existing, non-board-specific code/device
trees?  Fix that first, then complain if new code reintroduces the crud.

Also, if we're going to change the property name, we should also change the
underscore to a dash.

> > +               enet0: ethernet@24000 {
> > +                       cell-index = <0>;
> > +                       device_type = "network";
> > +                       model = "eTSEC";
> 
> Drop model property

Fix the code that checks for it.

-Scott

^ permalink raw reply

* Re: [PATCH 3/7] Basic Freescale MPC512x support
From: Jon Loeliger @ 2008-01-08 17:44 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev, John Rigby
In-Reply-To: <20080108174038.GA20819@lixom.net>

So, like, the other day Olof Johansson mumbled:
> 
> > @@ -0,0 +1,90 @@
> > +#include <asm/system.h>
> > +#include <asm/atomic.h>
> > +#include <asm/machdep.h>
> > +#include <asm/ipic.h>
> > +#include <asm/prom.h>
> > +#include <asm/time.h>
> > +#include <asm/of_platform.h>
> 
> Stephen will tell you to include linux/of_platform.h instead. :-)

Yeah, watch me outright NAK it too. :-)

jdl

^ permalink raw reply

* Re: [PATCH 2/4] nand base: Give drivers a chance to do late initialization.
From: Scott Wood @ 2008-01-08 17:48 UTC (permalink / raw)
  To: David Woodhouse; +Cc: linuxppc-dev, linux-mtd
In-Reply-To: <1199779069.4111.379.camel@shinybook.infradead.org>

On Tue, Jan 08, 2008 at 07:57:49AM +0000, David Woodhouse wrote:
> 
> On Thu, 2007-12-13 at 11:15 -0600, Scott Wood wrote:
> > Some nand controllers, such as the Freescale enhanced local bus controller,
> > need to do late initialization based on details of the chip that has been
> > probed, such as chip size, large/small pages, etc.  A late_init() callback
> > method is added to allow this.
> 
> Do you really need this so late? Can't it be done between
> nand_scan_ident() and nand_scan_tail()? That's why we split nand_scan()
> into two in the first place...

Yeah, that'd work.  I'll send an updated driver soon.

-Scott

^ permalink raw reply

* Re: [PATCH 1/3] add default device trees for MPC837x MDS board
From: Grant Likely @ 2008-01-08 17:53 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, Li Yang, paulus
In-Reply-To: <20080108173845.GA5188@loki.buserror.net>

On 1/8/08, Scott Wood <scottwood@freescale.com> wrote:
> On Tue, Jan 08, 2008 at 08:58:17AM -0700, Grant Likely wrote:
> > On 1/7/08, Li Yang <leoli@freescale.com> wrote:
> > > +                       phy_type = "utmi_wide";
> >
> > fsl,phy_type please.
>
> Again, code will break.  Can we stop ambushing people submitting board
> support with complaints against existing, non-board-specific code/device
> trees?  Fix that first, then complain if new code reintroduces the crud.

I disagree (about bringing up these comments).  New board port is the
time to bring these issue up.  It keeps the issue in the forefront so
it actually gets fixed.

>
> Also, if we're going to change the property name, we should also change the
> underscore to a dash.

Good point, I missed that

g.

-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH 3/7] Basic Freescale MPC512x support
From: Scott Wood @ 2008-01-08 17:55 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, John Rigby
In-Reply-To: <fa686aa40801080919y7c426007vd031bb79e8f9a03d@mail.gmail.com>

On Tue, Jan 08, 2008 at 10:19:20AM -0700, Grant Likely wrote:
> > +config MPC5121_ADS
> > +       bool "Freescale MPC5121E ADS"
> > +       select DEFAULT_UIMAGE
> > +       help
> > +         This option enables support for the MPC5121E ADS board.
> 
> Make this depend on PPC_MULTIPLATFORM and PPC32

I don't think PPC_MULTIPLATFORM is appropriate here... it seems to be
OF-specific.

-Scott

^ permalink raw reply

* Re: [PATCH 3/7] Basic Freescale MPC512x support
From: Grant Likely @ 2008-01-08 17:56 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, John Rigby
In-Reply-To: <20080108175513.GC5188@loki.buserror.net>

On 1/8/08, Scott Wood <scottwood@freescale.com> wrote:
> On Tue, Jan 08, 2008 at 10:19:20AM -0700, Grant Likely wrote:
> > > +config MPC5121_ADS
> > > +       bool "Freescale MPC5121E ADS"
> > > +       select DEFAULT_UIMAGE
> > > +       help
> > > +         This option enables support for the MPC5121E ADS board.
> >
> > Make this depend on PPC_MULTIPLATFORM and PPC32
>
> I don't think PPC_MULTIPLATFORM is appropriate here... it seems to be
> OF-specific.

52xx is multiplatform.  It works well on both OF and non-OF boards.

Cheers,
g.


-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* Re: [PATCH 3/7] Basic Freescale MPC512x support
From: John Rigby @ 2008-01-08 18:01 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev
In-Reply-To: <20080108174038.GA20819@lixom.net>

Olof Johansson wrote:
> Hi,
>
>
>   
>> diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
>> index 66a3d8c..81c3f05 100644
>> --- a/arch/powerpc/Kconfig
>> +++ b/arch/powerpc/Kconfig
>> @@ -470,7 +470,7 @@ config PCI
>>  	bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_85xx || PPC_86xx \
>>  		|| PPC_MPC52xx || (EMBEDDED && (PPC_PSERIES || PPC_ISERIES)) \
>>  		|| PPC_PS3
>> -	default y if !40x && !CPM2 && !8xx && !PPC_83xx \
>> +	default y if !40x && !CPM2 && !8xx && !PPC_512x && !PPC_83xx \
>>  		&& !PPC_85xx && !PPC_86xx
>>     
>
> This is getting out of control. Not a comment to this specific patch,
> but it's getting silly.
>
> Btw, why no PCI by default on this platform when it seemingly is default
> on 5200? I thought they were fairly similar.
>   

PCI has issues in first silicon so I left that out.

Also contrary to popular rumor, 5121 is more like a 83xx that 52xx.
The PCI and USB are very similar to 83xx.


>   
>> diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
>> new file mode 100644
>> index 0000000..399d279
>> --- /dev/null
>> +++ b/arch/powerpc/platforms/512x/Kconfig
>> @@ -0,0 +1,20 @@
>> +menu "Platform support"
>> +	depends on PPC_512x
>> +
>> +choice
>> +	prompt "Machine Type"
>> +	default MPC5121_ADS
>> +
>> +config MPC5121_ADS
>> +	bool "Freescale MPC5121E ADS"
>> +	select DEFAULT_UIMAGE
>> +	help
>> +	  This option enables support for the MPC5121E ADS board.
>> +
>> +endchoice
>>     
>
> For new platforms it makes more sense to make it possible to build
> multiplatform kernels instead of using 'choice'.
>
> I know some embedded board guys prefer to build a custom kernel for just
> their board (since it means extra revenue for them to spin a kernel
> for every customer), but it's still convenient to be able to build
> multiplatform kernels. Especially since there's some companies out there
> with intent to make end-user products with this cpu.
>   
Grant made the same comment about multiplatform support.
I'll change this.
>   
>> @@ -0,0 +1,90 @@
>> +#include <asm/system.h>
>> +#include <asm/atomic.h>
>> +#include <asm/machdep.h>
>> +#include <asm/ipic.h>
>> +#include <asm/prom.h>
>> +#include <asm/time.h>
>> +#include <asm/of_platform.h>
>>     
>
> Stephen will tell you to include linux/of_platform.h instead. :-)
>   
Oops, this patch was originally done before the open firmware
unification.  I guess checkpatch.pl needs an update too.
>   
>> @@ -229,7 +229,7 @@ config NR_CPUS
>>  
>>  config NOT_COHERENT_CACHE
>>  	bool
>> -	depends on 4xx || 8xx || E200
>> +	depends on 4xx || 8xx || E200 || PPC_512x
>>  	default y
>>     
>
> Why do you need this, when 5200 doesn't?
>
>
> -Olof
>
>   

^ permalink raw reply

* Re: [PATCH 3/7] Basic Freescale MPC512x support
From: Arnd Bergmann @ 2008-01-08 18:07 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: John Rigby
In-Reply-To: <1199808093-15929-4-git-send-email-jrigby@freescale.com>

On Tuesday 08 January 2008, John Rigby wrote:
> =A0obj-$(CONFIG_PPC_CHRP)=A0=A0=A0=A0=A0=A0=A0=A0=A0+=3D chrp/
> =A0obj-$(CONFIG_40x)=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0+=3D 40x/
> =A0obj-$(CONFIG_44x)=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0+=3D 44x/
> +obj-$(CONFIG_PPC_512x)=A0=A0=A0=A0=A0=A0=A0=A0=A0+=3D 512x/
> =A0obj-$(CONFIG_PPC_MPC52xx)=A0=A0=A0=A0=A0=A0+=3D 52xx/
> =A0obj-$(CONFIG_PPC_8xx)=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0+=3D 8xx/
> =A0obj-$(CONFIG_PPC_82xx)=A0=A0=A0=A0=A0=A0=A0=A0=A0+=3D 82xx/

Why do you name the directory 512x instead of 51xx, which would be
more consistent with the others? Do you expect other 51xx chips that
are mostly incompatible with 512x?

Moreover, is it really so different from 52xx that it needs a separate
directory? E.g. we often treat the 74xx and 7xx as 6xx variants.

	Arnd <><

^ permalink raw reply

* Re: [PATCH] Hwmon for Taco
From: Sean MacLennan @ 2008-01-08 18:09 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev
In-Reply-To: <fa686aa40801072259w63899e74y45d55bd5e9844b68@mail.gmail.com>

Grant Likely wrote:
> This is *very* board specific and not very complex a driver.  It
> should probably live with the platform code somewhere in
> arch/powerpc/platforms.  You can use the machine_device_initcall()
> hook to kick off the thread.
>   
Doh, this is why I post to this list. The platform code already had an 
obvious place to put this, so I moved it there.

I will cleanup the ad7414.c driver and repost the patch.

Cheers,
   Sean

^ permalink raw reply

* Re: [PATCH 3/7] Basic Freescale MPC512x support
From: Arnd Bergmann @ 2008-01-08 18:13 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Olof Johansson, John Rigby
In-Reply-To: <20080108174038.GA20819@lixom.net>

On Tuesday 08 January 2008, Olof Johansson wrote:
> > diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
> > index 66a3d8c..81c3f05 100644
> > --- a/arch/powerpc/Kconfig
> > +++ b/arch/powerpc/Kconfig
> > @@ -470,7 +470,7 @@ config PCI
> > =A0=A0=A0=A0=A0=A0bool "PCI support" if 40x || CPM2 || PPC_83xx || PPC_=
85xx || PPC_86xx \
> > =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0|| PPC_MPC52xx || (EMBEDDED &=
& (PPC_PSERIES || PPC_ISERIES)) \
> > =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0|| PPC_PS3
> > -=A0=A0=A0=A0=A0default y if !40x && !CPM2 && !8xx && !PPC_83xx \
> > +=A0=A0=A0=A0=A0default y if !40x && !CPM2 && !8xx && !PPC_512x && !PPC=
_83xx \
> > =A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0=A0&& !PPC_85xx && !PPC_86xx
>=20
> This is getting out of control. Not a comment to this specific patch,
> but it's getting silly.
>=20
> Btw, why no PCI by default on this platform when it seemingly is default
> on 5200? I thought they were fairly similar.
>=20

Just an idea how to restructure this, you could have

config PCI_POSSIBLE
	bool
	help
	  select this from your platform if it can support PCI.

config PCI_DEFAULT
	bool
	select
	help
	  select this from your platform if you want PCI on by default

config PCI
	bool "PCI support"
	depends on PCI_POSSIBLE || PCI_DEFAULT
	default PCI_DEFAULT

config 40x
	# there could be PCI, but normally there isn't
	select PCI_POSSIBLE
=09
config PPC_83xx=20
	# PCI is normally wanted on 83xx, but you can disable it
	select PCI_DEFAULT

config CHRP
	# CHRP can only be built correctly when PCI is enabled
	select PCI

	Arnd <><

^ permalink raw reply

* Re: [PATCH 6/7] Add mpc512x_find_ips_freq
From: Arnd Bergmann @ 2008-01-08 18:15 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: John Rigby
In-Reply-To: <1199808093-15929-7-git-send-email-jrigby@freescale.com>

On Tuesday 08 January 2008, John Rigby wrote:
> +unsigned long
> +mpc512x_find_ips_freq(struct device_node *node)
> +{

The driver that is using this is listed as 'tristate' in Kconfig, but
this function is not exported, so you get a link error if you want to
build it as a module.

	Arnd <><

^ permalink raw reply

* Re: [PATCH 3/7] Basic Freescale MPC512x support
From: John Rigby @ 2008-01-08 18:16 UTC (permalink / raw)
  To: Olof Johansson; +Cc: linuxppc-dev
In-Reply-To: <20080108174038.GA20819@lixom.net>


>
>   
>> @@ -229,7 +229,7 @@ config NR_CPUS
>>  
>>  config NOT_COHERENT_CACHE
>>  	bool
>> -	depends on 4xx || 8xx || E200
>> +	depends on 4xx || 8xx || E200 || PPC_512x
>>  	default y
>>     
>
> Why do you need this, when 5200 doesn't?
>
>   
Because the 5121 cache is not coherent.  The 5121 is not that similar
to 52xx.
> -Olof
>
>   

^ permalink raw reply

* Re: [PATCH 3/7] Basic Freescale MPC512x support
From: John Rigby @ 2008-01-08 18:25 UTC (permalink / raw)
  To: Arnd Bergmann; +Cc: linuxppc-dev
In-Reply-To: <200801081907.59052.arnd@arndb.de>

Arnd Bergmann wrote:
> On Tuesday 08 January 2008, John Rigby wrote:
>   
>>  obj-$(CONFIG_PPC_CHRP)         += chrp/
>>  obj-$(CONFIG_40x)              += 40x/
>>  obj-$(CONFIG_44x)              += 44x/
>> +obj-$(CONFIG_PPC_512x)         += 512x/
>>  obj-$(CONFIG_PPC_MPC52xx)      += 52xx/
>>  obj-$(CONFIG_PPC_8xx)          += 8xx/
>>  obj-$(CONFIG_PPC_82xx)         += 82xx/
>>     
>
> Why do you name the directory 512x instead of 51xx, which would be
> more consistent with the others? Do you expect other 51xx chips that
> are mostly incompatible with 512x?
>   
51xx would be confusing because 5100 was a precursor to the 5200.

Adding it to 52xx would is wrong because 5121 is really not that
much like a 5200.  It is really a 83xx minus some networking hw
plus some 5200 peripherals (PSCs and MSCAN).

In the best of possible worlds it would have a 83xx part number
and go in 83xx but that would be confusing since it is targeted
at the automotive market.
> Moreover, is it really so different from 52xx that it needs a separate
> directory? E.g. we often treat the 74xx and 7xx as 6xx variants.
>
> 	Arnd <><
>
>   

^ permalink raw reply

* Re: [PATCH] Hwmon for Taco
From: Sean MacLennan @ 2008-01-08 18:30 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev
In-Reply-To: <fa686aa40801072259w63899e74y45d55bd5e9844b68@mail.gmail.com>

Ok, here is the ad7414 only. taco-dtm is no more!

Cheers,
   Sean

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index a0445be..f14972a 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -57,6 +57,16 @@ config SENSORS_ABITUGURU3
 	  This driver can also be built as a module.  If so, the module
 	  will be called abituguru3.
 
+config SENSORS_AD7414
+	tristate "Analog Devices AD7414"
+	depends on I2C && EXPERIMENTAL
+	help
+	  If you say yes here you get support for the Analog Devices
+	  AD7414 temperature monitoring chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called ad7414.
+
 config SENSORS_AD7418
 	tristate "Analog Devices AD7416, AD7417 and AD7418"
 	depends on I2C && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 55595f6..fa6066e 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_SENSORS_W83791D)	+= w83791d.o
 
 obj-$(CONFIG_SENSORS_ABITUGURU)	+= abituguru.o
 obj-$(CONFIG_SENSORS_ABITUGURU3)+= abituguru3.o
+obj-$(CONFIG_SENSORS_AD7414)	+= ad7414.o
 obj-$(CONFIG_SENSORS_AD7418)	+= ad7418.o
 obj-$(CONFIG_SENSORS_ADM1021)	+= adm1021.o
 obj-$(CONFIG_SENSORS_ADM1025)	+= adm1025.o
@@ -72,4 +73,3 @@ obj-$(CONFIG_SENSORS_W83L785TS)	+= w83l785ts.o
 ifeq ($(CONFIG_HWMON_DEBUG_CHIP),y)
 EXTRA_CFLAGS += -DDEBUG
 endif
-
--- /dev/null	2005-11-20 22:22:37.000000000 -0500
+++ drivers/hwmon/ad7414.c	2008-01-08 02:43:24.000000000 -0500
@@ -0,0 +1,319 @@
+/*
+ * An hwmon driver for the Analog Devices AD7414
+ *
+ * Copyright 2006 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ *
+ * Based on ad7418.c
+ * Copyright 2006 Tower Technologies, Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/jiffies.h>
+#include <linux/i2c.h>
+#include <linux/hwmon.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+
+#define DRV_VERSION "0.2"
+
+/* straight from the datasheet */
+#define AD7414_TEMP_MIN (-55000)
+#define AD7414_TEMP_MAX 125000
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { 0x48, 0x4a, I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD;
+
+/* AD7414 registers */
+#define AD7414_REG_TEMP		0x00
+#define AD7414_REG_CONF		0x01
+#define AD7414_REG_T_HIGH	0x02
+#define AD7414_REG_T_LOW	0x03
+
+struct ad7414_data {
+	struct i2c_client	client;
+	struct device	*dev;
+	struct mutex		lock;
+	char			valid;		/* !=0 if following fields are valid */
+	unsigned long		last_updated;	/* In jiffies */
+	u16			temp_input;	/* Register values */
+	u8			temp_max;
+	u8			temp_min;
+	u8			temp_alert;
+	u8			temp_max_flag;
+	u8			temp_min_flag;
+};
+
+
+struct ad7414_dev {
+	struct list_head list;
+	struct device *dev;
+};
+
+static LIST_HEAD(ad7414_dev_list);
+
+
+static int ad7414_attach_adapter(struct i2c_adapter *adapter);
+static int ad7414_detect(struct i2c_adapter *adapter, int address, int kind);
+static int ad7414_detach_client(struct i2c_client *client);
+
+static struct i2c_driver ad7414_driver = {
+	.driver = {
+		.name	= "ad7414",
+	},
+	.attach_adapter	= ad7414_attach_adapter,
+	.detach_client	= ad7414_detach_client,
+};
+
+/*
+ * TEMP: 0.001C/bit (-55C to +125C)
+ * REG: (0.5C/bit, two's complement) << 7
+ */
+static inline int AD7414_TEMP_FROM_REG(u16 reg)
+{
+	/* use integer division instead of equivalent right shift to
+	 * guarantee arithmetic shift and preserve the sign
+	 */
+	return ((s16)reg / 128) * 500;
+}
+
+/* All registers are word-sized, except for the configuration registers.
+ * AD7414 uses a high-byte first convention, which is exactly opposite to
+ * the usual practice.
+ */
+static int ad7414_read(struct i2c_client *client, u8 reg)
+{
+	if (reg == AD7414_REG_TEMP)
+		return swab16(i2c_smbus_read_word_data(client, reg));
+	else
+		return i2c_smbus_read_byte_data(client, reg);
+}
+
+static int ad7414_write(struct i2c_client *client, u8 reg, u16 value)
+{
+	return i2c_smbus_write_byte_data(client, reg, value);
+}
+
+static void ad7414_init_client(struct i2c_client *client)
+{
+	struct ad7414_dev *new;
+
+	new = kzalloc(sizeof(*new), GFP_KERNEL);
+	if(new == NULL)
+		printk(KERN_ERR "ad7414_init_client: Unable to allocate memory\n");
+	else {
+		new->dev = &client->dev;
+		list_add_tail(&new->list, &ad7414_dev_list);
+	}
+}
+
+static struct ad7414_data *ad7414_update_device(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct ad7414_data *data = i2c_get_clientdata(client);
+
+	mutex_lock(&data->lock);
+
+	if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
+		|| !data->valid) {
+		dev_dbg(&client->dev, "starting ad7414 update\n");
+
+		data->temp_input = ad7414_read(client, AD7414_REG_TEMP);
+		data->temp_alert = (data->temp_input >> 5) & 0x01;
+		data->temp_max_flag = (data->temp_input >> 4) & 0x01;
+		data->temp_min_flag = (data->temp_input >> 3) & 0x01;
+		data->temp_max = ad7414_read(client, AD7414_REG_T_HIGH);
+		data->temp_min = ad7414_read(client, AD7414_REG_T_LOW);
+
+		data->last_updated = jiffies;
+		data->valid = 1;
+	}
+
+	mutex_unlock(&data->lock);
+
+	return data;
+}
+
+int ad7414_get_temp(int index)
+{
+	struct ad7414_dev *dev;
+
+	list_for_each_entry(dev, &ad7414_dev_list, list) {
+		if(index <= 0) {
+			struct ad7414_data *data = ad7414_update_device(dev->dev);
+			return data->temp_input;
+		}
+		--index;
+	}
+
+	return 0x1f4; /* +125 */
+}
+EXPORT_SYMBOL(ad7414_get_temp);
+
+#define show(value) \
+static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf)		\
+{									\
+	struct ad7414_data *data = ad7414_update_device(dev);		\
+	return sprintf(buf, "%d\n", AD7414_TEMP_FROM_REG(data->value));	\
+}
+show(temp_input);
+
+#define show_8(value)	\
+static ssize_t show_##value(struct device *dev, struct device_attribute *attr, char *buf)		\
+{								\
+	struct ad7414_data *data = ad7414_update_device(dev);	\
+	return sprintf(buf, "%d\n", data->value);		\
+}
+show_8(temp_max);
+show_8(temp_min);
+show_8(temp_alert);
+show_8(temp_max_flag);
+show_8(temp_min_flag);
+
+#define set(value, reg)	\
+static ssize_t set_##value(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)	\
+{								\
+	struct i2c_client *client = to_i2c_client(dev);		\
+	struct ad7414_data *data = i2c_get_clientdata(client);	\
+	int temp = simple_strtoul(buf, NULL, 10);		\
+								\
+	mutex_lock(&data->lock);				\
+	data->value = temp;					\
+	ad7414_write(client, reg, data->value);			\
+	mutex_unlock(&data->lock);				\
+	return count;						\
+}
+set(temp_max, AD7414_REG_T_HIGH);
+set(temp_min, AD7414_REG_T_LOW);
+
+static DEVICE_ATTR(temp1_max, S_IWUSR | S_IRUGO, show_temp_max, set_temp_max);
+static DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp_min, set_temp_min);
+static DEVICE_ATTR(temp1_input, S_IRUGO, show_temp_input, NULL);
+static DEVICE_ATTR(temp1_alert, S_IRUGO, show_temp_alert, NULL);
+static DEVICE_ATTR(temp1_max_flag, S_IRUGO, show_temp_max_flag, NULL);
+static DEVICE_ATTR(temp1_min_flag, S_IRUGO, show_temp_min_flag, NULL);
+
+static int ad7414_attach_adapter(struct i2c_adapter *adapter)
+{
+	if (!(adapter->class & I2C_CLASS_HWMON))
+		return 0;
+	return i2c_probe(adapter, &addr_data, ad7414_detect);
+}
+
+static struct attribute *ad7414_attributes[] = {
+	&dev_attr_temp1_input.attr,
+	&dev_attr_temp1_max.attr,
+	&dev_attr_temp1_min.attr,
+	&dev_attr_temp1_alert.attr,
+	&dev_attr_temp1_max_flag.attr,
+	&dev_attr_temp1_min_flag.attr,
+	NULL
+};
+
+static const struct attribute_group ad7414_group = {
+	.attrs = ad7414_attributes,
+};
+
+static int ad7414_detect(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client;
+	struct ad7414_data *data;
+	int err = 0;
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+					I2C_FUNC_SMBUS_WORD_DATA))
+		goto exit;
+
+	if (!(data = kzalloc(sizeof(struct ad7414_data), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	client = &data->client;
+	client->addr = address;
+	client->adapter = adapter;
+	client->driver = &ad7414_driver;
+	client->flags = 0;
+
+	i2c_set_clientdata(client, data);
+
+	mutex_init(&data->lock);
+
+	/* TODO: not testing for AD7414 done yet... */
+
+	strlcpy(client->name, ad7414_driver.driver.name, I2C_NAME_SIZE);
+
+	if ((err = i2c_attach_client(client)))
+		goto exit_free;
+
+	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+
+	/* Initialize the AD7414 chip */
+	ad7414_init_client(client);
+
+	/* Register sysfs hooks */
+	if ((err = sysfs_create_group(&client->dev.kobj, &ad7414_group)))
+		goto exit_detach;
+
+	data->dev = hwmon_device_register(&client->dev);
+	if (IS_ERR(data->dev)) {
+		err = PTR_ERR(data->dev);
+		goto exit_remove;
+	}
+
+	return 0;
+
+exit_remove:
+	sysfs_remove_group(&client->dev.kobj, &ad7414_group);
+exit_detach:
+	i2c_detach_client(client);
+exit_free:
+	kfree(data);
+exit:
+	return err;
+}
+
+static int ad7414_detach_client(struct i2c_client *client)
+{
+	struct ad7414_data *data = i2c_get_clientdata(client);
+	struct ad7414_dev *dev;
+
+	list_for_each_entry(dev, &ad7414_dev_list, list)
+		if(dev->dev == &client->dev) {
+			list_del(&dev->list);
+			break;
+		}
+
+	hwmon_device_unregister(data->dev);
+	sysfs_remove_group(&client->dev.kobj, &ad7414_group);
+	i2c_detach_client(client);
+	kfree(data);
+	return 0;
+}
+
+static int __init ad7414_init(void)
+{
+	return i2c_add_driver(&ad7414_driver);
+}
+
+static void __exit ad7414_exit(void)
+{
+	i2c_del_driver(&ad7414_driver);
+}
+
+MODULE_AUTHOR("Stefan Roese <sr@denx.de>");
+MODULE_DESCRIPTION("AD7414 driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ad7414_init);
+module_exit(ad7414_exit);

^ permalink raw reply related

* Re: [PATCH 4/8] pseries: phyp dump: use sysfs to release reserved mem
From: Linas Vepstas @ 2008-01-08 18:34 UTC (permalink / raw)
  To: Stephen Rothwell; +Cc: mahuja, linuxppc-dev, lkessler, strosake
In-Reply-To: <20080108144537.39f21cd4.sfr@canb.auug.org.au>

On 07/01/2008, Stephen Rothwell <sfr@canb.auug.org.au> wrote:
> On Mon, 07 Jan 2008 18:21:57 -0600 Manish Ahuja <ahuja@austin.ibm.com> wrote:
> >
> > +static int __init phyp_dump_setup(void)
> > +{
> >
> > +     /* Is there dump data waiting for us? */
> > +     rtas = of_find_node_by_path("/rtas");
> > +     dump_header = of_get_property(rtas, "ibm,kernel-dump", &header_len);
>                                                                ^^^^^^^^^^^
> You could pass NULL here as header_len appears to be unused. Also you
> need "of_node_put(rtas)" somewhere (probably just here would do).

Perhaps the routine should have been "of_get_node_by_path()" ?

In ye olden days, "finds" didn't require put, but "gets" did. I'm guessing
that this has now all been fixed up for the of_xxx routines, but I think
that pci_find_xxx still does not require a pci_put.

Why did I bother to write this email? I dunno...
--linas

^ permalink raw reply

* [PATCH RFC 0/3] PowerPC: implement support for GPIO LIB API
From: Anton Vorontsov @ 2008-01-08 18:43 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Arnd Bergmann, David Gibson

Hi all,

Thanks for the previous review and ideas. Here is the RFC for the
GPIO LIB support.

I'm using it like this:

	qe_pio_a: gpio-controller@1400 {
		#gpio-cells = <1>;
		compatible = "fsl,qe-pario-bank";
		reg = <0x1400 0x18>;
		gpio-controller;
	};

	qe_pio_e: gpio-controller@1460 {
		#gpio-cells = <1>;
		compatible = "fsl,qe-pario-bank";
		reg = <0x1460 0x18>;
		gpio-controller;
	};

	nand-flash@1,0 {
		compatible = "stmicro,NAND512W3A2BN6E", "fsl,upm-nand";
		reg = <1 0 1>;
		width = <1>;
		upm = "A";
		upm-addr-offset = <16>;
		upm-cmd-offset = <8>;
		gpios = <&qe_pio_e 18 &qe_pio_a 9>;
		wait-pattern;
		wait-write;
	};

As you can see I've split single "par_io" node into banks, thus
the benefits:
- we can handle banks of different width (Jochen Friedrich asked for
  this, IIRC. Or I've misunderstood ;-).
- we can handle banks with different paddings (no more #ifdef PPC85xx).

Also, it's possible to specify different gpio-controllers in the
gpios = <> property. gpio-specifier is controller specific.


The remaining question is about gpio.c placement. prom_parse.c doesn't
feel as the appropriate place anymore. I think of:

- drivers/gpio/of_gpio.c (driver/gpio/ is in -mm tree);
- drivers/of/gpio.c
- keep it in arch/powerpc/kernel/ (though, there is nothing
  much PowerPC specific).


So, to try these patches you'll need apply these from the -mm tree:
generic-gpio-gpio_chip-support.patch
generic-gpio-gpio_chip-support-fix.patch
generic-gpio-gpio_chip-support-gpiolib-locking-simplified.patch

Or just issue this in your working tree:

  git pull git://git.infradead.org/users/cbou/powerpc-gpio.git gpiolib

powerpc-gpio.git's gpiolib branch is galak/powerpc.git master branch +
-mm patches + these patches.


Support for CPM2 is pending.

Thanks!

-- 
Anton Vorontsov
email: cbou@mail.ru
backup email: ya-cbou@yandex.ru
irc://irc.freenode.net/bd2

^ permalink raw reply

* Re: [PATCH] i2c-ibm_iic driver - new patch
From: Sean MacLennan @ 2008-01-08 18:35 UTC (permalink / raw)
  To: Stephen Rothwell; +Cc: linuxppc-dev, Stefan Roese, Arnd Bergmann
In-Reply-To: <20080108173636.73db1623.sfr@canb.auug.org.au>

Let's try again.

Cheers,
    Sean

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index c466c6c..e9e1493 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -241,7 +241,6 @@ config I2C_PIIX4
 
 config I2C_IBM_IIC
 	tristate "IBM PPC 4xx on-chip I2C interface"
-	depends on IBM_OCP
 	help
 	  Say Y here if you want to use IIC peripheral found on 
 	  embedded IBM PPC 4xx based systems. 
diff --git a/drivers/i2c/busses/i2c-ibm_iic.c b/drivers/i2c/busses/i2c-ibm_iic.c
index 9b43ff7..98476fc 100644
--- a/drivers/i2c/busses/i2c-ibm_iic.c
+++ b/drivers/i2c/busses/i2c-ibm_iic.c
@@ -6,6 +6,9 @@
  * Copyright (c) 2003, 2004 Zultys Technologies.
  * Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
  *
+ * Copyright (c) 2008 PIKA Technologies
+ * Sean MacLennan <smaclennan@pikatech.com>
+ *
  * Based on original work by 
  * 	Ian DaSilva  <idasilva@mvista.com>
  *      Armin Kuster <akuster@mvista.com>
@@ -39,12 +42,17 @@
 #include <asm/io.h>
 #include <linux/i2c.h>
 #include <linux/i2c-id.h>
+
+#ifdef CONFIG_IBM_OCP
 #include <asm/ocp.h>
 #include <asm/ibm4xx.h>
+#else
+#include <linux/of_platform.h>
+#endif
 
 #include "i2c-ibm_iic.h"
 
-#define DRIVER_VERSION "2.1"
+#define DRIVER_VERSION "2.2"
 
 MODULE_DESCRIPTION("IBM IIC driver v" DRIVER_VERSION);
 MODULE_LICENSE("GPL");
@@ -650,13 +658,14 @@ static inline u8 iic_clckdiv(unsigned int opb)
 	opb /= 1000000;
 	
 	if (opb < 20 || opb > 150){
-		printk(KERN_CRIT "ibm-iic: invalid OPB clock frequency %u MHz\n",
+		printk(KERN_WARNING "ibm-iic: invalid OPB clock frequency %u MHz\n",
 			opb);
 		opb = opb < 20 ? 20 : 150;
 	}
 	return (u8)((opb + 9) / 10 - 1);
 }
 
+#ifdef CONFIG_IBM_OCP
 /*
  * Register single IIC interface
  */
@@ -672,7 +681,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
 			ocp->def->index);
 
 	if (!(dev = kzalloc(sizeof(*dev), GFP_KERNEL))) {
-		printk(KERN_CRIT "ibm-iic%d: failed to allocate device data\n",
+		printk(KERN_ERR "ibm-iic%d: failed to allocate device data\n",
 			ocp->def->index);
 		return -ENOMEM;
 	}
@@ -687,7 +696,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
 	}
 
 	if (!(dev->vaddr = ioremap(ocp->def->paddr, sizeof(struct iic_regs)))){
-		printk(KERN_CRIT "ibm-iic%d: failed to ioremap device registers\n",
+		printk(KERN_ERR "ibm-iic%d: failed to ioremap device registers\n",
 			dev->idx);
 		ret = -ENXIO;
 		goto fail2;
@@ -746,7 +755,7 @@ static int __devinit iic_probe(struct ocp_device *ocp){
 	adap->nr = dev->idx >= 0 ? dev->idx : 0;
 
 	if ((ret = i2c_add_numbered_adapter(adap)) < 0) {
-		printk(KERN_CRIT "ibm-iic%d: failed to register i2c adapter\n",
+		printk(KERN_ERR "ibm-iic%d: failed to register i2c adapter\n",
 			dev->idx);
 		goto fail;
 	}
@@ -779,7 +788,7 @@ static void __devexit iic_remove(struct ocp_device *ocp)
 	struct ibm_iic_private* dev = (struct ibm_iic_private*)ocp_get_drvdata(ocp);
 	BUG_ON(dev == NULL);
 	if (i2c_del_adapter(&dev->adap)){
-		printk(KERN_CRIT "ibm-iic%d: failed to delete i2c adapter :(\n",
+		printk(KERN_ERR "ibm-iic%d: failed to delete i2c adapter :(\n",
 			dev->idx);
 		/* That's *very* bad, just shutdown IRQ ... */
 		if (dev->irq >= 0){
@@ -831,3 +840,189 @@ static void __exit iic_exit(void)
 
 module_init(iic_init);
 module_exit(iic_exit);
+#else
+/*
+ * Register single IIC interface
+ */
+static int __devinit iic_probe(struct of_device *ofdev,
+			       const struct of_device_id *match)
+{
+	static int index = 0;
+	struct device_node *np = ofdev->node;
+	struct ibm_iic_private* dev;
+	struct i2c_adapter* adap;
+	const u32 *indexp, *freq;
+	int ret;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		printk(KERN_ERR "ibm-iic: failed to allocate device data\n");
+		return -ENOMEM;
+	}
+
+	/* This assumes we don't mix index and non-index entries. */
+	indexp = of_get_property(np, "index", NULL);
+	dev->idx = indexp ? *indexp : index++;
+
+	dev_set_drvdata(&ofdev->dev, dev);
+
+	dev->vaddr = of_iomap(np, 0);
+	if (dev->vaddr == NULL) {
+		printk(KERN_ERR "ibm-iic%d: failed to ioremap device registers\n",
+			dev->idx);
+		ret = -ENXIO;
+		goto fail1;
+	}
+
+	init_waitqueue_head(&dev->wq);
+
+	if (iic_force_poll)
+		dev->irq = NO_IRQ;
+	else {
+		dev->irq = irq_of_parse_and_map(np, 0);
+		if (dev->irq == NO_IRQ)
+			printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+		else {
+			/* Disable interrupts until we finish initialization,
+			   assumes level-sensitive IRQ setup...
+			*/
+			iic_interrupt_mode(dev, 0);
+			if (request_irq(dev->irq, iic_handler, 0, "IBM IIC", dev)){
+				printk(KERN_ERR "ibm-iic%d: request_irq %d failed\n",
+				       dev->idx, dev->irq);
+				/* Fallback to the polling mode */
+				dev->irq = NO_IRQ;
+			}
+		}
+	}
+
+	if (dev->irq == NO_IRQ)
+		printk(KERN_WARNING "ibm-iic%d: using polling mode\n",
+			   dev->idx);
+
+	/* Board specific settings */
+	if (iic_force_fast || of_get_property(np, "fast-mode", NULL))
+		dev->fast_mode = 1;
+	else
+		dev->fast_mode = 0;
+
+	/* clckdiv is the same for *all* IIC interfaces, but I'd rather
+	 * make a copy than introduce another global. --ebs
+	 */
+	freq = of_get_property(np, "clock-frequency", NULL);
+	if (freq == NULL) {
+		freq = of_get_property(np->parent, "clock-frequency", NULL);
+		if (freq == NULL) {
+			printk(KERN_ERR "ibm-iic%d: Unable to get bus frequency\n",
+			       dev->idx);
+			ret = -EBUSY;
+			goto fail;
+		}
+	}
+
+	dev->clckdiv = iic_clckdiv(*freq);
+	DBG("%d: clckdiv = %d\n", dev->idx, dev->clckdiv);
+
+	/* Initialize IIC interface */
+	iic_dev_init(dev);
+
+	/* Register it with i2c layer */
+	adap = &dev->adap;
+	adap->dev.parent = &ofdev->dev;
+	strcpy(adap->name, "IBM IIC");
+	i2c_set_adapdata(adap, dev);
+	adap->id = I2C_HW_OCP;
+	adap->class = I2C_CLASS_HWMON;
+	adap->algo = &iic_algo;
+	adap->client_register = NULL;
+	adap->client_unregister = NULL;
+	adap->timeout = 1;
+	adap->retries = 1;
+	adap->nr = dev->idx;
+
+	ret = i2c_add_numbered_adapter(adap);
+	if (ret  < 0) {
+		printk(KERN_ERR "ibm-iic%d: failed to register i2c adapter\n",
+			dev->idx);
+		goto fail;
+	}
+
+	printk(KERN_INFO "ibm-iic%d: using %s mode\n", dev->idx,
+		dev->fast_mode ? "fast (400 kHz)" : "standard (100 kHz)");
+
+	return 0;
+
+fail:
+	if (dev->irq != NO_IRQ){
+		iic_interrupt_mode(dev, 0);
+		free_irq(dev->irq, dev);
+	}
+
+	iounmap(dev->vaddr);
+fail1:
+	dev_set_drvdata(&ofdev->dev, NULL);
+	kfree(dev);
+	return ret;
+}
+
+/*
+ * Cleanup initialized IIC interface
+ */
+static int __devexit iic_remove(struct of_device *ofdev)
+{
+	struct ibm_iic_private* dev = dev_get_drvdata(&ofdev->dev);
+
+	BUG_ON(dev == NULL);
+	if (i2c_del_adapter(&dev->adap)){
+		printk(KERN_ERR "ibm-iic%d: failed to delete i2c adapter :(\n",
+			dev->idx);
+		/* That's *very* bad, just shutdown IRQ ... */
+		if (dev->irq != NO_IRQ){
+		    iic_interrupt_mode(dev, 0);
+		    free_irq(dev->irq, dev);
+		    dev->irq = NO_IRQ;
+		}
+	} else {
+		if (dev->irq != NO_IRQ){
+		    iic_interrupt_mode(dev, 0);
+		    free_irq(dev->irq, dev);
+		}
+		iounmap(dev->vaddr);
+		kfree(dev);
+	}
+
+	return 0;
+}
+
+
+static const struct of_device_id ibm_iic_match[] =
+{
+	{ .type = "i2c", .compatible = "ibm,iic-405ex", },
+	{ .type = "i2c", .compatible = "ibm,iic-405gp", },
+	{ .type = "i2c", .compatible = "ibm,iic-440gp", },
+	{ .type = "i2c", .compatible = "ibm,iic-440gpx", },
+	{ .type = "i2c", .compatible = "ibm,iic-440grx", },
+	{}
+};
+
+static struct of_platform_driver ibm_iic_driver =
+{
+	.name   = "ibm-iic",
+	.match_table = ibm_iic_match,
+	.probe  = iic_probe,
+	.remove = iic_remove,
+};
+
+static int __init ibm_iic_init(void)
+{
+	printk(KERN_INFO "IBM IIC driver v" DRIVER_VERSION "\n");
+	return of_register_platform_driver(&ibm_iic_driver);
+}
+module_init(ibm_iic_init);
+
+static void __exit ibm_iic_exit(void)
+{
+	of_unregister_platform_driver(&ibm_iic_driver);
+}
+module_exit(ibm_iic_exit);
+#endif

^ permalink raw reply related

* [PATCH 1/3] [POWERPC] Implement support for the GPIO LIB API
From: Anton Vorontsov @ 2008-01-08 18:45 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Arnd Bergmann, David Gibson
In-Reply-To: <20080108184341.GA29753@localhost.localdomain>

This patch implements support for the GPIO LIB API. Two calls
unimplemented though: irq_to_gpio and gpio_to_irq.

Various OF helpers provided to ease life and reduce code duplication.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 Documentation/powerpc/booting-without-of.txt |   58 ++++++++
 arch/powerpc/Kconfig                         |    5 +
 arch/powerpc/kernel/Makefile                 |    1 +
 arch/powerpc/kernel/gpio.c                   |  186 ++++++++++++++++++++++++++
 include/asm-powerpc/gpio.h                   |  126 +++++++++++++++++
 5 files changed, 376 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/kernel/gpio.c
 create mode 100644 include/asm-powerpc/gpio.h

diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index ee0209a..dd2613c 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -60,6 +60,10 @@ Table of Contents
     3) OpenPIC Interrupt Controllers
     4) ISA Interrupt Controllers
 
+  VIII - Specifying GPIO information for devices
+    1) gpios property
+    2) gpio-controller nodes
+
   Appendix A - Sample SOC node for MPC8540
 
 
@@ -2618,6 +2622,60 @@ encodings listed below:
 	2 =  high to low edge sensitive type enabled
 	3 =  low to high edge sensitive type enabled
 
+VIII - Specifying GPIO information for devices
+==============================================
+
+1) gpios property
+-----------------
+
+Nodes that makes use of GPIOs should define them using `gpios' property,
+format of which is: <&gpio-controller1-phandle gpio1-specifier
+		     &gpio-controller2-phandle gpio2-specifier
+		     ...>;
+
+Note that gpio-specifier length is controller dependent.
+
+gpio-specifier may encode: bank, pin position inside the bank,
+whether pin is open-drain and whether pin is active-low.
+
+Example of the node using GPIOs:
+
+	nand-flash@1,0 {
+		compatible = "stmicro,NAND512W3A2BN6E", "fsl,upm-nand";
+		reg = <1 0 1>;
+		width = <1>;
+		upm = "A";
+		upm-addr-offset = <16>;
+		upm-cmd-offset = <8>;
+		gpios = <&qe_pio_e 18>;
+		wait-pattern;
+		wait-write;
+	};
+
+In that example gpio-specifier is "18" and encodes GPIO pin number only,
+as accepted by the "qe_pio_e" gpio-controller.
+
+2) gpio-controller nodes
+------------------------
+
+Every GPIO controller node must have #gpio-cells property defined,
+this information will be used to translate gpio-specifiers.
+
+Example of two SOC GPIO banks defined as gpio-controller nodes:
+
+	qe_pio_a: gpio-controller@1400 {
+		#gpio-cells = <1>;
+		compatible = "fsl,qe-pario-bank";
+		reg = <0x1400 0x18>;
+		gpio-controller;
+	};
+
+	qe_pio_e: gpio-controller@1460 {
+		#gpio-cells = <1>;
+		compatible = "fsl,qe-pario-bank";
+		reg = <0x1460 0x18>;
+		gpio-controller;
+	};
 
 Appendix A - Sample SOC node for MPC8540
 ========================================
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 66a3d8c..b38c84a 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -73,6 +73,11 @@ config GENERIC_FIND_NEXT_BIT
 	bool
 	default y
 
+config GENERIC_GPIO
+	bool
+	help
+	  Generic GPIO API support
+
 config ARCH_NO_VIRT_TO_BUS
 	def_bool PPC64
 
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 9374bc9..943045c 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -65,6 +65,7 @@ obj-$(CONFIG_BOOTX_TEXT)	+= btext.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_PPC_UDBG_16550)	+= legacy_serial.o udbg_16550.o
+obj-$(CONFIG_GPIO_LIB)		+= gpio.o
 
 pci64-$(CONFIG_PPC64)		+= pci_dn.o isa-bridge.o
 obj-$(CONFIG_PCI)		+= pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \
diff --git a/arch/powerpc/kernel/gpio.c b/arch/powerpc/kernel/gpio.c
new file mode 100644
index 0000000..f41d1e0
--- /dev/null
+++ b/arch/powerpc/kernel/gpio.c
@@ -0,0 +1,186 @@
+/*
+ * OF helpers for the GPIO API
+ *
+ * Copyright (c) 2007  MontaVista Software, Inc.
+ * Copyright (c) 2007  Anton Vorontsov <avorontsov@ru.mvista.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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <asm/prom.h>
+#include <asm/gpio.h>
+
+int of_gpio_simple_xlate(struct of_gpio_chip *of_gc, struct device_node *np,
+			 const void *gpio_spec)
+{
+	const u32 *gpio = gpio_spec;
+
+	if (*gpio > of_gc->gc.ngpio)
+		return -EINVAL;
+
+	return *gpio;
+}
+EXPORT_SYMBOL(of_gpio_simple_xlate);
+
+int of_get_gpio(struct device_node *np, int index)
+{
+	int ret = -EINVAL;
+	struct device_node *gc;
+	struct of_gpio_chip *of_gc = NULL;
+	int size;
+	const u32 *gpios;
+	u32 nr_cells;
+	int i;
+	const void *gpio_spec;
+	const u32 *gpio_cells;
+	int gpio_index = 0;
+
+	gpios = of_get_property(np, "gpios", &size);
+	if (!gpios) {
+		ret = -ENOENT;
+		goto err0;
+	}
+	nr_cells = size / sizeof(u32);
+
+	for (i = 0; i < nr_cells;) {
+		const phandle *gpio_phandle;
+
+		gpio_phandle = gpios + i;
+		gpio_spec = gpio_phandle + 1;
+
+		gc = of_find_node_by_phandle(*gpio_phandle);
+		if (!gc) {
+			pr_debug("%s: could not find phandle for gpios\n",
+				 np->full_name);
+			goto err0;
+		}
+
+		of_gc = gc->data;
+		if (!of_gc) {
+			pr_debug("%s: gpio controller %s isn't registered\n",
+				 np->full_name, gc->full_name);
+			goto err1;
+		}
+
+		gpio_cells = of_get_property(gc, "#gpio-cells", &size);
+		if (!gpio_cells || size != sizeof(*gpio_cells) ||
+				*gpio_cells != of_gc->gpio_cells) {
+			pr_debug("%s: wrong #gpio-cells for %s\n",
+				 np->full_name, gc->full_name);
+			goto err1;
+		}
+
+		/* Next phandle is at phandle cells + #gpio-cells */
+		i += sizeof(*gpio_phandle) / sizeof(u32) + *gpio_cells;
+		if (i >= nr_cells + 1) {
+			pr_debug("%s: insufficient gpio-spec length\n",
+				 np->full_name);
+			goto err1;
+		}
+
+		if (gpio_index == index)
+			break;
+
+		of_gc = NULL;
+		of_node_put(gc);
+		gpio_index++;
+	}
+
+	if (!of_gc) {
+		ret = -ENOENT;
+		goto err0;
+	}
+
+	ret = of_gc->xlate(of_gc, np, gpio_spec);
+	if (ret < 0)
+		goto err1;
+
+	ret += of_gc->gc.base;
+err1:
+	of_node_put(gc);
+err0:
+	pr_debug("%s exited with status %d\n", __func__, ret);
+	return ret;
+}
+EXPORT_SYMBOL(of_get_gpio);
+
+static int of_get_gpiochip_base(struct device_node *np)
+{
+	struct device_node *gc = NULL;
+	int gpiochip_base = 0;
+
+	while ((gc = of_find_all_nodes(gc))) {
+		if (!of_get_property(gc, "gpio-controller", NULL))
+			continue;
+
+		if (gc != np) {
+			gpiochip_base += ARCH_GPIOS_PER_CHIP;
+			continue;
+		}
+
+		of_node_put(gc);
+
+		if (gpiochip_base >= ARCH_OF_GPIOS_END)
+			return -ENOSPC;
+
+		return gpiochip_base;
+	}
+
+	return -ENOENT;
+}
+
+int of_mm_gpiochip_add(struct device_node *np,
+		       const struct of_gpio_chip *of_gc)
+{
+	int ret = -ENOMEM;
+	struct of_mm_gpio_chip *mm_gc;
+
+	mm_gc = kzalloc(sizeof(*mm_gc), GFP_KERNEL);
+	if (!mm_gc)
+		goto err0;
+
+	mm_gc->of_gc = *of_gc;
+
+	mm_gc->of_gc.gc.label = kstrdup(np->full_name, GFP_KERNEL);
+	if (!mm_gc->of_gc.gc.label)
+		goto err1;
+
+	ret = of_get_gpiochip_base(np);
+	if (ret < 0)
+		goto err2;
+
+	mm_gc->regs = of_iomap(np, 0);
+	if (!mm_gc->regs) {
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	mm_gc->of_gc.gc.base = ret;
+
+	np->data = &mm_gc->of_gc;
+
+	ret = gpiochip_add(&mm_gc->of_gc.gc);
+	if (ret)
+		goto err2;
+
+	of_node_get(np);
+
+	pr_debug("%s: registered as generic GPIO chip, base is %d\n",
+		 np->full_name, mm_gc->of_gc.gc.base);
+	return 0;
+err2:
+	np->data = NULL;
+	kfree(mm_gc->of_gc.gc.label);
+err1:
+	kfree(mm_gc);
+err0:
+	pr_err("%s: GPIO chip registration failed with status %d\n",
+	       np->full_name, ret);
+	return ret;
+}
+EXPORT_SYMBOL(of_mm_gpiochip_add);
diff --git a/include/asm-powerpc/gpio.h b/include/asm-powerpc/gpio.h
new file mode 100644
index 0000000..1cc2e90
--- /dev/null
+++ b/include/asm-powerpc/gpio.h
@@ -0,0 +1,126 @@
+/*
+ * Generic GPIO API implementation for PowerPC.
+ *
+ * Copyright (c) 2007  MontaVista Software, Inc.
+ * Copyright (c) 2007  Anton Vorontsov <avorontsov@ru.mvista.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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __ASM_POWERPC_GPIO_H
+#define __ASM_POWERPC_GPIO_H
+
+#include <asm-generic/gpio.h>
+
+#ifdef CONFIG_GPIO_LIB
+
+#define ARCH_OF_GPIOS_BASE	0
+#define ARCH_OF_GPIOS_END	(ARCH_GPIOS_PER_CHIP * 7)
+#define ARCH_NON_OF_GPIOS_BASE	ARCH_OF_GPIOS_END
+#define ARCH_NON_OF_GPIOS_END	ARCH_NR_GPIOS
+
+#if ARCH_NON_OF_GPIOS_BASE >= ARCH_NON_OF_GPIOS_END
+#error "Default ARCH_NR_GPIOS isn't sufficient, define yours."
+#endif
+
+/*
+ * We don't (yet) implement inlined/rapid versions for on-chip gpios.
+ * Just call gpiolib.
+ */
+static inline int gpio_get_value(unsigned int gpio)
+{
+	return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned int gpio, int value)
+{
+	__gpio_set_value(gpio, value);
+}
+
+/*
+ * Not implemented, yet.
+ */
+static inline int gpio_to_irq(unsigned int gpio)
+{
+	return -ENOSYS;
+}
+
+static inline int irq_to_gpio(unsigned int irq)
+{
+	return -ENOSYS;
+}
+
+/*
+ * Generic OF GPIO chip
+ */
+struct of_gpio_chip {
+	struct gpio_chip gc;
+	int gpio_cells;
+	int (*xlate)(struct of_gpio_chip *of_gc, struct device_node *np,
+		     const void *gpio_spec);
+};
+
+#define to_of_gpio_chip(x) container_of(x, struct of_gpio_chip, gc)
+
+/*
+ * OF GPIO chip for memory mapped banks
+ */
+struct of_mm_gpio_chip {
+	struct of_gpio_chip of_gc;
+	void __iomem *regs;
+};
+
+#define to_of_mm_gpio_chip(x) container_of(to_of_gpio_chip(x), \
+					   struct of_mm_gpio_chip, of_gc)
+
+/**
+ * of_gpio_simple_xlate - Translate GPIO number given in the device tree
+ * @of_gc:	pointer to the OF GPIO chip
+ * @np:		device node to get GPIO from
+ * @gpio_spec:	pointer to the gpio-spec field in the `gpios' property
+ *
+ * This is gpio-controller specific function, returns translated GPIO
+ * number.
+ */
+extern int of_gpio_simple_xlate(struct of_gpio_chip *of_gc,
+				struct device_node *np,
+				const void *gpio_spec);
+
+/**
+ * of_get_gpio - Get a GPIO number from the device tree to use with GPIO API
+ * @np:		device node to get GPIO from
+ * @index:	index of the GPIO
+ *
+ * Returns GPIO number to use with Linux generic GPIO API, or one of the errno
+ * value on the error condition.
+ */
+extern int of_get_gpio(struct device_node *np, int index);
+
+/**
+ * of_mm_gpiochip_add - Add memory mapped GPIO chip (bank)
+ * @np:		device node of the GPIO chip
+ * @of_gc:	pointer to the of_gpio_chip template
+ *
+ * To use this function you should fill of_gc template with:
+ *
+ * 1) In the gpio_chip structure:
+ *    a) all callbacks
+ *    b) ngpios (GPIOs per bank)
+ *
+ * 2) In the of_gpio_chip structure:
+ *    a) xlate callback
+ *    b) gpio_cells
+ *
+ * If succeeded, this function will map bank's memory and will
+ * do all necessary work for you. Then you'll able to use .regs
+ * to manage GPIOs from the callbacks.
+ */
+extern int of_mm_gpiochip_add(struct device_node *np,
+			      const struct of_gpio_chip *of_gc);
+
+#endif /* CONFIG_GPIO_LIB */
+
+#endif /* __ASM_POWERPC_GPIO_H */
-- 
1.5.2.2

^ permalink raw reply related

* [PATCH 2/3] [POWERPC] QE: split par_io_config_pin()
From: Anton Vorontsov @ 2008-01-08 18:45 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Arnd Bergmann, David Gibson
In-Reply-To: <20080108184341.GA29753@localhost.localdomain>

This patch splits par_io_config_pin so we can use it with GPIO LIB API.

Also add a comment regarding #ifdef CONFIG_PPC_85xx being legacy.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 arch/powerpc/sysdev/qe_lib/qe_io.c |   60 +++++++++++++++++++++++------------
 1 files changed, 39 insertions(+), 21 deletions(-)

diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c
index e53ea4d..aef893b 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_io.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_io.c
@@ -37,6 +37,10 @@ struct port_regs {
 	__be32	cppar1;		/* Pin assignment register */
 	__be32	cppar2;		/* Pin assignment register */
 #ifdef CONFIG_PPC_85xx
+	/*
+	 * This is needed for legacy support only, should go away,
+	 * because we started using per-bank gpio chips.
+	 */
 	u8	pad[8];
 #endif
 };
@@ -63,28 +67,29 @@ int par_io_init(struct device_node *np)
 	return 0;
 }
 
-int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
-		      int assignment, int has_irq)
+static void __par_io_config_pin(struct port_regs __iomem *par_io,
+				u8 pin, int dir, int open_drain,
+				int assignment, int has_irq)
 {
-	u32 pin_mask1bit, pin_mask2bits, new_mask2bits, tmp_val;
-
-	if (!par_io)
-		return -1;
+	u32 pin_mask1bit;
+	u32 pin_mask2bits;
+	u32 new_mask2bits;
+	u32 tmp_val;
 
 	/* calculate pin location for single and 2 bits information */
 	pin_mask1bit = (u32) (1 << (NUM_OF_PINS - (pin + 1)));
 
 	/* Set open drain, if required */
-	tmp_val = in_be32(&par_io[port].cpodr);
+	tmp_val = in_be32(&par_io->cpodr);
 	if (open_drain)
-		out_be32(&par_io[port].cpodr, pin_mask1bit | tmp_val);
+		out_be32(&par_io->cpodr, pin_mask1bit | tmp_val);
 	else
-		out_be32(&par_io[port].cpodr, ~pin_mask1bit & tmp_val);
+		out_be32(&par_io->cpodr, ~pin_mask1bit & tmp_val);
 
 	/* define direction */
 	tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
-		in_be32(&par_io[port].cpdir2) :
-		in_be32(&par_io[port].cpdir1);
+		in_be32(&par_io->cpdir2) :
+		in_be32(&par_io->cpdir1);
 
 	/* get all bits mask for 2 bit per port */
 	pin_mask2bits = (u32) (0x3 << (NUM_OF_PINS -
@@ -96,36 +101,49 @@ int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
 
 	/* clear and set 2 bits mask */
 	if (pin > (NUM_OF_PINS / 2) - 1) {
-		out_be32(&par_io[port].cpdir2,
+		out_be32(&par_io->cpdir2,
 			 ~pin_mask2bits & tmp_val);
 		tmp_val &= ~pin_mask2bits;
-		out_be32(&par_io[port].cpdir2, new_mask2bits | tmp_val);
+		out_be32(&par_io->cpdir2, new_mask2bits | tmp_val);
 	} else {
-		out_be32(&par_io[port].cpdir1,
+		out_be32(&par_io->cpdir1,
 			 ~pin_mask2bits & tmp_val);
 		tmp_val &= ~pin_mask2bits;
-		out_be32(&par_io[port].cpdir1, new_mask2bits | tmp_val);
+		out_be32(&par_io->cpdir1, new_mask2bits | tmp_val);
 	}
 	/* define pin assignment */
 	tmp_val = (pin > (NUM_OF_PINS / 2) - 1) ?
-		in_be32(&par_io[port].cppar2) :
-		in_be32(&par_io[port].cppar1);
+		in_be32(&par_io->cppar2) :
+		in_be32(&par_io->cppar1);
 
 	new_mask2bits = (u32) (assignment << (NUM_OF_PINS -
 			(pin % (NUM_OF_PINS / 2) + 1) * 2));
 	/* clear and set 2 bits mask */
 	if (pin > (NUM_OF_PINS / 2) - 1) {
-		out_be32(&par_io[port].cppar2,
+		out_be32(&par_io->cppar2,
 			 ~pin_mask2bits & tmp_val);
 		tmp_val &= ~pin_mask2bits;
-		out_be32(&par_io[port].cppar2, new_mask2bits | tmp_val);
+		out_be32(&par_io->cppar2, new_mask2bits | tmp_val);
 	} else {
-		out_be32(&par_io[port].cppar1,
+		out_be32(&par_io->cppar1,
 			 ~pin_mask2bits & tmp_val);
 		tmp_val &= ~pin_mask2bits;
-		out_be32(&par_io[port].cppar1, new_mask2bits | tmp_val);
+		out_be32(&par_io->cppar1, new_mask2bits | tmp_val);
 	}
+}
+
+/*
+ * This is "legacy" function that takes port number as an argument
+ * instead of pointer to the appropriate bank.
+ */
+int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
+		      int assignment, int has_irq)
+{
+	if (!par_io || port >= num_par_io_ports)
+		return -EINVAL;
 
+	__par_io_config_pin(&par_io[port], pin, dir, open_drain, assignment,
+			    has_irq);
 	return 0;
 }
 EXPORT_SYMBOL(par_io_config_pin);
-- 
1.5.2.2

^ permalink raw reply related

* [PATCH 3/3] [POWERPC] QE: implement GPIO LIB API
From: Anton Vorontsov @ 2008-01-08 18:45 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Arnd Bergmann, David Gibson
In-Reply-To: <20080108184341.GA29753@localhost.localdomain>

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
---
 Documentation/powerpc/booting-without-of.txt |   32 +++++++----
 arch/powerpc/platforms/Kconfig               |    2 +
 arch/powerpc/sysdev/qe_lib/qe_io.c           |   73 ++++++++++++++++++++++++++
 include/asm-powerpc/qe.h                     |    1 +
 4 files changed, 96 insertions(+), 12 deletions(-)

diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index dd2613c..e279152 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1696,24 +1696,32 @@ platforms are moved over to use the flattened-device-tree model.
    information.
 
    Required properties:
-   - device_type : should be "par_io".
+   - #gpio-cells : should be "1".
+   - compatible : should be "fsl,qe-pario-bank"
    - reg : offset to the register set and its length.
-   - num-ports : number of Parallel I/O ports
+   - gpio-controller : node to identify gpio controllers.
 
-   Example:
-	par_io@1400 {
-		reg = <1400 100>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		device_type = "par_io";
-		num-ports = <7>;
-		ucc_pin@01 {
-			......
-		};
+   For example, two QE Par I/O banks:
+	qe_pio_a: gpio-controller@1400 {
+		#gpio-cells = <1>;
+		compatible = "fsl,qe-pario-bank";
+		reg = <0x1400 0x18>;
+		gpio-controller;
+	};
 
+	qe_pio_e: gpio-controller@1460 {
+		#gpio-cells = <1>;
+		compatible = "fsl,qe-pario-bank";
+		reg = <0x1460 0x18>;
+		gpio-controller;
+	};
 
    vi) Pin configuration nodes
 
+   NOTE: pin configuration nodes are obsolete. Usually, their existance
+         is an evidence of the firmware shortcomings. Such fixups are
+         better handled by the Linux board file, not the device tree.
+
    Required properties:
    - linux,phandle : phandle of this node; likely referenced by a QE
      device.
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index ea22cad..8dff946 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -265,6 +265,8 @@ config TAU_AVERAGE
 config QUICC_ENGINE
 	bool
 	select PPC_LIB_RHEAP
+	select GENERIC_GPIO
+	select GPIO_LIB
 	help
 	  The QUICC Engine (QE) is a new generation of communications
 	  coprocessors on Freescale embedded CPUs (akin to CPM in older chips).
diff --git a/arch/powerpc/sysdev/qe_lib/qe_io.c b/arch/powerpc/sysdev/qe_lib/qe_io.c
index aef893b..2a1ff45 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_io.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_io.c
@@ -23,6 +23,7 @@
 
 #include <asm/io.h>
 #include <asm/prom.h>
+#include <asm/gpio.h>
 #include <sysdev/fsl_soc.h>
 
 #undef DEBUG
@@ -213,6 +214,78 @@ int par_io_of_config(struct device_node *np)
 }
 EXPORT_SYMBOL(par_io_of_config);
 
+/*
+ * GPIO LIB API implementation
+ */
+
+static int qe_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct port_regs *regs = mm_gc->regs;
+	u32 pin_mask;
+
+	/* calculate pin location */
+	pin_mask = (u32) (1 << (NUM_OF_PINS - 1 - gpio));
+
+	return !!(in_be32(&regs->cpdata) & pin_mask);
+}
+
+static void qe_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+	struct port_regs *regs = mm_gc->regs;
+	u32 pin_mask;
+	u32 tmp_val;
+
+	/* calculate pin location */
+	pin_mask = (u32) (1 << (NUM_OF_PINS - 1 - gpio));
+
+	tmp_val = in_be32(&regs->cpdata);
+
+	if (val == 0)
+		out_be32(&regs->cpdata, ~pin_mask & tmp_val);
+	else
+		out_be32(&regs->cpdata, pin_mask | tmp_val);
+}
+
+static int qe_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+
+	__par_io_config_pin(mm_gc->regs, gpio, 2, 0, 0, 0);
+
+	return 0;
+}
+
+static int qe_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
+{
+	struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
+
+	__par_io_config_pin(mm_gc->regs, gpio, 1, 0, 0, 0);
+	qe_gpio_set(gc, gpio, val);
+
+	return 0;
+}
+
+static struct of_gpio_chip qe_gc = {
+	.gpio_cells = 1,
+	.xlate = of_gpio_simple_xlate,
+
+	.gc = {
+		.ngpio = NUM_OF_PINS,
+		.direction_input = qe_gpio_dir_in,
+		.direction_output = qe_gpio_dir_out,
+		.get = qe_gpio_get,
+		.set = qe_gpio_set,
+	},
+};
+
+int qe_gpiochip_add(struct device_node *np)
+{
+	return of_mm_gpiochip_add(np, &qe_gc);
+}
+EXPORT_SYMBOL(qe_gpiochip_add);
+
 #ifdef DEBUG
 static void dump_par_io(void)
 {
diff --git a/include/asm-powerpc/qe.h b/include/asm-powerpc/qe.h
index a24b7b1..2efda82 100644
--- a/include/asm-powerpc/qe.h
+++ b/include/asm-powerpc/qe.h
@@ -77,6 +77,7 @@ enum qe_clock {
 /* Export QE common operations */
 extern void qe_reset(void);
 extern int par_io_init(struct device_node *np);
+extern int qe_gpiochip_add(struct device_node *np);
 extern int par_io_of_config(struct device_node *np);
 extern int par_io_config_pin(u8 port, u8 pin, int dir, int open_drain,
 			     int assignment, int has_irq);
-- 
1.5.2.2

^ permalink raw reply related

* Re: [PATCH] Miscellaneous for Taco
From: Sean MacLennan @ 2008-01-08 18:41 UTC (permalink / raw)
  To: benh; +Cc: linuxppc-dev, Stefan Roese
In-Reply-To: <1199566583.7291.63.camel@pasglop>

How about just 44x?

Cheers,
    Sean

diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 7580aa5..682deae 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -39,6 +39,7 @@ config USB_ARCH_HAS_OHCI
        # PPC:
        default y if STB03xxx
        default y if PPC_MPC52xx
+       default y if 44x
        # MIPS:
        default y if SOC_AU1X00
        # more:

^ permalink raw reply related


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