diff options
author | Tom Rini <trini@ti.com> | 2014-11-05 07:23:32 -0500 |
---|---|---|
committer | Tom Rini <trini@ti.com> | 2014-11-05 07:23:32 -0500 |
commit | d5325eff10922acb11c39efece6d5f24de5b1998 (patch) | |
tree | 8ab0ce7214dcb242ab4edcc5d79f5ff78cd0446b /drivers | |
parent | 7417e7fdf2481320f1253393f6d560981849c9cb (diff) | |
parent | 44fd5914fb08ffcd96c9db7e448787f1d2aed801 (diff) | |
download | u-boot-imx-d5325eff10922acb11c39efece6d5f24de5b1998.zip u-boot-imx-d5325eff10922acb11c39efece6d5f24de5b1998.tar.gz u-boot-imx-d5325eff10922acb11c39efece6d5f24de5b1998.tar.bz2 |
Merge git://www.denx.de/git/u-boot-sunxi
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/gpio/sunxi_gpio.c | 170 | ||||
-rw-r--r-- | drivers/mmc/sunxi_mmc.c | 36 | ||||
-rw-r--r-- | drivers/serial/Makefile | 1 | ||||
-rw-r--r-- | drivers/serial/serial_dw.c | 39 | ||||
-rw-r--r-- | drivers/usb/host/ehci-sunxi.c | 12 |
5 files changed, 245 insertions, 13 deletions
diff --git a/drivers/gpio/sunxi_gpio.c b/drivers/gpio/sunxi_gpio.c index 0c50a8f..44135e5 100644 --- a/drivers/gpio/sunxi_gpio.c +++ b/drivers/gpio/sunxi_gpio.c @@ -11,9 +11,25 @@ */ #include <common.h> +#include <dm.h> +#include <errno.h> +#include <fdtdec.h> +#include <malloc.h> #include <asm/io.h> #include <asm/gpio.h> +#include <dm/device-internal.h> +DECLARE_GLOBAL_DATA_PTR; + +#define SUNXI_GPIOS_PER_BANK SUNXI_GPIO_A_NR + +struct sunxi_gpio_platdata { + struct sunxi_gpio *regs; + const char *bank_name; /* Name of bank, e.g. "B" */ + int gpio_count; +}; + +#ifndef CONFIG_DM_GPIO static int sunxi_gpio_output(u32 pin, u32 val) { u32 dat; @@ -100,3 +116,157 @@ int sunxi_name_to_gpio(const char *name) return -1; return group * 32 + pin; } +#endif + +#ifdef CONFIG_DM_GPIO +static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset) +{ + struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); + + sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT); + + return 0; +} + +static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset, + int value) +{ + struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); + u32 num = GPIO_NUM(offset); + + sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT); + clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0); + + return 0; +} + +static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset) +{ + struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); + u32 num = GPIO_NUM(offset); + unsigned dat; + + dat = readl(&plat->regs->dat); + dat >>= num; + + return dat & 0x1; +} + +static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset, + int value) +{ + struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); + u32 num = GPIO_NUM(offset); + + clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0); + return 0; +} + +static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset) +{ + struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); + int func; + + func = sunxi_gpio_get_cfgbank(plat->regs, offset); + if (func == SUNXI_GPIO_OUTPUT) + return GPIOF_OUTPUT; + else if (func == SUNXI_GPIO_INPUT) + return GPIOF_INPUT; + else + return GPIOF_FUNC; +} + +static const struct dm_gpio_ops gpio_sunxi_ops = { + .direction_input = sunxi_gpio_direction_input, + .direction_output = sunxi_gpio_direction_output, + .get_value = sunxi_gpio_get_value, + .set_value = sunxi_gpio_set_value, + .get_function = sunxi_gpio_get_function, +}; + +/** + * Returns the name of a GPIO bank + * + * GPIO banks are named A, B, C, ... + * + * @bank: Bank number (0, 1..n-1) + * @return allocated string containing the name + */ +static char *gpio_bank_name(int bank) +{ + char *name; + + name = malloc(2); + if (name) { + name[0] = 'A' + bank; + name[1] = '\0'; + } + + return name; +} + +static int gpio_sunxi_probe(struct udevice *dev) +{ + struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); + struct gpio_dev_priv *uc_priv = dev->uclass_priv; + + /* Tell the uclass how many GPIOs we have */ + if (plat) { + uc_priv->gpio_count = plat->gpio_count; + uc_priv->bank_name = plat->bank_name; + } + + return 0; +} +/** + * We have a top-level GPIO device with no actual GPIOs. It has a child + * device for each Sunxi bank. + */ +static int gpio_sunxi_bind(struct udevice *parent) +{ + struct sunxi_gpio_platdata *plat = parent->platdata; + struct sunxi_gpio_reg *ctlr; + int bank; + int ret; + + /* If this is a child device, there is nothing to do here */ + if (plat) + return 0; + + ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob, + parent->of_offset, "reg"); + for (bank = 0; bank < SUNXI_GPIO_BANKS; bank++) { + struct sunxi_gpio_platdata *plat; + struct udevice *dev; + + plat = calloc(1, sizeof(*plat)); + if (!plat) + return -ENOMEM; + plat->regs = &ctlr->gpio_bank[bank]; + plat->bank_name = gpio_bank_name(bank); + plat->gpio_count = SUNXI_GPIOS_PER_BANK; + + ret = device_bind(parent, parent->driver, + plat->bank_name, plat, -1, &dev); + if (ret) + return ret; + dev->of_offset = parent->of_offset; + } + + return 0; +} + +static const struct udevice_id sunxi_gpio_ids[] = { + { .compatible = "allwinner,sun7i-a20-pinctrl" }, + { } +}; + +U_BOOT_DRIVER(gpio_sunxi) = { + .name = "gpio_sunxi", + .id = UCLASS_GPIO, + .ops = &gpio_sunxi_ops, + .of_match = sunxi_gpio_ids, + .bind = gpio_sunxi_bind, + .probe = gpio_sunxi_probe, +}; +#endif diff --git a/drivers/mmc/sunxi_mmc.c b/drivers/mmc/sunxi_mmc.c index 16592e3..231f0a0 100644 --- a/drivers/mmc/sunxi_mmc.c +++ b/drivers/mmc/sunxi_mmc.c @@ -30,10 +30,22 @@ struct sunxi_mmc_host { /* support 4 mmc hosts */ struct sunxi_mmc_host mmc_host[4]; +static int sunxi_mmc_getcd_gpio(int sdc_no) +{ + switch (sdc_no) { + case 0: return sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN); + case 1: return sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN); + case 2: return sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN); + case 3: return sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN); + } + return -1; +} + static int mmc_resource_init(int sdc_no) { struct sunxi_mmc_host *mmchost = &mmc_host[sdc_no]; struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; + int cd_pin, ret = 0; debug("init mmc %d resource\n", sdc_no); @@ -60,7 +72,11 @@ static int mmc_resource_init(int sdc_no) } mmchost->mmc_no = sdc_no; - return 0; + cd_pin = sunxi_mmc_getcd_gpio(sdc_no); + if (cd_pin != -1) + ret = gpio_request(cd_pin, "mmc_cd"); + + return ret; } static int mmc_clk_io_on(int sdc_no) @@ -75,7 +91,7 @@ static int mmc_clk_io_on(int sdc_no) /* config ahb clock */ setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_MMC(sdc_no)); -#if defined(CONFIG_SUN6I) || defined(CONFIG_SUN8I) +#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN8I) /* unassert reset */ setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_RESET_OFFSET_MMC(sdc_no)); #endif @@ -351,15 +367,9 @@ out: static int sunxi_mmc_getcd(struct mmc *mmc) { struct sunxi_mmc_host *mmchost = mmc->priv; - int cd_pin = -1; - - switch (mmchost->mmc_no) { - case 0: cd_pin = sunxi_name_to_gpio(CONFIG_MMC0_CD_PIN); break; - case 1: cd_pin = sunxi_name_to_gpio(CONFIG_MMC1_CD_PIN); break; - case 2: cd_pin = sunxi_name_to_gpio(CONFIG_MMC2_CD_PIN); break; - case 3: cd_pin = sunxi_name_to_gpio(CONFIG_MMC3_CD_PIN); break; - } + int cd_pin; + cd_pin = sunxi_mmc_getcd_gpio(mmchost->mmc_no); if (cd_pin == -1) return 1; @@ -385,7 +395,7 @@ struct mmc *sunxi_mmc_init(int sdc_no) cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; cfg->host_caps = MMC_MODE_4BIT; cfg->host_caps |= MMC_MODE_HS_52MHz | MMC_MODE_HS; -#if defined(CONFIG_SUN6I) || defined(CONFIG_SUN7I) || defined(CONFIG_SUN8I) +#if defined(CONFIG_MACH_SUN6I) || defined(CONFIG_MACH_SUN7I) || defined(CONFIG_MACH_SUN8I) cfg->host_caps |= MMC_MODE_HC; #endif cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; @@ -393,7 +403,9 @@ struct mmc *sunxi_mmc_init(int sdc_no) cfg->f_min = 400000; cfg->f_max = 52000000; - mmc_resource_init(sdc_no); + if (mmc_resource_init(sdc_no) != 0) + return NULL; + mmc_clk_io_on(sdc_no); return mmc_create(cfg, &mmc_host[sdc_no]); diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile index 2c19ebc..8c84942 100644 --- a/drivers/serial/Makefile +++ b/drivers/serial/Makefile @@ -19,6 +19,7 @@ obj-$(CONFIG_ALTERA_UART) += altera_uart.o obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o obj-$(CONFIG_ARM_DCC) += arm_dcc.o obj-$(CONFIG_ATMEL_USART) += atmel_usart.o +obj-$(CONFIG_DW_SERIAL) += serial_dw.o obj-$(CONFIG_LPC32XX_HSUART) += lpc32xx_hsuart.o obj-$(CONFIG_MCFUART) += mcfuart.o obj-$(CONFIG_OPENCORES_YANU) += opencores_yanu.o diff --git a/drivers/serial/serial_dw.c b/drivers/serial/serial_dw.c new file mode 100644 index 0000000..a348f29 --- /dev/null +++ b/drivers/serial/serial_dw.c @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2014 Google, Inc + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <dm.h> +#include <ns16550.h> +#include <serial.h> + +static const struct udevice_id dw_serial_ids[] = { + { .compatible = "snps,dw-apb-uart" }, + { } +}; + +static int dw_serial_ofdata_to_platdata(struct udevice *dev) +{ + struct ns16550_platdata *plat = dev_get_platdata(dev); + int ret; + + ret = ns16550_serial_ofdata_to_platdata(dev); + if (ret) + return ret; + plat->clock = CONFIG_SYS_NS16550_CLK; + + return 0; +} + +U_BOOT_DRIVER(serial_ns16550) = { + .name = "serial_dw", + .id = UCLASS_SERIAL, + .of_match = dw_serial_ids, + .ofdata_to_platdata = dw_serial_ofdata_to_platdata, + .platdata_auto_alloc_size = sizeof(struct ns16550_platdata), + .priv_auto_alloc_size = sizeof(struct NS16550), + .probe = ns16550_serial_probe, + .ops = &ns16550_serial_ops, +}; diff --git a/drivers/usb/host/ehci-sunxi.c b/drivers/usb/host/ehci-sunxi.c index 23617b7..4befd57 100644 --- a/drivers/usb/host/ehci-sunxi.c +++ b/drivers/usb/host/ehci-sunxi.c @@ -105,7 +105,7 @@ static void sunxi_usb_phy_init(struct sunxi_ehci_hcd *sunxi_ehci) usb_phy_write(sunxi_ehci, 0x20, 0x14, 5); /* threshold adjustment disconnect */ -#ifdef CONFIG_SUN4I +#ifdef CONFIG_MACH_SUN4I usb_phy_write(sunxi_ehci, 0x2a, 3, 2); #else usb_phy_write(sunxi_ehci, 0x2a, 2, 2); @@ -163,11 +163,16 @@ int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr, { struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; struct sunxi_ehci_hcd *sunxi_ehci = &sunxi_echi_hcd[index]; + int err; /* enable common PHY only once */ if (index == 0) setbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE); + err = gpio_request(sunxi_ehci->gpio_vbus, "ehci_vbus"); + if (err) + return err; + sunxi_ehci_enable(sunxi_ehci); *hccr = get_io_base(sunxi_ehci->id); @@ -188,9 +193,14 @@ int ehci_hcd_stop(int index) { struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE; struct sunxi_ehci_hcd *sunxi_ehci = &sunxi_echi_hcd[index]; + int err; sunxi_ehci_disable(sunxi_ehci); + err = gpio_free(sunxi_ehci->gpio_vbus); + if (err) + return err; + /* disable common PHY only once, for the last enabled hcd */ if (enabled_hcd_count == 1) clrbits_le32(&ccm->usb_clk_cfg, CCM_USB_CTRL_PHYGATE); |