how to write display driver
Asked Answered
T

0

6

I am writing display drivers for micro oled. board is dart4460 (omap4460) which provides dss(display subsystem). so I am writing drivers using dss.

but I dont know what I wrote is right or not

oled display use dpi interface and i2c for commands

I referred to pico dlp projector driver source which uses dpi and i2c.

here are datasheets

dart4460: http://www.variscite.com/images/DART-4460-DS_107.pdf

micro oled display: https://www.dropbox.com/s/ixpws4qzo3ttj6e/SVGA050.pdf?dl=0

Code:

panel-svga.c

#define SLAVE_ADDR_READ     0x1F
#define SLAVW_ADDR_WRITE    0x1E

struct svga050_i2c_data {
struct mutex xfer_lock;
};

struct svga050_data {
struct i2c_client *client;
struct mutex lock;
};

static struct i2c_board_info svga050_i2c_board_info = {
I2C_BOARD_INFO("svga050_i2c_drive",SLAVE_ADDR_WRITE);
}

static struct omap_video_timings svga050_timings = {
   .x_res = 800,
   .y_res = 600,

   .pixel_clock = 40000,

   .hsw     = 128,
   .hfp     = 40,
   .hbp     = 88,

   .vsw     = 4,
   .vfp     = 1,
   .vbp     = 23,
};

static int svga050_panel_power_on(struct omap_dss_device *dssdev)
{
    int r;

if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE)
    return 0;

r = omapdss_dpi_display_enable(dssdev);
if (r)
    goto err0;

if (dssdev->platform_enable) {
    r = dssdev->platform_enable(dssdev);
    if (r)
        goto err1;
}

    return 0;
    err1:
       omapdss_dpi_display_disable(dssdev);
    err0:
       return r;
 }

 static void svga050_panel_power_off(struct omap_dss_device *dssdev)
{
    if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
        return;

    if (dssdev->platform_disable)
        dssdev->platform_disable(dssdev);

     omapdss_dpi_display_disable(dssdev);
 }

 static inline struct svga050_panel_data *get_panel_data(const struct  omap_dss_device *dssdev)
 {
     return (struct svga050_panel_data *)dssdev->data;
 }

  static int svga050_panel_probe(struct omap_dss_device *dssdev)
 {
    struct svga050_data *svga_data;
    struct i2c_adapter *adapter;
    struct i2c_client *svga_i2c_client;
    struct svga050_panel_data *svga_pdata=get_panel_data(dssdev);
    int r;

    dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
       OMAP_DSS_LCD_IHS;
    dssdev->panel.timings = svga050_timings;

    svga_data = devm_kzalloc(&dssdev->dev,sizeof(*svga_data), GFP_KERNEL);
    if (!svga_data) {
       r = -ENOMEM;
    goto err;
    }
    mutex_init(&ld->lock);
    dev_set_drvdata(&dssdev->dev, ld);
    return 0;
      err:
      return r;
    }

   static void svga050_panel_remove(struct omap_dss_device *dssdev)
  {
     struct svga050_data *ld = dev_get_drvdata(&dssdev->dev);

     kfree(ld);
   }

  static int svga050_panel_enable(struct omap_dss_device *dssdev)
 {
     struct svga050_data *ld = dev_get_drvdata(&dssdev->dev);
     int r;

      mutex_lock(&ld->lock);

     r = svga050_panel_power_on(dssdev);
     if (r)
    goto err;
    dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;

    mutex_unlock(&ld->lock);
    return 0;
    err:
      mutex_unlock(&ld->lock);
    return r;
 }

static void svga050_panel_disable(struct omap_dss_device *dssdev)
{
    struct svga050_data *ld = dev_get_drvdata(&dssdev->dev);

    mutex_lock(&ld->lock);

    svga050_panel_power_off(dssdev);
    dssdev->state = OMAP_DSS_DISPLAY_DISABLED;

    mutex_unlock(&ld->lock);
 }

 static int svga050_panel_suspend(struct omap_dss_device *dssdev)
{
    struct svga050_data *ld = dev_get_drvdata(&dssdev->dev);

    mutex_lock(&ld->lock);

    svga050_panel_power_off(dssdev);
    dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;

    mutex_unlock(&ld->lock);
    return 0;
}

static int svga050_panel_resume(struct omap_dss_device *dssdev)
{
   struct svga050_data *ld = dev_get_drvdata(&dssdev->dev);
   int r;

   mutex_lock(&ld->lock);

   r = svga050_panel_power_on(dssdev);
   if (r)
       goto err;
   dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;

   mutex_unlock(&ld->lock);
   return 0;
  err:
      mutex_unlock(&ld->lock);
  return r;
}

 static struct omap_dss_driver svga050_driver = {
     .probe     = svga050_panel_probe,
     .remove        = svga050_panel_remove,

     .enable        = svga050_panel_enable,
     .disable   = svga050_panel_disable,
     .suspend   = svga050_panel_suspend,
     .resume        = svga050_panel_resume,

     .driver         = {
        .name   = "svga050",
        .owner  = THIS_MODULE,
     },
  };

  static int svga050_i2c_read(struct i2c_client *client, u8 reg)
 {
    u8 read_cmd[] = { SLAVE_ADDR_READ, reg }, data;
    struct svga050_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client);
    struct i2c_msg msg[2];
    mutex_lock(&svga050_i2c_data->xfer_lock);
    msg[0].addr = client->addr;
    msg[0].flags = 0;
    msg[0].len = 2;
    msg[0].buf = read_cmd;
    msg[1].addr = client->addr;
    msg[1].flags = I2C_M_RD;
    msg[1].len = 2;
    msg[1].buf = data;
    i2c_transfer(client->adapter, msg, 2);
    mutex_unlock(&svga050_i2c_data->xfer_lock);
    return data;
 }

 static int svga050_i2c_write(struct i2c_client *client, u8 reg, u8 value)
 {
    u8 data[2];
    int i;
    struct i2c_msg msg;
    int i, r, msg_count = 1;
    struct svga050_i2c_data *picodlp_i2c_data = i2c_get_clientdata(client);

    data[0] = reg;
    data[1] = value;

    mutex_lock(&svga050_i2c_data->xfer_lock);
    msg.addr = client->addr;
    msg.flags = 0;
    msg.len = 2;
    msg.buf = data;
    r = i2c_transfer(client->adapter, &msg, msg_count);
    mutex_unlock(&svga050_i2c_data->xfer_lock);
    /*
     * i2c_transfer returns:
     * number of messages sent in case of success
     * a negative error number in case of failure
     */
    if (r != msg_count)
        goto err;
    /* In case of success */
    for (i = 0; i < 2; i++)
        dev_dbg(&client->dev,
                "addr %x bw 0x%02x[%d]: 0x%02x\n",
                client->addr, data[0] + i, i, data[i]);
    return 0;
   err:
    dev_err(&client->dev, "svga050_i2c_write error\n");
    return r;
 }
 static int svga050_i2c_write_array(struct i2c_client *client,
    const struct svga050_i2c_command commands[],
    int count)
 {
     int i, r = 0;
    for (i = 0; i < count; i++) {
        r = svga050_i2c_write(client, commands[i].reg,
            commands[i].value);
        if (r)
            return r;
     }
   return r;
   }

 static void init_svga050_panel(struct spi_device *spi)
 {
 }

 static int __devinit svga050_panel_i2c_probe(struct i2c_client *client,const struct i2c_device_id *id)
 {
     struct svga050_i2c_data *svga_i2c_data;

     svga_i2c_data=kzalloc(sizeof(struct svga050_i2c_data),GFP_KERNEL);
     if(svga_i2c_data == NULL)
         return -ENOMEM;

     i2c_set_clientdata(client,svga_i2c_data);

     mutex_init(&svga_i2c_data->xfer_lock);
     dev_err(&client->dev,"svga i2c initialized\n");
     return 0;
 }

 static int __devexit svga050_panel_i2c_remove(struct i2c_client *client)
 {
     struct svga050_i2c_data *sd1= i2c_get_clientdata(client);

     i2c_set_clientdata(client,NULL);
     kfree(sd1);
     return 0;
 }

 static const struct i2c_device_id svga050_i2c_idtable[]={
     {"svga050_i2c_driver",0},
     {},
 };

 static struct i2c_driver svga050_i2c_driver = {
     .driver        = {
     .name  = "svga050_i2c",
     .owner = THIS_MODULE,
},
     .probe     = svga050_panel_i2c_probe,
     .remove        = __exit_p(svga050_panel_i2c_remove),
     .id_table  = svga050_i2c_idtable,
 };

 static int __init svga050_panel_drv_init(void)
 {
     int r;
     r= i2c_add_driver(&svga050_i2c_driver);
     if(r < 0){
         printk(KERN_WARNING "svga050 i2c driver registration failed\n");
         return r;
      }
   r=omap_dss_register_driver(&svga050_driver);
   if(r < 0){
       printk(KERN_WARNING "svga050 dss driver registration failed\n");
       i2c_del_driver(&svga050_i2c_driver);
    }
    return r;
 }

 static void __exit svga050_panel_drv_exit(void)
 {
     omap_dss_unregister_driver(&svga050_driver);
     i2c_del_driver(&svga050_i2c_driver);
 }

 module_init(svga050_panel_drv_init);
 module_exit(svga050_panel_drv_exit);
 MODULE_LICENSE("GPL");

Board.c

static struct omap_dss_device svga050_device = {
.name           = "svga050",
.driver_name        = "svga050",
.type           = OMAP_DISPLAY_TYPE_DPI,
.phy.dpi.data_lines = 24,
.channel        = OMAP_DSS_CHANNEL_LCD2,
.platform_enable    = svga050_panel_enable_picodlp,
.platform_disable   = svga050_panel_disable_picodlp,
.data           = &svga050_pdata,
};

static struct omap_dss_device *svga050_dss_devices[] = {
    &svga050_device,
};

static struct picodlp_panel_data sdp4430_picodlp_pdata = {
    .svga050_adapter_id = 2,
};

my questions are :

  1. My code is right?

  2. I don't know how to write display init code by seeing datasheet.

    Can I write display init code by seeing this datasheet ?

  3. In panel_probe function, how can I get adapter ID ? how do I choose adapter I ?

  4. Is it right that I should write only i2c slave driver code in panel code ?

How can I select I2C master ? I want to use I2C3 or I2C4 for display commands

Tolman answered 27/4, 2015 at 7:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.