Path: blob/master/arch/powerpc/sysdev/mpc8xxx_gpio.c
10818 views
/*1* GPIOs on MPC512x/8349/8572/8610 and compatible2*3* Copyright (C) 2008 Peter Korsgaard <[email protected]>4*5* This file is licensed under the terms of the GNU General Public License6* version 2. This program is licensed "as is" without any warranty of any7* kind, whether express or implied.8*/910#include <linux/kernel.h>11#include <linux/init.h>12#include <linux/spinlock.h>13#include <linux/io.h>14#include <linux/of.h>15#include <linux/of_gpio.h>16#include <linux/gpio.h>17#include <linux/slab.h>18#include <linux/irq.h>1920#define MPC8XXX_GPIO_PINS 322122#define GPIO_DIR 0x0023#define GPIO_ODR 0x0424#define GPIO_DAT 0x0825#define GPIO_IER 0x0c26#define GPIO_IMR 0x1027#define GPIO_ICR 0x1428#define GPIO_ICR2 0x182930struct mpc8xxx_gpio_chip {31struct of_mm_gpio_chip mm_gc;32spinlock_t lock;3334/*35* shadowed data register to be able to clear/set output pins in36* open drain mode safely37*/38u32 data;39struct irq_host *irq;40void *of_dev_id_data;41};4243static inline u32 mpc8xxx_gpio2mask(unsigned int gpio)44{45return 1u << (MPC8XXX_GPIO_PINS - 1 - gpio);46}4748static inline struct mpc8xxx_gpio_chip *49to_mpc8xxx_gpio_chip(struct of_mm_gpio_chip *mm)50{51return container_of(mm, struct mpc8xxx_gpio_chip, mm_gc);52}5354static void mpc8xxx_gpio_save_regs(struct of_mm_gpio_chip *mm)55{56struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);5758mpc8xxx_gc->data = in_be32(mm->regs + GPIO_DAT);59}6061/* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs62* defined as output cannot be determined by reading GPDAT register,63* so we use shadow data register instead. The status of input pins64* is determined by reading GPDAT register.65*/66static int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)67{68u32 val;69struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);70struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);7172val = in_be32(mm->regs + GPIO_DAT) & ~in_be32(mm->regs + GPIO_DIR);7374return (val | mpc8xxx_gc->data) & mpc8xxx_gpio2mask(gpio);75}7677static int mpc8xxx_gpio_get(struct gpio_chip *gc, unsigned int gpio)78{79struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);8081return in_be32(mm->regs + GPIO_DAT) & mpc8xxx_gpio2mask(gpio);82}8384static void mpc8xxx_gpio_set(struct gpio_chip *gc, unsigned int gpio, int val)85{86struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);87struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);88unsigned long flags;8990spin_lock_irqsave(&mpc8xxx_gc->lock, flags);9192if (val)93mpc8xxx_gc->data |= mpc8xxx_gpio2mask(gpio);94else95mpc8xxx_gc->data &= ~mpc8xxx_gpio2mask(gpio);9697out_be32(mm->regs + GPIO_DAT, mpc8xxx_gc->data);9899spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);100}101102static int mpc8xxx_gpio_dir_in(struct gpio_chip *gc, unsigned int gpio)103{104struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);105struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);106unsigned long flags;107108spin_lock_irqsave(&mpc8xxx_gc->lock, flags);109110clrbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));111112spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);113114return 0;115}116117static int mpc8xxx_gpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)118{119struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);120struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);121unsigned long flags;122123mpc8xxx_gpio_set(gc, gpio, val);124125spin_lock_irqsave(&mpc8xxx_gc->lock, flags);126127setbits32(mm->regs + GPIO_DIR, mpc8xxx_gpio2mask(gpio));128129spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);130131return 0;132}133134static int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset)135{136struct of_mm_gpio_chip *mm = to_of_mm_gpio_chip(gc);137struct mpc8xxx_gpio_chip *mpc8xxx_gc = to_mpc8xxx_gpio_chip(mm);138139if (mpc8xxx_gc->irq && offset < MPC8XXX_GPIO_PINS)140return irq_create_mapping(mpc8xxx_gc->irq, offset);141else142return -ENXIO;143}144145static void mpc8xxx_gpio_irq_cascade(unsigned int irq, struct irq_desc *desc)146{147struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_desc_get_handler_data(desc);148struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;149unsigned int mask;150151mask = in_be32(mm->regs + GPIO_IER) & in_be32(mm->regs + GPIO_IMR);152if (mask)153generic_handle_irq(irq_linear_revmap(mpc8xxx_gc->irq,15432 - ffs(mask)));155}156157static void mpc8xxx_irq_unmask(struct irq_data *d)158{159struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);160struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;161unsigned long flags;162163spin_lock_irqsave(&mpc8xxx_gc->lock, flags);164165setbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));166167spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);168}169170static void mpc8xxx_irq_mask(struct irq_data *d)171{172struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);173struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;174unsigned long flags;175176spin_lock_irqsave(&mpc8xxx_gc->lock, flags);177178clrbits32(mm->regs + GPIO_IMR, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));179180spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);181}182183static void mpc8xxx_irq_ack(struct irq_data *d)184{185struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);186struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;187188out_be32(mm->regs + GPIO_IER, mpc8xxx_gpio2mask(irqd_to_hwirq(d)));189}190191static int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)192{193struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);194struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;195unsigned long flags;196197switch (flow_type) {198case IRQ_TYPE_EDGE_FALLING:199spin_lock_irqsave(&mpc8xxx_gc->lock, flags);200setbits32(mm->regs + GPIO_ICR,201mpc8xxx_gpio2mask(irqd_to_hwirq(d)));202spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);203break;204205case IRQ_TYPE_EDGE_BOTH:206spin_lock_irqsave(&mpc8xxx_gc->lock, flags);207clrbits32(mm->regs + GPIO_ICR,208mpc8xxx_gpio2mask(irqd_to_hwirq(d)));209spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);210break;211212default:213return -EINVAL;214}215216return 0;217}218219static int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type)220{221struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);222struct of_mm_gpio_chip *mm = &mpc8xxx_gc->mm_gc;223unsigned long gpio = irqd_to_hwirq(d);224void __iomem *reg;225unsigned int shift;226unsigned long flags;227228if (gpio < 16) {229reg = mm->regs + GPIO_ICR;230shift = (15 - gpio) * 2;231} else {232reg = mm->regs + GPIO_ICR2;233shift = (15 - (gpio % 16)) * 2;234}235236switch (flow_type) {237case IRQ_TYPE_EDGE_FALLING:238case IRQ_TYPE_LEVEL_LOW:239spin_lock_irqsave(&mpc8xxx_gc->lock, flags);240clrsetbits_be32(reg, 3 << shift, 2 << shift);241spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);242break;243244case IRQ_TYPE_EDGE_RISING:245case IRQ_TYPE_LEVEL_HIGH:246spin_lock_irqsave(&mpc8xxx_gc->lock, flags);247clrsetbits_be32(reg, 3 << shift, 1 << shift);248spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);249break;250251case IRQ_TYPE_EDGE_BOTH:252spin_lock_irqsave(&mpc8xxx_gc->lock, flags);253clrbits32(reg, 3 << shift);254spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);255break;256257default:258return -EINVAL;259}260261return 0;262}263264static struct irq_chip mpc8xxx_irq_chip = {265.name = "mpc8xxx-gpio",266.irq_unmask = mpc8xxx_irq_unmask,267.irq_mask = mpc8xxx_irq_mask,268.irq_ack = mpc8xxx_irq_ack,269.irq_set_type = mpc8xxx_irq_set_type,270};271272static int mpc8xxx_gpio_irq_map(struct irq_host *h, unsigned int virq,273irq_hw_number_t hw)274{275struct mpc8xxx_gpio_chip *mpc8xxx_gc = h->host_data;276277if (mpc8xxx_gc->of_dev_id_data)278mpc8xxx_irq_chip.irq_set_type = mpc8xxx_gc->of_dev_id_data;279280irq_set_chip_data(virq, h->host_data);281irq_set_chip_and_handler(virq, &mpc8xxx_irq_chip, handle_level_irq);282irq_set_irq_type(virq, IRQ_TYPE_NONE);283284return 0;285}286287static int mpc8xxx_gpio_irq_xlate(struct irq_host *h, struct device_node *ct,288const u32 *intspec, unsigned int intsize,289irq_hw_number_t *out_hwirq,290unsigned int *out_flags)291292{293/* interrupt sense values coming from the device tree equal either294* EDGE_FALLING or EDGE_BOTH295*/296*out_hwirq = intspec[0];297*out_flags = intspec[1];298299return 0;300}301302static struct irq_host_ops mpc8xxx_gpio_irq_ops = {303.map = mpc8xxx_gpio_irq_map,304.xlate = mpc8xxx_gpio_irq_xlate,305};306307static struct of_device_id mpc8xxx_gpio_ids[] __initdata = {308{ .compatible = "fsl,mpc8349-gpio", },309{ .compatible = "fsl,mpc8572-gpio", },310{ .compatible = "fsl,mpc8610-gpio", },311{ .compatible = "fsl,mpc5121-gpio", .data = mpc512x_irq_set_type, },312{ .compatible = "fsl,qoriq-gpio", },313{}314};315316static void __init mpc8xxx_add_controller(struct device_node *np)317{318struct mpc8xxx_gpio_chip *mpc8xxx_gc;319struct of_mm_gpio_chip *mm_gc;320struct gpio_chip *gc;321const struct of_device_id *id;322unsigned hwirq;323int ret;324325mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL);326if (!mpc8xxx_gc) {327ret = -ENOMEM;328goto err;329}330331spin_lock_init(&mpc8xxx_gc->lock);332333mm_gc = &mpc8xxx_gc->mm_gc;334gc = &mm_gc->gc;335336mm_gc->save_regs = mpc8xxx_gpio_save_regs;337gc->ngpio = MPC8XXX_GPIO_PINS;338gc->direction_input = mpc8xxx_gpio_dir_in;339gc->direction_output = mpc8xxx_gpio_dir_out;340if (of_device_is_compatible(np, "fsl,mpc8572-gpio"))341gc->get = mpc8572_gpio_get;342else343gc->get = mpc8xxx_gpio_get;344gc->set = mpc8xxx_gpio_set;345gc->to_irq = mpc8xxx_gpio_to_irq;346347ret = of_mm_gpiochip_add(np, mm_gc);348if (ret)349goto err;350351hwirq = irq_of_parse_and_map(np, 0);352if (hwirq == NO_IRQ)353goto skip_irq;354355mpc8xxx_gc->irq =356irq_alloc_host(np, IRQ_HOST_MAP_LINEAR, MPC8XXX_GPIO_PINS,357&mpc8xxx_gpio_irq_ops, MPC8XXX_GPIO_PINS);358if (!mpc8xxx_gc->irq)359goto skip_irq;360361id = of_match_node(mpc8xxx_gpio_ids, np);362if (id)363mpc8xxx_gc->of_dev_id_data = id->data;364365mpc8xxx_gc->irq->host_data = mpc8xxx_gc;366367/* ack and mask all irqs */368out_be32(mm_gc->regs + GPIO_IER, 0xffffffff);369out_be32(mm_gc->regs + GPIO_IMR, 0);370371irq_set_handler_data(hwirq, mpc8xxx_gc);372irq_set_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade);373374skip_irq:375return;376377err:378pr_err("%s: registration failed with status %d\n",379np->full_name, ret);380kfree(mpc8xxx_gc);381382return;383}384385static int __init mpc8xxx_add_gpiochips(void)386{387struct device_node *np;388389for_each_matching_node(np, mpc8xxx_gpio_ids)390mpc8xxx_add_controller(np);391392return 0;393}394arch_initcall(mpc8xxx_add_gpiochips);395396397