linux-fbdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Eric Miao <eric.y.miao@gmail.com>
To: Jun Nie <niej0001@gmail.com>
Cc: linux-fbdev-devel@lists.sourceforge.net,
	linux-arm-kernel@lists.infradead.org
Subject: Re: [PATCH 1/6] pxa: support pxa168 LCD controller SPI operation
Date: Tue, 3 Nov 2009 16:32:30 +0800	[thread overview]
Message-ID: <f17812d70911030032u1fc5f7afwce0d36da906867d8@mail.gmail.com> (raw)
In-Reply-To: <7c34ac520911022245x2845e5dex1311bd74a08606db@mail.gmail.com>

On Tue, Nov 3, 2009 at 2:45 PM, Jun Nie <niej0001@gmail.com> wrote:
> pxa: support pxa168 LCD controller SPI operation
>
> Signed-off-by: Jun Nie <njun@marvell.com>
> ---
>  arch/arm/mach-mmp/include/mach/pxa168fb.h |   29 +++++++++
>  drivers/video/pxa168fb.c                  |   92 +++++++++++++++++++++++++++++
>  drivers/video/pxa168fb.h                  |   24 +-------
>  include/video/pxa168fb.h                  |   18 ++++++
>  4 files changed, 140 insertions(+), 23 deletions(-)
>  create mode 100644 arch/arm/mach-mmp/include/mach/pxa168fb.h
>
> diff --git a/arch/arm/mach-mmp/include/mach/pxa168fb.h
> b/arch/arm/mach-mmp/include/mach/pxa168fb.h
> new file mode 100644
> index 0000000..897cc3e
> --- /dev/null
> +++ b/arch/arm/mach-mmp/include/mach/pxa168fb.h
> @@ -0,0 +1,29 @@
> +#ifndef __PXA168FBSPI_H__
> +#define __PXA168FBSPI_H__
> +
> +/* SPI Control Register. */
> +#define LCD_SPU_SPI_CTRL                       0x0180
> +#define     CFG_SCLKCNT(div)                   ((div) << 24)  /* 0xFF~0x2 */
> +#define     CFG_SCLKCNT_MASK                   0xFF000000
> +#define     CFG_RXBITS(rx)                     ((rx - 1) << 16)   /* 0x1F~0x1, 0x1:
> 2bits ... 0x1F: 32bits */
> +#define     CFG_RXBITS_MASK                    0x00FF0000
> +#define     CFG_TXBITS(tx)                      ((tx - 1) << 8)    /*
> 0x1F~0x1, 0x1: 2bits ... 0x1F: 32bits */
> +#define     CFG_TXBITS_MASK                    0x0000FF00
> +#define     CFG_CLKINV(clk)                    ((clk) << 7)
> +#define     CFG_CLKINV_MASK                    0x00000080
> +#define     CFG_KEEPXFER(transfer)             ((transfer) << 6)
> +#define     CFG_KEEPXFER_MASK                  0x00000040
> +#define     CFG_RXBITSTO0(rx)                  ((rx) << 5)
> +#define     CFG_RXBITSTO0_MASK                 0x00000020
> +#define     CFG_TXBITSTO0(tx)                  ((tx) << 4)
> +#define     CFG_TXBITSTO0_MASK                 0x00000010
> +#define     CFG_SPI_ENA(spi)                   ((spi) << 3)
> +#define     CFG_SPI_ENA_MASK                   0x00000008
> +#define     CFG_SPI_SEL(spi)                   ((spi) << 2)    /* 1: port1; 0: port0 */
> +#define     CFG_SPI_SEL_MASK                   0x00000004
> +#define     CFG_SPI_3W4WB(wire)                 ((wire)<<1)  /* 1:
> 3-wire; 0: 4-wire */
> +#define     CFG_SPI_3W4WB_MASK                 0x00000002
> +#define     CFG_SPI_START(start)               (start)
> +#define     CFG_SPI_START_MASK                 0x00000001
> +
> +#endif /* __PXA168FBSPI_H__ */

Shouldn't these be defined in drivers/video/pxa168fb.h? Or if
some of the definitions are to be used by platform code, move
them to include/video/pxa168fb.h.

> diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c
> index 84d8327..27bdf2b 100644
> --- a/drivers/video/pxa168fb.c
> +++ b/drivers/video/pxa168fb.c
> @@ -29,10 +29,91 @@
>  #include <linux/uaccess.h>
>  #include <video/pxa168fb.h>
>
> +#include <mach/pxa168fb.h>
> +#include <mach/gpio.h>
>  #include "pxa168fb.h"
>
>  #define DEFAULT_REFRESH                60      /* Hz */
>
> +static inline void spi_gpio_assert_set(int spi_gpio_cs, int val)
> +{
> +              if (gpio_is_valid(spi_gpio_cs))
> +                                     gpio_set_value(spi_gpio_cs, val);
> +}

Mmm.... two points:

1. spi_gpio_assert() sounds enough to me, no "_set" suffix necessary
2. is it possible that in some cases that this GPIO CS signal is inverted?

