Messages in this thread | | | Date | Thu, 26 Mar 2015 10:41:36 +0100 | From | Daniel Lezcano <> | Subject | Re: [PATCH 10/11] clocksource: flexcard: Add basic timestamp counter support |
| |
Hi Holger,
[Cc'ed John Stultz]
On 03/25/2015 10:51 AM, Holger Dengler wrote: > From: Benedikt Spranger <b.spranger@linutronix.de> > > The Eberspaecher Flexcard PMC II offers a Flexray network synchronized > counter with a selectable resolution of 1us, 100ns or 10ns. Add basic > support for the timestamp counter with 1us resolution, which is the > standard Flexray bus resolution. > > Signed-off-by: Holger Dengler <dengler@linutronix.de> > Signed-off-by: Benedikt Spranger <b.spranger@linutronix.de> > cc: Daniel Lezcano <daniel.lezcano@linaro.org> > cc: Thomas Gleixner <tglx@linutronix.de> > --- > drivers/clocksource/Kconfig | 11 ++ > drivers/clocksource/Makefile | 1 + > drivers/clocksource/flexcard-time.c | 235 ++++++++++++++++++++++++++++++++++++ > include/linux/mfd/flexcard.h | 6 + > 4 files changed, 253 insertions(+) > create mode 100644 drivers/clocksource/flexcard-time.c > > diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig > index 68161f7..a6b9308 100644 > --- a/drivers/clocksource/Kconfig > +++ b/drivers/clocksource/Kconfig > @@ -250,4 +250,15 @@ config CLKSRC_PXA > help > This enables OST0 support available on PXA and SA-11x0 > platforms. > + > +config CLKSRC_FLEXCARD > + tristate "Support for Flexcard clock function"
Why do you need this to be a module ?
The Kconfig policy is to have it selected by the arch Kconfig.
It should be like:
config CLKSRC_FLEXCARD bool select CLKSRC_MMIO
and then the Kconfig for MFD_FLEXCARD selects CLKSRC_FLEXCARD.
> + depends on MFD_FLEXCARD > + select CLKSRC_MMIO > + help > + This is the clocksource function driver for the > + Eberspaecher Flexcard PMC II carrier board. The > + Flexcard provide a Flexray synchronized counter > + configurable at 1, 10 or 100MHz. > + > endmenu > diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile > index 752d5c7..8bbc657 100644 > --- a/drivers/clocksource/Makefile > +++ b/drivers/clocksource/Makefile > @@ -51,3 +51,4 @@ obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o > obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o > obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o > obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o > +obj-$(CONFIG_CLKSRC_FLEXCARD) += flexcard-time.o > diff --git a/drivers/clocksource/flexcard-time.c b/drivers/clocksource/flexcard-time.c > new file mode 100644 > index 0000000..f2efb53 > --- /dev/null > +++ b/drivers/clocksource/flexcard-time.c > @@ -0,0 +1,235 @@ > +/* > + * Eberspaecher Flexcard PMC II - clocksource driver > + * > + * Copyright (c) 2014,2015 Linutronix GmbH > + * Author: Holger Dengler > + * Benedikt Spranger > + * > + * This program is free software; you can redistribute it and/or modify it > + * under the terms of the GNU General Public License version 2 as published > + * by the Free Software Foundation. > + */ > +#include <linux/kernel.h> > +#include <linux/module.h> > +#include <linux/init.h> > +#include <linux/fs.h> > +#include <linux/miscdevice.h> > +#include <linux/platform_device.h> > +#include <linux/posix-clock.h> > +#include <linux/mfd/core.h> > +#include <linux/mfd/flexcard.h> > + > +#define MAX_CLOCKS 16 > +#define CLKSEL_OFF 0x10 > + > +static dev_t flexcard_clk_devt; > +static struct class *flexcard_clk_class; > + > +struct flexcard_clk { > + struct posix_clock clock; > + dev_t devid; > + struct device *dev; > + void __iomem *ts64; > + void __iomem *reset; > +}; > + > +static int flexcard_clk_getres(struct posix_clock *pc, struct timespec *tp) > +{ > + tp->tv_sec = 0; > + tp->tv_nsec = 1000; > + > + return 0; > +} > + > +static int flexcard_clk_gettime(struct posix_clock *pc, struct timespec *tp) > +{ > + struct flexcard_clk *clk = container_of(pc, struct flexcard_clk, clock); > + u64 now; > + u32 upper, rem; > + > +retry: > + upper = readl(clk->ts64); > + now = ((u64) upper << 32) | readl(clk->ts64 + 4); > + if (upper != readl(clk->ts64)) > + goto retry; > + > + tp->tv_sec = div_u64_rem(now, clk->desc.freq, &rem); > + tp->tv_nsec = rem * 1000; > + > + return 0; > +} > + > +static int flexcard_clk_settime(struct posix_clock *pc, > + const struct timespec *tp) > +{ > + struct flexcard_clk *clk = container_of(pc, struct flexcard_clk, clock); > + > + /* The FlexCard clock could only be reset to 0 and not set */ > + if (tp->tv_sec || tp->tv_nsec) > + return -EINVAL; > + > + writel(FLEXCARD_RST_TS, clk->reset); > + > + return 0; > +} > + > +static struct posix_clock_operations flexcard_clk_ops = { > + .owner = THIS_MODULE, > + .clock_getres = flexcard_clk_getres, > + .clock_gettime = flexcard_clk_gettime, > + .clock_settime = flexcard_clk_settime, > +}; > + > +static int flexcard_clksrc_iomap(struct platform_device *pdev) > +{ > + struct flexcard_clk *clk = platform_get_drvdata(pdev); > + struct resource *res; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!res) > + return -ENXIO; > + > + clk->ts64 = devm_ioremap(&pdev->dev, res->start, resource_size(res)); > + if (!clk->ts64) > + return -ENOMEM; > + > + res = platform_get_resource(pdev, IORESOURCE_MEM, 1); > + if (!res) > + return -ENXIO; > + > + clk->reset = devm_ioremap(&pdev->dev, res->start, resource_size(res)); > + if (!clk->reset) > + return -ENOMEM; > + > + return 0; > +} > + > +static int flexcard_clksrc_probe(struct platform_device *pdev) > +{ > + const struct mfd_cell *cell; > + struct flexcard_clk *clk; > + int major, ret; > + > + cell = mfd_get_cell(pdev); > + if (!cell) > + return -ENODEV; > + > + if (cell->id >= MAX_CLOCKS) { > + dev_err(&pdev->dev, "all flexcard posix clocks in use\n"); > + return -EBUSY; > + } > + > + clk = devm_kzalloc(&pdev->dev, sizeof(*clk), GFP_KERNEL); > + if (!clk) > + return -ENOMEM; > + > + major = MAJOR(flexcard_clk_devt); > + platform_set_drvdata(pdev, clk); > + > + ret = flexcard_clksrc_iomap(pdev); > + if (ret) { > + dev_err(&pdev->dev, "failed to map resources: %d\n", ret); > + goto out; > + } > + > + clk->devid = MKDEV(major, cell->id); > + clk->clock.ops = flexcard_clk_ops; > + > + writel(FLEXCARD_CLK_1MHZ, clk->ts64 + CLKSEL_OFF); > + writel(FLEXCARD_RST_TS, clk->reset); > + > + clk->dev = device_create(flexcard_clk_class, &pdev->dev, clk->devid, > + clk, "flexcard_clk%d", cell->id); > + if (IS_ERR(clk->dev)) { > + ret = PTR_ERR(clk->dev); > + goto out; > + } > + > + ret = posix_clock_register(&clk->clock, clk->devid); > + if (ret) { > + dev_err(&pdev->dev, > + "failed to register flexcard posix clock: %d\n", ret); > + goto out_destroy; > + } > + > + dev_info(&pdev->dev, "flexcard posix clock %d registered", cell->id); > + > + return 0; > + > +out_destroy: > + device_destroy(flexcard_clk_class, clk->devid); > +out: > + return ret; > +} > + > +static int flexcard_clksrc_remove(struct platform_device *pdev) > +{ > + struct flexcard_clk *clk = platform_get_drvdata(pdev); > + > + posix_clock_unregister(&clk->clock); > + device_destroy(flexcard_clk_class, clk->devid); > + platform_set_drvdata(pdev, NULL); > + > + return 0; > +} > + > +static const struct platform_device_id flexcard_clksrc_id_table[] = { > + { "flexcard-clksrc", 0 }, > + {}, > +}; > +MODULE_DEVICE_TABLE(platform, flexcard_clksrc_id_table); > + > +static struct platform_driver flexcard_clksrc_driver = { > + .probe = flexcard_clksrc_probe, > + .remove = flexcard_clksrc_remove, > + .driver = { > + .name = "flexcard-clksrc", > + }, > + .id_table = flexcard_clksrc_id_table, > +}; > + > +static int __init flexcard_clksrc_init(void) > +{ > + int ret; > + > + flexcard_clk_class = class_create(THIS_MODULE, "flexcard_clk"); > + if (IS_ERR(flexcard_clk_class)) { > + pr_err("flexcard_clk: failed to allocate class\n"); > + return PTR_ERR(flexcard_clk_class); > + } > + > + ret = alloc_chrdev_region(&flexcard_clk_devt, 0, MAX_CLOCKS, > + "flexcard_clk"); > + if (ret < 0) { > + pr_err("failed to allocate device region\n"); > + goto out; > + } > + > + ret = platform_driver_register(&flexcard_clksrc_driver); > + if (ret < 0) > + goto out_unregister; > + > + return 0; > + > +out_unregister: > + unregister_chrdev_region(flexcard_clk_devt, MAX_CLOCKS); > +out: > + class_destroy(flexcard_clk_class); > + > + return ret; > +} > + > +static void __exit flexcard_clksrc_exit(void) > +{ > + platform_driver_unregister(&flexcard_clksrc_driver); > + unregister_chrdev_region(flexcard_clk_devt, MAX_CLOCKS); > + class_destroy(flexcard_clk_class); > +} > + > +MODULE_AUTHOR("Holger Dengler <dengler@linutronix.de>"); > +MODULE_AUTHOR("Benedikt Spranger <b.spranger@linutronix.de>"); > +MODULE_DESCRIPTION("Eberspaecher Flexcard PMC II clocksource driver"); > +MODULE_LICENSE("GPL v2"); > + > +module_init(flexcard_clksrc_init); > +module_exit(flexcard_clksrc_exit); > diff --git a/include/linux/mfd/flexcard.h b/include/linux/mfd/flexcard.h > index 964d78c..d7ecf3d 100644 > --- a/include/linux/mfd/flexcard.h > +++ b/include/linux/mfd/flexcard.h > @@ -19,8 +19,14 @@ > #define FLEXCARD_FR_OFFSET 0x4000 > #define FLEXCARD_FR_SIZE 0x2000 > > +#define FLEXCARD_RST_TS 0x8000 > + > #define FLEXCARD_MAX_NAME 16 > > +#define FLEXCARD_CLK_1MHZ 0 > +#define FLEXCARD_CLK_10MHZ 1 > +#define FLEXCARD_CLK_100MHZ 2 > + > struct flexcard_device { > raw_spinlock_t irq_lock; > struct pci_dev *pdev; >
-- <http://www.linaro.org/> Linaro.org │ Open source software for ARM SoCs
Follow Linaro: <http://www.facebook.com/pages/Linaro> Facebook | <http://twitter.com/#!/linaroorg> Twitter | <http://www.linaro.org/linaro-blog/> Blog
| |