On Mon, Jul 16, 2018 at 04:58:32PM +0530, Jagan Teki wrote: > Add initial clock driver Allwinner for H3_H5. > > Implemented clock enable and disable functions for > USB OHCI, EHCI, OTG and PHY gate and clock registers. > > Signed-off-by: Jagan Teki <ja...@amarulasolutions.com> > --- > drivers/clk/sunxi/Kconfig | 7 ++ > drivers/clk/sunxi/Makefile | 2 + > drivers/clk/sunxi/clk_h3.c | 131 +++++++++++++++++++++++++++++++++++++ > 3 files changed, 140 insertions(+) > create mode 100644 drivers/clk/sunxi/clk_h3.c > > diff --git a/drivers/clk/sunxi/Kconfig b/drivers/clk/sunxi/Kconfig > index 3a86c91e75..065cadf2fe 100644 > --- a/drivers/clk/sunxi/Kconfig > +++ b/drivers/clk/sunxi/Kconfig > @@ -8,6 +8,13 @@ config CLK_SUNXI > > if CLK_SUNXI > > +config CLK_SUN8I_H3 > + bool "Clock driver for Allwinner H3/H5" > + default MACH_SUNXI_H3_H5 > + help > + This enables common clock driver support for platforms based > + on Allwinner H3/H5 SoC. > + > config CLK_SUN50I_A64 > bool "Clock driver for Allwinner A64" > default MACH_SUN50I > diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile > index 860bb6dfea..37e6bcb147 100644 > --- a/drivers/clk/sunxi/Makefile > +++ b/drivers/clk/sunxi/Makefile > @@ -5,4 +5,6 @@ > # > > obj-$(CONFIG_CLK_SUNXI) += clk_sunxi.o > + > +obj-$(CONFIG_CLK_SUN8I_H3) += clk_h3.o > obj-$(CONFIG_CLK_SUN50I_A64) += clk_a64.o > diff --git a/drivers/clk/sunxi/clk_h3.c b/drivers/clk/sunxi/clk_h3.c > new file mode 100644 > index 0000000000..e924017717 > --- /dev/null > +++ b/drivers/clk/sunxi/clk_h3.c > @@ -0,0 +1,131 @@ > +// SPDX-License-Identifier: (GPL-2.0+ OR MIT) > +/* > + * Copyright (C) 2018 Amarula Solutions B.V. > + * Author: Jagan Teki <ja...@amarulasolutions.com> > + */ > + > +#include <common.h> > +#include <clk-uclass.h> > +#include <dm.h> > +#include <errno.h> > +#include <asm/io.h> > +#include <asm/arch/clock.h> > +#include <dt-bindings/clock/sun8i-h3-ccu.h> > + > +struct h3_clk_priv { > + void *base; > +}; > + > +static int h3_clk_enable(struct clk *clk) > +{ > + struct h3_clk_priv *priv = dev_get_priv(clk->dev); > + > + debug("%s(#%ld)\n", __func__, clk->id); > + > + switch (clk->id) { > + case CLK_BUS_OTG: > + case CLK_BUS_EHCI0: > + case CLK_BUS_EHCI1: > + case CLK_BUS_EHCI2: > + case CLK_BUS_EHCI3: > + case CLK_BUS_OHCI0: > + case CLK_BUS_OHCI1: > + case CLK_BUS_OHCI2: > + case CLK_BUS_OHCI3: > + setbits_le32(priv->base + 0x60, > + BIT(23 + (clk->id - CLK_BUS_OTG))); > + return 0; > + case CLK_USB_PHY0: > + case CLK_USB_PHY1: > + case CLK_USB_PHY2: > + case CLK_USB_PHY3: > + setbits_le32(priv->base + 0xcc, > + BIT(8 + (clk->id - CLK_USB_PHY0))); > + return 0; > + case CLK_USB_OHCI0: > + case CLK_USB_OHCI1: > + case CLK_USB_OHCI2: > + case CLK_USB_OHCI3: > + setbits_le32(priv->base + 0xcc, > + BIT(16 + (clk->id - CLK_USB_OHCI0))); > + return 0; > + default: > + debug("%s (CLK#%ld) unhandled\n", __func__, clk->id); > + return -ENODEV; > + } > +} > + > +static int h3_clk_disable(struct clk *clk) > +{ > + struct h3_clk_priv *priv = dev_get_priv(clk->dev); > + > + debug("%s(#%ld)\n", __func__, clk->id); > + > + switch (clk->id) { > + case CLK_BUS_OTG: > + case CLK_BUS_EHCI0: > + case CLK_BUS_EHCI1: > + case CLK_BUS_EHCI2: > + case CLK_BUS_EHCI3: > + case CLK_BUS_OHCI0: > + case CLK_BUS_OHCI1: > + case CLK_BUS_OHCI2: > + case CLK_BUS_OHCI3: > + clrbits_le32(priv->base + 0x60, > + BIT(23 + (clk->id - CLK_BUS_OTG))); > + return 0; > + case CLK_USB_PHY0: > + case CLK_USB_PHY1: > + case CLK_USB_PHY2: > + case CLK_USB_PHY3: > + clrbits_le32(priv->base + 0xcc, > + BIT(8 + (clk->id - CLK_USB_PHY0))); > + return 0; > + case CLK_USB_OHCI0: > + case CLK_USB_OHCI1: > + case CLK_USB_OHCI2: > + case CLK_USB_OHCI3: > + clrbits_le32(priv->base + 0xcc, > + BIT(16 + (clk->id - CLK_USB_OHCI0))); > + return 0; > + default: > + debug("%s (CLK#%ld) unhandled\n", __func__, clk->id); > + return -ENODEV; > + } > +} > + > +static struct clk_ops h3_clk_ops = { > + .enable = h3_clk_enable, > + .disable = h3_clk_disable, > +}; > + > +static int h3_clk_probe(struct udevice *dev) > +{ > + return 0; > +} > + > +static int h3_clk_ofdata_to_platdata(struct udevice *dev) > +{ > + struct h3_clk_priv *priv = dev_get_priv(dev); > + > + priv->base = dev_read_addr_ptr(dev); > + > + return 0; > +} > + > +static const struct udevice_id h3_clk_ids[] = { > + { .compatible = "allwinner,sun8i-h3-ccu" }, > + { .compatible = "allwinner,sun50i-h5-ccu" }, > + { } > +}; > + > +U_BOOT_DRIVER(clk_sun8i_h3) = { > + .name = "sun8i_h3_ccu", > + .id = UCLASS_CLK, > + .of_match = h3_clk_ids, > + .priv_auto_alloc_size = sizeof(struct h3_clk_priv), > + .ofdata_to_platdata = h3_clk_ofdata_to_platdata, > + .ops = &h3_clk_ops, > + .probe = h3_clk_probe, > + .bind = sunxi_clk_bind, > +};
Speaking from experience, you do not want to have separate implementations for each and every SoCs. This might be enough for enabling / disabling the clocks, but as soon as you'll throw the set_rate / get_rate callbacks into the mix it's going to turn into a nightmare. Maxime -- Maxime Ripard, Bootlin (formerly Free Electrons) Embedded Linux and Kernel engineering https://bootlin.com
signature.asc
Description: PGP signature
_______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot