From: Eric M. <eri...@gm...> - 2009-11-03 08:33:03
|
On Tue, Nov 3, 2009 at 2:45 PM, Jun Nie <nie...@gm...> wrote: > pxa: support pxa168 LCD controller SPI operation > > Signed-off-by: Jun Nie <nj...@ma...> > --- > 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 > lin...@li... > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel > |
From: Jun N. <nie...@gm...> - 2009-11-03 06:45:32
|
pxa: support pxa168 LCD controller SPI operation Signed-off-by: Jun Nie <nj...@ma...> --- 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__ */ 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); +} + +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); + } + 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); + } + +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); /* * 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"); 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 |
From: Jun N. <nie...@gm...> - 2009-11-03 07:29:03
|
2009/11/3 Jun Nie <nie...@gm...>: > pxa: support pxa168 LCD controller SPI operation > > Signed-off-by: Jun Nie <nj...@ma...> > --- > 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__ */ > 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); > +} > + > +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); > + } > + 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); > + } > + > +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); > > /* > * 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"); > 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 > add lin...@vg... |
From: Russell K. - A. L. <li...@ar...> - 2009-11-08 17:10:31
|
On Tue, Nov 03, 2009 at 02:45:20PM +0800, Jun Nie wrote: > 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> linux/gpio.h > +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; Please stop using '-1' as a general error return value. It has a specific meaning, translating as "operation not permitted" or "permission denied". This is not what this error is. Always propagate error codes back when you have them. |
From: Jun N. <nie...@gm...> - 2009-11-16 09:34:25
|
>From 40bb744e91d8058faa38fb953ade1964c865e846 Mon Sep 17 00:00:00 2001 From: Jun Nie <nj...@ma...> Date: Fri, 13 Nov 2009 14:02:20 +0800 Subject: [PATCH] pxa: support pxa168 LCD controller SPI operation Signed-off-by: Jun Nie <nj...@ma...> --- drivers/video/pxa168fb.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++ drivers/video/pxa168fb.h | 24 +------------- include/video/pxa168fb.h | 47 ++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 23 deletions(-) diff --git a/drivers/video/pxa168fb.c b/drivers/video/pxa168fb.c index 84d8327..aec95c4 100644 --- a/drivers/video/pxa168fb.c +++ b/drivers/video/pxa168fb.c @@ -27,12 +27,90 @@ #include <linux/clk.h> #include <linux/err.h> #include <linux/uaccess.h> +#include <linux/gpio.h> #include <video/pxa168fb.h> #include "pxa168fb.h" #define DEFAULT_REFRESH 60 /* Hz */ +static inline void spi_gpio_assert(int spi_gpio_cs, int val) +{ + if (gpio_is_valid(spi_gpio_cs)) + gpio_set_value(spi_gpio_cs, val); +} + +int pxa168fb_spi_send(struct pxa168fb_info *fbi, void *value, int count, + unsigned int spi_gpio_cs, unsigned int cs_active, + unsigned int interval_us) +{ + u32 x, spi_byte_len; + u8 *cmd = (u8 *)value; + int i, isr, iopad, ret = 0; + + if (gpio_is_valid(spi_gpio_cs)) { + ret = gpio_direction_output(spi_gpio_cs, !cs_active); + if (ret) + goto spi_exit; + } + 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(spi_gpio_cs, cs_active); + 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(spi_gpio_cs, !cs_active); + ret = -EINVAL; + goto spi_exit; + } + cmd += spi_byte_len; + x = readl(fbi->reg_base + LCD_SPU_SPI_CTRL); + x |= CFG_SPI_START_MASK; + 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 &= ~CFG_SPI_START_MASK; + writel(x, fbi->reg_base + LCD_SPU_SPI_CTRL); + spi_gpio_assert(spi_gpio_cs, !cs_active); + } + +spi_exit: + if (gpio_is_valid(spi_gpio_cs)) + gpio_direction_input(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) { /* @@ -728,6 +806,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. diff --git a/drivers/video/pxa168fb.h b/drivers/video/pxa168fb.h index eee0927..55ec4dc 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 include/video/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..01c18bc 100644 --- a/include/video/pxa168fb.h +++ b/include/video/pxa168fb.h @@ -14,6 +14,32 @@ #include <linux/fb.h> #include <linux/interrupt.h> +/* SPI Control Register. */ +#define LCD_SPU_SPI_CTRL 0x0180 +#define CFG_SCLKCNT(div) ((div) << 24) /* 0xFF~0x2 */ +#define CFG_SCLKCNT_MASK 0xFF000000 +/* SPI RX/TX bit length, 0x1F~0x1, 0x1: 2bits ... 0x1F: 32bits */ +#define CFG_RXBITS(rx) ((rx - 1) << 16) +#define CFG_RXBITS_MASK 0x00FF0000 +#define CFG_TXBITS(tx) ((tx - 1) << 8) +#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 + /* Dumb interface */ #define PIN_MODE_DUMB_24 0 #define PIN_MODE_DUMB_18_SPI 1 @@ -122,6 +148,27 @@ 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 + * cs_active: CS active polarity for SPI transaction + * 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 cs_active, + unsigned int interval_us); + #endif /* __ASM_MACH_PXA168FB_H */ -- 1.5.4.3 |