spi interface lcd driver for imx28 evkboard

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

spi interface lcd driver for imx28 evkboard

3,771 Views
sandeshgowda
Contributor III

1) pixel clock is not varying ?

2) spi clock is not varying when iam passing spi device clk 30 Mhz and it shows default 12 Mhz

Labels (1)
0 Kudos
Reply
12 Replies

2,349 Views
MarekVasut
Senior Contributor I

Please give us more details. At least:

1) What type of SmartLCD controller do you intend to use

2) How do you attach it to the CPU

3) What kind of result do you expect

4) What kind of software do you run (Linux version and U-Boot version)

0 Kudos
Reply

2,349 Views
sandeshgowda
Contributor III

1) NT39016D  lcd controller

2) on chip

3) RGB data in lcd panel(TM035KDH04)

4) linux-2.6.35.3

0 Kudos
Reply

2,349 Views
MarekVasut
Senior Contributor I

OK, so you want to connect this controller to the iMX28 via SPI and expect data to show up on it, right ?

You will need to write a driver for this particular controller that would pump the framebuffer data via the SPI into the SmartLCD controller periodically.

btw it might work switching to mainline with i.MX28, mainline is much more advanced and maintained.

0 Kudos
Reply

2,349 Views
sandeshgowda
Contributor III

I had written driver, in that I am passing lcd panel information and filling registers(lcd panel controller) and writing through spi  write function.

here i got an issue

1) what ever the data i am sending through spi is not reaching to the controller. i have checked it by probing the pins through CRO.

       plz let me know abit the issue

0 Kudos
Reply

2,349 Views
MarekVasut
Senior Contributor I

Do you see the data on the SPI bus ? If not, then your pin muxing is likely wrong or you're using wrong controller (there are four SPI controllers on MX28).

0 Kudos
Reply

2,349 Views
sandeshgowda
Contributor III

1) I probed the data line of spi, it showing nothing. but the clk line showing 12Mhz but the spi device frequency which i am passing is 30 Mhz

2) pinmuxing is correct, i cross checked

my spi bus 1 is registered as mxs-spi.0 and the ssp2 resources is allocated to this bus no 1, is it correct ?

0 Kudos
Reply

2,349 Views
MarekVasut
Senior Contributor I

1) This might be the down-division from 480MHz, but I'd expect you to get 24MHz at least as that's much closer.

But anyway, if you see SCK toggling, but no data being emited, this is where we should poke. Can you share your display driver or at least the routine submitting the data to the SPI ?

2) OK

-> Can you show us your changed /wrt the SPI busses to arch/arm/ ? We should be able to divine something from that maybe.

0 Kudos
Reply

2,349 Views
sandeshgowda
Contributor III

arch/arm/mach-mx28/device.c

          };     
static struct resource ssp2_resources[] = {
        {
                .start  = SSP2_PHYS_ADDR,
                .end    = SSP2_PHYS_ADDR + 0x2000 - 1,
                .flags  = IORESOURCE_MEM,
        }, {
                .start  = MXS_DMA_CHANNEL_AHB_APBH_SSP2,
                .end    = MXS_DMA_CHANNEL_AHB_APBH_SSP2,
                .flags  = IORESOURCE_DMA,
        }, {
                .start  = IRQ_SSP2_DMA,
                .end    = IRQ_SSP2_DMA,
                .flags  = IORESOURCE_IRQ,
        }, {
                .start  = IRQ_SSP2,
                .end    = IRQ_SSP2,
                .flags  = IORESOURCE_IRQ,
        },
};     
       
static void __init mx28_init_spi(void)
{
        struct platform_device *pdev;

        pdev = mxs_get_device("mxs-spi", 0);
        if (pdev == NULL || IS_ERR(pdev))
                return;
        pdev->resource = ssp2_resources;
        pdev->num_resources = ARRAY_SIZE(ssp2_resources);
        pdev->dev.platform_data = &spi_data;
               
        mxs_add_device(pdev, 3);
}      

*************** display driver code ****************************


#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/console.h>
#include <linux/errno.h>
#include <linux/fsl_devices.h>
#include <linux/gpio.h>
#include "mx28_pins.h"
//p
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/notifier.h>
#include <linux/regulator/consumer.h>
#include <linux/platform_device.h>

#include <mach/device.h>
#include <mach/lcdif.h>
#include <mach/regs-pwm.h>
#include <mach/system.h>
#include <linux/spi/spi.h>

#define DOTCLK_H_ACTIVE  320
#define DOTCLK_H_PULSE_WIDTH 10
#define DOTCLK_HF_PORCH  164
#define DOTCLK_HB_PORCH  89
#define DOTCLK_H_WAIT_CNT  (DOTCLK_H_PULSE_WIDTH + DOTCLK_HB_PORCH)
#define DOTCLK_H_PERIOD (DOTCLK_H_WAIT_CNT + DOTCLK_HF_PORCH + DOTCLK_H_ACTIVE)

