From a771e5448ed259f768434d498daf8d8b292713de Mon Sep 17 00:00:00 2001 From: Jae Hyun Yoo Date: Mon, 11 Feb 2019 17:02:35 -0800 Subject: [PATCH] Add Aspeed PWM driver which uses FTTMR010 timer IP This commit adds Aspeed PWM driver which uses timer pulse output feature in Aspeed SoCs. The timer IP is derived from Faraday Technologies FTTMR010 IP but has some customized register structure changes only for Aspeed SoCs. Signed-off-by: Jae Hyun Yoo --- arch/arm/boot/dts/aspeed-g5.dtsi | 2 +- drivers/clocksource/timer-fttmr010.c | 25 ++ drivers/input/misc/pwm-beeper.c | 8 +- drivers/pwm/Kconfig | 9 + drivers/pwm/Makefile | 1 + drivers/pwm/pwm-fttmr010.c | 465 +++++++++++++++++++++++++++++++++++ include/clocksource/timer-fttmr010.h | 17 ++ 7 files changed, 522 insertions(+), 5 deletions(-) create mode 100644 drivers/pwm/pwm-fttmr010.c create mode 100644 include/clocksource/timer-fttmr010.h diff --git a/arch/arm/boot/dts/aspeed-g5.dtsi b/arch/arm/boot/dts/aspeed-g5.dtsi index 6686a13a5354..ccf2845cd788 100644 --- a/arch/arm/boot/dts/aspeed-g5.dtsi +++ b/arch/arm/boot/dts/aspeed-g5.dtsi @@ -301,7 +301,7 @@ timer: timer@1e782000 { /* This timer is a Faraday FTTMR010 derivative */ - compatible = "aspeed,ast2400-timer"; + compatible = "aspeed,ast2500-timer"; reg = <0x1e782000 0x90>; interrupts = <16 17 18 35 36 37 38 39>; clocks = <&syscon ASPEED_CLK_APB>; diff --git a/drivers/clocksource/timer-fttmr010.c b/drivers/clocksource/timer-fttmr010.c index cf93f6419b51..8226ccf5cc2c 100644 --- a/drivers/clocksource/timer-fttmr010.c +++ b/drivers/clocksource/timer-fttmr010.c @@ -20,6 +20,8 @@ #include #include +#include + /* * Register definitions for the timers */ @@ -77,6 +79,9 @@ #define TIMER_3_INT_OVERFLOW BIT(8) #define TIMER_INT_ALL_MASK 0x1ff +DEFINE_SPINLOCK(timer_fttmr010_lock); +EXPORT_SYMBOL(timer_fttmr010_lock); + struct fttmr010 { void __iomem *base; unsigned int tick_rate; @@ -123,8 +128,11 @@ static int fttmr010_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt) { struct fttmr010 *fttmr010 = to_fttmr010(evt); + unsigned long flags; u32 cr; + spin_lock_irqsave(&timer_fttmr010_lock, flags); + /* Stop */ cr = readl(fttmr010->base + TIMER_CR); cr &= ~fttmr010->t1_enable_val; @@ -147,27 +155,37 @@ static int fttmr010_timer_set_next_event(unsigned long cycles, cr |= fttmr010->t1_enable_val; writel(cr, fttmr010->base + TIMER_CR); + spin_unlock_irqrestore(&timer_fttmr010_lock, flags); + return 0; } static int fttmr010_timer_shutdown(struct clock_event_device *evt) { struct fttmr010 *fttmr010 = to_fttmr010(evt); + unsigned long flags; u32 cr; + spin_lock_irqsave(&timer_fttmr010_lock, flags); + /* Stop */ cr = readl(fttmr010->base + TIMER_CR); cr &= ~fttmr010->t1_enable_val; writel(cr, fttmr010->base + TIMER_CR); + spin_unlock_irqrestore(&timer_fttmr010_lock, flags); + return 0; } static int fttmr010_timer_set_oneshot(struct clock_event_device *evt) { struct fttmr010 *fttmr010 = to_fttmr010(evt); + unsigned long flags; u32 cr; + spin_lock_irqsave(&timer_fttmr010_lock, flags); + /* Stop */ cr = readl(fttmr010->base + TIMER_CR); cr &= ~fttmr010->t1_enable_val; @@ -186,6 +204,8 @@ static int fttmr010_timer_set_oneshot(struct clock_event_device *evt) cr |= TIMER_1_INT_MATCH1; writel(cr, fttmr010->base + TIMER_INTR_MASK); + spin_unlock_irqrestore(&timer_fttmr010_lock, flags); + return 0; } @@ -193,8 +213,11 @@ static int fttmr010_timer_set_periodic(struct clock_event_device *evt) { struct fttmr010 *fttmr010 = to_fttmr010(evt); u32 period = DIV_ROUND_CLOSEST(fttmr010->tick_rate, HZ); + unsigned long flags; u32 cr; + spin_lock_irqsave(&timer_fttmr010_lock, flags); + /* Stop */ cr = readl(fttmr010->base + TIMER_CR); cr &= ~fttmr010->t1_enable_val; @@ -221,6 +244,8 @@ static int fttmr010_timer_set_periodic(struct clock_event_device *evt) cr |= fttmr010->t1_enable_val; writel(cr, fttmr010->base + TIMER_CR); + spin_unlock_irqrestore(&timer_fttmr010_lock, flags); + return 0; } diff --git a/drivers/input/misc/pwm-beeper.c b/drivers/input/misc/pwm-beeper.c index edca0d737750..a3baa52f187f 100644 --- a/drivers/input/misc/pwm-beeper.c +++ b/drivers/input/misc/pwm-beeper.c @@ -52,7 +52,7 @@ static int pwm_beeper_on(struct pwm_beeper *beeper, unsigned long period) if (error) return error; - if (!beeper->amplifier_on) { + if (beeper->amplifier && !beeper->amplifier_on) { error = regulator_enable(beeper->amplifier); if (error) { pwm_disable(beeper->pwm); @@ -67,7 +67,7 @@ static int pwm_beeper_on(struct pwm_beeper *beeper, unsigned long period) static void pwm_beeper_off(struct pwm_beeper *beeper) { - if (beeper->amplifier_on) { + if (beeper->amplifier && beeper->amplifier_on) { regulator_disable(beeper->amplifier); beeper->amplifier_on = false; } @@ -163,9 +163,9 @@ static int pwm_beeper_probe(struct platform_device *pdev) if (IS_ERR(beeper->amplifier)) { error = PTR_ERR(beeper->amplifier); if (error != -EPROBE_DEFER) - dev_err(dev, "Failed to get 'amp' regulator: %d\n", + dev_dbg(dev, "Failed to get 'amp' regulator: %d\n", error); - return error; + beeper->amplifier = NULL; } INIT_WORK(&beeper->work, pwm_beeper_work); diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig index 504d252716f2..9d4642c668c9 100644 --- a/drivers/pwm/Kconfig +++ b/drivers/pwm/Kconfig @@ -168,6 +168,15 @@ config PWM_FSL_FTM To compile this driver as a module, choose M here: the module will be called pwm-fsl-ftm. +config PWM_FTTMR010 + tristate "Faraday Technology FTTMR010 timer PWM support" + help + Generic PWM framework driver for Faraday Technology FTTMR010 Timer + PWM output + + To compile this driver as a module, choose M here: the module + will be called pwm-fttmr010 + config PWM_HIBVT tristate "HiSilicon BVT PWM support" depends on ARCH_HISI || COMPILE_TEST diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile index 9c676a0dadf5..13b7b20ad5ab 100644 --- a/drivers/pwm/Makefile +++ b/drivers/pwm/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_PWM_CRC) += pwm-crc.o obj-$(CONFIG_PWM_CROS_EC) += pwm-cros-ec.o obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o +obj-$(CONFIG_PWM_FTTMR010) += pwm-fttmr010.o obj-$(CONFIG_PWM_HIBVT) += pwm-hibvt.o obj-$(CONFIG_PWM_IMG) += pwm-img.o obj-$(CONFIG_PWM_IMX) += pwm-imx.o diff --git a/drivers/pwm/pwm-fttmr010.c b/drivers/pwm/pwm-fttmr010.c new file mode 100644 index 000000000000..459ace3eba6a --- /dev/null +++ b/drivers/pwm/pwm-fttmr010.c @@ -0,0 +1,465 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2019 Intel Corporation + +#include +#include +#include +#include +#include +#include +#include + +/* For timer_fttmr010_lock */ +#include + +#define TIMER_CR 0x30 + +#define TIMER5_ASPEED_COUNT 0x50 +#define TIMER5_ASPEED_LOAD 0x54 +#define TIMER5_ASPEED_MATCH1 0x58 +#define TIMER5_ASPEED_MATCH2 0x5c +#define TIMER6_ASPEED_COUNT 0x60 +#define TIMER6_ASPEED_LOAD 0x64 +#define TIMER6_ASPEED_MATCH1 0x68 +#define TIMER6_ASPEED_MATCH2 0x6c +#define TIMER7_ASPEED_COUNT 0x70 +#define TIMER7_ASPEED_LOAD 0x74 +#define TIMER7_ASPEED_MATCH1 0x78 +#define TIMER7_ASPEED_MATCH2 0x7c +#define TIMER8_ASPEED_COUNT 0x80 +#define TIMER8_ASPEED_LOAD 0x84 +#define TIMER8_ASPEED_MATCH1 0x88 +#define TIMER8_ASPEED_MATCH2 0x8c + +#define TIMER_5_CR_ASPEED_ENABLE BIT(16) +#define TIMER_5_CR_ASPEED_CLOCK BIT(17) +#define TIMER_5_CR_ASPEED_INT BIT(18) +#define TIMER_5_CR_ASPEED_PULSE_OUT BIT(19) +#define TIMER_6_CR_ASPEED_ENABLE BIT(20) +#define TIMER_6_CR_ASPEED_CLOCK BIT(21) +#define TIMER_6_CR_ASPEED_INT BIT(22) +#define TIMER_6_CR_ASPEED_PULSE_OUT BIT(23) +#define TIMER_7_CR_ASPEED_ENABLE BIT(24) +#define TIMER_7_CR_ASPEED_CLOCK BIT(25) +#define TIMER_7_CR_ASPEED_INT BIT(26) +#define TIMER_7_CR_ASPEED_PULSE_OUT BIT(27) +#define TIMER_8_CR_ASPEED_ENABLE BIT(28) +#define TIMER_8_CR_ASPEED_CLOCK BIT(29) +#define TIMER_8_CR_ASPEED_INT BIT(30) +#define TIMER_8_CR_ASPEED_PULSE_OUT BIT(31) + +/** + * struct pwm_fttmr010_variant - variant data depends on SoC + * @bits: timer counter resolution + * @chan_min: lowest timer channel which has pwm pulse output + * @chan_max: highest timer channel which has pwm pulse output + * @output_mask: pwm pulse output mask which is defined in device tree + */ +struct pwm_fttmr010_variant { + u8 bits; + u8 chan_min; + u8 chan_max; + u8 output_mask; +}; + +/** + * struct pwm_fttmr010_chan - private data of FTTMR010 PWM channel + * @period_ns: current period in nanoseconds programmed to the hardware + * @duty_ns: current duty time in nanoseconds programmed to the hardware + */ +struct pwm_fttmr010_chan { + u32 period_ns; + u32 duty_ns; +}; + +/** + * struct pwm_fttmr010 - private data of FTTMR010 PWM + * @chip: generic PWM chip + * @variant: local copy of hardware variant data + * @disabled_mask: disabled status for all channels - one bit per channel + * @base: base address of mapped PWM registers + * @clk: clock used to drive the timers + */ +struct pwm_fttmr010 { + struct pwm_chip chip; + struct pwm_fttmr010_variant variant; + u8 disabled_mask; + void __iomem *base; + struct clk *clk; + u32 clk_tick_ns; +}; + +#if !defined(CONFIG_FTTMR010_TIMER) +/* + * Timer block is shared between timer-fttmr010 and pwm-fttmr010 drivers + * and some registers need access synchronization. If both drivers are + * compiled in, the spinlock is defined in the clocksource driver, + * otherwise following definition is used. + * + * Currently we do not need any more complex synchronization method + * because all the supported SoCs contain only one instance of the Timer + * IP. Once this changes, both drivers will need to be modified to + * properly synchronize accesses to particular instances. + */ +static DEFINE_SPINLOCK(timer_fttmr010_lock); +#endif + +static inline +struct pwm_fttmr010 *to_pwm_fttmr010(struct pwm_chip *chip) +{ + return container_of(chip, struct pwm_fttmr010, chip); +} + +static int pwm_fttmr010_request(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct pwm_fttmr010 *priv = to_pwm_fttmr010(chip); + struct pwm_fttmr010_chan *chan; + + if (!(priv->variant.output_mask & BIT(pwm->hwpwm))) { + dev_warn(chip->dev, + "tried to request PWM channel %d without output\n", + pwm->hwpwm); + return -EINVAL; + } + + chan = devm_kzalloc(chip->dev, sizeof(*chan), GFP_KERNEL); + if (!chan) + return -ENOMEM; + + pwm_set_chip_data(pwm, chan); + + return 0; +} + +static void pwm_fttmr010_free(struct pwm_chip *chip, struct pwm_device *pwm) +{ + devm_kfree(chip->dev, pwm_get_chip_data(pwm)); + pwm_set_chip_data(pwm, NULL); +} + +static int pwm_fttmr010_enable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct pwm_fttmr010 *priv = to_pwm_fttmr010(chip); + ulong flags; + u32 cr; + + spin_lock_irqsave(&timer_fttmr010_lock, flags); + + cr = readl(priv->base + TIMER_CR); + + switch (pwm->hwpwm) { + case 5: + cr |= (TIMER_5_CR_ASPEED_ENABLE | TIMER_5_CR_ASPEED_PULSE_OUT); + break; + case 6: + cr |= (TIMER_6_CR_ASPEED_ENABLE | TIMER_6_CR_ASPEED_PULSE_OUT); + break; + case 7: + cr |= (TIMER_7_CR_ASPEED_ENABLE | TIMER_7_CR_ASPEED_PULSE_OUT); + break; + case 8: + cr |= (TIMER_8_CR_ASPEED_ENABLE | TIMER_8_CR_ASPEED_PULSE_OUT); + break; + } + + writel(cr, priv->base + TIMER_CR); + + spin_unlock_irqrestore(&timer_fttmr010_lock, flags); + + priv->disabled_mask &= ~BIT(pwm->hwpwm); + + return 0; +} + +static void pwm_fttmr010_disable(struct pwm_chip *chip, struct pwm_device *pwm) +{ + struct pwm_fttmr010 *priv = to_pwm_fttmr010(chip); + ulong flags; + u32 cr; + + spin_lock_irqsave(&timer_fttmr010_lock, flags); + + cr = readl(priv->base + TIMER_CR); + + switch (pwm->hwpwm) { + case 5: + cr &= ~(TIMER_5_CR_ASPEED_ENABLE | TIMER_5_CR_ASPEED_PULSE_OUT); + break; + case 6: + cr &= ~(TIMER_6_CR_ASPEED_ENABLE | TIMER_6_CR_ASPEED_PULSE_OUT); + break; + case 7: + cr &= ~(TIMER_7_CR_ASPEED_ENABLE | TIMER_7_CR_ASPEED_PULSE_OUT); + break; + case 8: + cr &= ~(TIMER_8_CR_ASPEED_ENABLE | TIMER_8_CR_ASPEED_PULSE_OUT); + break; + } + + writel(cr, priv->base + TIMER_CR); + + spin_unlock_irqrestore(&timer_fttmr010_lock, flags); + + priv->disabled_mask |= BIT(pwm->hwpwm); +} + +static int pwm_fttmr010_config(struct pwm_chip *chip, struct pwm_device *pwm, + int duty_ns, int period_ns) +{ + u32 tload, tmatch, creg_offset, lreg_offset, mreg_offset; + struct pwm_fttmr010_chan *chan = pwm_get_chip_data(pwm); + struct pwm_fttmr010 *priv = to_pwm_fttmr010(chip); + + /* + * We currently avoid using 64bit arithmetic by using the + * fact that anything faster than 1Hz is easily representable + * by 32bits. + */ + if (period_ns > NSEC_PER_SEC) + return -ERANGE; + + /* No need to update */ + if (chan->period_ns == period_ns || chan->duty_ns == duty_ns) + return 0; + + tload = period_ns / priv->clk_tick_ns; + + /* Period is too short */ + if (tload <= 1) + return -ERANGE; + + tmatch = duty_ns / priv->clk_tick_ns; + + /* 0% duty is not available */ + if (!tmatch) + ++tmatch; + + tmatch = tload - tmatch; + + /* Decrement to get tick numbers, instead of tick counts */ + --tload; + --tmatch; + + if (tload == 0 || tmatch == 0) + return -ERANGE; + + dev_dbg(priv->chip.dev, "clk_tick_ns:%u, tload:%u, tmatch:%u\n", + priv->clk_tick_ns, tload, tmatch); + + switch (pwm->hwpwm) { + case 5: + creg_offset = TIMER5_ASPEED_COUNT; + lreg_offset = TIMER5_ASPEED_LOAD; + mreg_offset = TIMER5_ASPEED_MATCH1; + break; + case 6: + creg_offset = TIMER6_ASPEED_COUNT; + lreg_offset = TIMER6_ASPEED_LOAD; + mreg_offset = TIMER6_ASPEED_MATCH1; + break; + case 7: + creg_offset = TIMER7_ASPEED_COUNT; + lreg_offset = TIMER7_ASPEED_LOAD; + mreg_offset = TIMER7_ASPEED_MATCH1; + break; + case 8: + creg_offset = TIMER8_ASPEED_COUNT; + lreg_offset = TIMER8_ASPEED_LOAD; + mreg_offset = TIMER8_ASPEED_MATCH1; + break; + } + + writel(tload, priv->base + creg_offset); + writel(tload, priv->base + lreg_offset); + writel(tmatch, priv->base + mreg_offset); + + chan->period_ns = period_ns; + chan->duty_ns = duty_ns; + + return 0; +} + +static const struct pwm_ops pwm_fttmr010_ops = { + .request = pwm_fttmr010_request, + .free = pwm_fttmr010_free, + .enable = pwm_fttmr010_enable, + .disable = pwm_fttmr010_disable, + .config = pwm_fttmr010_config, + .owner = THIS_MODULE, +}; + +#ifdef CONFIG_OF +static const struct pwm_fttmr010_variant aspeed_variant = { + .bits = 32, + .chan_min = 5, + .chan_max = 8, +}; + +static const struct of_device_id pwm_fttmr010_matches[] = { + { .compatible = "aspeed,ast2400-timer", .data = &aspeed_variant }, + { .compatible = "aspeed,ast2500-timer", .data = &aspeed_variant }, + { }, +}; +MODULE_DEVICE_TABLE(of, pwm_fttmr010_matches); + +static int pwm_fttmr010_parse_dt(struct pwm_fttmr010 *priv) +{ + struct device_node *np = priv->chip.dev->of_node; + const struct of_device_id *match; + struct property *prop; + const __be32 *cur; + u32 val; + + match = of_match_node(pwm_fttmr010_matches, np); + if (!match) + return -ENODEV; + + memcpy(&priv->variant, match->data, sizeof(priv->variant)); + + of_property_for_each_u32(np, "fttmr010,pwm-outputs", prop, cur, val) { + if (val < priv->variant.chan_min || + val > priv->variant.chan_max) { + dev_err(priv->chip.dev, + "invalid channel index in fttmr010,pwm-outputs property\n"); + continue; + } + priv->variant.output_mask |= BIT(val); + } + + return 0; +} +#else +static int pwm_fttmr010_parse_dt(struct pwm_fttmr010 *priv) +{ + return -ENODEV; +} +#endif + +static int pwm_fttmr010_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct pwm_fttmr010 *priv; + struct resource *res; + ulong clk_rate; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->chip.dev = &pdev->dev; + priv->chip.ops = &pwm_fttmr010_ops; + priv->chip.base = -1; + + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { + ret = pwm_fttmr010_parse_dt(priv); + if (ret) + return ret; + + priv->chip.of_xlate = of_pwm_xlate_with_flags; + priv->chip.of_pwm_n_cells = 3; + } else { + if (!pdev->dev.platform_data) { + dev_err(&pdev->dev, "no platform data specified\n"); + return -EINVAL; + } + + memcpy(&priv->variant, pdev->dev.platform_data, + sizeof(priv->variant)); + } + + priv->chip.npwm = priv->variant.chan_max + 1; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + priv->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + priv->clk = devm_clk_get(&pdev->dev, "PCLK"); + if (IS_ERR(priv->clk)) { + dev_err(dev, "failed to get timer base clk\n"); + return PTR_ERR(priv->clk); + } + + ret = clk_prepare_enable(priv->clk); + if (ret < 0) { + dev_err(dev, "failed to enable base clock\n"); + return ret; + } + + clk_rate = clk_get_rate(priv->clk); + priv->clk_tick_ns = NSEC_PER_SEC / clk_rate; + + platform_set_drvdata(pdev, priv); + + ret = pwmchip_add(&priv->chip); + if (ret < 0) { + dev_err(dev, "failed to register PWM chip\n"); + clk_disable_unprepare(priv->clk); + return ret; + } + + dev_dbg(dev, "clk at %lu\n", clk_rate); + + return 0; +} + +static int pwm_fttmr010_remove(struct platform_device *pdev) +{ + struct pwm_fttmr010 *priv = platform_get_drvdata(pdev); + int ret; + + ret = pwmchip_remove(&priv->chip); + if (ret < 0) + return ret; + + clk_disable_unprepare(priv->clk); + + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int pwm_fttmr010_resume(struct device *dev) +{ + struct pwm_fttmr010 *priv = dev_get_drvdata(dev); + struct pwm_chip *chip = &priv->chip; + unsigned int i; + + for (i = chip->variant.chan_min; i < chip->variant.chan_max; i++) { + struct pwm_device *pwm = &chip->pwms[i]; + struct pwm_fttmr010_chan *chan = pwm_get_chip_data(pwm); + + if (!chan) + continue; + + if (chan->period_ns) { + pwm_fttmr010_config(chip, pwm, chan->duty_ns, + chan->period_ns); + } + + if (priv->disabled_mask & BIT(i)) + pwm_fttmr010_disable(chip, pwm); + else + pwm_fttmr010_enable(chip, pwm); + } + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(pwm_fttmr010_pm_ops, NULL, pwm_fttmr010_resume); + +static struct platform_driver pwm_fttmr010_driver = { + .driver = { + .name = "fttmr010-timer-pwm", + .pm = &pwm_fttmr010_pm_ops, + .of_match_table = of_match_ptr(pwm_fttmr010_matches), + }, + .probe = pwm_fttmr010_probe, + .remove = pwm_fttmr010_remove, +}; +module_platform_driver(pwm_fttmr010_driver); + +MODULE_AUTHOR("Jae Hyun Yoo "); +MODULE_DESCRIPTION("FTTMR010 PWM Driver for timer pulse outputs"); +MODULE_LICENSE("GPL v2"); diff --git a/include/clocksource/timer-fttmr010.h b/include/clocksource/timer-fttmr010.h new file mode 100644 index 000000000000..d8d6a2f14130 --- /dev/null +++ b/include/clocksource/timer-fttmr010.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __CLOCKSOURCE_TIMER_FTTMR010_H +#define __CLOCKSOURCE_TIMER_FTTMR010_H + +#include + +/* + * Following declaration must be in an ifdef due to this symbol being static + * in timer-fttmr010 driver if the clocksource driver is not compiled in and the + * spinlock is not shared between both drivers. + */ +#ifdef CONFIG_FTTMR010_TIMER +extern spinlock_t timer_fttmr010_lock; +#endif + +#endif /* __CLOCKSOURCE_TIMER_FTTMR010_H */ -- 2.7.4