diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 1a9685eb8002..8bdb02aeaf0c 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -4466,6 +4466,44 @@ static const struct panel_desc arm_rtsm = { .bus_format = MEDIA_BUS_FMT_RGB888_1X24, }; +static const struct drm_display_mode clockwork_cpi3_lcd_mode = { + .clock = 5800, + .hdisplay = 320, + .hsync_start = 320 + 6, + .hsync_end = 320 + 6 + 2, + .htotal = 320 + 6 + 2 + 60, + .vdisplay = 240, + .vsync_start = 240 + 2, + .vsync_end = 240 + 2 + 2, + .vtotal = 240 + 2 + 2 + 6, + .flags = DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_PHSYNC, +}; + +static const struct panel_desc clockwork_cpi3_lcd = { + .modes = &clockwork_cpi3_lcd_mode, + .num_modes = 1, + .bpc = 8, +}; + +static const struct drm_display_mode clockwork_cpi3_hdmi_mode = { + .clock = 74250, + .hdisplay = 1280, + .hsync_start = 1280 + 110, + .hsync_end = 1280 + 110 + 40, + .htotal = 1280 + 110 + 40 + 220, + .vdisplay = 720, + .vsync_start = 720 + 5, + .vsync_end = 720 + 5 + 5, + .vtotal = 720 + 5 + 5 + 20, + .flags = DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_PHSYNC, +}; + +static const struct panel_desc clockwork_cpi3_hdmi = { + .modes = &clockwork_cpi3_hdmi_mode, + .num_modes = 1, + .bpc = 8, +}; + static const struct of_device_id platform_of_match[] = { { .compatible = "ampire,am-1280800n3tzqw-t00h", @@ -4906,6 +4944,12 @@ static const struct of_device_id platform_of_match[] = { /* Must be the last entry */ .compatible = "panel-dpi", .data = &panel_dpi, + }, { + .compatible = "clockwork,cpi3-lcd", + .data = &clockwork_cpi3_lcd, + }, { + .compatible = "clockwork,cpi3-hdmi", + .data = &clockwork_cpi3_hdmi, }, { /* sentinel */ } diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index e32694c13da5..9b606f172f80 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -135,6 +135,12 @@ config LCD_OTM3225A If you have a panel based on the OTM3225A controller chip then say y to include a driver for it. +config LCD_KD027 + tristate "STARTEK KD027 LCD Driver" + help + If you have a KD027 LCD panel, say Y to enable its LCD control + driver. + endif # LCD_CLASS_DEVICE # @@ -464,6 +470,12 @@ config BACKLIGHT_LED If you have a LCD backlight adjustable by LED class driver, say Y to enable this driver. +config BACKLIGHT_OCP8178 + tristate "OCP8178 Backlight Driver" + depends on GPIOLIB + help + If you have an OCP8178, say Y to enable the backlight driver. + endif # BACKLIGHT_CLASS_DEVICE endmenu diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index cae2c83422ae..7eaf58dda80f 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile @@ -17,6 +17,7 @@ obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o obj-$(CONFIG_LCD_TDO24M) += tdo24m.o obj-$(CONFIG_LCD_TOSA) += tosa_lcd.o obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o +obj-$(CONFIG_LCD_KD027) += kd027_lcd.o obj-$(CONFIG_BACKLIGHT_88PM860X) += 88pm860x_bl.o obj-$(CONFIG_BACKLIGHT_AAT2870) += aat2870_bl.o @@ -58,3 +59,4 @@ obj-$(CONFIG_BACKLIGHT_WM831X) += wm831x_bl.o obj-$(CONFIG_BACKLIGHT_ARCXCNN) += arcxcnn_bl.o obj-$(CONFIG_BACKLIGHT_RAVE_SP) += rave-sp-backlight.o obj-$(CONFIG_BACKLIGHT_LED) += led_bl.o +obj-$(CONFIG_BACKLIGHT_OCP8178) += ocp8178_bl.o diff --git a/drivers/video/backlight/kd027_lcd.c b/drivers/video/backlight/kd027_lcd.c new file mode 100644 index 000000000000..24abec39d3bd --- /dev/null +++ b/drivers/video/backlight/kd027_lcd.c @@ -0,0 +1,250 @@ +/* + * kd027_lcd.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * + * + */ + +#include /* Only for legacy support */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct kd027_lcd { + struct gpio_desc* rst_pin; + struct gpio_desc* cs_pin; + struct gpio_desc* sck_pin; + struct gpio_desc* sda_pin; + unsigned char init_seq[100]; + unsigned char suspend_seq[20]; + unsigned char resume_seq[20]; + int init_seq_len; + int suspend_seq_len; + int resume_seq_len; +}; + +struct kd027_lcd * lcd_data; + +static void kd027_write_lcd(unsigned char data) +{ + unsigned char i; + + for(i = 0; i < 8; i++) { + if (data & 0x80) + gpiod_set_value(lcd_data->sda_pin, 1); + else + gpiod_set_value(lcd_data->sda_pin, 0); + gpiod_set_value(lcd_data->sck_pin, 0); + gpiod_set_value(lcd_data->sck_pin, 1); + data <<= 1; + } +} + +static void kd027_write_cmd_data(unsigned char c, unsigned char d) +{ + gpiod_set_value(lcd_data->cs_pin, 0); + kd027_write_lcd(c); + kd027_write_lcd(d); + gpiod_set_value(lcd_data->cs_pin, 1); +} + +static void kd027_init(void) +{ + int i; + for(i = 0; i < lcd_data->init_seq_len/2; i++) { + kd027_write_cmd_data(lcd_data->init_seq[i * 2], lcd_data->init_seq[i * 2 + 1]); + } +} + +#ifdef CONFIG_PROC_FS +static char global_buffer[64]; + +static int kd027_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "kd027\n"); + return 0; +} + +static int kd027_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, kd027_proc_show, NULL); +} + +static ssize_t kd027_proc_read(struct file * file, char __user * buf, size_t size, loff_t * loff) +{ + return 0; +} + +static ssize_t kd027_proc_write(struct file * file, const char __user * buf, size_t size, loff_t * loff) +{ + int cmd, data; + char* tmp; + + if(copy_from_user(global_buffer, buf, size)) + return -EFAULT; + + global_buffer[size] = 0; + cmd = simple_strtol(global_buffer, 0, 16); + tmp = strchr(global_buffer, ' '); + if(tmp) { + data = simple_strtol(tmp+1, 0, 16); + kd027_write_cmd_data(cmd, data); + } + + return size; +} + +static const struct proc_ops kd027_proc_fops = { + .proc_open = kd027_proc_open, + .proc_read = kd027_proc_read, + .proc_write = kd027_proc_write, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int __init kd027_proc_init(void) +{ + struct proc_dir_entry *r; + + r = proc_create("driver/lcd", S_IRWXUGO, NULL, &kd027_proc_fops); + if (!r) + return -ENOMEM; + return 0; +} +#else +static inline int kd027_proc_init(void) { return 0; } +#endif /* CONFIG_PROC_FS */ + +static int kd027_probe(struct platform_device *pdev) +{ + int ret; + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + + if ( !np) { + dev_err(&pdev->dev, + "failed to find platform data or device tree node.\n"); + return -ENODEV; + } + + lcd_data = devm_kzalloc(&pdev->dev, sizeof(*lcd_data), GFP_KERNEL); + if (lcd_data == NULL) + return -ENOMEM; + + lcd_data->init_seq_len = of_property_read_variable_u8_array(np, "init-seq", lcd_data->init_seq, 1, 100); + lcd_data->suspend_seq_len = of_property_read_variable_u8_array(np, "suspend-seq", lcd_data->suspend_seq, 1, 20); + lcd_data->resume_seq_len = of_property_read_variable_u8_array(np, "resume-seq", lcd_data->resume_seq, 1, 20); + + lcd_data->rst_pin = devm_gpiod_get(dev, "lcd-rst", GPIOD_OUT_HIGH); + if (IS_ERR(lcd_data->rst_pin)) { + ret = PTR_ERR(lcd_data->rst_pin); + + if (ret != -EPROBE_DEFER) { + dev_err(dev, + "Error: The gpios parameter is missing or invalid.\n"); + } + return ret; + } + + lcd_data->cs_pin = devm_gpiod_get(dev, "lcd-cs", GPIOD_OUT_HIGH); + if (IS_ERR(lcd_data->cs_pin)) { + ret = PTR_ERR(lcd_data->cs_pin); + + if (ret != -EPROBE_DEFER) { + dev_err(dev, + "Error: The gpios parameter is missing or invalid.\n"); + } + return ret; + } + + lcd_data->sck_pin = devm_gpiod_get(dev, "lcd-sck", GPIOD_OUT_HIGH); + if (IS_ERR(lcd_data->sck_pin)) { + ret = PTR_ERR(lcd_data->sck_pin); + + if (ret != -EPROBE_DEFER) { + dev_err(dev, + "Error: The gpios parameter is missing or invalid.\n"); + } + return ret; + } + + lcd_data->sda_pin = devm_gpiod_get(dev, "lcd-sda", GPIOD_OUT_HIGH); + if (IS_ERR(lcd_data->sda_pin)) { + ret = PTR_ERR(lcd_data->sda_pin); + + if (ret != -EPROBE_DEFER) { + dev_err(dev, + "Error: The gpios parameter is missing or invalid.\n"); + } + return ret; + } + + kd027_init(); + kd027_proc_init(); + + return 0; +} + +static int kd027_suspend(struct platform_device * pdev, pm_message_t state) +{ + int i; + for(i = 0; i < lcd_data->suspend_seq_len/2; i++) { + kd027_write_cmd_data(lcd_data->suspend_seq[i * 2], lcd_data->suspend_seq[i * 2 + 1]); + } + return 0; +} + +static int kd027_resume(struct platform_device * pdev) +{ + int i; + for(i = 0; i < lcd_data->resume_seq_len/2; i++) { + kd027_write_cmd_data(lcd_data->resume_seq[i * 2], lcd_data->resume_seq[i * 2 + 1]); + } + return 0; +} + +#ifdef CONFIG_OF +static struct of_device_id kd027_of_match[] = { + { .compatible = "kd027-lcd" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, kd027_of_match); +#endif + +static struct platform_driver kd027_device_driver = { + .probe = kd027_probe, + .suspend = kd027_suspend, + .resume = kd027_resume, + .driver = { + .name = "kd027-lcd", + .of_match_table = of_match_ptr(kd027_of_match), + }, +}; + +module_platform_driver(kd027_device_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("KD027 Driver"); + diff --git a/drivers/video/backlight/ocp8178_bl.c b/drivers/video/backlight/ocp8178_bl.c new file mode 100644 index 000000000000..0ffb9e513e50 --- /dev/null +++ b/drivers/video/backlight/ocp8178_bl.c @@ -0,0 +1,349 @@ +/* + * ocp8178_bl.c - ocp8178 backlight driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include +#include +#include +#include /* Only for legacy support */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct ocp8178_backlight { + struct device *dev; + struct device *fbdev; + + struct gpio_desc *gpiod; + int def_value; + int current_value; +}; + +#define DETECT_DELAY 200 +#define DETECT_TIME 500 +#define DETECT_WINDOW_TIME 1000 +#define START_TIME 10 +#define END_TIME 10 +#define SHUTDOWN_TIME 3000 +#define LOW_BIT_HIGH_TIME 10 +#define LOW_BIT_LOW_TIME 50 +#define HIGH_BIT_HIGH_TIME 50 +#define HIGH_BIT_LOW_TIME 10 +#define MAX_BRIGHTNESS_VALUE 9 + +static void entry_1wire_mode(struct ocp8178_backlight *gbl) +{ + unsigned long flags = 0; + local_irq_save(flags); + gpiod_set_value(gbl->gpiod, 0); + mdelay(SHUTDOWN_TIME/1000); + gpiod_set_value(gbl->gpiod, 1); + udelay(DETECT_DELAY); + gpiod_set_value(gbl->gpiod, 0); + udelay(DETECT_TIME); + gpiod_set_value(gbl->gpiod, 1); + udelay(DETECT_WINDOW_TIME); + local_irq_restore(flags); +} + +static inline void write_bit(struct ocp8178_backlight *gbl, int bit) +{ + if (bit) { + gpiod_set_value(gbl->gpiod, 0); + udelay(HIGH_BIT_LOW_TIME); + gpiod_set_value(gbl->gpiod, 1); + udelay(HIGH_BIT_HIGH_TIME); + } else { + gpiod_set_value(gbl->gpiod, 0); + udelay(LOW_BIT_LOW_TIME); + gpiod_set_value(gbl->gpiod, 1); + udelay(LOW_BIT_HIGH_TIME); + } +} + +static void write_byte(struct ocp8178_backlight *gbl, int byte) +{ + unsigned long flags = 0; + unsigned char data = 0x72; + int i; + + local_irq_save(flags); + + gpiod_set_value(gbl->gpiod, 1); + udelay(START_TIME); + for(i = 0; i < 8; i++) { + if(data & 0x80) { + write_bit(gbl, 1); + } else { + write_bit(gbl, 0); + } + data <<= 1; + } + gpiod_set_value(gbl->gpiod, 0); + udelay(END_TIME); + + data = byte & 0x1f; + + gpiod_set_value(gbl->gpiod, 1); + udelay(START_TIME); + for(i = 0; i < 8; i++) { + if(data & 0x80) { + write_bit(gbl, 1); + } else { + write_bit(gbl, 0); + } + data <<= 1; + } + gpiod_set_value(gbl->gpiod, 0); + udelay(END_TIME); + gpiod_set_value(gbl->gpiod, 1); + + local_irq_restore(flags); +} + +unsigned char ocp8178_bl_table[MAX_BRIGHTNESS_VALUE+1] = {0, 1, 4, 8, 12, 16, 20, 24, 28, 31}; + +static int ocp8178_update_status(struct backlight_device *bl) +{ + struct ocp8178_backlight *gbl = bl_get_data(bl); + int brightness = bl->props.brightness; + + if (bl->props.power != FB_BLANK_UNBLANK || + bl->props.fb_blank != FB_BLANK_UNBLANK || + bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) + brightness = 0; + + if(brightness > MAX_BRIGHTNESS_VALUE) { + brightness = MAX_BRIGHTNESS_VALUE; + } + + write_byte(gbl, ocp8178_bl_table[brightness]); + gbl->current_value = brightness; + + return 0; +} + +static int ocp8178_get_brightness(struct backlight_device *bl) +{ + struct ocp8178_backlight *gbl = bl_get_data(bl); + return gbl->current_value; +} + +static int ocp8178_check_fb(struct backlight_device *bl, + struct fb_info *info) +{ + struct ocp8178_backlight *gbl = bl_get_data(bl); + return gbl->fbdev == NULL || gbl->fbdev == info->dev; +} + +static const struct backlight_ops ocp8178_backlight_ops = { + .options = BL_CORE_SUSPENDRESUME, + .update_status = ocp8178_update_status, + .get_brightness = ocp8178_get_brightness, + .check_fb = ocp8178_check_fb, +}; + +static int ocp8178_probe_dt(struct platform_device *pdev, + struct ocp8178_backlight *gbl) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + enum gpiod_flags flags; + int ret = 0; + u32 value32; + + of_property_read_u32(np, "default-brightness", &value32); + if(value32 > MAX_BRIGHTNESS_VALUE) + gbl->def_value = MAX_BRIGHTNESS_VALUE; + else + gbl->def_value = value32; + flags = gbl->def_value ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW; + + gbl->gpiod = devm_gpiod_get(dev, "backlight-control", flags); + if (IS_ERR(gbl->gpiod)) { + ret = PTR_ERR(gbl->gpiod); + + if (ret != -EPROBE_DEFER) { + dev_err(dev, + "Error: The gpios parameter is missing or invalid.\n"); + } + } + + return ret; +} + +static struct backlight_device *backlight; + +#ifdef CONFIG_PROC_FS +static char global_buffer[64]; + +static int ocp8178_proc_show(struct seq_file *m, void *v) +{ + seq_printf(m, "ocp8178\n"); + return 0; +} + +static int ocp8178_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, ocp8178_proc_show, NULL); +} + +static int ocp8178_proc_read(struct file * file, char __user * buf, size_t size, loff_t * loff) +{ + int value, len; + struct backlight_device *bl = backlight; + value = ocp8178_get_brightness(bl); + len = snprintf(global_buffer, sizeof(global_buffer), "%d\n", value); + return simple_read_from_buffer(buf, size, loff, global_buffer, len); +} + +static int ocp8178_proc_write(struct file * file, const char __user * buf, size_t size, loff_t * loff) +{ + int data; + struct backlight_device *bl = backlight; + + if(copy_from_user(global_buffer, buf, size)) + return -EFAULT; + + global_buffer[size] = 0; + if(global_buffer[0] == '+') { + bl->props.brightness = (bl->props.brightness + 1) % (MAX_BRIGHTNESS_VALUE + 1); + } else if(global_buffer[0] == '-') { + bl->props.brightness = (bl->props.brightness + MAX_BRIGHTNESS_VALUE) % (MAX_BRIGHTNESS_VALUE + 1); + } else { + data = simple_strtol(global_buffer, 0, 10); + if(data < 0) { + bl->props.brightness = 0; + } else if(data > MAX_BRIGHTNESS_VALUE) { + bl->props.brightness = MAX_BRIGHTNESS_VALUE; + } else { + bl->props.brightness = data; + } + } + backlight_update_status(bl); + + return size; +} + +static const struct proc_ops ocp8178_proc_fops = { + .proc_open = ocp8178_proc_open, + .proc_read = ocp8178_proc_read, + .proc_write = ocp8178_proc_write, + .proc_lseek = seq_lseek, + .proc_release = single_release, +}; + +static int __init ocp8178_proc_init(void) +{ + struct proc_dir_entry *r; + + r = proc_create("driver/backlight", S_IRWXUGO, NULL, &ocp8178_proc_fops); + if (!r) + return -ENOMEM; + return 0; +} +#else +static inline int ocp8178_proc_init(void) { return 0; } +#endif /* CONFIG_PROC_FS */ + +static int ocp8178_probe(struct platform_device *pdev) +{ + struct backlight_properties props; + struct backlight_device *bl; + struct ocp8178_backlight *gbl; + struct device_node *np = pdev->dev.of_node; + int ret; + + if ( !np) { + dev_err(&pdev->dev, + "failed to find platform data or device tree node.\n"); + return -ENODEV; + } + + gbl = devm_kzalloc(&pdev->dev, sizeof(*gbl), GFP_KERNEL); + if (gbl == NULL) + return -ENOMEM; + + gbl->dev = &pdev->dev; + + ret = ocp8178_probe_dt(pdev, gbl); + if (ret) + return ret; + + gbl->current_value = gbl->def_value; + + memset(&props, 0, sizeof(props)); + props.type = BACKLIGHT_RAW; + props.max_brightness = MAX_BRIGHTNESS_VALUE; + bl = devm_backlight_device_register(&pdev->dev, dev_name(&pdev->dev), + &pdev->dev, gbl, &ocp8178_backlight_ops, + &props); + if (IS_ERR(bl)) { + dev_err(&pdev->dev, "failed to register backlight\n"); + return PTR_ERR(bl); + } + + entry_1wire_mode(gbl); + + bl->props.brightness = gbl->def_value; + backlight_update_status(bl); + + platform_set_drvdata(pdev, bl); + + backlight = bl; + ocp8178_proc_init(); + + return 0; +} + +static int ocp8178_suspend(struct platform_device *pdev, pm_message_t state) +{ + return 0; +} + +static int ocp8178_resume(struct platform_device *pdev) +{ + return 0; +} + +static struct of_device_id ocp8178_of_match[] = { + { .compatible = "ocp8178-backlight" }, + { /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, ocp8178_of_match); + +static struct platform_driver ocp8178_driver = { + .driver = { + .name = "ocp8178-backlight", + .of_match_table = of_match_ptr(ocp8178_of_match), + }, + .probe = ocp8178_probe, + .suspend = ocp8178_suspend, + .resume = ocp8178_resume, +}; + +module_platform_driver(ocp8178_driver); + +MODULE_DESCRIPTION("OCP8178 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c index e035a63bbe5b..b2eb9cf314fb 100644 --- a/drivers/video/fbdev/core/fbcon.c +++ b/drivers/video/fbdev/core/fbcon.c @@ -357,6 +357,7 @@ static int get_color(struct vc_data *vc, struct fb_info *info, static void fb_flashcursor(struct work_struct *work) { +#if 0 struct fb_info *info = container_of(work, struct fb_info, queue); struct fbcon_ops *ops = info->fbcon_par; struct vc_data *vc = NULL; @@ -387,6 +388,7 @@ static void fb_flashcursor(struct work_struct *work) ops->cursor(vc, info, mode, get_color(vc, info, c, 1), get_color(vc, info, c, 0)); console_unlock(); +#endif } static void cursor_timer_handler(struct timer_list *t) @@ -1319,6 +1321,7 @@ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only) static void fbcon_cursor(struct vc_data *vc, int mode) { +#if 0 struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]]; struct fbcon_ops *ops = info->fbcon_par; int c = scr_readw((u16 *) vc->vc_pos); @@ -1340,6 +1343,7 @@ static void fbcon_cursor(struct vc_data *vc, int mode) ops->cursor(vc, info, mode, get_color(vc, info, c, 1), get_color(vc, info, c, 0)); +#endif } static int scrollback_phys_max = 0; diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c index 528c87ff14d8..21ae9491051c 100644 --- a/drivers/video/fbdev/core/fbmem.c +++ b/drivers/video/fbdev/core/fbmem.c @@ -524,6 +524,9 @@ static int fb_show_logo_line(struct fb_info *info, int rotate, image.width = logo->width; image.height = logo->height; + image.dx = (info->var.xres/2) - (logo->width/2); + image.dy = (info->var.yres/2) - (logo->height/2); + n = 1; if (rotate) { logo_rotate = kmalloc_array(logo->width, logo->height,