#define DOTCLK_V_ACTIVE  240
#define DOTCLK_V_PULSE_WIDTH  10
#define DOTCLK_VF_PORCH  10
#define DOTCLK_VB_PORCH  23
#define DOTCLK_V_WAIT_CNT (DOTCLK_V_PULSE_WIDTH + DOTCLK_VB_PORCH)
#define DOTCLK_V_PERIOD (DOTCLK_VF_PORCH + DOTCLK_V_ACTIVE + DOTCLK_V_WAIT_CNT)

static struct clk *lcd_clk;

static int init_panel(struct device *dev, dma_addr_t phys, int memsize,
              struct mxs_platform_fb_entry *pentry)
{
   
    int ret = 0;


    lcd_clk = clk_get(dev, "dis_lcdif");
    if (IS_ERR(lcd_clk)) {
        ret = PTR_ERR(lcd_clk);
        goto out;
    }
    ret = clk_enable(lcd_clk);
    if (ret) {
        clk_put(lcd_clk);
        goto out;
    }

    ret = clk_set_rate(lcd_clk, 1000000 / pentry->cycle_time_ns);    /* kHz */
    if (ret) {
        clk_disable(lcd_clk);
        clk_put(lcd_clk);
        goto out;
    }

    /*
     * Make sure we do a high-to-low transition to reset the panel.
     * First make it low for 100 msec, hi for 10 msec, low for 10 msec,
     * then hi.
     */
    __raw_writel(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR);    /* low */
    mdelay(100);
    __raw_writel(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1_SET);    /* high */
    mdelay(10);
    __raw_writel(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1_CLR);    /* low */

    /* For the Samsung, Reset must be held low at least 30 uSec
     * Therefore, we'll hold it low for about 10 mSec just to be sure.
     * Then we'll wait 1 mSec afterwards.
     */
    mdelay(10);
    __raw_writel(BM_LCDIF_CTRL1_RESET, REGS_LCDIF_BASE + HW_LCDIF_CTRL1_SET);    /* high */
    mdelay(1);

    setup_dotclk_panel(DOTCLK_V_PULSE_WIDTH, DOTCLK_V_PERIOD,
               DOTCLK_V_WAIT_CNT, DOTCLK_V_ACTIVE,
               DOTCLK_H_PULSE_WIDTH, DOTCLK_H_PERIOD,
               DOTCLK_H_WAIT_CNT, DOTCLK_H_ACTIVE, 0);

    ret = mxs_lcdif_dma_init(dev, phys, memsize);
    if (ret)
        goto out;

//    mxs_lcd_set_bl_pdata(pentry->bl_data);
    mxs_lcdif_notify_clients(MXS_LCDIF_PANEL_INIT, pentry);
    return 0;

out:
    return ret;
}

static void release_panel(struct device *dev,
              struct mxs_platform_fb_entry *pentry)
{
    mxs_lcdif_notify_clients(MXS_LCDIF_PANEL_RELEASE, pentry);
    release_dotclk_panel();
    mxs_lcdif_dma_release();
    clk_disable(lcd_clk);
    clk_put(lcd_clk);
}

static int blank_panel(int blank)
{
    int ret = 0, count;

    switch (blank) {
    case FB_BLANK_NORMAL:
    case FB_BLANK_VSYNC_SUSPEND:
    case FB_BLANK_HSYNC_SUSPEND:
    case FB_BLANK_POWERDOWN:
        __raw_writel(BM_LCDIF_CTRL_BYPASS_COUNT,
                 REGS_LCDIF_BASE + HW_LCDIF_CTRL_CLR);
        for (count = 10000; count; count--) {
            if (__raw_readl(REGS_LCDIF_BASE + HW_LCDIF_STAT) &
                BM_LCDIF_STAT_TXFIFO_EMPTY)
                break;
            udelay(1);
        }
        break;

    case FB_BLANK_UNBLANK:
        __raw_writel(BM_LCDIF_CTRL_BYPASS_COUNT,
                 REGS_LCDIF_BASE + HW_LCDIF_CTRL_SET);
        break;

    default:
        ret = -EINVAL;
    }
    return ret;
}

static struct mxs_platform_fb_entry fb_entry = {
    .name = "tm035kdh",
    .x_res = 240, //480,
    .y_res = 320, //800,
    .bpp = 32,
    .cycle_time_ns = 35, //35,
    .lcd_type = MXS_LCD_PANEL_DOTCLK,
    .init_panel = init_panel,
    .release_panel = release_panel,
//    .blank_panel = blank_panel,
    .run_panel = mxs_lcdif_run,
    .stop_panel = mxs_lcdif_stop,
    .pan_display = mxs_lcdif_pan_display,
};


