diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/base/regmap/Makefile | 3 | ||||
-rw-r--r-- | drivers/base/regmap/internal.h | 9 | ||||
-rw-r--r-- | drivers/base/regmap/regmap-mmio.c | 271 | ||||
-rw-r--r-- | drivers/clk/clk.c | 43 | ||||
-rw-r--r-- | drivers/gpio/gpiolib.c | 2 | ||||
-rw-r--r-- | drivers/mfd/syscon.c | 47 | ||||
-rw-r--r-- | drivers/net/designware_stm32.c | 3 | ||||
-rw-r--r-- | drivers/pinctrl/pinctrl-single.c | 2 | ||||
-rw-r--r-- | drivers/usb/core/hub.c | 3 | ||||
-rw-r--r-- | drivers/usb/gadget/f_fastboot.c | 2 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.c | 5 | ||||
-rw-r--r-- | drivers/usb/musb/musb_dsps.c | 55 | ||||
-rw-r--r-- | drivers/usb/musb/phy-am335x-control.c | 25 | ||||
-rw-r--r-- | drivers/usb/musb/phy-am335x.c | 22 | ||||
-rw-r--r-- | drivers/usb/musb/phy-am335x.h | 6 |
15 files changed, 417 insertions, 81 deletions
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile index 4dc3d8c510..ab2387037d 100644 --- a/drivers/base/regmap/Makefile +++ b/drivers/base/regmap/Makefile @@ -1 +1,2 @@ -obj-y += regmap.o
\ No newline at end of file +obj-y += regmap.o +obj-y += regmap-mmio.o diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 52df5290a1..5b19459828 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -1,5 +1,10 @@ +#ifndef REGMAP_INTERNAL_H_ +#define REGMAP_INTERNAL_H_ #include <linux/list.h> +#include <driver.h> + +struct regmap_bus; struct regmap { struct device_d *dev; @@ -15,4 +20,6 @@ struct regmap { unsigned int max_register; struct cdev cdev; -};
\ No newline at end of file +}; + +#endif diff --git a/drivers/base/regmap/regmap-mmio.c b/drivers/base/regmap/regmap-mmio.c new file mode 100644 index 0000000000..f8d2cda843 --- /dev/null +++ b/drivers/base/regmap/regmap-mmio.c @@ -0,0 +1,271 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Register map access API - MMIO support +// +// Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. + +#include <linux/clk.h> +#include <linux/err.h> +#include <io.h> +#include <regmap.h> + +#include "internal.h" + +struct regmap_mmio_context { + void __iomem *regs; + unsigned val_bytes; + + struct clk *clk; + + void (*reg_write)(struct regmap_mmio_context *ctx, + unsigned int reg, unsigned int val); + unsigned int (*reg_read)(struct regmap_mmio_context *ctx, + unsigned int reg); +}; + +static int regmap_mmio_regbits_check(size_t reg_bits) +{ + switch (reg_bits) { + case 8: + case 16: + case 32: +#ifdef CONFIG_64BIT + case 64: +#endif + return 0; + default: + return -EINVAL; + } +} + +static int regmap_mmio_get_min_stride(size_t val_bits) +{ + int min_stride; + + switch (val_bits) { + case 8: + /* The core treats 0 as 1 */ + min_stride = 0; + return 0; + case 16: + min_stride = 2; + break; + case 32: + min_stride = 4; + break; +#ifdef CONFIG_64BIT + case 64: + min_stride = 8; + break; +#endif + default: + return -EINVAL; + } + + return min_stride; +} + +static void regmap_mmio_write8(struct regmap_mmio_context *ctx, + unsigned int reg, + unsigned int val) +{ + writeb(val, ctx->regs + reg); +} + +static void regmap_mmio_write16le(struct regmap_mmio_context *ctx, + unsigned int reg, + unsigned int val) +{ + writew(val, ctx->regs + reg); +} + +static void regmap_mmio_write32le(struct regmap_mmio_context *ctx, + unsigned int reg, + unsigned int val) +{ + writel(val, ctx->regs + reg); +} + +#ifdef CONFIG_64BIT +static void regmap_mmio_write64le(struct regmap_mmio_context *ctx, + unsigned int reg, + unsigned int val) +{ + writeq(val, ctx->regs + reg); +} +#endif + +static int regmap_mmio_write(void *context, unsigned int reg, unsigned int val) +{ + struct regmap_mmio_context *ctx = context; + int ret; + + ret = clk_enable(ctx->clk); + if (ret < 0) + return ret; + + ctx->reg_write(ctx, reg, val); + + clk_disable(ctx->clk); + + return 0; +} + +static unsigned int regmap_mmio_read8(struct regmap_mmio_context *ctx, + unsigned int reg) +{ + return readb(ctx->regs + reg); +} + +static unsigned int regmap_mmio_read16le(struct regmap_mmio_context *ctx, + unsigned int reg) +{ + return readw(ctx->regs + reg); +} + +static unsigned int regmap_mmio_read32le(struct regmap_mmio_context *ctx, + unsigned int reg) +{ + return readl(ctx->regs + reg); +} + +#ifdef CONFIG_64BIT +static unsigned int regmap_mmio_read64le(struct regmap_mmio_context *ctx, + unsigned int reg) +{ + return readq(ctx->regs + reg); +} +#endif + +static int regmap_mmio_read(void *context, unsigned int reg, unsigned int *val) +{ + struct regmap_mmio_context *ctx = context; + int ret; + + ret = clk_enable(ctx->clk); + if (ret < 0) + return ret; + + *val = ctx->reg_read(ctx, reg); + + clk_disable(ctx->clk); + + return 0; +} + +static const struct regmap_bus regmap_mmio = { + .reg_write = regmap_mmio_write, + .reg_read = regmap_mmio_read, +}; + +static struct regmap_mmio_context *regmap_mmio_gen_context(void __iomem *regs, + const struct regmap_config *config) +{ + struct regmap_mmio_context *ctx; + int min_stride; + int ret; + + ret = regmap_mmio_regbits_check(config->reg_bits); + if (ret) + return ERR_PTR(ret); + + if (config->pad_bits) + return ERR_PTR(-EINVAL); + + min_stride = regmap_mmio_get_min_stride(config->val_bits); + if (min_stride < 0) + return ERR_PTR(min_stride); + + if (config->reg_stride < min_stride) + return ERR_PTR(-EINVAL); + + ctx = xzalloc(sizeof(*ctx)); + + ctx->regs = regs; + ctx->val_bytes = config->val_bits / 8; + + switch (config->val_bits) { + case 8: + ctx->reg_read = regmap_mmio_read8; + ctx->reg_write = regmap_mmio_write8; + break; + case 16: + ctx->reg_read = regmap_mmio_read16le; + ctx->reg_write = regmap_mmio_write16le; + break; + case 32: + ctx->reg_read = regmap_mmio_read32le; + ctx->reg_write = regmap_mmio_write32le; + break; + default: + ret = -EINVAL; + goto err_free; + } + + return ctx; + +err_free: + kfree(ctx); + + return ERR_PTR(ret); +} + +struct regmap *regmap_init_mmio_clk(struct device_d *dev, + const char *clk_id, + void __iomem *regs, + const struct regmap_config *config) +{ + struct regmap_mmio_context *ctx; + + ctx = regmap_mmio_gen_context(regs, config); + if (IS_ERR(ctx)) + return ERR_CAST(ctx); + + if (clk_id) { + ctx->clk = clk_get(dev, clk_id); + if (IS_ERR(ctx->clk)) { + kfree(ctx); + return ERR_CAST(ctx->clk); + } + } + + return regmap_init(dev, ®map_mmio, ctx, config); +} + +struct regmap *of_regmap_init_mmio_clk(struct device_node *np, + const char *clk_id, + void __iomem *regs, + const struct regmap_config *config) +{ + struct regmap_mmio_context *ctx; + + ctx = regmap_mmio_gen_context(regs, config); + if (IS_ERR(ctx)) + return ERR_CAST(ctx); + + if (clk_id) { + ctx->clk = of_clk_get_by_name(np, clk_id); + if (IS_ERR(ctx->clk)) { + kfree(ctx); + return ERR_CAST(ctx->clk); + } + } + + return regmap_init(NULL, ®map_mmio, ctx, config); +} + +int regmap_mmio_attach_clk(struct regmap *map, struct clk *clk) +{ + struct regmap_mmio_context *ctx = map->bus_context; + + ctx->clk = clk; + + return 0; +} + +void regmap_mmio_detach_clk(struct regmap *map) +{ + struct regmap_mmio_context *ctx = map->bus_context; + + ctx->clk = NULL; +} diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ea3304bc7c..b27ad6d249 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -84,12 +84,14 @@ void clk_disable(struct clk *clk) if (!clk->enable_count) return; + if (clk->enable_count == 1 && clk->flags & CLK_IS_CRITICAL) { + pr_warn("Disabling critical clock %s\n", clk->name); + return; + } + clk->enable_count--; if (!clk->enable_count) { - if (clk->flags & CLK_IS_CRITICAL) - return; - if (clk->ops->disable) clk->ops->disable(clk); @@ -282,6 +284,9 @@ int clk_register(struct clk *clk) list_add_tail(&clk->list, &clks); + if (clk->flags & CLK_IS_CRITICAL) + clk_enable(clk); + return 0; } @@ -627,12 +632,40 @@ int of_clk_init(struct device_node *root, const struct of_device_id *matches) } #endif +static const char *clk_hw_stat(struct clk *clk) +{ + if (clk->ops->is_enabled) { + if (clk->ops->is_enabled(clk)) + return "enabled"; + else + return "disabled"; + } + + if (!clk->ops->enable) + return "always enabled"; + + return "unknown"; +} + static void dump_one(struct clk *clk, int verbose, int indent) { struct clk *c; + int enabled = clk_is_enabled(clk); + const char *hwstat, *stat; + + hwstat = clk_hw_stat(clk); + + if (enabled == 0) + stat = "disabled"; + else + stat = "enabled"; + + printf("%*s%s (rate %lu, enable_count: %d, %s)\n", indent * 4, "", + clk->name, + clk_get_rate(clk), + clk->enable_count, + hwstat); - printf("%*s%s (rate %lu, %sabled)\n", indent * 4, "", clk->name, clk_get_rate(clk), - clk_is_enabled(clk) ? "en" : "dis"); if (verbose) { if (clk->num_parents > 1) { diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index cfa77360b3..27674af54c 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -86,7 +86,7 @@ static int gpioinfo_request(struct gpio_info *gi, const char *label) done: if (ret) - pr_err("_gpio_request: gpio-%ld (%s) status %d\n", + pr_err("_gpio_request: gpio-%td (%s) status %d\n", gi - gpio_desc, label ? : "?", ret); return ret; diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c index 8099419378..f1e6559d71 100644 --- a/drivers/mfd/syscon.c +++ b/drivers/mfd/syscon.c @@ -19,6 +19,7 @@ #include <xfuncs.h> #include <of_address.h> #include <linux/err.h> +#include <linux/clk.h> #include <mfd/syscon.h> @@ -31,34 +32,13 @@ struct syscon { struct regmap *regmap; }; -static int syscon_reg_write(void *context, unsigned int reg, - unsigned int val) -{ - struct syscon *syscon = context; - writel(val, syscon->base + reg); - return 0; -} - -static int syscon_reg_read(void *context, unsigned int reg, - unsigned int *val) -{ - struct syscon *syscon = context; - *val = readl(syscon->base + reg); - return 0; -} - -static const struct regmap_bus syscon_regmap_bus = { - .reg_write = syscon_reg_write, - .reg_read = syscon_reg_read, -}; - static const struct regmap_config syscon_regmap_config = { .reg_bits = 32, .val_bits = 32, .reg_stride = 4, }; -static struct syscon *of_syscon_register(struct device_node *np) +static struct syscon *of_syscon_register(struct device_node *np, bool check_clk) { int ret; struct syscon *syscon; @@ -79,10 +59,23 @@ static struct syscon *of_syscon_register(struct device_node *np) list_add_tail(&syscon->list, &syscon_list); - syscon->regmap = regmap_init(NULL, - &syscon_regmap_bus, - syscon, - &syscon_regmap_config); + syscon->regmap = of_regmap_init_mmio_clk(np, NULL, syscon->base, + &syscon_regmap_config); + + if (check_clk) { + struct clk *clk = of_clk_get(np, 0); + if (IS_ERR(clk)) { + ret = PTR_ERR(clk); + /* clock is optional */ + if (ret != -ENOENT) + goto err_map; + } else { + ret = regmap_mmio_attach_clk(syscon->regmap, clk); + if (ret) + goto err_map; + } + } + return syscon; err_map: @@ -101,7 +94,7 @@ static struct syscon *node_to_syscon(struct device_node *np) } if (!syscon) - syscon = of_syscon_register(np); + syscon = of_syscon_register(np, true); if (IS_ERR(syscon)) return ERR_CAST(syscon); diff --git a/drivers/net/designware_stm32.c b/drivers/net/designware_stm32.c index 4c682a5dac..1e0cdfa695 100644 --- a/drivers/net/designware_stm32.c +++ b/drivers/net/designware_stm32.c @@ -57,12 +57,11 @@ static inline struct eqos_stm32 *to_stm32(struct eqos *eqos) return eqos->priv; } -enum { CLK_STMMACETH, CLK_MAX_RX, CLK_MAX_TX, CLK_SYSCFG, }; +enum { CLK_STMMACETH, CLK_MAX_RX, CLK_MAX_TX, }; static const struct clk_bulk_data stm32_clks[] = { [CLK_STMMACETH] = { .id = "stmmaceth" }, [CLK_MAX_RX] = { .id = "mac-clk-rx" }, [CLK_MAX_TX] = { .id = "mac-clk-tx" }, - [CLK_SYSCFG] = { .id = "syscfg-clk" }, }; static unsigned long eqos_get_csr_clk_rate_stm32(struct eqos *eqos) diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c index d4f411b4ad..2cd58df931 100644 --- a/drivers/pinctrl/pinctrl-single.c +++ b/drivers/pinctrl/pinctrl-single.c @@ -87,8 +87,8 @@ static int pcs_set_state(struct pinctrl_device *pdev, struct device_node *np) for (i = 0; i < rows; i++) { offset = be32_to_cpup(mux + index++); - mask = be32_to_cpup(mux + index++); val = be32_to_cpup(mux + index++); + mask = be32_to_cpup(mux + index++); reg = pcs->read(pcs->base + offset); reg &= ~mask; reg |= val; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 8874775f17..466bbe527b 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -406,6 +406,9 @@ static int usb_device_list_scan(void) if (ret) goto out; } + + /* Avoid hammering the HUB with port scans */ + mdelay(25); } out: diff --git a/drivers/usb/gadget/f_fastboot.c b/drivers/usb/gadget/f_fastboot.c index 0a3aff3cf0..426ee9db0b 100644 --- a/drivers/usb/gadget/f_fastboot.c +++ b/drivers/usb/gadget/f_fastboot.c @@ -957,6 +957,8 @@ static int fastboot_handle_sparse(struct f_fastboot *f_fb, if (ret) goto out; } else { + discard_range(fd, retlen, pos); + pos = lseek(fd, pos, SEEK_SET); if (pos == -1) { ret = -errno; diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 4c11e6580c..b84da5516c 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c @@ -1136,8 +1136,9 @@ fail2: musb_platform_exit(musb); fail1: - dev_err(musb->controller, - "musb_init_controller failed with status %d\n", status); + if (status != -EPROBE_DEFER) + dev_err(musb->controller, + "musb_init_controller failed with status %d\n", status); musb_free(musb); diff --git a/drivers/usb/musb/musb_dsps.c b/drivers/usb/musb/musb_dsps.c index 3b76b6cc61..d54a663e9d 100644 --- a/drivers/usb/musb/musb_dsps.c +++ b/drivers/usb/musb/musb_dsps.c @@ -39,7 +39,6 @@ #include <linux/barebox-wrapper.h> #include "musb_core.h" -#include "phy-am335x.h" static __maybe_unused struct of_device_id musb_dsps_dt_ids[]; @@ -217,10 +216,6 @@ static int dsps_musb_init(struct musb *musb) const struct dsps_musb_wrapper *wrp = glue->wrp; u32 rev, val, mode; - musb->xceiv = am335x_get_usb_phy(); - if (IS_ERR(musb->xceiv)) - return PTR_ERR(musb->xceiv); - /* Returns zero if e.g. not clocked */ rev = dsps_readl(musb->ctrl_base, wrp->revision); if (!rev) @@ -319,11 +314,13 @@ static int dsps_set_mode(void *ctx, enum usb_dr_mode mode) static int dsps_probe(struct device_d *dev) { - struct resource *iores; + struct resource *iores[2]; struct musb_hdrc_platform_data *pdata; struct musb_hdrc_config *config; struct device_node *dn = dev->device_node; const struct dsps_musb_wrapper *wrp; + struct device_node *phy_node; + struct device_d *phy_dev; struct dsps_glue *glue; int ret; @@ -337,6 +334,14 @@ static int dsps_probe(struct device_d *dev) return -ENODEV; } + phy_node = of_parse_phandle(dn, "phys", 0); + if (!phy_node) + return -ENODEV; + + phy_dev = of_find_device_by_node(phy_node); + if (!phy_dev || !phy_dev->priv) + return -EPROBE_DEFER; + /* allocate glue */ glue = kzalloc(sizeof(*glue), GFP_KERNEL); if (!glue) { @@ -349,17 +354,22 @@ static int dsps_probe(struct device_d *dev) pdata = &glue->pdata; - iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); - glue->musb.mregs = IOMEM(iores->start); + iores[0] = dev_request_mem_resource(dev, 0); + if (IS_ERR(iores[0])) { + ret = PTR_ERR(iores[0]); + goto free_glue; + } + glue->musb.mregs = IOMEM(iores[0]->start); - iores = dev_request_mem_resource(dev, 1); - if (IS_ERR(iores)) - return PTR_ERR(iores); - glue->musb.ctrl_base = IOMEM(iores->start); + iores[1] = dev_request_mem_resource(dev, 1); + if (IS_ERR(iores[1])) { + ret = PTR_ERR(iores[1]); + goto release_iores0; + } + glue->musb.ctrl_base = IOMEM(iores[1]->start); glue->musb.controller = dev; + glue->musb.xceiv = phy_dev->priv; config = &glue->config; @@ -377,11 +387,24 @@ static int dsps_probe(struct device_d *dev) if (pdata->mode == MUSB_PORT_MODE_DUAL_ROLE) { ret = usb_register_otg_device(dev, dsps_set_mode, glue); if (ret) - return ret; + goto release_iores1; return 0; } - return musb_init_controller(&glue->musb, pdata); + ret = musb_init_controller(&glue->musb, pdata); + if (ret) + goto release_iores1; + + return 0; + +release_iores1: + release_region(iores[1]); +release_iores0: + release_region(iores[0]); +free_glue: + free(glue); + + return ret; } static const struct dsps_musb_wrapper am33xx_driver_data = { diff --git a/drivers/usb/musb/phy-am335x-control.c b/drivers/usb/musb/phy-am335x-control.c index c84525ec7e..41a3689ed3 100644 --- a/drivers/usb/musb/phy-am335x-control.c +++ b/drivers/usb/musb/phy-am335x-control.c @@ -109,15 +109,15 @@ struct phy_control *am335x_get_phy_control(struct device_d *dev) node = of_parse_phandle(dev->device_node, "ti,ctrl_mod", 0); if (!node) - return NULL; + return ERR_PTR(-ENOENT); dev = of_find_device_by_node(node); if (!dev) - return NULL; + return ERR_PTR(-EPROBE_DEFER); ctrl_usb = dev->priv; if (!ctrl_usb) - return NULL; + return ERR_PTR(-EPROBE_DEFER); return &ctrl_usb->phy_ctrl; } @@ -141,13 +141,17 @@ static int am335x_control_usb_probe(struct device_d *dev) ctrl_usb->dev = dev; iores = dev_request_mem_resource(dev, 0); - if (IS_ERR(iores)) - return PTR_ERR(iores); + if (IS_ERR(iores)) { + ret = PTR_ERR(iores); + goto free_ctrl; + } ctrl_usb->phy_reg = IOMEM(iores->start); iores = dev_request_mem_resource(dev, 1); - if (IS_ERR(iores)) - return PTR_ERR(iores); + if (IS_ERR(iores)) { + ret = PTR_ERR(iores); + goto release_resource; + } ctrl_usb->wkup = IOMEM(iores->start); spin_lock_init(&ctrl_usb->lock); @@ -155,6 +159,13 @@ static int am335x_control_usb_probe(struct device_d *dev) dev->priv = ctrl_usb; return 0; + +release_resource: + release_region(iores); +free_ctrl: + free(ctrl_usb); + + return 0; }; static struct driver_d am335x_control_driver = { diff --git a/drivers/usb/musb/phy-am335x.c b/drivers/usb/musb/phy-am335x.c index df31255d89..f2e870d7ee 100644 --- a/drivers/usb/musb/phy-am335x.c +++ b/drivers/usb/musb/phy-am335x.c @@ -5,7 +5,6 @@ #include <linux/err.h> #include "am35x-phy-control.h" #include "musb_core.h" -#include "phy-am335x.h" struct am335x_usbphy { void __iomem *base; @@ -14,13 +13,6 @@ struct am335x_usbphy { struct usb_phy phy; }; -static struct am335x_usbphy *am_usbphy; - -struct usb_phy *am335x_get_usb_phy(void) -{ - return &am_usbphy->phy; -} - static int am335x_init(struct usb_phy *phy) { struct am335x_usbphy *am_usbphy = container_of(phy, struct am335x_usbphy, phy); @@ -31,6 +23,7 @@ static int am335x_init(struct usb_phy *phy) static int am335x_phy_probe(struct device_d *dev) { + struct am335x_usbphy *am_usbphy; struct resource *iores; int ret; @@ -44,22 +37,27 @@ static int am335x_phy_probe(struct device_d *dev) am_usbphy->base = IOMEM(iores->start); am_usbphy->phy_ctrl = am335x_get_phy_control(dev); - if (!am_usbphy->phy_ctrl) - return -ENODEV; + if (IS_ERR(am_usbphy->phy_ctrl)) { + ret = PTR_ERR(am_usbphy->phy_ctrl); + goto err_release; + } am_usbphy->id = of_alias_get_id(dev->device_node, "phy"); if (am_usbphy->id < 0) { dev_err(dev, "Missing PHY id: %d\n", am_usbphy->id); - return am_usbphy->id; + ret = am_usbphy->id; + goto err_release; } am_usbphy->phy.init = am335x_init; - dev->priv = am_usbphy; + dev->priv = &am_usbphy->phy; dev_info(dev, "am_usbphy %p enabled\n", &am_usbphy->phy); return 0; +err_release: + release_region(iores); err_free: free(am_usbphy); diff --git a/drivers/usb/musb/phy-am335x.h b/drivers/usb/musb/phy-am335x.h deleted file mode 100644 index 27da2e3b10..0000000000 --- a/drivers/usb/musb/phy-am335x.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _PHY_AM335x_H_ -#define _PHY_AM335x_H_ - -struct usb_phy *am335x_get_usb_phy(void); - -#endif |