diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2017-09-08 08:41:17 +0200 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2017-09-08 08:41:17 +0200 |
commit | f8e5898ea86ea5e82d5291ec88f664f825621da5 (patch) | |
tree | 1f19b63bcea8004c2cf3dc69390ec545dc55d3d4 /drivers | |
parent | 2408090cbdf1ada60271eb84ca81be3e34993a7a (diff) | |
parent | a7cb0daf5772dfdfd76a4c4505d2c855e20c6451 (diff) | |
download | barebox-f8e5898ea86ea5e82d5291ec88f664f825621da5.tar.gz barebox-f8e5898ea86ea5e82d5291ec88f664f825621da5.tar.xz |
Merge branch 'for-next/at91'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/gadget/at91_udc.c | 56 | ||||
-rw-r--r-- | drivers/video/atmel_hlcdfb.c | 5 | ||||
-rw-r--r-- | drivers/video/atmel_lcdfb.c | 19 | ||||
-rw-r--r-- | drivers/video/atmel_lcdfb.h | 8 | ||||
-rw-r--r-- | drivers/video/atmel_lcdfb_core.c | 247 |
5 files changed, 287 insertions, 48 deletions
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c index 5f6bebc733..18427114d1 100644 --- a/drivers/usb/gadget/at91_udc.c +++ b/drivers/usb/gadget/at91_udc.c @@ -21,7 +21,7 @@ #include <clock.h> #include <usb/ch9.h> #include <usb/gadget.h> -#include <gpio.h> +#include <of_gpio.h> #include <linux/list.h> #include <linux/clk.h> @@ -1375,6 +1375,22 @@ static void at91_udc_gadget_poll(struct usb_gadget *gadget) 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 @@ static int __init at91udc_probe(struct device_d *dev) 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 @@ static int __init at91udc_probe(struct device_d *dev) 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 @@ fail0: 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 f7aab7f454..5d130f598e 100644 --- a/drivers/video/atmel_hlcdfb.c +++ b/drivers/video/atmel_hlcdfb.c @@ -178,7 +178,6 @@ static u32 atmel_hlcdfb_get_rgbmode(struct fb_info *info) 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 @@ static void atmel_hlcdfb_setup_core_base(struct fb_info *info) 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 a0e41d10c2..7c05e857b3 100644 --- a/drivers/video/atmel_lcdfb.c +++ b/drivers/video/atmel_lcdfb.c @@ -81,9 +81,7 @@ static void atmel_lcdfb_stop(struct atmel_lcdfb_info *sinfo, u32 flags) 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_limit_screeninfo(struct fb_videomode *mode) 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 @@ static void atmel_lcdfb_setup_core(struct fb_info *info) } /* 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 @@ static int atmel_lcdc_probe(struct device_d *dev) 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 ea4c7e647a..a011d42019 100644 --- a/drivers/video/atmel_lcdfb.h +++ b/drivers/video/atmel_lcdfb.h @@ -21,10 +21,16 @@ struct atmel_lcdfb_info { 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 f6c5d7c051..45b0c63d06 100644 --- a/drivers/video/atmel_lcdfb_core.c +++ b/drivers/video/atmel_lcdfb_core.c @@ -19,6 +19,8 @@ */ #include <common.h> +#include <of_gpio.h> +#include <gpio.h> #include <dma.h> #include <io.h> #include <linux/err.h> @@ -39,13 +41,17 @@ static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo) 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 @@ static int atmel_lcdfb_check_var(struct fb_info *info) { 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 @@ static int atmel_lcdfb_check_var(struct fb_info *info) 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 @@ static int atmel_lcdfb_check_var(struct fb_info *info) 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,42 +248,228 @@ static struct fb_ops atmel_lcdc_ops = { .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; + 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; + + info = &sinfo->info; + info->modes.modes = pdata->mode_list; + info->modes.num_modes = pdata->num_modes; + info->mode = &info->modes.modes[0]; + info->xres = info->mode->xres; + 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->mmio = IOMEM(iores->start); + sinfo = xzalloc(sizeof(*sinfo)); sinfo->dev_data = data; + sinfo->mmio = IOMEM(iores->start); - /* 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]; - info->xres = info->mode->xres; - info->yres = info->mode->yres; - info->bits_per_pixel = pdata->default_bpp; + + 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; |