diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/core/Makefile | 3 | ||||
-rw-r--r-- | drivers/core/device-remove.c | 187 | ||||
-rw-r--r-- | drivers/core/device.c | 178 | ||||
-rw-r--r-- | drivers/core/lists.c | 50 | ||||
-rw-r--r-- | drivers/core/root.c | 4 | ||||
-rw-r--r-- | drivers/gpio/at91_gpio.c | 241 | ||||
-rw-r--r-- | drivers/misc/cros_ec.c | 1 | ||||
-rw-r--r-- | drivers/mtd/spi/sandbox.c | 4 | ||||
-rw-r--r-- | drivers/serial/atmel_usart.c | 116 | ||||
-rw-r--r-- | drivers/serial/serial-uclass.c | 77 | ||||
-rw-r--r-- | drivers/serial/serial_tegra.c | 16 | ||||
-rw-r--r-- | drivers/spi/spi-uclass.c | 34 |
12 files changed, 625 insertions, 286 deletions
diff --git a/drivers/core/Makefile b/drivers/core/Makefile index 151c239..f14695b 100644 --- a/drivers/core/Makefile +++ b/drivers/core/Makefile @@ -4,5 +4,6 @@ # SPDX-License-Identifier: GPL-2.0+ # -obj-y := device.o lists.o root.o uclass.o util.o +obj-$(CONFIG_DM) += device.o lists.o root.o uclass.o util.o obj-$(CONFIG_OF_CONTROL) += simple-bus.o +obj-$(CONFIG_DM_DEVICE_REMOVE) += device-remove.o diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c new file mode 100644 index 0000000..8fc6b71 --- /dev/null +++ b/drivers/core/device-remove.c @@ -0,0 +1,187 @@ +/* + * Device manager + * + * Copyright (c) 2014 Google, Inc + * + * (C) Copyright 2012 + * Pavel Herrmann <morpheus.ibis@gmail.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <errno.h> +#include <malloc.h> +#include <dm/device.h> +#include <dm/device-internal.h> +#include <dm/uclass.h> +#include <dm/uclass-internal.h> +#include <dm/util.h> + +/** + * device_chld_unbind() - Unbind all device's children from the device + * + * On error, the function continues to unbind all children, and reports the + * first error. + * + * @dev: The device that is to be stripped of its children + * @return 0 on success, -ve on error + */ +static int device_chld_unbind(struct udevice *dev) +{ + struct udevice *pos, *n; + int ret, saved_ret = 0; + + assert(dev); + + list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { + ret = device_unbind(pos); + if (ret && !saved_ret) + saved_ret = ret; + } + + return saved_ret; +} + +/** + * device_chld_remove() - Stop all device's children + * @dev: The device whose children are to be removed + * @return 0 on success, -ve on error + */ +static int device_chld_remove(struct udevice *dev) +{ + struct udevice *pos, *n; + int ret; + + assert(dev); + + list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { + ret = device_remove(pos); + if (ret) + return ret; + } + + return 0; +} + +int device_unbind(struct udevice *dev) +{ + struct driver *drv; + int ret; + + if (!dev) + return -EINVAL; + + if (dev->flags & DM_FLAG_ACTIVATED) + return -EINVAL; + + drv = dev->driver; + assert(drv); + + if (drv->unbind) { + ret = drv->unbind(dev); + if (ret) + return ret; + } + + ret = device_chld_unbind(dev); + if (ret) + return ret; + + ret = uclass_unbind_device(dev); + if (ret) + return ret; + + if (dev->parent) + list_del(&dev->sibling_node); + free(dev); + + return 0; +} + +/** + * device_free() - Free memory buffers allocated by a device + * @dev: Device that is to be started + */ +void device_free(struct udevice *dev) +{ + int size; + + if (dev->driver->priv_auto_alloc_size) { + free(dev->priv); + dev->priv = NULL; + } + if (dev->flags & DM_FLAG_ALLOC_PDATA) { + free(dev->platdata); + dev->platdata = NULL; + } + size = dev->uclass->uc_drv->per_device_auto_alloc_size; + if (size) { + free(dev->uclass_priv); + dev->uclass_priv = NULL; + } + if (dev->parent) { + size = dev->parent->driver->per_child_auto_alloc_size; + if (size) { + free(dev->parent_priv); + dev->parent_priv = NULL; + } + } +} + +int device_remove(struct udevice *dev) +{ + struct driver *drv; + int ret; + + if (!dev) + return -EINVAL; + + if (!(dev->flags & DM_FLAG_ACTIVATED)) + return 0; + + drv = dev->driver; + assert(drv); + + ret = uclass_pre_remove_device(dev); + if (ret) + return ret; + + ret = device_chld_remove(dev); + if (ret) + goto err; + + if (drv->remove) { + ret = drv->remove(dev); + if (ret) + goto err_remove; + } + + if (dev->parent && dev->parent->driver->child_post_remove) { + ret = dev->parent->driver->child_post_remove(dev); + if (ret) { + dm_warn("%s: Device '%s' failed child_post_remove()", + __func__, dev->name); + } + } + + device_free(dev); + + dev->seq = -1; + dev->flags &= ~DM_FLAG_ACTIVATED; + + return ret; + +err_remove: + /* We can't put the children back */ + dm_warn("%s: Device '%s' failed to remove, but children are gone\n", + __func__, dev->name); +err: + ret = uclass_post_probe_device(dev); + if (ret) { + dm_warn("%s: Device '%s' failed to post_probe on error path\n", + __func__, dev->name); + } + + return ret; +} diff --git a/drivers/core/device.c b/drivers/core/device.c index 49faa29..6793e1c 100644 --- a/drivers/core/device.c +++ b/drivers/core/device.c @@ -24,52 +24,6 @@ DECLARE_GLOBAL_DATA_PTR; -/** - * device_chld_unbind() - Unbind all device's children from the device - * - * On error, the function continues to unbind all children, and reports the - * first error. - * - * @dev: The device that is to be stripped of its children - * @return 0 on success, -ve on error - */ -static int device_chld_unbind(struct udevice *dev) -{ - struct udevice *pos, *n; - int ret, saved_ret = 0; - - assert(dev); - - list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { - ret = device_unbind(pos); - if (ret && !saved_ret) - saved_ret = ret; - } - - return saved_ret; -} - -/** - * device_chld_remove() - Stop all device's children - * @dev: The device whose children are to be removed - * @return 0 on success, -ve on error - */ -static int device_chld_remove(struct udevice *dev) -{ - struct udevice *pos, *n; - int ret; - - assert(dev); - - list_for_each_entry_safe(pos, n, &dev->child_head, sibling_node) { - ret = device_remove(pos); - if (ret) - return ret; - } - - return 0; -} - int device_bind(struct udevice *parent, struct driver *drv, const char *name, void *platdata, int of_offset, struct udevice **devp) { @@ -167,71 +121,6 @@ int device_bind_by_name(struct udevice *parent, bool pre_reloc_only, -1, devp); } -int device_unbind(struct udevice *dev) -{ - struct driver *drv; - int ret; - - if (!dev) - return -EINVAL; - - if (dev->flags & DM_FLAG_ACTIVATED) - return -EINVAL; - - drv = dev->driver; - assert(drv); - - if (drv->unbind) { - ret = drv->unbind(dev); - if (ret) - return ret; - } - - ret = device_chld_unbind(dev); - if (ret) - return ret; - - ret = uclass_unbind_device(dev); - if (ret) - return ret; - - if (dev->parent) - list_del(&dev->sibling_node); - free(dev); - - return 0; -} - -/** - * device_free() - Free memory buffers allocated by a device - * @dev: Device that is to be started - */ -static void device_free(struct udevice *dev) -{ - int size; - - if (dev->driver->priv_auto_alloc_size) { - free(dev->priv); - dev->priv = NULL; - } - if (dev->flags & DM_FLAG_ALLOC_PDATA) { - free(dev->platdata); - dev->platdata = NULL; - } - size = dev->uclass->uc_drv->per_device_auto_alloc_size; - if (size) { - free(dev->uclass_priv); - dev->uclass_priv = NULL; - } - if (dev->parent) { - size = dev->parent->driver->per_child_auto_alloc_size; - if (size) { - free(dev->parent_priv); - dev->parent_priv = NULL; - } - } -} - int device_probe_child(struct udevice *dev, void *parent_priv) { struct driver *drv; @@ -342,63 +231,6 @@ int device_probe(struct udevice *dev) return device_probe_child(dev, NULL); } -int device_remove(struct udevice *dev) -{ - struct driver *drv; - int ret; - - if (!dev) - return -EINVAL; - - if (!(dev->flags & DM_FLAG_ACTIVATED)) - return 0; - - drv = dev->driver; - assert(drv); - - ret = uclass_pre_remove_device(dev); - if (ret) - return ret; - - ret = device_chld_remove(dev); - if (ret) - goto err; - - if (drv->remove) { - ret = drv->remove(dev); - if (ret) - goto err_remove; - } - - if (dev->parent && dev->parent->driver->child_post_remove) { - ret = dev->parent->driver->child_post_remove(dev); - if (ret) { - dm_warn("%s: Device '%s' failed child_post_remove()", - __func__, dev->name); - } - } - - device_free(dev); - - dev->seq = -1; - dev->flags &= ~DM_FLAG_ACTIVATED; - - return ret; - -err_remove: - /* We can't put the children back */ - dm_warn("%s: Device '%s' failed to remove, but children are gone\n", - __func__, dev->name); -err: - ret = uclass_post_probe_device(dev); - if (ret) { - dm_warn("%s: Device '%s' failed to post_probe on error path\n", - __func__, dev->name); - } - - return ret; -} - void *dev_get_platdata(struct udevice *dev) { if (!dev) { @@ -548,3 +380,13 @@ int device_find_next_child(struct udevice **devp) return 0; } + +struct udevice *dev_get_parent(struct udevice *child) +{ + return child->parent; +} + +ulong dev_get_of_data(struct udevice *dev) +{ + return dev->of_id->data; +} diff --git a/drivers/core/lists.c b/drivers/core/lists.c index 3a1ea85..ff115c4 100644 --- a/drivers/core/lists.c +++ b/drivers/core/lists.c @@ -25,9 +25,6 @@ struct driver *lists_driver_lookup_name(const char *name) const int n_ents = ll_entry_count(struct driver, driver); struct driver *entry; - if (!drv || !n_ents) - return NULL; - for (entry = drv; entry != drv + n_ents; entry++) { if (!strcmp(name, entry->name)) return entry; @@ -44,9 +41,6 @@ struct uclass_driver *lists_uclass_lookup(enum uclass_id id) const int n_ents = ll_entry_count(struct uclass_driver, uclass); struct uclass_driver *entry; - if ((id == UCLASS_INVALID) || !uclass) - return NULL; - for (entry = uclass; entry != uclass + n_ents; entry++) { if (entry->id == id) return entry; @@ -77,34 +71,60 @@ int lists_bind_drivers(struct udevice *parent, bool pre_reloc_only) return result; } +int device_bind_driver(struct udevice *parent, const char *drv_name, + const char *dev_name, struct udevice **devp) +{ + struct driver *drv; + int ret; + + drv = lists_driver_lookup_name(drv_name); + if (!drv) { + printf("Cannot find driver '%s'\n", drv_name); + return -ENOENT; + } + ret = device_bind(parent, drv, dev_name, NULL, -1, devp); + if (ret) { + printf("Cannot create device named '%s' (err=%d)\n", + dev_name, ret); + return ret; + } + + return 0; +} + #ifdef CONFIG_OF_CONTROL /** * driver_check_compatible() - Check if a driver is compatible with this node * * @param blob: Device tree pointer * @param offset: Offset of node in device tree - * @param of_matchL List of compatible strings to match + * @param of_match: List of compatible strings to match + * @param of_idp: Returns the match that was found * @return 0 if there is a match, -ENOENT if no match, -ENODEV if the node * does not have a compatible string, other error <0 if there is a device * tree error */ static int driver_check_compatible(const void *blob, int offset, - const struct udevice_id *of_match) + const struct udevice_id *of_match, + const struct udevice_id **of_idp) { int ret; + *of_idp = NULL; if (!of_match) return -ENOENT; while (of_match->compatible) { ret = fdt_node_check_compatible(blob, offset, of_match->compatible); - if (!ret) + if (!ret) { + *of_idp = of_match; return 0; - else if (ret == -FDT_ERR_NOTFOUND) + } else if (ret == -FDT_ERR_NOTFOUND) { return -ENODEV; - else if (ret < 0) + } else if (ret < 0) { return -EINVAL; + } of_match++; } @@ -116,6 +136,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, { struct driver *driver = ll_entry_start(struct driver, driver); const int n_ents = ll_entry_count(struct driver, driver); + const struct udevice_id *id; struct driver *entry; struct udevice *dev; bool found = false; @@ -127,7 +148,8 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, if (devp) *devp = NULL; for (entry = driver; entry != driver + n_ents; entry++) { - ret = driver_check_compatible(blob, offset, entry->of_match); + ret = driver_check_compatible(blob, offset, entry->of_match, + &id); name = fdt_get_name(blob, offset, NULL); if (ret == -ENOENT) { continue; @@ -136,8 +158,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, break; } else if (ret) { dm_warn("Device tree error at offset %d\n", offset); - if (!result || ret != -ENOENT) - result = ret; + result = ret; break; } @@ -147,6 +168,7 @@ int lists_bind_fdt(struct udevice *parent, const void *blob, int offset, dm_warn("Error binding driver '%s'\n", entry->name); return ret; } else { + dev->of_id = id; found = true; if (devp) *devp = dev; diff --git a/drivers/core/root.c b/drivers/core/root.c index a328a48..47b3acf 100644 --- a/drivers/core/root.c +++ b/drivers/core/root.c @@ -73,10 +73,8 @@ int dm_scan_platdata(bool pre_reloc_only) dm_warn("Some drivers were not found\n"); ret = 0; } - if (ret) - return ret; - return 0; + return ret; } #ifdef CONFIG_OF_CONTROL diff --git a/drivers/gpio/at91_gpio.c b/drivers/gpio/at91_gpio.c index 6517af1..6129c02 100644 --- a/drivers/gpio/at91_gpio.c +++ b/drivers/gpio/at91_gpio.c @@ -10,11 +10,14 @@ #include <config.h> #include <common.h> +#include <dm.h> #include <asm/io.h> #include <linux/sizes.h> +#include <asm/gpio.h> #include <asm/arch/hardware.h> #include <asm/arch/at91_pio.h> -#include <asm/arch/gpio.h> + +#define GPIO_PER_BANK 32 static struct at91_port *at91_pio_get_port(unsigned port) { @@ -39,19 +42,25 @@ static struct at91_port *at91_pio_get_port(unsigned port) } } +static void at91_set_port_pullup(struct at91_port *at91_port, unsigned offset, + int use_pullup) +{ + u32 mask; + + mask = 1 << offset; + if (use_pullup) + writel(mask, &at91_port->puer); + else + writel(mask, &at91_port->pudr); + writel(mask, &at91_port->per); +} + int at91_set_pio_pullup(unsigned port, unsigned pin, int use_pullup) { struct at91_port *at91_port = at91_pio_get_port(port); - u32 mask; - if (at91_port && (pin < 32)) { - mask = 1 << pin; - if (use_pullup) - writel(1 << pin, &at91_port->puer); - else - writel(1 << pin, &at91_port->pudr); - writel(mask, &at91_port->per); - } + if (at91_port && (pin < GPIO_PER_BANK)) + at91_set_port_pullup(at91_port, pin, use_pullup); return 0; } @@ -64,7 +73,7 @@ int at91_set_pio_periph(unsigned port, unsigned pin, int use_pullup) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); @@ -82,7 +91,7 @@ int at91_set_a_periph(unsigned port, unsigned pin, int use_pullup) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); @@ -108,7 +117,7 @@ int at91_set_b_periph(unsigned port, unsigned pin, int use_pullup) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); @@ -135,7 +144,7 @@ int at91_set_c_periph(unsigned port, unsigned pin, int use_pullup) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); @@ -157,7 +166,7 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->idr); at91_set_pio_pullup(port, pin, use_pullup); @@ -172,6 +181,29 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup) } #endif +#ifdef CONFIG_DM_GPIO +static bool at91_get_port_output(struct at91_port *at91_port, int offset) +{ + u32 mask, val; + + mask = 1 << offset; + val = readl(&at91_port->osr); + return val & mask; +} +#endif + +static void at91_set_port_input(struct at91_port *at91_port, int offset, + int use_pullup) +{ + u32 mask; + + mask = 1 << offset; + writel(mask, &at91_port->idr); + at91_set_port_pullup(at91_port, offset, use_pullup); + writel(mask, &at91_port->odr); + writel(mask, &at91_port->per); +} + /* * mux the pin to the gpio controller (instead of "A" or "B" peripheral), and * configure it for an input. @@ -179,19 +211,29 @@ int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup) int at91_set_pio_input(unsigned port, u32 pin, int use_pullup) { struct at91_port *at91_port = at91_pio_get_port(port); - u32 mask; - if (at91_port && (pin < 32)) { - mask = 1 << pin; - writel(mask, &at91_port->idr); - at91_set_pio_pullup(port, pin, use_pullup); - writel(mask, &at91_port->odr); - writel(mask, &at91_port->per); - } + if (at91_port && (pin < GPIO_PER_BANK)) + at91_set_port_input(at91_port, pin, use_pullup); return 0; } +static void at91_set_port_output(struct at91_port *at91_port, int offset, + int value) +{ + u32 mask; + + mask = 1 << offset; + writel(mask, &at91_port->idr); + writel(mask, &at91_port->pudr); + if (value) + writel(mask, &at91_port->sodr); + else + writel(mask, &at91_port->codr); + writel(mask, &at91_port->oer); + writel(mask, &at91_port->per); +} + /* * mux the pin to the gpio controller (instead of "A" or "B" peripheral), * and configure it for an output. @@ -199,19 +241,9 @@ int at91_set_pio_input(unsigned port, u32 pin, int use_pullup) int at91_set_pio_output(unsigned port, u32 pin, int value) { struct at91_port *at91_port = at91_pio_get_port(port); - u32 mask; - if (at91_port && (port < ATMEL_PIO_PORTS) && (pin < 32)) { - mask = 1 << pin; - writel(mask, &at91_port->idr); - writel(mask, &at91_port->pudr); - if (value) - writel(mask, &at91_port->sodr); - else - writel(mask, &at91_port->codr); - writel(mask, &at91_port->oer); - writel(mask, &at91_port->per); - } + if (at91_port && (pin < GPIO_PER_BANK)) + at91_set_port_output(at91_port, pin, value); return 0; } @@ -224,7 +256,7 @@ int at91_set_pio_deglitch(unsigned port, unsigned pin, int is_on) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; if (is_on) { #if defined(CPU_HAS_PIO3) @@ -248,7 +280,7 @@ int at91_set_pio_debounce(unsigned port, unsigned pin, int is_on, int div) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; if (is_on) { writel(mask, &at91_port->ifscer); @@ -271,7 +303,7 @@ int at91_set_pio_pulldown(unsigned port, unsigned pin, int is_on) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(mask, &at91_port->pudr); if (is_on) @@ -291,7 +323,7 @@ int at91_set_pio_disable_schmitt_trig(unsigned port, unsigned pin) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; writel(readl(&at91_port->schmitt) | mask, &at91_port->schmitt); @@ -310,7 +342,7 @@ int at91_set_pio_multi_drive(unsigned port, unsigned pin, int is_on) struct at91_port *at91_port = at91_pio_get_port(port); u32 mask; - if (at91_port && (pin < 32)) { + if (at91_port && (pin < GPIO_PER_BANK)) { mask = 1 << pin; if (is_on) writel(mask, &at91_port->mder); @@ -321,41 +353,54 @@ int at91_set_pio_multi_drive(unsigned port, unsigned pin, int is_on) return 0; } +static void at91_set_port_value(struct at91_port *at91_port, int offset, + int value) +{ + u32 mask; + + mask = 1 << offset; + if (value) + writel(mask, &at91_port->sodr); + else + writel(mask, &at91_port->codr); +} + /* * assuming the pin is muxed as a gpio output, set its value. */ int at91_set_pio_value(unsigned port, unsigned pin, int value) { struct at91_port *at91_port = at91_pio_get_port(port); - u32 mask; - if (at91_port && (pin < 32)) { - mask = 1 << pin; - if (value) - writel(mask, &at91_port->sodr); - else - writel(mask, &at91_port->codr); - } + if (at91_port && (pin < GPIO_PER_BANK)) + at91_set_port_value(at91_port, pin, value); return 0; } +static int at91_get_port_value(struct at91_port *at91_port, int offset) +{ + u32 pdsr = 0, mask; + + mask = 1 << offset; + pdsr = readl(&at91_port->pdsr) & mask; + + return pdsr != 0; +} /* * read the pin's value (works even if it's not muxed as a gpio). */ int at91_get_pio_value(unsigned port, unsigned pin) { struct at91_port *at91_port = at91_pio_get_port(port); - u32 pdsr = 0, mask; - if (at91_port && (pin < 32)) { - mask = 1 << pin; - pdsr = readl(&at91_port->pdsr) & mask; - } + if (at91_port && (pin < GPIO_PER_BANK)) + return at91_get_port_value(at91_port, pin); - return pdsr != 0; + return 0; } +#ifndef CONFIG_DM_GPIO /* Common GPIO API */ int gpio_request(unsigned gpio, const char *label) @@ -395,3 +440,91 @@ int gpio_set_value(unsigned gpio, int value) return 0; } +#endif + +#ifdef CONFIG_DM_GPIO + +struct at91_port_priv { + struct at91_port *regs; +}; + +/* set GPIO pin 'gpio' as an input */ +static int at91_gpio_direction_input(struct udevice *dev, unsigned offset) +{ + struct at91_port_priv *port = dev_get_platdata(dev); + + at91_set_port_input(port->regs, offset, 0); + + return 0; +} + +/* set GPIO pin 'gpio' as an output, with polarity 'value' */ +static int at91_gpio_direction_output(struct udevice *dev, unsigned offset, + int value) +{ + struct at91_port_priv *port = dev_get_platdata(dev); + + at91_set_port_output(port->regs, offset, value); + + return 0; +} + +/* read GPIO IN value of pin 'gpio' */ +static int at91_gpio_get_value(struct udevice *dev, unsigned offset) +{ + struct at91_port_priv *port = dev_get_platdata(dev); + + return at91_get_port_value(port->regs, offset); +} + +/* write GPIO OUT value to pin 'gpio' */ +static int at91_gpio_set_value(struct udevice *dev, unsigned offset, + int value) +{ + struct at91_port_priv *port = dev_get_platdata(dev); + + at91_set_port_value(port->regs, offset, value); + + return 0; +} + +static int at91_gpio_get_function(struct udevice *dev, unsigned offset) +{ + struct at91_port_priv *port = dev_get_platdata(dev); + + /* GPIOF_FUNC is not implemented yet */ + if (at91_get_port_output(port->regs, offset)) + return GPIOF_OUTPUT; + else + return GPIOF_INPUT; +} + +static const struct dm_gpio_ops gpio_at91_ops = { + .direction_input = at91_gpio_direction_input, + .direction_output = at91_gpio_direction_output, + .get_value = at91_gpio_get_value, + .set_value = at91_gpio_set_value, + .get_function = at91_gpio_get_function, +}; + +static int at91_gpio_probe(struct udevice *dev) +{ + struct at91_port_priv *port = dev_get_priv(dev); + struct at91_port_platdata *plat = dev_get_platdata(dev); + struct gpio_dev_priv *uc_priv = dev->uclass_priv; + + uc_priv->bank_name = plat->bank_name; + uc_priv->gpio_count = GPIO_PER_BANK; + port->regs = (struct at91_port *)plat->base_addr; + + return 0; +} + +U_BOOT_DRIVER(gpio_at91) = { + .name = "gpio_at91", + .id = UCLASS_GPIO, + .ops = &gpio_at91_ops, + .probe = at91_gpio_probe, + .priv_auto_alloc_size = sizeof(struct at91_port_priv), +}; +#endif diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c index 521edfd..9b4effb 100644 --- a/drivers/misc/cros_ec.c +++ b/drivers/misc/cros_ec.c @@ -701,6 +701,7 @@ static int cros_ec_check_version(struct cros_ec_dev *dev) /* Try sending a version 3 packet */ dev->protocol_version = 3; + req.in_data = 0; if (ec_command_inptr(dev, EC_CMD_HELLO, 0, &req, sizeof(req), (uint8_t **)&resp, sizeof(*resp)) > 0) { return 0; diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c index be6c43e..3024b98 100644 --- a/drivers/mtd/spi/sandbox.c +++ b/drivers/mtd/spi/sandbox.c @@ -602,14 +602,14 @@ static int sandbox_sf_bind_bus_cs(struct sandbox_state *state, int busnum, spec, ret); return ret; } - ret = device_find_child_by_seq(bus, cs, true, &slave); + ret = spi_find_chip_select(bus, cs, &slave); if (!ret) { printf("Chip select %d already exists for spec '%s'\n", cs, spec); return -EEXIST; } - ret = spi_bind_device(bus, cs, "spi_flash_std", spec, &slave); + ret = device_bind_driver(bus, "spi_flash_std", spec, &slave); if (ret) return ret; diff --git a/drivers/serial/atmel_usart.c b/drivers/serial/atmel_usart.c index 8f0e348..4fe992b 100644 --- a/drivers/serial/atmel_usart.c +++ b/drivers/serial/atmel_usart.c @@ -7,11 +7,16 @@ * SPDX-License-Identifier: GPL-2.0+ */ #include <common.h> +#include <dm.h> +#include <errno.h> #include <watchdog.h> #include <serial.h> #include <linux/compiler.h> #include <asm/io.h> +#ifdef CONFIG_DM_SERIAL +#include <asm/arch/atmel_serial.h> +#endif #include <asm/arch/clk.h> #include <asm/arch/hardware.h> @@ -19,9 +24,9 @@ DECLARE_GLOBAL_DATA_PTR; -static void atmel_serial_setbrg(void) +static void atmel_serial_setbrg_internal(atmel_usart3_t *usart, int id, + int baudrate) { - atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE; unsigned long divisor; unsigned long usart_hz; @@ -30,15 +35,13 @@ static void atmel_serial_setbrg(void) * Baud Rate = -------------- * 16 * CD */ - usart_hz = get_usart_clk_rate(CONFIG_USART_ID); - divisor = (usart_hz / 16 + gd->baudrate / 2) / gd->baudrate; + usart_hz = get_usart_clk_rate(id); + divisor = (usart_hz / 16 + baudrate / 2) / baudrate; writel(USART3_BF(CD, divisor), &usart->brgr); } -static int atmel_serial_init(void) +static void atmel_serial_init_internal(atmel_usart3_t *usart) { - atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE; - /* * Just in case: drain transmitter register * 1000us is enough for baudrate >= 9600 @@ -47,9 +50,10 @@ static int atmel_serial_init(void) __udelay(1000); writel(USART3_BIT(RSTRX) | USART3_BIT(RSTTX), &usart->cr); +} - serial_setbrg(); - +static void atmel_serial_activate(atmel_usart3_t *usart) +{ writel((USART3_BF(USART_MODE, USART3_USART_MODE_NORMAL) | USART3_BF(USCLKS, USART3_USCLKS_MCK) | USART3_BF(CHRL, USART3_CHRL_8) @@ -59,6 +63,22 @@ static int atmel_serial_init(void) writel(USART3_BIT(RXEN) | USART3_BIT(TXEN), &usart->cr); /* 100us is enough for the new settings to be settled */ __udelay(100); +} + +#ifndef CONFIG_DM_SERIAL +static void atmel_serial_setbrg(void) +{ + atmel_serial_setbrg_internal((atmel_usart3_t *)CONFIG_USART_BASE, + CONFIG_USART_ID, gd->baudrate); +} + +static int atmel_serial_init(void) +{ + atmel_usart3_t *usart = (atmel_usart3_t *)CONFIG_USART_BASE; + + atmel_serial_init_internal(usart); + serial_setbrg(); + atmel_serial_activate(usart); return 0; } @@ -109,3 +129,81 @@ __weak struct serial_device *default_serial_console(void) { return &atmel_serial_drv; } +#endif + +#ifdef CONFIG_DM_SERIAL + +struct atmel_serial_priv { + atmel_usart3_t *usart; +}; + +int atmel_serial_setbrg(struct udevice *dev, int baudrate) +{ + struct atmel_serial_priv *priv = dev_get_priv(dev); + + atmel_serial_setbrg_internal(priv->usart, 0 /* ignored */, baudrate); + atmel_serial_activate(priv->usart); + + return 0; +} + +static int atmel_serial_getc(struct udevice *dev) +{ + struct atmel_serial_priv *priv = dev_get_priv(dev); + + if (!(readl(&priv->usart->csr) & USART3_BIT(RXRDY))) + return -EAGAIN; + + return readl(&priv->usart->rhr); +} + +static int atmel_serial_putc(struct udevice *dev, const char ch) +{ + struct atmel_serial_priv *priv = dev_get_priv(dev); + + if (!(readl(&priv->usart->csr) & USART3_BIT(TXRDY))) + return -EAGAIN; + + writel(ch, &priv->usart->thr); + + return 0; +} + +static int atmel_serial_pending(struct udevice *dev, bool input) +{ + struct atmel_serial_priv *priv = dev_get_priv(dev); + uint32_t csr = readl(&priv->usart->csr); + + if (input) + return csr & USART3_BIT(RXRDY) ? 1 : 0; + else + return csr & USART3_BIT(TXEMPTY) ? 0 : 1; +} + +static const struct dm_serial_ops atmel_serial_ops = { + .putc = atmel_serial_putc, + .pending = atmel_serial_pending, + .getc = atmel_serial_getc, + .setbrg = atmel_serial_setbrg, +}; + +static int atmel_serial_probe(struct udevice *dev) +{ + struct atmel_serial_platdata *plat = dev->platdata; + struct atmel_serial_priv *priv = dev_get_priv(dev); + + priv->usart = (atmel_usart3_t *)plat->base_addr; + atmel_serial_init_internal(priv->usart); + + return 0; +} + +U_BOOT_DRIVER(serial_atmel) = { + .name = "serial_atmel", + .id = UCLASS_SERIAL, + .probe = atmel_serial_probe, + .ops = &atmel_serial_ops, + .flags = DM_FLAG_PRE_RELOC, + .priv_auto_alloc_size = sizeof(struct atmel_serial_priv), +}; +#endif diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c index 0f019c8..b09053f 100644 --- a/drivers/serial/serial-uclass.c +++ b/drivers/serial/serial-uclass.c @@ -6,6 +6,7 @@ #include <common.h> #include <dm.h> +#include <environment.h> #include <errno.h> #include <fdtdec.h> #include <os.h> @@ -19,6 +20,11 @@ DECLARE_GLOBAL_DATA_PTR; +/* + * Table with supported baudrates (defined in config_xyz.h) + */ +static const unsigned long baudrate_table[] = CONFIG_SYS_BAUDRATE_TABLE; + #ifndef CONFIG_SYS_MALLOC_F_LEN #error "Serial is required before relocation - define CONFIG_SYS_MALLOC_F_LEN to make this work" #endif @@ -160,10 +166,12 @@ void serial_stdio_init(void) { } +#ifdef CONFIG_DM_STDIO static void serial_stub_putc(struct stdio_dev *sdev, const char ch) { _serial_putc(sdev->priv, ch); } +#endif void serial_stub_puts(struct stdio_dev *sdev, const char *str) { @@ -180,11 +188,74 @@ int serial_stub_tstc(struct stdio_dev *sdev) return _serial_tstc(sdev->priv); } +/** + * on_baudrate() - Update the actual baudrate when the env var changes + * + * This will check for a valid baudrate and only apply it if valid. + */ +static int on_baudrate(const char *name, const char *value, enum env_op op, + int flags) +{ + int i; + int baudrate; + + switch (op) { + case env_op_create: + case env_op_overwrite: + /* + * Switch to new baudrate if new baudrate is supported + */ + baudrate = simple_strtoul(value, NULL, 10); + + /* Not actually changing */ + if (gd->baudrate == baudrate) + return 0; + + for (i = 0; i < ARRAY_SIZE(baudrate_table); ++i) { + if (baudrate == baudrate_table[i]) + break; + } + if (i == ARRAY_SIZE(baudrate_table)) { + if ((flags & H_FORCE) == 0) + printf("## Baudrate %d bps not supported\n", + baudrate); + return 1; + } + if ((flags & H_INTERACTIVE) != 0) { + printf("## Switch baudrate to %d bps and press ENTER ...\n", + baudrate); + udelay(50000); + } + + gd->baudrate = baudrate; + + serial_setbrg(); + + udelay(50000); + + if ((flags & H_INTERACTIVE) != 0) + while (1) { + if (getc() == '\r') + break; + } + + return 0; + case env_op_delete: + printf("## Baudrate may not be deleted\n"); + return 1; + default: + return 0; + } +} +U_BOOT_ENV_CALLBACK(baudrate, on_baudrate); + static int serial_post_probe(struct udevice *dev) { - struct stdio_dev sdev; struct dm_serial_ops *ops = serial_get_ops(dev); +#ifdef CONFIG_DM_STDIO struct serial_dev_priv *upriv = dev->uclass_priv; + struct stdio_dev sdev; +#endif int ret; /* Set the baud rate */ @@ -194,9 +265,9 @@ static int serial_post_probe(struct udevice *dev) return ret; } +#ifdef CONFIG_DM_STDIO if (!(gd->flags & GD_FLG_RELOC)) return 0; - memset(&sdev, '\0', sizeof(sdev)); strncpy(sdev.name, dev->name, sizeof(sdev.name)); @@ -207,7 +278,7 @@ static int serial_post_probe(struct udevice *dev) sdev.getc = serial_stub_getc; sdev.tstc = serial_stub_tstc; stdio_register_dev(&sdev, &upriv->sdev); - +#endif return 0; } diff --git a/drivers/serial/serial_tegra.c b/drivers/serial/serial_tegra.c index 7eb70e1..b9227f0 100644 --- a/drivers/serial/serial_tegra.c +++ b/drivers/serial/serial_tegra.c @@ -9,6 +9,7 @@ #include <ns16550.h> #include <serial.h> +#ifdef CONFIG_OF_CONTROL static const struct udevice_id tegra_serial_ids[] = { { .compatible = "nvidia,tegra20-uart" }, { } @@ -26,13 +27,28 @@ static int tegra_serial_ofdata_to_platdata(struct udevice *dev) return 0; } +#else +struct ns16550_platdata tegra_serial = { + .base = CONFIG_SYS_NS16550_COM1, + .reg_shift = 2, + .clock = V_NS16550_CLK, +}; + +U_BOOT_DEVICE(ns16550_serial) = { + "serial_tegra20", &tegra_serial +}; +#endif + U_BOOT_DRIVER(serial_ns16550) = { .name = "serial_tegra20", .id = UCLASS_SERIAL, +#ifdef CONFIG_OF_CONTROL .of_match = tegra_serial_ids, .ofdata_to_platdata = tegra_serial_ofdata_to_platdata, .platdata_auto_alloc_size = sizeof(struct ns16550_platdata), +#endif .priv_auto_alloc_size = sizeof(struct NS16550), .probe = ns16550_serial_probe, .ops = &ns16550_serial_ops, + .flags = DM_FLAG_PRE_RELOC, }; diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c index 637d420..7a57bce 100644 --- a/drivers/spi/spi-uclass.c +++ b/drivers/spi/spi-uclass.c @@ -115,16 +115,7 @@ int spi_chip_select(struct udevice *dev) return slave ? slave->cs : -ENOENT; } -/** - * spi_find_chip_select() - Find the slave attached to chip select - * - * @bus: SPI bus to search - * @cs: Chip select to look for - * @devp: Returns the slave device if found - * @return 0 if found, -ENODEV on error - */ -static int spi_find_chip_select(struct udevice *bus, int cs, - struct udevice **devp) +int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp) { struct udevice *dev; @@ -197,27 +188,6 @@ int spi_cs_info(struct udevice *bus, uint cs, struct spi_cs_info *info) return -ENODEV; } -int spi_bind_device(struct udevice *bus, int cs, const char *drv_name, - const char *dev_name, struct udevice **devp) -{ - struct driver *drv; - int ret; - - drv = lists_driver_lookup_name(drv_name); - if (!drv) { - printf("Cannot find driver '%s'\n", drv_name); - return -ENOENT; - } - ret = device_bind(bus, drv, dev_name, NULL, -1, devp); - if (ret) { - printf("Cannot create device named '%s' (err=%d)\n", - dev_name, ret); - return ret; - } - - return 0; -} - int spi_find_bus_and_cs(int busnum, int cs, struct udevice **busp, struct udevice **devp) { @@ -264,7 +234,7 @@ int spi_get_bus_and_cs(int busnum, int cs, int speed, int mode, if (ret == -ENODEV && drv_name) { debug("%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n", __func__, dev_name, busnum, cs, drv_name); - ret = spi_bind_device(bus, cs, drv_name, dev_name, &dev); + ret = device_bind_driver(bus, drv_name, dev_name, &dev); if (ret) return ret; created = true; |