> +int pxa168fb_spi_send(struct pxa168fb_info *fbi, void *value, int count,
> +               unsigned int spi_gpio_cs, unsigned int interval_us)
> +{
> +       u32 x, spi_byte_len;
> +       u8 *cmd = (u8 *)value;
> +       int i, err, isr, iopad, ret = 0;
> +
> +       if (gpio_is_valid(spi_gpio_cs)) {
> +               err = gpio_request(spi_gpio_cs, "LCD_SPI_CS");
> +               if (err) {
> +                       dev_err(fbi->dev, "failed to request GPIO for LCD CS\n");
> +                       return -1;
> +               }
> +               gpio_direction_output(spi_gpio_cs, 1);
> +       }

Is this possible this been done at some initialization stage and do only once?

> +       spi_byte_len = readl(fbi->reg_base + LCD_SPU_SPI_CTRL);
> +       spi_byte_len = (spi_byte_len >> 8) & 0xff;
> +       /* Alignment should be (spi_byte_len + 7) >> 3, but
> +        * spi controller request set one less than bit length */
> +       spi_byte_len = (spi_byte_len + 8) >> 3;
> +       /* spi command provided by platform should be 1, 2, or 4 byte aligned */
> +       if(3 == spi_byte_len)
> +               spi_byte_len = 4;
> +
> +       iopad = readl(fbi->reg_base + SPU_IOPAD_CONTROL);
> +       if ((iopad & CFG_IOPADMODE_MASK) != PIN_MODE_DUMB_18_SPI)
> +               writel(PIN_MODE_DUMB_18_SPI, fbi->reg_base + SPU_IOPAD_CONTROL);
> +       isr = readl(fbi->reg_base + SPU_IRQ_ISR);
> +       writel((isr & ~SPI_IRQ_ENA_MASK), fbi->reg_base + SPU_IRQ_ISR);
> +       for (i = 0; i < count; i++) {
> +               spi_gpio_assert_set(spi_gpio_cs, 0);
> +               udelay(interval_us);
> +               switch (spi_byte_len){
> +               case 1:
> +                       writel(*cmd, fbi->reg_base + LCD_SPU_SPI_TXDATA);
> +                       break;
> +               case 2:
> +                       writel(*(u16*)cmd, fbi->reg_base + LCD_SPU_SPI_TXDATA);
> +                       break;
> +               case 4:
> +                       writel(*(u32*)cmd, fbi->reg_base + LCD_SPU_SPI_TXDATA);
> +                       break;
> +               default:
> +                       dev_err(fbi->dev, "Wrong spi bit length\n");
> +                       spi_gpio_assert_set(spi_gpio_cs, 1);
> +                       ret = -1;
> +                       goto spi_exit;
> +               }
> +               cmd += spi_byte_len;
> +               x = readl(fbi->reg_base + LCD_SPU_SPI_CTRL);
> +               x |= 0x1;
> +               writel(x, fbi->reg_base + LCD_SPU_SPI_CTRL);
> +               isr = readl(fbi->reg_base + SPU_IRQ_ISR);
> +               while(!(isr & SPI_IRQ_ENA_MASK)) {
> +                       udelay(1);
> +                       isr = readl(fbi->reg_base + SPU_IRQ_ISR);
> +               }
> +               x = readl(fbi->reg_base + LCD_SPU_SPI_CTRL);
> +               x &= ~0x1;
> +               writel(x, fbi->reg_base + LCD_SPU_SPI_CTRL);
> +               spi_gpio_assert_set(spi_gpio_cs, 1);
> +       }

So after this loop, the 'spi_gpio_cs' is left asserted, which isn't good.

> +
> +spi_exit:
> +       if (gpio_is_valid(spi_gpio_cs))
> +               gpio_free(spi_gpio_cs);
> +       if ((iopad & CFG_IOPADMODE_MASK) != PIN_MODE_DUMB_18_SPI)
> +               writel(iopad, fbi->reg_base + SPU_IOPAD_CONTROL);
> +
> +       return ret;
> +}
> +EXPORT_SYMBOL(pxa168fb_spi_send);
> +
>  static int determine_best_pix_fmt(struct fb_var_screeninfo *var)
>  {
>        /*
> @@ -687,6 +768,7 @@ static int __init pxa168fb_probe(struct
> platform_device *pdev)
>        }
>
>        info->fix.smem_start = (unsigned long)fbi->fb_start_dma;
> +       set_graphics_start(info, 0, 0);

This need a separate patch.

>
>        /*
>         * Set video mode according to platform data.
> @@ -728,6 +810,9 @@ static int __init pxa168fb_probe(struct
> platform_device *pdev)
>        writel(0, fbi->reg_base + LCD_SPU_SRAM_PARA0);
>        writel(CFG_CSB_256x32(0x1)|CFG_CSB_256x24(0x1)|CFG_CSB_256x8(0x1),
>                fbi->reg_base + LCD_SPU_SRAM_PARA1);
> +       if ((mi->spi_ctrl != -1) && (mi->spi_ctrl & CFG_SPI_ENA_MASK))
> +               writel(mi->spi_ctrl, fbi->reg_base + LCD_SPU_SPI_CTRL);
> +
>
>        /*
>         * Allocate color map.
> @@ -764,6 +849,13 @@ static int __init pxa168fb_probe(struct
> platform_device *pdev)
>        }
>
>        platform_set_drvdata(pdev, fbi);
> +       if (mi->pxa168fb_lcd_power){
> +               if(mi->pxa168fb_lcd_power(fbi, mi->spi_gpio_cs, mi->spi_gpio_reset, 1)){
> +                       dev_err(&pdev->dev, "Failed to power up pxa168-fb\n");
> +                       goto failed_free_irq;
> +               }
> +       }
> +       dev_info(fbi->dev, "frame buffer detected\n");

Need another patch for this as well?

>        return 0;
>
>  failed_free_irq:
> diff --git a/drivers/video/pxa168fb.h b/drivers/video/pxa168fb.h
> index eee0927..1e4859e 100644
> --- a/drivers/video/pxa168fb.h
> +++ b/drivers/video/pxa168fb.h
> @@ -170,29 +170,7 @@
>  #define     DMA_FRAME_CNT_MASK                 0x00000003  /* Video */
>
>  /* SPI Control Register. */
> -#define LCD_SPU_SPI_CTRL                       0x0180
> -#define     CFG_SCLKCNT(div)                   ((div) << 24)  /* 0xFF~0x2 */
> -#define     CFG_SCLKCNT_MASK                   0xFF000000
> -#define     CFG_RXBITS(rx)                     ((rx) << 16)   /* 0x1F~0x1 */
> -#define     CFG_RXBITS_MASK                    0x00FF0000
> -#define     CFG_TXBITS(tx)                     ((tx) << 8)    /* 0x1F~0x1 */
> -#define     CFG_TXBITS_MASK                    0x0000FF00
> -#define     CFG_CLKINV(clk)                    ((clk) << 7)
> -#define     CFG_CLKINV_MASK                    0x00000080
> -#define     CFG_KEEPXFER(transfer)             ((transfer) << 6)
> -#define     CFG_KEEPXFER_MASK                  0x00000040
> -#define     CFG_RXBITSTO0(rx)                  ((rx) << 5)
> -#define     CFG_RXBITSTO0_MASK                 0x00000020
> -#define     CFG_TXBITSTO0(tx)                  ((tx) << 4)
> -#define     CFG_TXBITSTO0_MASK                 0x00000010
> -#define     CFG_SPI_ENA(spi)                   ((spi) << 3)
> -#define     CFG_SPI_ENA_MASK                   0x00000008
> -#define     CFG_SPI_SEL(spi)                   ((spi) << 2)
> -#define     CFG_SPI_SEL_MASK                   0x00000004
> -#define     CFG_SPI_3W4WB(wire)                        ((wire) << 1)
> -#define     CFG_SPI_3W4WB_MASK                 0x00000002
> -#define     CFG_SPI_START(start)               (start)
> -#define     CFG_SPI_START_MASK                 0x00000001
> +/* For SPI register, please refer to
> arch/arm/mach-mmp/include/mach/pxa168fb.h */
>
>  /* SPI Tx Data Register */
>  #define LCD_SPU_SPI_TXDATA                     0x0184
> diff --git a/include/video/pxa168fb.h b/include/video/pxa168fb.h
> index b5cc72f..f0497ae 100644
> --- a/include/video/pxa168fb.h
> +++ b/include/video/pxa168fb.h
> @@ -122,6 +122,24 @@ struct pxa168fb_mach_info {
>        unsigned        panel_rbswap:1;
>        unsigned        active:1;
>        unsigned        enable_lcd:1;
> +       /*
> +        * SPI control
> +        */
> +       unsigned int    spi_ctrl;
> +       unsigned int    spi_gpio_cs;
> +       unsigned int    spi_gpio_reset;
> +       /*
> +        * power on/off function.
> +        */
> +       int (*pxa168fb_lcd_power)(struct pxa168fb_info *, unsigned int,
> unsigned int, int);
>  };
>
> +/* SPI utility for configure panel SPI command.
> + * value: command array, element should be 1, 2 or 4 byte aligned.
> + * count: command array length
> + * spi_gpio_cs: gpio number for spi chip select
> + * interval_us: time interval between two commands, us as unit */
> +int pxa168fb_spi_send(struct pxa168fb_info *fbi, void *value, int count,
> +               unsigned int spi_gpio_cs, unsigned int interval_us);
> +
>  #endif /* __ASM_MACH_PXA168FB_H */
> --
> 1.5.4.3
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Linux-fbdev-devel mailing list
Linux-fbdev-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-fbdev-devel

  parent reply	other threads:[~2009-11-03  8:33 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-11-03  6:45 [PATCH 1/6] pxa: support pxa168 LCD controller SPI operation Jun Nie
2009-11-03  7:28 ` Jun Nie
2009-11-03  8:32 ` Eric Miao [this message]
2009-11-08 16:53 ` Russell King - ARM Linux

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f17812d70911030032u1fc5f7afwce0d36da906867d8@mail.gmail.com \
    --to=eric.y.miao@gmail.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-fbdev-devel@lists.sourceforge.net \
    --cc=niej0001@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).