Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 1 | /* |
| 2 | * MPC5200 General Purpose Timer device driver |
| 3 | * |
| 4 | * Copyright (c) 2009 Secret Lab Technologies Ltd. |
| 5 | * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix |
| 6 | * |
| 7 | * This program is free software; you can redistribute it and/or modify it |
| 8 | * under the terms of the GNU General Public License as published by the |
| 9 | * Free Software Foundation; either version 2 of the License, or (at your |
| 10 | * option) any later version. |
| 11 | * |
| 12 | * This file is a driver for the the General Purpose Timer (gpt) devices |
| 13 | * found on the MPC5200 SoC. Each timer has an IO pin which can be used |
| 14 | * for GPIO or can be used to raise interrupts. The timer function can |
| 15 | * be used independently from the IO pin, or it can be used to control |
| 16 | * output signals or measure input signals. |
| 17 | * |
| 18 | * This driver supports the GPIO and IRQ controller functions of the GPT |
| 19 | * device. Timer functions are not yet supported, nor is the watchdog |
| 20 | * timer. |
| 21 | * |
| 22 | * To use the GPIO function, the following two properties must be added |
| 23 | * to the device tree node for the gpt device (typically in the .dts file |
| 24 | * for the board): |
| 25 | * gpio-controller; |
| 26 | * #gpio-cells = < 2 >; |
| 27 | * This driver will register the GPIO pin if it finds the gpio-controller |
| 28 | * property in the device tree. |
| 29 | * |
| 30 | * To use the IRQ controller function, the following two properties must |
| 31 | * be added to the device tree node for the gpt device: |
| 32 | * interrupt-controller; |
| 33 | * #interrupt-cells = < 1 >; |
| 34 | * The IRQ controller binding only uses one cell to specify the interrupt, |
| 35 | * and the IRQ flags are encoded in the cell. A cell is not used to encode |
| 36 | * the IRQ number because the GPT only has a single IRQ source. For flags, |
| 37 | * a value of '1' means rising edge sensitive and '2' means falling edge. |
| 38 | * |
| 39 | * The GPIO and the IRQ controller functions can be used at the same time, |
| 40 | * but in this use case the IO line will only work as an input. Trying to |
| 41 | * use it as a GPIO output will not work. |
| 42 | * |
| 43 | * When using the GPIO line as an output, it can either be driven as normal |
| 44 | * IO, or it can be an Open Collector (OC) output. At the moment it is the |
| 45 | * responsibility of either the bootloader or the platform setup code to set |
| 46 | * the output mode. This driver does not change the output mode setting. |
| 47 | */ |
| 48 | |
Grant Likely | 4f59ecf | 2009-11-04 16:42:33 -0700 | [diff] [blame^] | 49 | #include <linux/device.h> |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 50 | #include <linux/irq.h> |
| 51 | #include <linux/interrupt.h> |
| 52 | #include <linux/io.h> |
Grant Likely | 4f59ecf | 2009-11-04 16:42:33 -0700 | [diff] [blame^] | 53 | #include <linux/list.h> |
| 54 | #include <linux/mutex.h> |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 55 | #include <linux/of.h> |
| 56 | #include <linux/of_platform.h> |
| 57 | #include <linux/of_gpio.h> |
| 58 | #include <linux/kernel.h> |
Grant Likely | 4f59ecf | 2009-11-04 16:42:33 -0700 | [diff] [blame^] | 59 | #include <asm/div64.h> |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 60 | #include <asm/mpc52xx.h> |
| 61 | |
| 62 | MODULE_DESCRIPTION("Freescale MPC52xx gpt driver"); |
| 63 | MODULE_AUTHOR("Sascha Hauer, Grant Likely"); |
| 64 | MODULE_LICENSE("GPL"); |
| 65 | |
| 66 | /** |
| 67 | * struct mpc52xx_gpt - Private data structure for MPC52xx GPT driver |
| 68 | * @dev: pointer to device structure |
| 69 | * @regs: virtual address of GPT registers |
| 70 | * @lock: spinlock to coordinate between different functions. |
| 71 | * @of_gc: of_gpio_chip instance structure; used when GPIO is enabled |
| 72 | * @irqhost: Pointer to irq_host instance; used when IRQ mode is supported |
| 73 | */ |
| 74 | struct mpc52xx_gpt_priv { |
Grant Likely | 4f59ecf | 2009-11-04 16:42:33 -0700 | [diff] [blame^] | 75 | struct list_head list; /* List of all GPT devices */ |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 76 | struct device *dev; |
| 77 | struct mpc52xx_gpt __iomem *regs; |
| 78 | spinlock_t lock; |
| 79 | struct irq_host *irqhost; |
Grant Likely | 4f59ecf | 2009-11-04 16:42:33 -0700 | [diff] [blame^] | 80 | u32 ipb_freq; |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 81 | |
| 82 | #if defined(CONFIG_GPIOLIB) |
| 83 | struct of_gpio_chip of_gc; |
| 84 | #endif |
| 85 | }; |
| 86 | |
Grant Likely | 4f59ecf | 2009-11-04 16:42:33 -0700 | [diff] [blame^] | 87 | LIST_HEAD(mpc52xx_gpt_list); |
| 88 | DEFINE_MUTEX(mpc52xx_gpt_list_mutex); |
| 89 | |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 90 | #define MPC52xx_GPT_MODE_MS_MASK (0x07) |
| 91 | #define MPC52xx_GPT_MODE_MS_IC (0x01) |
| 92 | #define MPC52xx_GPT_MODE_MS_OC (0x02) |
| 93 | #define MPC52xx_GPT_MODE_MS_PWM (0x03) |
| 94 | #define MPC52xx_GPT_MODE_MS_GPIO (0x04) |
| 95 | |
| 96 | #define MPC52xx_GPT_MODE_GPIO_MASK (0x30) |
| 97 | #define MPC52xx_GPT_MODE_GPIO_OUT_LOW (0x20) |
| 98 | #define MPC52xx_GPT_MODE_GPIO_OUT_HIGH (0x30) |
| 99 | |
Grant Likely | 4f59ecf | 2009-11-04 16:42:33 -0700 | [diff] [blame^] | 100 | #define MPC52xx_GPT_MODE_COUNTER_ENABLE (0x1000) |
| 101 | #define MPC52xx_GPT_MODE_CONTINUOUS (0x0400) |
| 102 | #define MPC52xx_GPT_MODE_OPEN_DRAIN (0x0200) |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 103 | #define MPC52xx_GPT_MODE_IRQ_EN (0x0100) |
| 104 | |
| 105 | #define MPC52xx_GPT_MODE_ICT_MASK (0x030000) |
| 106 | #define MPC52xx_GPT_MODE_ICT_RISING (0x010000) |
| 107 | #define MPC52xx_GPT_MODE_ICT_FALLING (0x020000) |
| 108 | #define MPC52xx_GPT_MODE_ICT_TOGGLE (0x030000) |
| 109 | |
| 110 | #define MPC52xx_GPT_STATUS_IRQMASK (0x000f) |
| 111 | |
| 112 | /* --------------------------------------------------------------------- |
| 113 | * Cascaded interrupt controller hooks |
| 114 | */ |
| 115 | |
| 116 | static void mpc52xx_gpt_irq_unmask(unsigned int virq) |
| 117 | { |
| 118 | struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq); |
| 119 | unsigned long flags; |
| 120 | |
| 121 | spin_lock_irqsave(&gpt->lock, flags); |
| 122 | setbits32(&gpt->regs->mode, MPC52xx_GPT_MODE_IRQ_EN); |
| 123 | spin_unlock_irqrestore(&gpt->lock, flags); |
| 124 | } |
| 125 | |
| 126 | static void mpc52xx_gpt_irq_mask(unsigned int virq) |
| 127 | { |
| 128 | struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq); |
| 129 | unsigned long flags; |
| 130 | |
| 131 | spin_lock_irqsave(&gpt->lock, flags); |
| 132 | clrbits32(&gpt->regs->mode, MPC52xx_GPT_MODE_IRQ_EN); |
| 133 | spin_unlock_irqrestore(&gpt->lock, flags); |
| 134 | } |
| 135 | |
| 136 | static void mpc52xx_gpt_irq_ack(unsigned int virq) |
| 137 | { |
| 138 | struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq); |
| 139 | |
| 140 | out_be32(&gpt->regs->status, MPC52xx_GPT_STATUS_IRQMASK); |
| 141 | } |
| 142 | |
| 143 | static int mpc52xx_gpt_irq_set_type(unsigned int virq, unsigned int flow_type) |
| 144 | { |
| 145 | struct mpc52xx_gpt_priv *gpt = get_irq_chip_data(virq); |
| 146 | unsigned long flags; |
| 147 | u32 reg; |
| 148 | |
| 149 | dev_dbg(gpt->dev, "%s: virq=%i type=%x\n", __func__, virq, flow_type); |
| 150 | |
| 151 | spin_lock_irqsave(&gpt->lock, flags); |
| 152 | reg = in_be32(&gpt->regs->mode) & ~MPC52xx_GPT_MODE_ICT_MASK; |
| 153 | if (flow_type & IRQF_TRIGGER_RISING) |
| 154 | reg |= MPC52xx_GPT_MODE_ICT_RISING; |
| 155 | if (flow_type & IRQF_TRIGGER_FALLING) |
| 156 | reg |= MPC52xx_GPT_MODE_ICT_FALLING; |
| 157 | out_be32(&gpt->regs->mode, reg); |
| 158 | spin_unlock_irqrestore(&gpt->lock, flags); |
| 159 | |
| 160 | return 0; |
| 161 | } |
| 162 | |
| 163 | static struct irq_chip mpc52xx_gpt_irq_chip = { |
| 164 | .typename = "MPC52xx GPT", |
| 165 | .unmask = mpc52xx_gpt_irq_unmask, |
| 166 | .mask = mpc52xx_gpt_irq_mask, |
| 167 | .ack = mpc52xx_gpt_irq_ack, |
| 168 | .set_type = mpc52xx_gpt_irq_set_type, |
| 169 | }; |
| 170 | |
| 171 | void mpc52xx_gpt_irq_cascade(unsigned int virq, struct irq_desc *desc) |
| 172 | { |
| 173 | struct mpc52xx_gpt_priv *gpt = get_irq_data(virq); |
| 174 | int sub_virq; |
| 175 | u32 status; |
| 176 | |
| 177 | status = in_be32(&gpt->regs->status) & MPC52xx_GPT_STATUS_IRQMASK; |
| 178 | if (status) { |
| 179 | sub_virq = irq_linear_revmap(gpt->irqhost, 0); |
| 180 | generic_handle_irq(sub_virq); |
| 181 | } |
| 182 | } |
| 183 | |
| 184 | static int mpc52xx_gpt_irq_map(struct irq_host *h, unsigned int virq, |
| 185 | irq_hw_number_t hw) |
| 186 | { |
| 187 | struct mpc52xx_gpt_priv *gpt = h->host_data; |
| 188 | |
| 189 | dev_dbg(gpt->dev, "%s: h=%p, virq=%i\n", __func__, h, virq); |
| 190 | set_irq_chip_data(virq, gpt); |
| 191 | set_irq_chip_and_handler(virq, &mpc52xx_gpt_irq_chip, handle_edge_irq); |
| 192 | |
| 193 | return 0; |
| 194 | } |
| 195 | |
| 196 | static int mpc52xx_gpt_irq_xlate(struct irq_host *h, struct device_node *ct, |
| 197 | u32 *intspec, unsigned int intsize, |
| 198 | irq_hw_number_t *out_hwirq, |
| 199 | unsigned int *out_flags) |
| 200 | { |
| 201 | struct mpc52xx_gpt_priv *gpt = h->host_data; |
| 202 | |
| 203 | dev_dbg(gpt->dev, "%s: flags=%i\n", __func__, intspec[0]); |
| 204 | |
Grant Likely | 4f59ecf | 2009-11-04 16:42:33 -0700 | [diff] [blame^] | 205 | if ((intsize < 1) || (intspec[0] > 3)) { |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 206 | dev_err(gpt->dev, "bad irq specifier in %s\n", ct->full_name); |
| 207 | return -EINVAL; |
| 208 | } |
| 209 | |
| 210 | *out_hwirq = 0; /* The GPT only has 1 IRQ line */ |
| 211 | *out_flags = intspec[0]; |
| 212 | |
| 213 | return 0; |
| 214 | } |
| 215 | |
| 216 | static struct irq_host_ops mpc52xx_gpt_irq_ops = { |
| 217 | .map = mpc52xx_gpt_irq_map, |
| 218 | .xlate = mpc52xx_gpt_irq_xlate, |
| 219 | }; |
| 220 | |
| 221 | static void |
| 222 | mpc52xx_gpt_irq_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node) |
| 223 | { |
| 224 | int cascade_virq; |
| 225 | unsigned long flags; |
Grant Likely | 4f59ecf | 2009-11-04 16:42:33 -0700 | [diff] [blame^] | 226 | u32 mode; |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 227 | |
| 228 | cascade_virq = irq_of_parse_and_map(node, 0); |
Grant Likely | 4f59ecf | 2009-11-04 16:42:33 -0700 | [diff] [blame^] | 229 | if (!cascade_virq) |
| 230 | return; |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 231 | |
| 232 | gpt->irqhost = irq_alloc_host(node, IRQ_HOST_MAP_LINEAR, 1, |
| 233 | &mpc52xx_gpt_irq_ops, -1); |
| 234 | if (!gpt->irqhost) { |
| 235 | dev_err(gpt->dev, "irq_alloc_host() failed\n"); |
| 236 | return; |
| 237 | } |
| 238 | |
| 239 | gpt->irqhost->host_data = gpt; |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 240 | set_irq_data(cascade_virq, gpt); |
| 241 | set_irq_chained_handler(cascade_virq, mpc52xx_gpt_irq_cascade); |
| 242 | |
Grant Likely | 4f59ecf | 2009-11-04 16:42:33 -0700 | [diff] [blame^] | 243 | /* If the GPT is currently disabled, then change it to be in Input |
| 244 | * Capture mode. If the mode is non-zero, then the pin could be |
| 245 | * already in use for something. */ |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 246 | spin_lock_irqsave(&gpt->lock, flags); |
Grant Likely | 4f59ecf | 2009-11-04 16:42:33 -0700 | [diff] [blame^] | 247 | mode = in_be32(&gpt->regs->mode); |
| 248 | if ((mode & MPC52xx_GPT_MODE_MS_MASK) == 0) |
| 249 | out_be32(&gpt->regs->mode, mode | MPC52xx_GPT_MODE_MS_IC); |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 250 | spin_unlock_irqrestore(&gpt->lock, flags); |
| 251 | |
| 252 | dev_dbg(gpt->dev, "%s() complete. virq=%i\n", __func__, cascade_virq); |
| 253 | } |
| 254 | |
| 255 | |
| 256 | /* --------------------------------------------------------------------- |
| 257 | * GPIOLIB hooks |
| 258 | */ |
| 259 | #if defined(CONFIG_GPIOLIB) |
| 260 | static inline struct mpc52xx_gpt_priv *gc_to_mpc52xx_gpt(struct gpio_chip *gc) |
| 261 | { |
| 262 | return container_of(to_of_gpio_chip(gc), struct mpc52xx_gpt_priv,of_gc); |
| 263 | } |
| 264 | |
| 265 | static int mpc52xx_gpt_gpio_get(struct gpio_chip *gc, unsigned int gpio) |
| 266 | { |
| 267 | struct mpc52xx_gpt_priv *gpt = gc_to_mpc52xx_gpt(gc); |
| 268 | |
| 269 | return (in_be32(&gpt->regs->status) >> 8) & 1; |
| 270 | } |
| 271 | |
| 272 | static void |
| 273 | mpc52xx_gpt_gpio_set(struct gpio_chip *gc, unsigned int gpio, int v) |
| 274 | { |
| 275 | struct mpc52xx_gpt_priv *gpt = gc_to_mpc52xx_gpt(gc); |
| 276 | unsigned long flags; |
| 277 | u32 r; |
| 278 | |
| 279 | dev_dbg(gpt->dev, "%s: gpio:%d v:%d\n", __func__, gpio, v); |
| 280 | r = v ? MPC52xx_GPT_MODE_GPIO_OUT_HIGH : MPC52xx_GPT_MODE_GPIO_OUT_LOW; |
| 281 | |
| 282 | spin_lock_irqsave(&gpt->lock, flags); |
| 283 | clrsetbits_be32(&gpt->regs->mode, MPC52xx_GPT_MODE_GPIO_MASK, r); |
| 284 | spin_unlock_irqrestore(&gpt->lock, flags); |
| 285 | } |
| 286 | |
| 287 | static int mpc52xx_gpt_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio) |
| 288 | { |
| 289 | struct mpc52xx_gpt_priv *gpt = gc_to_mpc52xx_gpt(gc); |
| 290 | unsigned long flags; |
| 291 | |
| 292 | dev_dbg(gpt->dev, "%s: gpio:%d\n", __func__, gpio); |
| 293 | |
| 294 | spin_lock_irqsave(&gpt->lock, flags); |
| 295 | clrbits32(&gpt->regs->mode, MPC52xx_GPT_MODE_GPIO_MASK); |
| 296 | spin_unlock_irqrestore(&gpt->lock, flags); |
| 297 | |
| 298 | return 0; |
| 299 | } |
| 300 | |
| 301 | static int |
| 302 | mpc52xx_gpt_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val) |
| 303 | { |
| 304 | mpc52xx_gpt_gpio_set(gc, gpio, val); |
| 305 | return 0; |
| 306 | } |
| 307 | |
| 308 | static void |
| 309 | mpc52xx_gpt_gpio_setup(struct mpc52xx_gpt_priv *gpt, struct device_node *node) |
| 310 | { |
| 311 | int rc; |
| 312 | |
| 313 | /* Only setup GPIO if the device tree claims the GPT is |
| 314 | * a GPIO controller */ |
| 315 | if (!of_find_property(node, "gpio-controller", NULL)) |
| 316 | return; |
| 317 | |
| 318 | gpt->of_gc.gc.label = kstrdup(node->full_name, GFP_KERNEL); |
| 319 | if (!gpt->of_gc.gc.label) { |
| 320 | dev_err(gpt->dev, "out of memory\n"); |
| 321 | return; |
| 322 | } |
| 323 | |
| 324 | gpt->of_gc.gpio_cells = 2; |
| 325 | gpt->of_gc.gc.ngpio = 1; |
| 326 | gpt->of_gc.gc.direction_input = mpc52xx_gpt_gpio_dir_in; |
| 327 | gpt->of_gc.gc.direction_output = mpc52xx_gpt_gpio_dir_out; |
| 328 | gpt->of_gc.gc.get = mpc52xx_gpt_gpio_get; |
| 329 | gpt->of_gc.gc.set = mpc52xx_gpt_gpio_set; |
| 330 | gpt->of_gc.gc.base = -1; |
| 331 | gpt->of_gc.xlate = of_gpio_simple_xlate; |
| 332 | node->data = &gpt->of_gc; |
| 333 | of_node_get(node); |
| 334 | |
| 335 | /* Setup external pin in GPIO mode */ |
| 336 | clrsetbits_be32(&gpt->regs->mode, MPC52xx_GPT_MODE_MS_MASK, |
| 337 | MPC52xx_GPT_MODE_MS_GPIO); |
| 338 | |
| 339 | rc = gpiochip_add(&gpt->of_gc.gc); |
| 340 | if (rc) |
| 341 | dev_err(gpt->dev, "gpiochip_add() failed; rc=%i\n", rc); |
| 342 | |
| 343 | dev_dbg(gpt->dev, "%s() complete.\n", __func__); |
| 344 | } |
| 345 | #else /* defined(CONFIG_GPIOLIB) */ |
| 346 | static void |
| 347 | mpc52xx_gpt_gpio_setup(struct mpc52xx_gpt_priv *p, struct device_node *np) { } |
| 348 | #endif /* defined(CONFIG_GPIOLIB) */ |
| 349 | |
Grant Likely | 4f59ecf | 2009-11-04 16:42:33 -0700 | [diff] [blame^] | 350 | /*********************************************************************** |
| 351 | * Timer API |
| 352 | */ |
| 353 | |
| 354 | /** |
| 355 | * mpc52xx_gpt_from_irq - Return the GPT device associated with an IRQ number |
| 356 | * @irq: irq of timer. |
| 357 | */ |
| 358 | struct mpc52xx_gpt_priv *mpc52xx_gpt_from_irq(int irq) |
| 359 | { |
| 360 | struct mpc52xx_gpt_priv *gpt; |
| 361 | struct list_head *pos; |
| 362 | |
| 363 | /* Iterate over the list of timers looking for a matching device */ |
| 364 | mutex_lock(&mpc52xx_gpt_list_mutex); |
| 365 | list_for_each(pos, &mpc52xx_gpt_list) { |
| 366 | gpt = container_of(pos, struct mpc52xx_gpt_priv, list); |
| 367 | if (gpt->irqhost && irq == irq_linear_revmap(gpt->irqhost, 0)) { |
| 368 | mutex_unlock(&mpc52xx_gpt_list_mutex); |
| 369 | return gpt; |
| 370 | } |
| 371 | } |
| 372 | mutex_unlock(&mpc52xx_gpt_list_mutex); |
| 373 | |
| 374 | return NULL; |
| 375 | } |
| 376 | EXPORT_SYMBOL(mpc52xx_gpt_from_irq); |
| 377 | |
| 378 | /** |
| 379 | * mpc52xx_gpt_start_timer - Set and enable the GPT timer |
| 380 | * @gpt: Pointer to gpt private data structure |
| 381 | * @period: period of timer |
| 382 | * @continuous: set to 1 to make timer continuous free running |
| 383 | * |
| 384 | * An interrupt will be generated every time the timer fires |
| 385 | */ |
| 386 | int mpc52xx_gpt_start_timer(struct mpc52xx_gpt_priv *gpt, int period, |
| 387 | int continuous) |
| 388 | { |
| 389 | u32 clear, set; |
| 390 | u64 clocks; |
| 391 | u32 prescale; |
| 392 | unsigned long flags; |
| 393 | |
| 394 | clear = MPC52xx_GPT_MODE_MS_MASK | MPC52xx_GPT_MODE_CONTINUOUS; |
| 395 | set = MPC52xx_GPT_MODE_MS_GPIO | MPC52xx_GPT_MODE_COUNTER_ENABLE; |
| 396 | if (continuous) |
| 397 | set |= MPC52xx_GPT_MODE_CONTINUOUS; |
| 398 | |
| 399 | /* Determine the number of clocks in the requested period. 64 bit |
| 400 | * arithmatic is done here to preserve the precision until the value |
| 401 | * is scaled back down into the u32 range. Period is in 'ns', bus |
| 402 | * frequency is in Hz. */ |
| 403 | clocks = (u64)period * (u64)gpt->ipb_freq; |
| 404 | do_div(clocks, 1000000000); /* Scale it down to ns range */ |
| 405 | |
| 406 | /* This device cannot handle a clock count greater than 32 bits */ |
| 407 | if (clocks > 0xffffffff) |
| 408 | return -EINVAL; |
| 409 | |
| 410 | /* Calculate the prescaler and count values from the clocks value. |
| 411 | * 'clocks' is the number of clock ticks in the period. The timer |
| 412 | * has 16 bit precision and a 16 bit prescaler. Prescaler is |
| 413 | * calculated by integer dividing the clocks by 0x10000 (shifting |
| 414 | * down 16 bits) to obtain the smallest possible divisor for clocks |
| 415 | * to get a 16 bit count value. |
| 416 | * |
| 417 | * Note: the prescale register is '1' based, not '0' based. ie. a |
| 418 | * value of '1' means divide the clock by one. 0xffff divides the |
| 419 | * clock by 0xffff. '0x0000' does not divide by zero, but wraps |
| 420 | * around and divides by 0x10000. That is why prescale must be |
| 421 | * a u32 variable, not a u16, for this calculation. */ |
| 422 | prescale = (clocks >> 16) + 1; |
| 423 | do_div(clocks, prescale); |
| 424 | if (clocks > 0xffff) { |
| 425 | pr_err("calculation error; prescale:%x clocks:%llx\n", |
| 426 | prescale, clocks); |
| 427 | return -EINVAL; |
| 428 | } |
| 429 | |
| 430 | /* Set and enable the timer */ |
| 431 | spin_lock_irqsave(&gpt->lock, flags); |
| 432 | out_be32(&gpt->regs->count, prescale << 16 | clocks); |
| 433 | clrsetbits_be32(&gpt->regs->mode, clear, set); |
| 434 | spin_unlock_irqrestore(&gpt->lock, flags); |
| 435 | |
| 436 | return 0; |
| 437 | } |
| 438 | EXPORT_SYMBOL(mpc52xx_gpt_start_timer); |
| 439 | |
| 440 | void mpc52xx_gpt_stop_timer(struct mpc52xx_gpt_priv *gpt) |
| 441 | { |
| 442 | clrbits32(&gpt->regs->mode, MPC52xx_GPT_MODE_COUNTER_ENABLE); |
| 443 | } |
| 444 | EXPORT_SYMBOL(mpc52xx_gpt_stop_timer); |
| 445 | |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 446 | /* --------------------------------------------------------------------- |
| 447 | * of_platform bus binding code |
| 448 | */ |
| 449 | static int __devinit mpc52xx_gpt_probe(struct of_device *ofdev, |
| 450 | const struct of_device_id *match) |
| 451 | { |
| 452 | struct mpc52xx_gpt_priv *gpt; |
| 453 | |
| 454 | gpt = kzalloc(sizeof *gpt, GFP_KERNEL); |
| 455 | if (!gpt) |
| 456 | return -ENOMEM; |
| 457 | |
| 458 | spin_lock_init(&gpt->lock); |
| 459 | gpt->dev = &ofdev->dev; |
Grant Likely | 4f59ecf | 2009-11-04 16:42:33 -0700 | [diff] [blame^] | 460 | gpt->ipb_freq = mpc5xxx_get_bus_frequency(ofdev->node); |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 461 | gpt->regs = of_iomap(ofdev->node, 0); |
| 462 | if (!gpt->regs) { |
| 463 | kfree(gpt); |
| 464 | return -ENOMEM; |
| 465 | } |
| 466 | |
| 467 | dev_set_drvdata(&ofdev->dev, gpt); |
| 468 | |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 469 | mpc52xx_gpt_gpio_setup(gpt, ofdev->node); |
| 470 | mpc52xx_gpt_irq_setup(gpt, ofdev->node); |
| 471 | |
Grant Likely | 4f59ecf | 2009-11-04 16:42:33 -0700 | [diff] [blame^] | 472 | mutex_lock(&mpc52xx_gpt_list_mutex); |
| 473 | list_add(&gpt->list, &mpc52xx_gpt_list); |
| 474 | mutex_unlock(&mpc52xx_gpt_list_mutex); |
| 475 | |
Grant Likely | 5496eab | 2009-02-04 13:35:42 -0700 | [diff] [blame] | 476 | return 0; |
| 477 | } |
| 478 | |
| 479 | static int mpc52xx_gpt_remove(struct of_device *ofdev) |
| 480 | { |
| 481 | return -EBUSY; |
| 482 | } |
| 483 | |
| 484 | static const struct of_device_id mpc52xx_gpt_match[] = { |
| 485 | { .compatible = "fsl,mpc5200-gpt", }, |
| 486 | |
| 487 | /* Depreciated compatible values; don't use for new dts files */ |
| 488 | { .compatible = "fsl,mpc5200-gpt-gpio", }, |
| 489 | { .compatible = "mpc5200-gpt", }, |
| 490 | {} |
| 491 | }; |
| 492 | |
| 493 | static struct of_platform_driver mpc52xx_gpt_driver = { |
| 494 | .name = "mpc52xx-gpt", |
| 495 | .match_table = mpc52xx_gpt_match, |
| 496 | .probe = mpc52xx_gpt_probe, |
| 497 | .remove = mpc52xx_gpt_remove, |
| 498 | }; |
| 499 | |
| 500 | static int __init mpc52xx_gpt_init(void) |
| 501 | { |
| 502 | if (of_register_platform_driver(&mpc52xx_gpt_driver)) |
| 503 | pr_err("error registering MPC52xx GPT driver\n"); |
| 504 | |
| 505 | return 0; |
| 506 | } |
| 507 | |
| 508 | /* Make sure GPIOs and IRQs get set up before anyone tries to use them */ |
| 509 | subsys_initcall(mpc52xx_gpt_init); |