diff --git a/arch/arm/boards/at91sam9261ek/init.c b/arch/arm/boards/at91sam9261ek/init.c index 72716b8..58f253b 100644 --- a/arch/arm/boards/at91sam9261ek/init.c +++ b/arch/arm/boards/at91sam9261ek/init.c @@ -158,22 +158,6 @@ * LCD Controller */ #if defined(CONFIG_DRIVER_VIDEO_ATMEL) -static int ek_gpio_request_output(int gpio, const char *name) -{ - int ret; - - ret = gpio_request(gpio, name); - if (ret) { - pr_err("%s: can not request gpio %d (%d)\n", name, gpio, ret); - return ret; - } - - ret = gpio_direction_output(gpio, 1); - if (ret) - pr_err("%s: can not configure gpio %d as output (%d)\n", name, gpio, ret); - return ret; -} - /* TFT */ static struct fb_videomode at91_tft_vga_modes[] = { { @@ -195,35 +179,20 @@ | ATMEL_LCDC_DISTYPE_TFT \ | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE) -static void at91_lcdc_tft_power_control(int on) -{ - if (on) - gpio_set_value(AT91_PIN_PA12, 0); /* power up */ - else - gpio_set_value(AT91_PIN_PA12, 1); /* power down */ -} - static struct atmel_lcdfb_platform_data ek_lcdc_data = { .lcdcon_is_backlight = true, .default_bpp = 16, .default_dmacon = ATMEL_LCDC_DMAEN, .default_lcdcon2 = AT91SAM9261_DEFAULT_TFT_LCDCON2, .guard_time = 1, - .atmel_lcdfb_power_control = at91_lcdc_tft_power_control, + .gpio_power_control = AT91_PIN_PA12, + .gpio_power_control_active_low = true, .mode_list = at91_tft_vga_modes, .num_modes = ARRAY_SIZE(at91_tft_vga_modes), }; -static int at91_lcdc_gpio(void) -{ - return ek_gpio_request_output(AT91_PIN_PA12, "lcdc_tft_power"); -} - static void ek_add_device_lcdc(void) { - if (at91_lcdc_gpio()) - return; - if (machine_is_at91sam9g10ek()) ek_lcdc_data.lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB; diff --git a/arch/arm/boards/at91sam9263ek/init.c b/arch/arm/boards/at91sam9263ek/init.c index 682449b..b71cc55 100644 --- a/arch/arm/boards/at91sam9263ek/init.c +++ b/arch/arm/boards/at91sam9263ek/init.c @@ -156,22 +156,6 @@ * LCD Controller */ #if defined(CONFIG_DRIVER_VIDEO_ATMEL) -static int ek_gpio_request_output(int gpio, const char *name) -{ - int ret; - - ret = gpio_request(gpio, name); - if (ret) { - pr_err("%s: can not request gpio %d (%d)\n", name, gpio, ret); - return ret; - } - - ret = gpio_direction_output(gpio, 1); - if (ret) - pr_err("%s: can not configure gpio %d as output (%d)\n", name, gpio, ret); - return ret; -} - static struct fb_videomode at91_tft_vga_modes[] = { { .name = "TX09D50VM1CCA @ 60", @@ -192,11 +176,6 @@ | ATMEL_LCDC_DISTYPE_TFT \ | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE) -static void at91_lcdc_power_control(int on) -{ - gpio_set_value(AT91_PIN_PA30, on); -} - /* Driver datas */ static struct atmel_lcdfb_platform_data ek_lcdc_data = { .lcdcon_is_backlight = true, @@ -204,16 +183,13 @@ .default_dmacon = ATMEL_LCDC_DMAEN, .default_lcdcon2 = AT91SAM9263_DEFAULT_LCDCON2, .guard_time = 1, - .atmel_lcdfb_power_control = at91_lcdc_power_control, + .gpio_power_control = AT91_PIN_PA30, .mode_list = at91_tft_vga_modes, .num_modes = ARRAY_SIZE(at91_tft_vga_modes), }; static void ek_add_device_lcdc(void) { - if (ek_gpio_request_output(AT91_PIN_PA30, "lcdc_power")) - return; - at91_add_device_lcdc(&ek_lcdc_data); } diff --git a/arch/arm/boards/at91sam9m10ihd/init.c b/arch/arm/boards/at91sam9m10ihd/init.c index dcd93c1..de601d5 100644 --- a/arch/arm/boards/at91sam9m10ihd/init.c +++ b/arch/arm/boards/at91sam9m10ihd/init.c @@ -177,22 +177,6 @@ mem_initcall(at91sam9m10g45ek_mem_init); #if defined(CONFIG_DRIVER_VIDEO_ATMEL) -static int ek_gpio_request_output(int gpio, const char *name) -{ - int ret; - - ret = gpio_request(gpio, name); - if (ret) { - pr_err("%s: can not request gpio %d (%d)\n", name, gpio, ret); - return ret; - } - - ret = gpio_direction_output(gpio, 1); - if (ret) - pr_err("%s: can not configure gpio %d as output (%d)\n", name, gpio, ret); - return ret; -} - static struct fb_videomode at91fb_default_monspecs[] = { { .name = "MULTEK", @@ -213,11 +197,6 @@ | ATMEL_LCDC_DISTYPE_TFT \ | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE) -static void at91_lcdc_power_control(int on) -{ - gpio_set_value(AT91_PIN_PE6, on); -} - /* Driver datas */ static struct atmel_lcdfb_platform_data ek_lcdc_data = { .lcdcon_is_backlight = true, @@ -226,16 +205,13 @@ .default_lcdcon2 = AT91SAM9G45_DEFAULT_LCDCON2, .guard_time = 9, .lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB, - .atmel_lcdfb_power_control = at91_lcdc_power_control, + .gpio_power_control = AT91_PIN_PE6, .mode_list = at91fb_default_monspecs, .num_modes = ARRAY_SIZE(at91fb_default_monspecs), }; static void ek_add_device_lcd(void) { - if (ek_gpio_request_output(AT91_PIN_PE6, "lcdc_power")) - return; - at91_add_device_lcdc(&ek_lcdc_data); } #else diff --git a/arch/arm/boards/at91sam9n12ek/init.c b/arch/arm/boards/at91sam9n12ek/init.c index b9431b2..bc3fb8e 100644 --- a/arch/arm/boards/at91sam9n12ek/init.c +++ b/arch/arm/boards/at91sam9n12ek/init.c @@ -127,23 +127,6 @@ #endif /* CONFIG_DRIVER_NET_KS8851_MLL */ #if defined(CONFIG_DRIVER_VIDEO_ATMEL_HLCD) -static int ek_gpio_request_output(int gpio, const char *name) -{ - int ret; - - ret = gpio_request(gpio, name); - if (ret) { - pr_err("%s: can not request gpio %d (%d)\n", name, gpio, ret); - return ret; - } - - ret = gpio_direction_output(gpio, 1); - if (ret) - pr_err("%s: can not configure gpio %d as output (%d)\n", name, gpio, ret); - return ret; -} - - /* * LCD Controller */ @@ -166,11 +149,6 @@ /* Default output mode is TFT 24 bit */ #define BPP_OUT_DEFAULT_LCDCFG5 (LCDC_LCDCFG5_MODE_OUTPUT_24BPP) -static void at91_lcdc_power_control(int on) -{ - gpio_set_value(AT91_PIN_PC25, !on); -} - /* Driver datas */ static struct atmel_lcdfb_platform_data ek_lcdc_data = { .lcdcon_is_backlight = true, @@ -179,16 +157,14 @@ .default_lcdcon2 = BPP_OUT_DEFAULT_LCDCFG5, .guard_time = 9, .lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB, - .atmel_lcdfb_power_control = at91_lcdc_power_control, + .gpio_power_control = AT91_PIN_PC25, + .gpio_power_control_active_low = true, .mode_list = at91_tft_vga_modes, .num_modes = ARRAY_SIZE(at91_tft_vga_modes), }; static void ek_add_device_lcdc(void) { - if (ek_gpio_request_output(AT91_PIN_PC25, "lcdc_power")) - return; - at91_add_device_lcdc(&ek_lcdc_data); } #else diff --git a/arch/arm/mach-at91/include/mach/barebox-arm-head.h b/arch/arm/mach-at91/include/mach/barebox-arm-head.h index d4bb96f..e0e0750 100644 --- a/arch/arm/mach-at91/include/mach/barebox-arm-head.h +++ b/arch/arm/mach-at91/include/mach/barebox-arm-head.h @@ -7,13 +7,13 @@ #define AT91_EXV6 ".word _barebox_bare_init_size\n" #endif -static inline void barebox_arm_head(void) +static inline void __barebox_arm_head(void) { __asm__ __volatile__ ( #ifdef CONFIG_THUMB2_BAREBOX #error Thumb2 is not supported #else - "b barebox_arm_reset_vector\n" + "b 2f\n" "1: b 1b\n" "1: b 1b\n" "1: b 1b\n" @@ -27,7 +27,19 @@ * barebox can skip relocation */ ".word _barebox_image_size\n" /* image size to copy */ + ".rept 8\n" + ".word 0x55555555\n" + ".endr\n" + "2:\n" ); } -#endif /* __ASM_ARM_HEAD_H */ +static inline void barebox_arm_head(void) +{ + __barebox_arm_head(); + __asm__ __volatile__ ( + "b barebox_arm_reset_vector\n" + ); +} + +#endif /* __MACH_ARM_HEAD_H */ diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 5f6bebc..1842711 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include #include @@ -1375,6 +1375,22 @@ at91_udc_irq(udc); } +static void __init at91udc_of_init(struct at91_udc *udc, struct device_node *np) +{ + enum of_gpio_flags flags; + struct at91_udc_data *board; + + board = &udc->board; + + board->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0, + &flags); + board->vbus_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0; + + board->pullup_pin = of_get_named_gpio_flags(np, "atmel,pullup-gpio", 0, + &flags); + board->pullup_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0; +} + /*-------------------------------------------------------------------------*/ static int __init at91udc_probe(struct device_d *dev) @@ -1382,18 +1398,29 @@ struct resource *iores; struct at91_udc *udc = &controller; int retval; - - if (!dev->platform_data) { - /* small (so we copy it) but critical! */ - DBG(udc, "missing platform_data\n"); - return -ENODEV; - } + const char *iclk_name; + const char *fclk_name; /* init software state */ udc->dev = dev; - udc->board = *(struct at91_udc_data *) dev->platform_data; udc->enabled = 0; + if (dev->platform_data) { + /* small (so we copy it) */ + udc->board = *(struct at91_udc_data *)dev->platform_data; + iclk_name = "udc_clk"; + fclk_name = "udpck"; + } else { + if (!IS_ENABLED(CONFIG_OFDEVICE) || !dev->device_node) { + dev_err(dev, "no DT and no platform_data\n"); + return -ENODEV; + } + + at91udc_of_init(udc, dev->device_node); + iclk_name = "pclk"; + fclk_name = "hclk"; + } + /* rm9200 needs manual D+ pullup; off by default */ if (cpu_is_at91rm9200()) { if (udc->board.pullup_pin <= 0) { @@ -1435,8 +1462,8 @@ udc_reinit(udc); /* get interface and function clocks */ - udc->iclk = clk_get(dev, "udc_clk"); - udc->fclk = clk_get(dev, "udpck"); + udc->iclk = clk_get(dev, iclk_name); + udc->fclk = clk_get(dev, fclk_name); if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk)) { DBG(udc, "clocks missing\n"); retval = -ENODEV; @@ -1491,10 +1518,17 @@ DBG(udc, "%s probe failed, %d\n", driver_name, retval); return retval; } - +static const struct of_device_id at91_udc_dt_ids[] = { + { .compatible = "atmel,at91rm9200-udc" }, + { .compatible = "atmel,at91sam9260-udc" }, + { .compatible = "atmel,at91sam9261-udc" }, + { .compatible = "atmel,at91sam9263-udc" }, + { /* sentinel */ } +}; static struct driver_d at91_udc_driver = { .name = driver_name, .probe = at91udc_probe, + .of_compatible = DRV_OF_COMPAT(at91_udc_dt_ids), }; device_platform_driver(at91_udc_driver); diff --git a/drivers/video/atmel_hlcdfb.c b/drivers/video/atmel_hlcdfb.c index f7aab7f..5d130f5 100644 --- a/drivers/video/atmel_hlcdfb.c +++ b/drivers/video/atmel_hlcdfb.c @@ -178,7 +178,6 @@ static void atmel_hlcdfb_setup_core_base(struct fb_info *info) { struct atmel_lcdfb_info *sinfo = info->priv; - struct atmel_lcdfb_platform_data *pdata = sinfo->pdata; struct fb_videomode *mode = info->mode; unsigned long value; unsigned long clk_value_khz; @@ -205,8 +204,8 @@ lcdc_writel(sinfo, ATMEL_LCDC_LCDCFG0, value); /* Initialize control register 5 */ - /* In 9x5, the default_lcdcon2 will use for LCDCFG5 */ - value = pdata->default_lcdcon2; + /* In 9x5, the lcdcon2 will use for LCDCFG5 */ + value = sinfo->lcdcon2; value |= (sinfo->guard_time << LCDC_LCDCFG5_GUARDTIME_OFFSET) | LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS; diff --git a/drivers/video/atmel_lcdfb.c b/drivers/video/atmel_lcdfb.c index a0e41d1..7c05e85 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -81,9 +81,7 @@ static void atmel_lcdfb_start(struct atmel_lcdfb_info *sinfo) { - struct atmel_lcdfb_platform_data *pdata = sinfo->pdata; - - lcdc_writel(sinfo, ATMEL_LCDC_DMACON, pdata->default_dmacon); + lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->dmacon); lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, (sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR); @@ -123,7 +121,6 @@ static void atmel_lcdfb_setup_core(struct fb_info *info) { struct atmel_lcdfb_info *sinfo = info->priv; - struct atmel_lcdfb_platform_data *pdata = sinfo->pdata; struct fb_videomode *mode = info->mode; unsigned long clk_value_khz; unsigned long pix_factor = 2; @@ -159,7 +156,7 @@ } /* Initialize control register 2 */ - value = pdata->default_lcdcon2; + value = sinfo->lcdcon2; if (!(mode->sync & FB_SYNC_HOR_HIGH_ACT)) value |= ATMEL_LCDC_INVLINE_INVERTED; @@ -246,8 +243,20 @@ return atmel_lcdc_register(dev, &atmel_lcdfb_data); } +static __maybe_unused struct of_device_id atmel_lcdfb_compatible[] = { + { .compatible = "atmel,at91sam9261-lcdc", }, + { .compatible = "atmel,at91sam9263-lcdc", }, + { .compatible = "atmel,at91sam9g10-lcdc", }, + { .compatible = "atmel,at91sam9g45-lcdc", }, + { .compatible = "atmel,at91sam9g45es-lcdc", }, + { .compatible = "atmel,at91sam9rl-lcdc", }, + { .compatible = "atmel,at32ap-lcdc", }, + { /* sentinel */ } +}; + static struct driver_d atmel_lcdc_driver = { .name = "atmel_lcdfb", .probe = atmel_lcdc_probe, + .of_compatible = DRV_OF_COMPAT(atmel_lcdfb_compatible), }; device_platform_driver(atmel_lcdc_driver); diff --git a/drivers/video/atmel_lcdfb.h b/drivers/video/atmel_lcdfb.h index ea4c7e6..a011d42 100644 --- a/drivers/video/atmel_lcdfb.h +++ b/drivers/video/atmel_lcdfb.h @@ -21,10 +21,16 @@ unsigned int guard_time; unsigned int smem_len; + unsigned int lcdcon2; + unsigned int dmacon; + unsigned int lcd_wiring_mode; + bool have_intensity_bit; + + int gpio_power_control; + bool gpio_power_control_active_low; struct clk *bus_clk; struct clk *lcdc_clk; - struct atmel_lcdfb_platform_data *pdata; struct atmel_lcdfb_devdata *dev_data; void *dma_desc; }; diff --git a/drivers/video/atmel_lcdfb_core.c b/drivers/video/atmel_lcdfb_core.c index f6c5d7c..45b0c63 100644 --- a/drivers/video/atmel_lcdfb_core.c +++ b/drivers/video/atmel_lcdfb_core.c @@ -19,6 +19,8 @@ */ #include +#include +#include #include #include #include @@ -39,13 +41,17 @@ clk_disable(sinfo->lcdc_clk); } -static void atmel_lcdc_power_controller(struct fb_info *fb_info, int i) +static void atmel_lcdc_power_controller(struct fb_info *fb_info, int on) { struct atmel_lcdfb_info *sinfo = fb_info->priv; - struct atmel_lcdfb_platform_data *pdata = sinfo->pdata; - if (pdata->atmel_lcdfb_power_control) - pdata->atmel_lcdfb_power_control(1); + if (sinfo->gpio_power_control < 0) + return; + + if (sinfo->gpio_power_control_active_low) + gpio_set_value(sinfo->gpio_power_control, !on); + else + gpio_set_value(sinfo->gpio_power_control, on); } /** @@ -69,7 +75,6 @@ { struct device_d *dev = &info->dev; struct atmel_lcdfb_info *sinfo = info->priv; - struct atmel_lcdfb_platform_data *pdata = sinfo->pdata; struct fb_videomode *mode = info->mode; unsigned long clk_value_khz; @@ -126,11 +131,11 @@ break; case 16: /* Older SOCs use IBGR:555 rather than BGR:565. */ - if (pdata->have_intensity_bit) + if (sinfo->have_intensity_bit) info->green.length = 5; else info->green.length = 6; - if (pdata->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { + if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { /* RGB:5X5 mode */ info->red.offset = info->green.length + 5; info->blue.offset = 0; @@ -147,7 +152,7 @@ info->transp.length = 8; /* fall through */ case 24: - if (pdata->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { + if (sinfo->lcd_wiring_mode == ATMEL_LCDC_WIRING_RGB) { /* RGB:888 mode */ info->red.offset = 16; info->blue.offset = 0; @@ -243,33 +248,176 @@ .fb_disable = atmel_lcdc_disable_controller, }; -int atmel_lcdc_register(struct device_d *dev, struct atmel_lcdfb_devdata *data) +static int power_control_init(struct device_d *dev, + struct atmel_lcdfb_info *sinfo, + int gpio, + bool active_low) { - struct resource *iores; - struct atmel_lcdfb_info *sinfo; - struct atmel_lcdfb_platform_data *pdata = dev->platform_data; - int ret = 0; - struct fb_info *info; + int ret; + const char *name = "lcdc_power"; - if (!pdata) { - dev_err(dev, "missing platform_data\n"); - return -EINVAL; + sinfo->gpio_power_control = gpio; + sinfo->gpio_power_control_active_low = active_low; + + /* If no GPIO specified then stop */ + if (!gpio_is_valid(gpio)) + return 0; + + ret = gpio_request(gpio, name); + if (ret) { + dev_err(dev, "%s: can not request gpio %d (%d)\n", + name, gpio, ret); + return ret; + } + ret = gpio_direction_output(gpio, 1); + if (ret) { + dev_err(dev, "%s: can not configure gpio %d as output (%d)\n", + name, gpio, ret); + return ret; } - sinfo = xzalloc(sizeof(*sinfo)); - sinfo->pdata = pdata; + return ret; +} + +/* + * Syntax: atmel,lcd-wiring-mode: lcd wiring mode "RGB", "BRG", "IRGB", "IBRG" + * The optional "I" indicates that green has an intensity bit as used by some + * older displays + */ +static int of_get_wiring_mode(struct device_node *np, + struct atmel_lcdfb_info *sinfo) +{ + const char *mode; + int ret; + + ret = of_property_read_string(np, "atmel,lcd-wiring-mode", &mode); + if (ret < 0) { + /* Not present, use defaults */ + sinfo->lcd_wiring_mode = ATMEL_LCDC_WIRING_BGR; + sinfo->have_intensity_bit = false; + return 0; + } + + if (!strcasecmp(mode, "BGR")) { + sinfo->lcd_wiring_mode = ATMEL_LCDC_WIRING_BGR; + sinfo->have_intensity_bit = false; + } else if (!strcasecmp(mode, "RGB")) { + sinfo->lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB; + sinfo->have_intensity_bit = false; + } else if (!strcasecmp(mode, "IBGR")) { + sinfo->lcd_wiring_mode = ATMEL_LCDC_WIRING_BGR; + sinfo->have_intensity_bit = true; + } else if (!strcasecmp(mode, "IRGB")) { + sinfo->lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB; + sinfo->have_intensity_bit = true; + } else { + return -ENODEV; + } + return 0; +} + +static int of_get_power_control(struct device_d *dev, + struct device_node *np, + struct atmel_lcdfb_info *sinfo) +{ + enum of_gpio_flags flags; + bool active_low; + int gpio; + + gpio = of_get_named_gpio_flags(np, "atmel,power-control-gpio", 0, &flags); + if (!gpio_is_valid(gpio)) { + /* No power control - ignore */ + return 0; + } + active_low = (flags & OF_GPIO_ACTIVE_LOW ? true : false); + return power_control_init(dev, sinfo, gpio, active_low); +} + +static int lcdfb_of_init(struct device_d *dev, struct atmel_lcdfb_info *sinfo) +{ + struct fb_info *info = &sinfo->info; + struct display_timings *modes; + struct device_node *display; + int ret; + + /* Required properties */ + display = of_parse_phandle(dev->device_node, "display", 0); + if (!display) { + dev_err(dev, "no display phandle\n"); + return -ENOENT; + } + ret = of_property_read_u32(display, "atmel,guard-time", &sinfo->guard_time); + if (ret < 0) { + dev_err(dev, "failed to get atmel,guard-time property\n"); + goto err; + } + ret = of_property_read_u32(display, "atmel,lcdcon2", &sinfo->lcdcon2); + if (ret < 0) { + dev_err(dev, "failed to get atmel,lcdcon2 property\n"); + goto err; + } + ret = of_property_read_u32(display, "atmel,dmacon", &sinfo->dmacon); + if (ret < 0) { + dev_err(dev, "failed to get atmel,dmacon property\n"); + goto err; + } + ret = of_property_read_u32(display, "bits-per-pixel", &info->bits_per_pixel); + if (ret < 0) { + dev_err(dev, "failed to get bits-per-pixel property\n"); + goto err; + } + modes = of_get_display_timings(display); + if (IS_ERR(modes)) { + dev_err(dev, "unable to parse display timings\n"); + ret = PTR_ERR(modes); + goto err; + } + info->modes.modes = modes->modes; + info->modes.num_modes = modes->num_modes; + + /* Optional properties */ + ret = of_get_wiring_mode(display, sinfo); + if (ret < 0) { + dev_err(dev, "failed to get atmel,lcd-wiring-mode property\n"); + goto err; + } + ret = of_get_power_control(dev, display, sinfo); + if (ret < 0) { + dev_err(dev, "failed to get power control gpio\n"); + goto err; + } + return 0; +err: + return ret; +} + +static int lcdfb_pdata_init(struct device_d *dev, struct atmel_lcdfb_info *sinfo) +{ + struct atmel_lcdfb_platform_data *pdata; + struct fb_info *info; + bool active_low; + int gpio; + int ret; + + pdata = dev->platform_data; + + /* If gpio == 0 (default in pdata) then we assume no power control */ + gpio = pdata->gpio_power_control; + if (gpio == 0) + gpio = -1; + + active_low = pdata->gpio_power_control_active_low; + ret = power_control_init(dev, sinfo, gpio, active_low); + if (ret) + goto err; + sinfo->guard_time = pdata->guard_time; - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - sinfo->mmio = IOMEM(iores->start); + sinfo->lcdcon2 = pdata->default_lcdcon2; + sinfo->dmacon = pdata->default_dmacon; + sinfo->lcd_wiring_mode = pdata->lcd_wiring_mode; + sinfo->have_intensity_bit = pdata->have_intensity_bit; - sinfo->dev_data = data; - - /* just init */ info = &sinfo->info; - info->priv = sinfo; - info->fbops = &atmel_lcdc_ops; info->modes.modes = pdata->mode_list; info->modes.num_modes = pdata->num_modes; info->mode = &info->modes.modes[0]; @@ -277,8 +425,51 @@ info->yres = info->mode->yres; info->bits_per_pixel = pdata->default_bpp; +err: + return ret; +} + +int atmel_lcdc_register(struct device_d *dev, struct atmel_lcdfb_devdata *data) +{ + struct atmel_lcdfb_info *sinfo; + const char *bus_clk_name; + struct resource *iores; + struct fb_info *info; + int ret = 0; + + iores = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores)) + return PTR_ERR(iores); + + sinfo = xzalloc(sizeof(*sinfo)); + sinfo->dev_data = data; + sinfo->mmio = IOMEM(iores->start); + + info = &sinfo->info; + info->priv = sinfo; + info->fbops = &atmel_lcdc_ops; + + if (dev->platform_data) { + ret = lcdfb_pdata_init(dev, sinfo); + if (ret) { + dev_err(dev, "failed to init lcdfb from pdata\n"); + goto err; + } + bus_clk_name = "hck1"; + } else { + if (!IS_ENABLED(CONFIG_OFDEVICE) || !dev->device_node) + return -EINVAL; + + ret = lcdfb_of_init(dev, sinfo); + if (ret) { + dev_err(dev, "failed to init lcdfb from DT\n"); + goto err; + } + bus_clk_name = "hclk"; + } + /* Enable LCDC Clocks */ - sinfo->bus_clk = clk_get(dev, "hck1"); + sinfo->bus_clk = clk_get(dev, bus_clk_name); if (IS_ERR(sinfo->bus_clk)) { ret = PTR_ERR(sinfo->bus_clk); goto err; diff --git a/include/video/atmel_lcdc.h b/include/video/atmel_lcdc.h index 132ee59..07a30e2 100644 --- a/include/video/atmel_lcdc.h +++ b/include/video/atmel_lcdc.h @@ -44,7 +44,8 @@ u8 lcd_wiring_mode; unsigned int default_lcdcon2; unsigned int default_dmacon; - void (*atmel_lcdfb_power_control)(int on); + int gpio_power_control; + bool gpio_power_control_active_low; struct fb_videomode *mode_list; unsigned num_modes;