Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

MIPS: lantiq: adds support for gptu timers

Lantiq socs have a General Purpose Timer Unit (GPTU). This driver allows us to
initialize the timers. The voice firmware needs these timers as a reference.

Signed-off-by: John Crispin <blogic@openwrt.org>
Patchwork: http://patchwork.linux-mips.org/patch/4236/

+215 -1
+1 -1
arch/mips/lantiq/xway/Makefile
··· 1 - obj-y := prom.o sysctrl.o clk.o reset.o gpio.o dma.o 1 + obj-y := prom.o sysctrl.o clk.o reset.o gpio.o dma.o gptu.o
+214
arch/mips/lantiq/xway/gptu.c
··· 1 + /* 2 + * This program is free software; you can redistribute it and/or modify it 3 + * under the terms of the GNU General Public License version 2 as published 4 + * by the Free Software Foundation. 5 + * 6 + * Copyright (C) 2012 John Crispin <blogic@openwrt.org> 7 + * Copyright (C) 2012 Lantiq GmbH 8 + */ 9 + 10 + #include <linux/interrupt.h> 11 + #include <linux/ioport.h> 12 + #include <linux/module.h> 13 + #include <linux/of_platform.h> 14 + #include <linux/of_irq.h> 15 + 16 + #include <lantiq_soc.h> 17 + #include "../clk.h" 18 + 19 + /* the magic ID byte of the core */ 20 + #define GPTU_MAGIC 0x59 21 + /* clock control register */ 22 + #define GPTU_CLC 0x00 23 + /* id register */ 24 + #define GPTU_ID 0x08 25 + /* interrupt node enable */ 26 + #define GPTU_IRNEN 0xf4 27 + /* interrupt control register */ 28 + #define GPTU_IRCR 0xf8 29 + /* interrupt capture register */ 30 + #define GPTU_IRNCR 0xfc 31 + /* there are 3 identical blocks of 2 timers. calculate register offsets */ 32 + #define GPTU_SHIFT(x) (x % 2 ? 4 : 0) 33 + #define GPTU_BASE(x) (((x >> 1) * 0x20) + 0x10) 34 + /* timer control register */ 35 + #define GPTU_CON(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x00) 36 + /* timer auto reload register */ 37 + #define GPTU_RUN(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x08) 38 + /* timer manual reload register */ 39 + #define GPTU_RLD(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x10) 40 + /* timer count register */ 41 + #define GPTU_CNT(x) (GPTU_BASE(x) + GPTU_SHIFT(x) + 0x18) 42 + 43 + /* GPTU_CON(x) */ 44 + #define CON_CNT BIT(2) 45 + #define CON_EDGE_ANY (BIT(7) | BIT(6)) 46 + #define CON_SYNC BIT(8) 47 + #define CON_CLK_INT BIT(10) 48 + 49 + /* GPTU_RUN(x) */ 50 + #define RUN_SEN BIT(0) 51 + #define RUN_RL BIT(2) 52 + 53 + /* set clock to runmode */ 54 + #define CLC_RMC BIT(8) 55 + /* bring core out of suspend */ 56 + #define CLC_SUSPEND BIT(4) 57 + /* the disable bit */ 58 + #define CLC_DISABLE BIT(0) 59 + 60 + #define gptu_w32(x, y) ltq_w32((x), gptu_membase + (y)) 61 + #define gptu_r32(x) ltq_r32(gptu_membase + (x)) 62 + 63 + enum gptu_timer { 64 + TIMER1A = 0, 65 + TIMER1B, 66 + TIMER2A, 67 + TIMER2B, 68 + TIMER3A, 69 + TIMER3B 70 + }; 71 + 72 + static void __iomem *gptu_membase; 73 + static struct resource irqres[6]; 74 + 75 + static irqreturn_t timer_irq_handler(int irq, void *priv) 76 + { 77 + int timer = irq - irqres[0].start; 78 + gptu_w32(1 << timer, GPTU_IRNCR); 79 + return IRQ_HANDLED; 80 + } 81 + 82 + static void gptu_hwinit(void) 83 + { 84 + gptu_w32(0x00, GPTU_IRNEN); 85 + gptu_w32(0xff, GPTU_IRNCR); 86 + gptu_w32(CLC_RMC | CLC_SUSPEND, GPTU_CLC); 87 + } 88 + 89 + static void gptu_hwexit(void) 90 + { 91 + gptu_w32(0x00, GPTU_IRNEN); 92 + gptu_w32(0xff, GPTU_IRNCR); 93 + gptu_w32(CLC_DISABLE, GPTU_CLC); 94 + } 95 + 96 + static int gptu_enable(struct clk *clk) 97 + { 98 + int ret = request_irq(irqres[clk->bits].start, timer_irq_handler, 99 + IRQF_TIMER, "gtpu", NULL); 100 + if (ret) { 101 + pr_err("gptu: failed to request irq\n"); 102 + return ret; 103 + } 104 + 105 + gptu_w32(CON_CNT | CON_EDGE_ANY | CON_SYNC | CON_CLK_INT, 106 + GPTU_CON(clk->bits)); 107 + gptu_w32(1, GPTU_RLD(clk->bits)); 108 + gptu_w32(gptu_r32(GPTU_IRNEN) | BIT(clk->bits), GPTU_IRNEN); 109 + gptu_w32(RUN_SEN | RUN_RL, GPTU_RUN(clk->bits)); 110 + return 0; 111 + } 112 + 113 + static void gptu_disable(struct clk *clk) 114 + { 115 + gptu_w32(0, GPTU_RUN(clk->bits)); 116 + gptu_w32(0, GPTU_CON(clk->bits)); 117 + gptu_w32(0, GPTU_RLD(clk->bits)); 118 + gptu_w32(gptu_r32(GPTU_IRNEN) & ~BIT(clk->bits), GPTU_IRNEN); 119 + free_irq(irqres[clk->bits].start, NULL); 120 + } 121 + 122 + static inline void clkdev_add_gptu(struct device *dev, const char *con, 123 + unsigned int timer) 124 + { 125 + struct clk *clk = kzalloc(sizeof(struct clk), GFP_KERNEL); 126 + 127 + clk->cl.dev_id = dev_name(dev); 128 + clk->cl.con_id = con; 129 + clk->cl.clk = clk; 130 + clk->enable = gptu_enable; 131 + clk->disable = gptu_disable; 132 + clk->bits = timer; 133 + clkdev_add(&clk->cl); 134 + } 135 + 136 + static int __devinit gptu_probe(struct platform_device *pdev) 137 + { 138 + struct clk *clk; 139 + struct resource *res; 140 + 141 + if (of_irq_to_resource_table(pdev->dev.of_node, irqres, 6) != 6) { 142 + dev_err(&pdev->dev, "Failed to get IRQ list\n"); 143 + return -EINVAL; 144 + } 145 + 146 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 147 + if (!res) { 148 + dev_err(&pdev->dev, "Failed to get resource\n"); 149 + return -ENOMEM; 150 + } 151 + 152 + /* remap gptu register range */ 153 + gptu_membase = devm_request_and_ioremap(&pdev->dev, res); 154 + if (!gptu_membase) { 155 + dev_err(&pdev->dev, "Failed to remap resource\n"); 156 + return -ENOMEM; 157 + } 158 + 159 + /* enable our clock */ 160 + clk = clk_get(&pdev->dev, NULL); 161 + if (IS_ERR(clk)) { 162 + dev_err(&pdev->dev, "Failed to get clock\n"); 163 + return -ENOENT; 164 + } 165 + clk_enable(clk); 166 + 167 + /* power up the core */ 168 + gptu_hwinit(); 169 + 170 + /* the gptu has a ID register */ 171 + if (((gptu_r32(GPTU_ID) >> 8) & 0xff) != GPTU_MAGIC) { 172 + dev_err(&pdev->dev, "Failed to find magic\n"); 173 + gptu_hwexit(); 174 + return -ENAVAIL; 175 + } 176 + 177 + /* register the clocks */ 178 + clkdev_add_gptu(&pdev->dev, "timer1a", TIMER1A); 179 + clkdev_add_gptu(&pdev->dev, "timer1b", TIMER1B); 180 + clkdev_add_gptu(&pdev->dev, "timer2a", TIMER2A); 181 + clkdev_add_gptu(&pdev->dev, "timer2b", TIMER2B); 182 + clkdev_add_gptu(&pdev->dev, "timer3a", TIMER3A); 183 + clkdev_add_gptu(&pdev->dev, "timer3b", TIMER3B); 184 + 185 + dev_info(&pdev->dev, "gptu: 6 timers loaded\n"); 186 + 187 + return 0; 188 + } 189 + 190 + static const struct of_device_id gptu_match[] = { 191 + { .compatible = "lantiq,gptu-xway" }, 192 + {}, 193 + }; 194 + MODULE_DEVICE_TABLE(of, dma_match); 195 + 196 + static struct platform_driver dma_driver = { 197 + .probe = gptu_probe, 198 + .driver = { 199 + .name = "gptu-xway", 200 + .owner = THIS_MODULE, 201 + .of_match_table = gptu_match, 202 + }, 203 + }; 204 + 205 + int __init gptu_init(void) 206 + { 207 + int ret = platform_driver_register(&dma_driver); 208 + 209 + if (ret) 210 + pr_info("gptu: Error registering platform driver\n"); 211 + return ret; 212 + } 213 + 214 + arch_initcall(gptu_init);