From: Benedikt Spranger <b.spran...@linutronix.de> The Flexcard timestamp counter can be triggered from two external trigger inputs or an internal clock at 1 MHz, 10 Mhz or 100 MHz. Add support for timestamp trigger selection.
Signed-off-by: Holger Dengler <deng...@linutronix.de> Signed-off-by: Benedikt Spranger <b.spran...@linutronix.de> cc: Daniel Lezcano <daniel.lezc...@linaro.org> cc: Thomas Gleixner <t...@linutronix.de> --- drivers/clocksource/flexcard-time.c | 50 ++++++++++++++++++++++++++++++++++--- include/uapi/linux/flexcard.h | 16 ++++++++++++ 2 files changed, 63 insertions(+), 3 deletions(-) diff --git a/drivers/clocksource/flexcard-time.c b/drivers/clocksource/flexcard-time.c index f2efb53..101a989 100644 --- a/drivers/clocksource/flexcard-time.c +++ b/drivers/clocksource/flexcard-time.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> +#include <linux/flexcard.h> #include <linux/fs.h> #include <linux/miscdevice.h> #include <linux/platform_device.h> @@ -26,8 +27,10 @@ static dev_t flexcard_clk_devt; static struct class *flexcard_clk_class; struct flexcard_clk { + struct flexcard_clk_desc desc; struct posix_clock clock; dev_t devid; + u32 mul; struct device *dev; void __iomem *ts64; void __iomem *reset; @@ -35,8 +38,9 @@ struct flexcard_clk { static int flexcard_clk_getres(struct posix_clock *pc, struct timespec *tp) { + struct flexcard_clk *clk = container_of(pc, struct flexcard_clk, clock); tp->tv_sec = 0; - tp->tv_nsec = 1000; + tp->tv_nsec = clk->mul; return 0; } @@ -54,7 +58,7 @@ retry: goto retry; tp->tv_sec = div_u64_rem(now, clk->desc.freq, &rem); - tp->tv_nsec = rem * 1000; + tp->tv_nsec = rem * clk->mul; return 0; } @@ -73,11 +77,48 @@ static int flexcard_clk_settime(struct posix_clock *pc, return 0; } +static long flexcard_clk_ioctl(struct posix_clock *pc, unsigned int cmd, + unsigned long arg) +{ + struct flexcard_clk *clk = container_of(pc, struct flexcard_clk, clock); + struct flexcard_clk_desc desc; + + if (copy_from_user(&desc, (void __user *)arg, sizeof(desc))) + return -EFAULT; + + switch (cmd) { + case FLEXCARD_CLK_1MHZ: + clk->desc.freq = 1000000; + break; + case FLEXCARD_CLK_10MHZ: + clk->desc.freq = 10000000; + break; + case FLEXCARD_CLK_100MHZ: + clk->desc.freq = 100000000; + break; + case FLEXCARD_CLK_EXT1: + case FLEXCARD_CLK_EXT2: + if (desc.freq < 1 || desc.freq > NSEC_PER_SEC) + return -EINVAL; + break; + default: + return -ENOTTY; + } + + clk->desc = desc; + clk->mul = NSEC_PER_SEC/desc.freq; + writel(clk->desc.type, clk->ts64 + CLKSEL_OFF); + 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, + .ioctl = flexcard_clk_ioctl, }; static int flexcard_clksrc_iomap(struct platform_device *pdev) @@ -134,8 +175,11 @@ static int flexcard_clksrc_probe(struct platform_device *pdev) clk->devid = MKDEV(major, cell->id); clk->clock.ops = flexcard_clk_ops; + clk->desc.type = FLEXCARD_CLK_1MHZ; + clk->desc.freq = 1000000; + clk->mul = 1000; - writel(FLEXCARD_CLK_1MHZ, clk->ts64 + CLKSEL_OFF); + writel(clk->desc.type, clk->ts64 + CLKSEL_OFF); writel(FLEXCARD_RST_TS, clk->reset); clk->dev = device_create(flexcard_clk_class, &pdev->dev, clk->devid, diff --git a/include/uapi/linux/flexcard.h b/include/uapi/linux/flexcard.h index 9b73d8d..7939d94 100644 --- a/include/uapi/linux/flexcard.h +++ b/include/uapi/linux/flexcard.h @@ -15,6 +15,22 @@ #include <linux/types.h> +enum flexcard_clk_type { + FLEXCARD_CLK_1MHZ = 0x0, + FLEXCARD_CLK_10MHZ = 0x1, + FLEXCARD_CLK_100MHZ = 0x2, + FLEXCARD_CLK_EXT1 = 0x11, + FLEXCARD_CLK_EXT2 = 0x12, +}; + +struct flexcard_clk_desc { + enum flexcard_clk_type type; + __u32 freq; +}; + +#define FCGCLKSRC _IOR(0xeb, 0, struct flexcard_clk_desc) +#define FCSCLKSRC _IOW(0xeb, 1, struct flexcard_clk_desc) + struct fc_version { __u8 dev; __u8 min; -- 2.1.4 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/