* [PATCH 1/4] ARM: sa1100: convert to common clock framework
2016-08-30 10:51 ` [PATCH 0/4] SA11x0 Clocks and removal of Neponset SMC91x hack Russell King - ARM Linux
@ 2016-08-30 10:52 ` Russell King
2016-08-30 10:52 ` [PATCH 2/4] net: smc91x: add external clock support Russell King
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Russell King @ 2016-08-30 10:52 UTC (permalink / raw)
To: linux-arm-kernel, netdev; +Cc: Nicolas Pitre
Convert sa1100 to use the common clock framework.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
arch/arm/Kconfig | 1 +
arch/arm/mach-sa1100/clock.c | 191 +++++++++++++++++++------------------------
2 files changed, 87 insertions(+), 105 deletions(-)
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index a91c47f30986..e6706601dbe9 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -588,6 +588,7 @@ config ARCH_SA1100
select CLKSRC_MMIO
select CLKSRC_PXA
select CLKSRC_OF if OF
+ select COMMON_CLK
select CPU_FREQ
select CPU_SA1100
select GENERIC_CLOCKEVENTS
diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c
index f6f75c9325bf..ebb39eba3717 100644
--- a/arch/arm/mach-sa1100/clock.c
+++ b/arch/arm/mach-sa1100/clock.c
@@ -1,151 +1,132 @@
/*
* linux/arch/arm/mach-sa1100/clock.c
*/
-#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/device.h>
-#include <linux/list.h>
#include <linux/errno.h>
#include <linux/err.h>
-#include <linux/string.h>
#include <linux/clk.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/io.h>
#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
#include <mach/hardware.h>
#include <mach/generic.h>
-struct clkops {
- void (*enable)(struct clk *);
- void (*disable)(struct clk *);
- unsigned long (*get_rate)(struct clk *);
-};
-
-struct clk {
- const struct clkops *ops;
- unsigned int enabled;
+static const char *clk_tucr_parents[] = {
+ "clk32768", "clk3686400",
};
-#define DEFINE_CLK(_name, _ops) \
-struct clk clk_##_name = { \
- .ops = _ops, \
- }
-
-static DEFINE_SPINLOCK(clocks_lock);
+static DEFINE_SPINLOCK(tucr_lock);
-static void clk_gpio27_enable(struct clk *clk)
+static int clk_gpio27_enable(struct clk_hw *hw)
{
+ unsigned long flags;
+
/*
* First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
* (SA-1110 Developer's Manual, section 9.1.2.1)
*/
+ local_irq_save(flags);
GAFR |= GPIO_32_768kHz;
GPDR |= GPIO_32_768kHz;
- TUCR = TUCR_3_6864MHz;
-}
-
-static void clk_gpio27_disable(struct clk *clk)
-{
- TUCR = 0;
- GPDR &= ~GPIO_32_768kHz;
- GAFR &= ~GPIO_32_768kHz;
-}
-
-static void clk_cpu_enable(struct clk *clk)
-{
-}
-
-static void clk_cpu_disable(struct clk *clk)
-{
-}
-
-static unsigned long clk_cpu_get_rate(struct clk *clk)
-{
- return sa11x0_getspeed(0) * 1000;
-}
-
-int clk_enable(struct clk *clk)
-{
- unsigned long flags;
-
- if (clk) {
- spin_lock_irqsave(&clocks_lock, flags);
- if (clk->enabled++ == 0)
- clk->ops->enable(clk);
- spin_unlock_irqrestore(&clocks_lock, flags);
- }
+ local_irq_restore(flags);
return 0;
}
-EXPORT_SYMBOL(clk_enable);
-void clk_disable(struct clk *clk)
+static void clk_gpio27_disable(struct clk_hw *hw)
{
unsigned long flags;
- if (clk) {
- WARN_ON(clk->enabled == 0);
- spin_lock_irqsave(&clocks_lock, flags);
- if (--clk->enabled == 0)
- clk->ops->disable(clk);
- spin_unlock_irqrestore(&clocks_lock, flags);
- }
-}
-EXPORT_SYMBOL(clk_disable);
-
-unsigned long clk_get_rate(struct clk *clk)
-{
- if (clk && clk->ops && clk->ops->get_rate)
- return clk->ops->get_rate(clk);
-
- return 0;
+ local_irq_save(flags);
+ GPDR &= ~GPIO_32_768kHz;
+ GAFR &= ~GPIO_32_768kHz;
+ local_irq_restore(flags);
}
-EXPORT_SYMBOL(clk_get_rate);
-const struct clkops clk_gpio27_ops = {
- .enable = clk_gpio27_enable,
- .disable = clk_gpio27_disable,
+static const struct clk_ops clk_gpio27_ops = {
+ .enable = clk_gpio27_enable,
+ .disable = clk_gpio27_disable,
};
-const struct clkops clk_cpu_ops = {
- .enable = clk_cpu_enable,
- .disable = clk_cpu_disable,
- .get_rate = clk_cpu_get_rate,
+static const char *clk_gpio27_parents[] = {
+ "tucr-mux",
};
-static DEFINE_CLK(gpio27, &clk_gpio27_ops);
-
-static DEFINE_CLK(cpu, &clk_cpu_ops);
-
-static unsigned long clk_36864_get_rate(struct clk *clk)
+static unsigned long clk_mpll_recalc_rate(struct clk_hw *hw, unsigned long prate)
{
- return 3686400;
+ return sa11x0_getspeed(0) * 1000;
}
-static struct clkops clk_36864_ops = {
- .enable = clk_cpu_enable,
- .disable = clk_cpu_disable,
- .get_rate = clk_36864_get_rate,
+static const struct clk_ops cpu_clock_ops = {
+ .recalc_rate = clk_mpll_recalc_rate,
};
-static DEFINE_CLK(36864, &clk_36864_ops);
-
-static struct clk_lookup sa11xx_clkregs[] = {
- CLKDEV_INIT("sa1111.0", NULL, &clk_gpio27),
- CLKDEV_INIT("sa1100-rtc", NULL, NULL),
- CLKDEV_INIT("sa11x0-fb", NULL, &clk_cpu),
- CLKDEV_INIT("sa11x0-pcmcia", NULL, &clk_cpu),
- CLKDEV_INIT("sa11x0-pcmcia.0", NULL, &clk_cpu),
- CLKDEV_INIT("sa11x0-pcmcia.1", NULL, &clk_cpu),
- /* sa1111 names devices using internal offsets, PCMCIA is at 0x1800 */
- CLKDEV_INIT("1800", NULL, &clk_cpu),
- CLKDEV_INIT(NULL, "OSTIMER0", &clk_36864),
+static const char *clk_mpll_parents[] = {
+ "clk3686400",
};
int __init sa11xx_clk_init(void)
{
- clkdev_add_table(sa11xx_clkregs, ARRAY_SIZE(sa11xx_clkregs));
+ struct clk_init_data init;
+ struct clk_hw *hw;
+ int ret;
+
+ hw = clk_hw_register_fixed_rate(NULL, "clk32768", NULL, 0, 32768);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ clk_hw_register_clkdev(hw, NULL, "sa1100-rtc");
+
+ hw = clk_hw_register_fixed_rate(NULL, "clk3686400", NULL, 0, 3686400);
+ if (IS_ERR(hw))
+ return PTR_ERR(hw);
+
+ clk_hw_register_clkdev(hw, "OSTIMER0", NULL);
+
+ init.name = "mpll";
+ init.ops = &cpu_clock_ops;
+ init.flags = CLK_IS_BASIC;
+ init.parent_names = clk_mpll_parents;
+ init.num_parents = ARRAY_SIZE(clk_mpll_parents);
+ hw = kzalloc(sizeof(*hw), GFP_KERNEL);
+ if (!hw)
+ return -ENOMEM;
+ hw->init = &init;
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
+ kfree(hw);
+ return ret;
+ }
+
+ clk_hw_register_clkdev(hw, NULL, "sa11x0-fb");
+ clk_hw_register_clkdev(hw, NULL, "sa11x0-pcmcia");
+ clk_hw_register_clkdev(hw, NULL, "sa11x0-pcmcia.0");
+ clk_hw_register_clkdev(hw, NULL, "sa11x0-pcmcia.1");
+ clk_hw_register_clkdev(hw, NULL, "1800");
+
+ hw = clk_hw_register_mux(NULL, "tucr-mux", clk_tucr_parents,
+ ARRAY_SIZE(clk_tucr_parents), 0,
+ (void __iomem *)&TUCR, FShft(TUCR_TSEL),
+ FAlnMsk(TUCR_TSEL), 0, &tucr_lock);
+ clk_set_rate(hw->clk, 3686400);
+
+ init.name = "gpio27";
+ init.ops = &clk_gpio27_ops;
+ init.parent_names = clk_gpio27_parents;
+ init.num_parents = ARRAY_SIZE(clk_gpio27_parents);
+ hw = kzalloc(sizeof(*hw), GFP_KERNEL);
+ if (!hw)
+ return -ENOMEM;
+ hw->init = &init;
+ ret = clk_hw_register(NULL, hw);
+ if (ret) {
+ kfree(hw);
+ return ret;
+ }
+
+ clk_hw_register_clkdev(hw, NULL, "sa1111.0");
+
return 0;
}
--
2.1.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 2/4] net: smc91x: add external clock support
2016-08-30 10:51 ` [PATCH 0/4] SA11x0 Clocks and removal of Neponset SMC91x hack Russell King - ARM Linux
2016-08-30 10:52 ` [PATCH 1/4] ARM: sa1100: convert to common clock framework Russell King
@ 2016-08-30 10:52 ` Russell King
2016-08-30 10:52 ` [PATCH 3/4] ARM: sa1100/neponset: add ethernet oscillator Russell King
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Russell King @ 2016-08-30 10:52 UTC (permalink / raw)
To: linux-arm-kernel, netdev; +Cc: Nicolas Pitre
The smc91x can be operated with either a directly attached crystal, or
an externally supplied clock. When used with an externally supplied
clock, this clock may require some configuration or control. Add calls
to the driver to lookup, enable and disable this optional clock.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
drivers/net/ethernet/smsc/smc91x.c | 38 ++++++++++++++++++++++++++++++++++++--
drivers/net/ethernet/smsc/smc91x.h | 1 +
2 files changed, 37 insertions(+), 2 deletions(-)
diff --git a/drivers/net/ethernet/smsc/smc91x.c b/drivers/net/ethernet/smsc/smc91x.c
index 503a3b6dce91..43dbc1c7b9a5 100644
--- a/drivers/net/ethernet/smsc/smc91x.c
+++ b/drivers/net/ethernet/smsc/smc91x.c
@@ -73,6 +73,7 @@ static const char version[] =
#include <linux/irq.h>
#include <linux/errno.h>
#include <linux/ioport.h>
+#include <linux/clk.h>
#include <linux/crc32.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
@@ -2284,6 +2285,18 @@ static int smc_drv_probe(struct platform_device *pdev)
}
}
+ /*
+ * Some platforms drive the xtal input from an external clock
+ * source which may require some control. Request the clock,
+ * but allow probing to continue if no clock is specified.
+ */
+ lp->xtal = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(lp->xtal)) {
+ if (PTR_ERR(lp->xtal) != -ENOENT)
+ return PTR_ERR(lp->xtal);
+ lp->xtal = NULL;
+ }
+
#if IS_BUILTIN(CONFIG_OF)
match = of_match_device(of_match_ptr(smc91x_match), &pdev->dev);
if (match) {
@@ -2375,15 +2388,20 @@ static int smc_drv_probe(struct platform_device *pdev)
if (machine_is_assabet() && machine_has_neponset())
neponset_ncr_set(NCR_ENET_OSC_EN);
#endif
+ if (lp->xtal) {
+ ret = clk_prepare_enable(lp->xtal);
+ if (ret)
+ goto out_release_attrib;
+ }
platform_set_drvdata(pdev, ndev);
ret = smc_enable_device(pdev);
if (ret)
- goto out_release_attrib;
+ goto out_disable_xtal;
addr = ioremap(res->start, SMC_IO_EXTENT);
if (!addr) {
ret = -ENOMEM;
- goto out_release_attrib;
+ goto out_disable_xtal;
}
#ifdef CONFIG_ARCH_PXA
@@ -2407,6 +2425,9 @@ static int smc_drv_probe(struct platform_device *pdev)
iounmap(addr);
out_release_attrib:
smc_release_attrib(pdev, ndev);
+ out_disable_xtal:
+ if (lp->xtal)
+ clk_disable_unprepare(lp->xtal);
out_release_io:
release_mem_region(res->start, SMC_IO_EXTENT);
out_free_netdev:
@@ -2441,6 +2462,9 @@ static int smc_drv_remove(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, SMC_IO_EXTENT);
+ if (lp->xtal)
+ clk_disable_unprepare(lp->xtal);
+
free_netdev(ndev);
return 0;
@@ -2453,9 +2477,14 @@ static int smc_drv_suspend(struct device *dev)
if (ndev) {
if (netif_running(ndev)) {
+ struct smc_local *lp = netdev_priv(ndev);
+
netif_device_detach(ndev);
smc_shutdown(ndev);
smc_phy_powerdown(ndev);
+
+ if (lp->xtal)
+ clk_disable_unprepare(lp->xtal);
}
}
return 0;
@@ -2468,6 +2497,11 @@ static int smc_drv_resume(struct device *dev)
if (ndev) {
struct smc_local *lp = netdev_priv(ndev);
+ if (lp->xtal) {
+ int ret = clk_prepare_enable(lp->xtal);
+ if (ret)
+ return ret;
+ }
smc_enable_device(pdev);
if (netif_running(ndev)) {
smc_reset(ndev);
diff --git a/drivers/net/ethernet/smsc/smc91x.h b/drivers/net/ethernet/smsc/smc91x.h
index e17671c9d1b0..5377c2e1b8b9 100644
--- a/drivers/net/ethernet/smsc/smc91x.h
+++ b/drivers/net/ethernet/smsc/smc91x.h
@@ -266,6 +266,7 @@ struct smc_local {
struct gpio_desc *power_gpio;
struct gpio_desc *reset_gpio;
+ struct clk *xtal;
/* version/revision of the SMC91x chip */
int version;
--
2.1.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH 3/4] ARM: sa1100/neponset: add ethernet oscillator
2016-08-30 10:51 ` [PATCH 0/4] SA11x0 Clocks and removal of Neponset SMC91x hack Russell King - ARM Linux
2016-08-30 10:52 ` [PATCH 1/4] ARM: sa1100: convert to common clock framework Russell King
2016-08-30 10:52 ` [PATCH 2/4] net: smc91x: add external clock support Russell King
@ 2016-08-30 10:52 ` Russell King
2016-08-30 10:52 ` [PATCH 4/4] net: smc91x: remove neponset specific oscillator hack Russell King
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: Russell King @ 2016-08-30 10:52 UTC (permalink / raw)
To: linux-arm-kernel, netdev; +Cc: Nicolas Pitre
Add the clock structure for the external SMC91x ethernet oscillator.
This oscillator has an enable signal which allows the oscillator to be
placed in low power mode when not required.
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---
arch/arm/mach-sa1100/neponset.c | 42 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 42 insertions(+)
diff --git a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c
index bff6efdfaeaf..700659cadebb 100644
--- a/arch/arm/mach-sa1100/neponset.c
+++ b/arch/arm/mach-sa1100/neponset.c
@@ -1,6 +1,8 @@
/*
* linux/arch/arm/mach-sa1100/neponset.c
*/
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
#include <linux/err.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/machine.h>
@@ -78,6 +80,9 @@ struct neponset_drvdata {
struct platform_device *smc91x;
unsigned irq_base;
struct gpio_chip *gpio[4];
+ struct clk_hw *enet_osc_ck;
+ struct clk_hw *enet_osc_gate;
+ struct clk_lookup *enet_osc_cl;
};
static struct gpiod_lookup_table neponset_uart1_gpio_table = {
@@ -217,6 +222,38 @@ static int neponset_init_gpio(struct gpio_chip **gcp,
return 0;
}
+static int neponset_init_enet(struct device *dev, struct neponset_drvdata *d)
+{
+ int ret;
+
+ d->enet_osc_ck = clk_hw_register_fixed_rate(dev, "nep_enet_osc",
+ NULL, 0, 20000000);
+ if (IS_ERR(d->enet_osc_ck))
+ return PTR_ERR(d->enet_osc_ck);
+
+ d->enet_osc_gate = clk_hw_register_gpio_gate(dev, "nep_enet_gate",
+ "nep_enet_osc",
+ d->gpio[0]->base + 3,
+ false, 0);
+ if (IS_ERR(d->enet_osc_gate)) {
+ ret = PTR_ERR(d->enet_osc_gate);
+ goto err;
+ }
+
+ d->enet_osc_cl = clkdev_hw_create(d->enet_osc_gate, NULL, "smc91x.0");
+ if (!d->enet_osc_cl) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ return 0;
+
+err:
+ if (d->enet_osc_ck)
+ clk_hw_unregister_fixed_rate(d->enet_osc_ck);
+ return ret;
+}
+
static struct sa1111_platform_data sa1111_info = {
.disable_devs = SA1111_DEVID_PS2_MSE,
};
@@ -333,6 +370,8 @@ static int neponset_probe(struct platform_device *dev)
gpiod_add_lookup_table(&neponset_uart3_gpio_table);
gpiod_add_lookup_table(&neponset_pcmcia_table);
+ neponset_init_enet(&dev->dev, d);
+
/*
* We would set IRQ_GPIO25 to be a wake-up IRQ, but unfortunately
* something on the Neponset activates this IRQ on sleep (eth?)
@@ -385,6 +424,9 @@ static int neponset_remove(struct platform_device *dev)
if (!IS_ERR(d->smc91x))
platform_device_unregister(d->smc91x);
+ clkdev_drop(d->enet_osc_cl);
+ clk_hw_unregister_fixed_rate(d->enet_osc_ck);
+
gpiod_remove_lookup_table(&neponset_pcmcia_table);
gpiod_remove_lookup_table(&neponset_uart3_gpio_table);
gpiod_remove_lookup_table(&neponset_uart1_gpio_table);
--
2.1.0
^ permalink raw reply related [flat|nested] 8+ messages in thread