/* *author :Meige team *version:1.0 *data:2016.9.9 *function description : an i2c interface for mipi bridge or others i2c slave */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mdss_i2c_dsi0_edp.h" extern char *saved_command_line; struct edp_i2c_interface { struct i2c_client *edp_client; int gpio_rstn; //sn65dsi84 电源复位脚 int gpio_edp_3v3_en; //sn65dsi84 电源使能脚 int gpio_bkl_en; //背光使能脚 int gpio_lcd_12v_en; //lcd 电源使能脚 int gpio_lcd_dvdd_en; //lcd 电源使能脚 atomic_t video_status; struct notifier_block fb_notif; struct workqueue_struct *workq; struct delayed_work delay_work_id; struct delayed_work led_work_id; int led_bright_lvl; int led_set_done; }; #define BRIGHTNESS__MAX 255 static struct led_classdev backlight_pwm = { .name = "seclcd-backlight", .brightness = BRIGHTNESS__MAX / 2, .max_brightness = BRIGHTNESS__MAX, .default_trigger = "bkl-trigger", .flags = SET_BRIGHTNESS_ASYNC, }; static struct edp_i2c_interface *edp_mipi_i2c ; int edp_mipi_i2c_init_ok(void); static int edp_write_reg(int reg, int val) { int rc = 0; rc = i2c_smbus_write_byte_data(edp_mipi_i2c->edp_client,reg,val); if (rc < 0) { pr_err("%s: edp_write_reg fail \n", __func__); return rc; } return rc ; } void edp_video_set(int on) { pr_err("%s, on:%d\n", __func__, on); atomic_set(&edp_mipi_i2c->video_status, on); queue_delayed_work(edp_mipi_i2c->workq, &edp_mipi_i2c->delay_work_id, 0); } int sn65dsi86_dump_regs(void) { int value = 0; int index; if (!edp_mipi_i2c){ pr_err("failed to dump regs cause of null pointer\n"); return -1; } for(index=0xf0;index<0xf9;index++){ value = i2c_smbus_read_byte_data(edp_mipi_i2c->edp_client,index); pr_err("addr(0x%x) = 0x%x\n",index,value); } return 0; } int edp_mipi_i2c_init(struct mdss_dsi_ctrl_pdata *ctrl, int from_mdp) { if (!edp_mipi_i2c) return -1; pr_err("%s\n", __func__); pr_info("MEIG:%s config start!\n", __func__); gpio_direction_output(edp_mipi_i2c->gpio_rstn, 0); mdelay(10); gpio_direction_output(edp_mipi_i2c->gpio_rstn, 1); mdelay(20); edp_mipi_i2c_init_ok(); mdelay(20); //gpio_direction_output(edp_mipi_i2c->gpio_bkl_en, 1); edp_video_set(1); return 0; } EXPORT_SYMBOL_GPL(edp_mipi_i2c_init); /*This function para Get from FAE*/ int edp_mipi_i2c_init_ok(void) { if (!edp_mipi_i2c) return -1; edp_write_reg(0x09,0x00); edp_write_reg(0x0A,0x09); edp_write_reg(0x0D,0x00); edp_write_reg(0x10,0x26); edp_write_reg(0x11,0x00); edp_write_reg(0x12,0x5c); edp_write_reg(0x13,0x5c); edp_write_reg(0x20,0x80); edp_write_reg(0x21,0x07); edp_write_reg(0x22,0x00); edp_write_reg(0x23,0x00); edp_write_reg(0x24,0x38); edp_write_reg(0x25,0x04); edp_write_reg(0x2C,0x20); edp_write_reg(0x2D,0x00); edp_write_reg(0x30,0x05); edp_write_reg(0x31,0x00); edp_write_reg(0x34,0xc8); edp_write_reg(0x36,0x20); edp_write_reg(0x38,0x30); edp_write_reg(0x3A,0x03); edp_write_reg(0x3C,0x00);//normal edp_write_reg(0x3D,0x00); edp_write_reg(0x3E,0x00); edp_write_reg(0x5B,0x01); edp_write_reg(0x93,0x20); edp_write_reg(0x94,0x80); //edp_write_reg(0x3C,0x10);//test edp_write_reg(0x5C,0x01);//rm hpd edp_write_reg(0x5A,0x05); edp_write_reg(0x0d,0x01); mdelay(20); edp_write_reg(0x64,0x01); edp_write_reg(0x74,0x00); edp_write_reg(0x75,0x01); edp_write_reg(0x76,0x0A); edp_write_reg(0x77,0x01); edp_write_reg(0x78,0x81); edp_write_reg(0x96,0x01); edp_write_reg(0x5A,0x0D); mdelay(20); return 0 ; } void edp_mipi_i2c_disable(void) { if (!edp_mipi_i2c) return; pr_err("%s\n", __func__); gpio_direction_output(edp_mipi_i2c->gpio_bkl_en, 0); edp_write_reg(0xA5,0x00); mdelay(20); edp_write_reg(0x96,0x0); edp_write_reg(0x93,0x04); edp_write_reg(0x0d,0x0); mdelay(20); gpio_direction_output(edp_mipi_i2c->gpio_rstn, 0); mdelay(20); } static void edp_video_work(struct work_struct *work) { if (!edp_mipi_i2c) return; pr_err("%s\n", __func__); if (atomic_read(&edp_mipi_i2c->video_status)) { mdelay(500); gpio_direction_output(edp_mipi_i2c->gpio_bkl_en, 1); } else { //edp_mipi_i2c_disable(); } } static void gpio_to_pwm(struct led_classdev *led_cdev, enum led_brightness value) { if (!edp_mipi_i2c) return; edp_mipi_i2c->led_bright_lvl = value; //edp_mipi_i2c->led_set_done = 0; queue_delayed_work(edp_mipi_i2c->workq, &edp_mipi_i2c->led_work_id, 0); //while (!edp_mipi_i2c->led_set_done); } static void edp_led_work(struct work_struct *work) { struct i2c_client *client = NULL; static int led_init = 0; int value; if (!edp_mipi_i2c) return; value = edp_mipi_i2c->led_bright_lvl; if (!led_init) { pr_err("%s leg_trigger set\n", __func__); client = edp_mipi_i2c->edp_client; backlight_pwm.brightness_set = gpio_to_pwm; backlight_pwm.dev = &client->dev; led_trigger_set_default(&backlight_pwm); led_init = 1; return; } if(value > BRIGHTNESS__MAX) value = BRIGHTNESS__MAX; value = 255 - value; pr_info("MEIG: :gpio_to_pwm start value = %d\n", value); if((value < 0) || (value > BRIGHTNESS__MAX )){ edp_write_reg(0xA3,BRIGHTNESS__MAX); //edp_write_reg(0xA5,0x00); } else{ edp_write_reg(0xA5,0x02); edp_write_reg(0x5F,0x80); edp_write_reg(0xA0,0x64); edp_write_reg(0xA1,0xFF); edp_write_reg(0xA2,0x00); edp_write_reg(0xA3,value); edp_write_reg(0xA4,0x00); if (!gpio_get_value(edp_mipi_i2c->gpio_bkl_en)){ gpio_direction_output(edp_mipi_i2c->gpio_bkl_en, 1); } } edp_mipi_i2c->led_set_done = 1; } #if defined(CONFIG_FB__) static int _fb_notifier_callback_(struct notifier_block *self, unsigned long event, void *data) { struct fb_event *evdata = data; int *blank; if (!edp_mipi_i2c) return -1; if (evdata && evdata->data && event == FB_EVENT_BLANK && edp_mipi_i2c && edp_mipi_i2c->edp_client) { blank = evdata->data; pr_err("%s blank:%d\n", __func__, blank); if (*blank == FB_BLANK_UNBLANK){ pr_debug("%s :_fb_notifier_callback_ 1 \n", __func__); //edp_mipi_i2c_init(NULL, 0); } else if (*blank == FB_BLANK_NORMAL){ pr_debug("%s :_fb_notifier_callback_ 2 \n", __func__); //edp_mipi_i2c_disable(); //gpio_direction_output(edp_mipi_i2c->gpio_bkl_en, 0); } } return 0; } #endif static void mdss_edp_gpio_init(void) { int ret; ret = of_get_named_gpio(edp_mipi_i2c->edp_client->dev.of_node, "edp,vcc12v_en", 0); if (ret < 0) { pr_err("%s get edp,vcc12v_en error!\n", __func__); edp_mipi_i2c->gpio_lcd_12v_en = -1; } else { edp_mipi_i2c->gpio_lcd_12v_en = ret; if (gpio_request(edp_mipi_i2c->gpio_lcd_12v_en, "gpio_lcd_12v_en")) pr_err("%s request gpio_lcd_12v_en error!\n", __func__); else gpio_direction_output(edp_mipi_i2c->gpio_lcd_12v_en, 1); } ret = of_get_named_gpio(edp_mipi_i2c->edp_client->dev.of_node, "lcd,3_3v_en", 0); if (ret < 0) { pr_err("%s get lcd,3_3v_en error!\n", __func__); edp_mipi_i2c->gpio_edp_3v3_en = -1; } else { edp_mipi_i2c->gpio_edp_3v3_en = ret; if (gpio_request(edp_mipi_i2c->gpio_edp_3v3_en, "sn,gpio_edp_3v3_en") < 0) pr_err("%s request gpio_edp_3v3_en error!\n", __func__); else gpio_direction_output(edp_mipi_i2c->gpio_edp_3v3_en, 1); } ret = of_get_named_gpio(edp_mipi_i2c->edp_client->dev.of_node, "edp,dvdd_en", 0); if (ret < 0) { pr_err("%s get edp,dvdd_en error!\n", __func__); edp_mipi_i2c->gpio_lcd_dvdd_en = -1; } else { edp_mipi_i2c->gpio_lcd_dvdd_en = ret; if (gpio_request(edp_mipi_i2c->gpio_lcd_dvdd_en, "gpio_lcd_dvdd_en")) pr_err("%s request gpio_lcd_dvdd_en error!", __func__); else gpio_direction_output(edp_mipi_i2c->gpio_lcd_dvdd_en, 1); } ret = of_get_named_gpio(edp_mipi_i2c->edp_client->dev.of_node, "edp,gpio_rstn", 0); if (ret < 0) { pr_err("%s get edp,gpio_rstn gpio error!\n", __func__); edp_mipi_i2c->gpio_rstn = -1; } else { edp_mipi_i2c->gpio_rstn = ret; if (gpio_request(edp_mipi_i2c->gpio_rstn, "sn,gpio_rstn")) pr_err("%s request gpio_rstn error!\n", __func__); else { gpio_direction_output(edp_mipi_i2c->gpio_rstn, 1); mdelay(10); } } ret = of_get_named_gpio(edp_mipi_i2c->edp_client->dev.of_node, "bkl,en", 0); if(ret < 0) { pr_err("%s get bkl,en gpio error!\n", __func__); edp_mipi_i2c->gpio_bkl_en = -1; } else { edp_mipi_i2c->gpio_bkl_en = ret; if (gpio_request(edp_mipi_i2c->gpio_bkl_en, "gpio_bkl_en") < 0) pr_err("%s request gpio_bkl_en error!\n", __func__); else gpio_direction_output(edp_mipi_i2c->gpio_bkl_en, 1); } } static int mipi_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { int err; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "%s: check_functionality failed.", __func__); err = -ENODEV; goto exit0; } /* Allocate memory for driver data */ edp_mipi_i2c = kzalloc(sizeof(struct edp_i2c_interface), GFP_KERNEL); if (!edp_mipi_i2c) { pr_err("%s: memory allocation failed.", __func__); err = -ENOMEM; goto exit0; } /***** I2C initialization *****/ edp_mipi_i2c->edp_client = client; mdss_edp_gpio_init(); /* set client data */ i2c_set_clientdata(client, edp_mipi_i2c); err = i2c_smbus_read_byte_data(client, 0x5B); if (err < 0) { pr_err("%s: i2c test Failed ret = %d\n", __func__, err); goto exit1; } pr_info("%s 1111 sn65dsi84 i2c test ok .id = %d\n", __func__, err); #if defined(CONFIG_FB__) edp_mipi_i2c->fb_notif.notifier_call = _fb_notifier_callback_; err = fb_register_client(&edp_mipi_i2c->fb_notif); if (err) { pr_err("%s:_fb_notifier_callback_err!", __func__); } #endif edp_mipi_i2c->workq = create_workqueue("video_workq"); if (!edp_mipi_i2c->workq) { pr_err("%s, create workqueue fail\n", __func__); goto exit1; } sn65dsi86_dump_regs(); INIT_DELAYED_WORK(&edp_mipi_i2c->delay_work_id, edp_video_work); INIT_DELAYED_WORK(&edp_mipi_i2c->led_work_id, edp_led_work); queue_delayed_work(edp_mipi_i2c->workq, &edp_mipi_i2c->led_work_id, 1*HZ); return 0; exit1: kfree(edp_mipi_i2c); edp_mipi_i2c = NULL; exit0: return err; } static const struct of_device_id mipi_i2c_of_match[] = { { .compatible = "ti,sn65dsi86",}, {}, }; static const struct i2c_device_id mipi_i2c_id[] = { {"ti,sn65dsi86", 0}, {}, }; static int mipi_i2c_remove(struct i2c_client *client) { return 0; } static struct i2c_driver mipi_i2c_driver = { .driver = { .name = "ti,sn65dsi86", .owner = THIS_MODULE, .of_match_table = mipi_i2c_of_match, //.pm = &mipi_i2c_pm_ops, }, .probe = mipi_i2c_probe, .remove = mipi_i2c_remove, .id_table = mipi_i2c_id, }; module_i2c_driver(mipi_i2c_driver); MODULE_LICENSE("GPL");