static const struct {
        unsigned char addr;
        unsigned char data;
} tftcluster_spi_init_seq[] = {
                          {0x00,0x07}, {0x01,0x00}, {0x02,0x03}, {0x03,0xCC}, {0x04,0x46}, {0x05,0x0D}, {0x06,0x00}, {0x07,0x00}, {0x08,0x08}, {0x09,0x40}, {0x0A,0x88}, {0x0B,0x88}, {0x0C,0x20}, {0x0D,0x20}, {0x0E,0x10}, {0x0F,0xA4}, {0x10,0x04}, {0x11,0x24}, {0x12,0x24}, {0x1E,0x00}, {0x20,0x00},
};

static int tftcluster_spi_send(struct spi_device *spi, unsigned char reg_addr,
                        unsigned char reg_data)
{
        int ret = 0;
        unsigned int cmd = 0, data = 0, data1 = 0;

        cmd = 0x0000 | reg_addr; /* register address write */
        data1 = 0x0000 | reg_data ; /* register data write */
        data = (data1 << 8) | cmd;
//     printk("\nAddr: %x  Data: %x Write_Data: %x \n",cmd, data1, data);

        ret = spi_write(spi, (unsigned char *)&data, 2);
        if (ret)
                pr_err("error in spi_write %x\n", data);

        return ret;
}

static int tftcluster_spi_rcv(struct spi_device *spi, unsigned char reg_addr)
{
        int ret = 0;

        ret = spi_w8r8(spi, reg_addr);

//      ret = spi_read(spi, (unsigned char *)&data, 2);
//   spi_write_then_read(spi, (const void *)&data, 1,
   //                             (void *)&ret, 1);
    printk("Addr: %x Data: %x \n",reg_addr,ret);

//     if (ret)
   //           pr_err("error in spi_read %x\n", reg_addr);

        return ret;


}

static int __devexit lcd_spi_remove(struct spi_device *spi)
{
//       lcd_spi = NULL;
        return 0;
}


static int spi_init_tftcluster_lcd(struct spi_device *spi)
{
        unsigned int i,ret=0;
    unsigned char  addr=0x00;

        /* Initialization Sequence */
        /* tftcluster_spi_send(spi, REG, VAL) */

        for (i = 0; i <= (ARRAY_SIZE(tftcluster_spi_init_seq) - 1); i++)
                tftcluster_spi_send(spi, tftcluster_spi_init_seq[i].addr,
                                tftcluster_spi_init_seq[i].data);

/*       for (i = 0; i <= (ARRAY_SIZE(tftcluster_spi_init_seq) - 1); i++)
       {
               tftcluster_spi_rcv(spi, (addr+i));

        }*/


//      udelay(20);
//    tftcluster_lcd_auto_power_off(lcd_spi);

        return 0;
}

static int __devinit lcd_spi_probe(struct spi_device *spi)
{

     printk("\n\n\nlcd_spi probe successfully\n\n\n");
    spi->mode = SPI_3WIRE;
//      spi->bits_per_word = 16;        //32
        spi_setup(spi);

    spi_init_tftcluster_lcd(spi);

       return 0;

}


static struct spi_driver lcd_spi_dev_driver = {


        .driver = {
                   .name = "lcd_spi",
                   .bus  = &spi_bus_type,
                   .owner = THIS_MODULE,
                   },
        .probe = lcd_spi_probe,
        .remove = __devexit_p(lcd_spi_remove),
};

static int __init register_devices(void)
{
        struct platform_device *pdev;
        pdev = mxs_get_device("mxs-fb", 0);

        if (pdev == NULL || IS_ERR(pdev))
        {
                printk("\n\n register device \n\n");
                return -ENODEV;
        }
   
        mxs_lcd_register_entry(&fb_entry, pdev->dev.platform_data);
        spi_register_driver(&lcd_spi_dev_driver);

        return 0;
}

subsys_initcall(register_devices);

                       

****************************************************

i shared the driver code and spi bus stuff in device file.

please check and let me know if there is any issues

0 Kudos
Reply

2,349 Views
MarekVasut
Senior Contributor I

The SPI_3WIRE mode doesn't seem right, the SI/SO signals are not shared in this setup. Also , your driver seems to be partly talking to LCDIF and partly to SPI, that doesn't seem right either.

0 Kudos
Reply

2,349 Views
sandeshgowda
Contributor III

1) My lcd interface is 3-wire spi. MOSI/MISO signals are shared in hardware. Only one signal line is connected to lcd, either we can transfer or recieve

2)  Coming to LCDIF is used to transfer the pixel clock and lcd specifications to the framebuffer. spi is used to control the LCD.

If there is any thing else is required please let me know

0 Kudos
Reply

2,349 Views
YixingKong
Senior Contributor IV

Sandesh

This discussion is closed since no activity. If you still need help, please feel free to reply with an update to this discussion, or create another discussion.

Thanks,

Yixing

0 Kudos
Reply

2,349 Views
YixingKong
Senior Contributor IV

Sandesh

Had your issue got resolved? If yes, we are going to close the discussion in 3 days. If you still need help, please feel

free to reply with an update to this discussion.

Thanks,
Yixing

0 Kudos
Reply