- 论坛徽章:
- 0
|
我是个新手,这几天在接手移植一块板子,这是我参照的一个板子,对GPIO的操作,不过我有些看不明白,即使参照它的手册也是不明白,我想在这里找一些线索,不过没有头绪啊.感觉笨得要死.新板子上的灯是对四个PIO引进行操作.
- #define AT91_PIOA 0x400
- #define AT91_PIOB 0x600
- #define AT91_PIOC 0x800
- static const u32 pio_controller_offset[4] = {
- AT91_PIOA,
- AT91_PIOB,
- AT91_PIOC,
- };
- /*--------------------------------------------------------------------------*/
- /* Not all hardware capabilities are exposed through these calls; they
- * only encapsulate the most common features and modes. (So if you
- * want to change signals in groups, do it directly.)
- *
- * Bootloaders will usually handle some of the pin multiplexing setup.
- * The intent is certainly that by the time Linux is fully booted, all
- * pins should have been fully initialized. These setup calls should
- * only be used by board setup routines, or possibly in driver probe().
- *
- * For bootloaders doing all that setup, these calls could be inlined
- * as NOPs so Linux won't duplicate any setup code
- */
- /*
- * mux the pin to the corresponding internal peripheral role.
- */
- void at91_gpio_periph_enable (unsigned int pio_va_base,
- unsigned char pin,
- unsigned char peripheral,
- unsigned char use_pullup,
- unsigned char use_filter)
- {
- unsigned int mask = pin_to_mask(pin);
- writel(mask, (pio_va_base + PIO_IDR));
- if(use_pullup)
- writel(mask, (pio_va_base + PIO_PPUER));
- else
- writel(mask, (pio_va_base + PIO_PPUDR));
- switch (peripheral)
- {
- case 1:
- writel(mask, (pio_va_base + PIO_BSR));
- break;
- case 0:
- default:
- writel(mask, (pio_va_base + PIO_ASR));
- break;
- }
- /* The Peripheral controls the pin (pio disabled) */
- writel(mask, (pio_va_base + PIO_PDR));
- }
- EXPORT_SYMBOL(at91_gpio_periph_enable);
- void at91_gpio_configure (unsigned int pio_va_base,
- unsigned char pin,
- unsigned char in_out,
- unsigned char use_pullup,
- unsigned char use_filter)
- {
- unsigned int mask = pin_to_mask(pin);
-
- /* The PIO controls the pin (periph disabled) */
- writel(mask, (pio_va_base + PIO_PER));
- if(in_out) { /* the pin is an input */
- writel(mask, (pio_va_base + PIO_ODR));
- }
- else { /* the pin is an output */
- writel(mask, (pio_va_base + PIO_OER));
- }
- if(use_pullup)
- writel(mask, (pio_va_base + PIO_PPUER));
- else
- writel(mask, (pio_va_base + PIO_PPUDR));
- }
- EXPORT_SYMBOL(at91_gpio_configure);
- void at91_gpio_set_level (unsigned int pio_va_base, unsigned int pin, unsigned int level)
- {
- unsigned int mask = pin_to_mask(pin);
- // This is just a sanity action to force a pin
- // to output before driving it.
- writel(mask, pio_va_base + PIO_PER);
- writel(mask, pio_va_base + PIO_OER);
-
- if (level)
- writel(mask, pio_va_base + PIO_SODR);
- else // pin should be cleared
- writel(mask, pio_va_base + PIO_CODR);
- }
- EXPORT_SYMBOL(at91_gpio_set_level);
- unsigned int at91_gpio_get_level (unsigned int pio_va_base, unsigned int pin)
- {
- unsigned int mask = pin_to_mask(pin);
- // This is just a sanity action to force a pin
- // to input before reading it.
- writel(mask, pio_va_base + PIO_PER);
- writel(mask, pio_va_base + PIO_ODR);
- return (readl(pio_va_base + PIO_PDSR) & mask);
- }
- EXPORT_SYMBOL(at91_gpio_get_level);
- int at91_device_pio_setup (struct at91_pioline *pPin) {
- if(!pPin) {
- printk(KERN_ERR "Define the PIO muxing of this device first !!\n");
- return -ENODEV;
- }
- /* Sets all the pio muxing of the corresponding device as defined in its platform_data struct */
- while (pPin->pin_name)
- {
- if ((pPin->pio_ctrl_id != AT91C_ID_PIOA) &&
- (pPin->pio_ctrl_id != AT91C_ID_PIOB) &&
- (pPin->pio_ctrl_id != AT91C_ID_PIOC)) {
- printk(KERN_ERR "Bad PIO controler ID %u, correct values are {%u, %u ,%u}\n",
- pPin->pio_ctrl_id, AT91C_ID_PIOA, AT91C_ID_PIOB, AT91C_ID_PIOC);
- return -ENODEV;
- }
- if (pPin->type == TYPE_PERIPH) // PIN is in PERIPH mode
- at91_gpio_periph_enable(pPin->pio_ctrl_va_base, pPin->pin_num, pPin->direction, pPin->use_pullup, pPin->use_filter);
- else // PIN is in PIO mode
- at91_gpio_configure(pPin->pio_ctrl_va_base, pPin->pin_num, pPin->direction, pPin->use_pullup, pPin->use_filter);
- pPin++;
- }
- return 0;
- }
- EXPORT_SYMBOL(at91_device_pio_setup);
- static inline void __iomem *pin_to_controller(unsigned pin)
- {
- void __iomem *sys_base = (void __iomem *) AT91C_VA_BASE_SYS;
- pin -= PIN_BASE;
- pin /= 32;
- return sys_base + pio_controller_offset[pin];
- return NULL;
- }
- static inline unsigned pin_to_mask_o(unsigned pin)
- {
- pin -= PIN_BASE;
- return 1 << (pin % 32);
- }
- /*
- * read the pin's value (works even if it's not muxed as a gpio).
- */
- int at91_get_gpio_value(unsigned pin)
- {
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask_o(pin);
- u32 pdsr;
- if (!pio)
- return -EINVAL;
- pdsr = __raw_readl(pio + PIO_PDSR);
- return (pdsr & mask) != 0;
- }
- EXPORT_SYMBOL(at91_get_gpio_value);
- /*--------------------------------------------------------------------------*/
- /* Several AIC controller irqs are dispatched through this GPIO handler.
- * To use any AT91_PIN_* as an externally triggered IRQ, first call
- * at91_set_gpio_input() then maybe enable its glitch filter.
- * Then just request_irq() with the pin ID; it works like any ARM IRQ
- * handler, though it always triggers on rising and falling edges.
- *
- * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after
- * configuring them with at91_set_a_periph() or at91_set_b_periph().
- * IRQ0..IRQ6 should be configurable, e.g. level vs edge triggering.
- */
- static void gpio_irq_mask(unsigned pin)
- {
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask_o(pin);
- if (pio)
- __raw_writel(mask, pio + PIO_IDR);
- }
- static void gpio_irq_unmask(unsigned pin)
- {
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask_o(pin);
- printk("gpio_irq_unmask %d %x\n", (int) pin, (int) pio);
- if (pio)
- __raw_writel(mask, pio + PIO_IER);
- }
- static int gpio_irq_type(unsigned pin, unsigned type)
- {
- return (type == IRQT_BOTHEDGE) ? 0 : -EINVAL;
- }
- static struct irqchip gpio_irqchip = {
- .mask = gpio_irq_mask,
- .unmask = gpio_irq_unmask,
- .set_type = gpio_irq_type,
- };
- static void gpio_irq_handler(unsigned irq, struct irqdesc *desc, struct pt_regs *regs)
- {
- unsigned pin;
- struct irqdesc *gpio;
- void __iomem *pio;
- u32 isr;
- pio = (void __force __iomem *) desc->chipdata;
- /* temporarily mask (level sensitive) parent IRQ */
- desc->chip->ack(irq);
- for (;;) {
- isr = __raw_readl(pio + PIO_ISR) & __raw_readl(pio + PIO_IMR);
- if (!isr)
- break;
- pin = (unsigned) desc->data;
- gpio = &irq_desc[pin];
- while (isr) {
- if (isr & 1)
- gpio->handle(pin, gpio, regs);
- pin++;
- gpio++;
- isr >>= 1;
- }
- }
- desc->chip->unmask(irq);
- /* now it may re-trigger */
- }
- /* call this from board-specific init_irq */
- void __init at91_gpio_irq_setup(unsigned banks)
- {
- unsigned pioc, pin, id;
- if (banks > 4)
- banks = 4;
- for (pioc = 0, pin = PIN_BASE, id = AT91_ID_PIOA;
- pioc < banks;
- pioc++, id++) {
- void __iomem *controller;
- unsigned i;
- controller = (void __iomem *) AT91C_VA_BASE_SYS + pio_controller_offset[pioc];
- __raw_writel(~0, controller + PIO_IDR);
- set_irq_data(id, (void *) pin);
- set_irq_chipdata(id, (void __force *) controller);
- for (i = 0; i < 32; i++, pin++) {
- set_irq_chip(pin, &gpio_irqchip);
- set_irq_handler(pin, do_simple_IRQ);
- set_irq_flags(pin, IRQF_VALID);
- }
- set_irq_chained_handler(id, gpio_irq_handler);
- printk("set_irq_chained_handler %d\n", id);
- /* enable the PIO peripheral clock */
- at91_enable_periph_clock(id);
- //at91_sys_write(AT91_PMC_PCER, 1 << id);
- }
- pr_info("AT91: %d gpio irqs in %d banks\n", pin - PIN_BASE, banks);
- }
复制代码 |
|