rendered paste body--- /home/ph5/scm/hh.o/linux/kernel26/include/linux/mfd/htc-egpio.h 2007-09-16 00:23:04.000000000 +0200+++ include/linux/mfd/htc-egpio.h 2007-11-24 21:51:37.000000000 +0100@@ -5,56 +5,54 @@ #ifndef __HTC_EGPIO_H__ #define __HTC_EGPIO_H__ -enum {- /* Maximum number of 16 bit registers a chip may have. */- MAX_EGPIO_REGS = 8,- /* Number of IRQS the EGPIO chip will claim. */- MAX_EGPIO_IRQS = 16,-};+#include <asm/gpio.h> -/* Available pin types. */-enum {- /* This pin corresponds to an input gpio */- HTC_EGPIO_TYPE_INPUT,- /* This pin corresponds to an output gpio */- HTC_EGPIO_TYPE_OUTPUT,-};+/* Descriptive values for all-in or all-out htc_egpio_chip descriptors. */+#define HTC_EGPIO_OUTPUT (~0)+#define HTC_EGPIO_INPUT 0 -/* Information on each pin on the chip. */-struct htc_egpio_pinInfo {- /* The gpio id of the pin (eg, gpio_base+18 is the third bit- * of the second register). */- int gpio;- /* The type - input, irq, output */- int type;- /* For output pins - the poweron default */- int output_initial;- /* For input pins with a corresponding irq, the irqs bit offset. */- int input_irq;+/**+ * struct htc_egpio_chip - descriptor to create gpio_chip for register range+ * @reg_start: index of first register+ * @gpio_base: gpio number of first pin in this register range+ * @num_gpios: number of gpios in this register range+ * (number of registers = DIV_ROUND_UP(num_gpios, reg_width))+ * @direction: bitfield, '0' = input, '1' = output,+ * this depends on ARCH_GPIOS_PER_CHIP not being greater than BITS_PER_LONG+ */+#if ARCH_GPIOS_PER_CHIP > BITS_PER_LONG+#error htc-egpio only works if ARCH_GPIOS_PER_CHIP <= BITS_PER_LONG+#endif+struct htc_egpio_chip {+ int reg_start;+ int gpio_base;+ int num_gpios;+ unsigned long direction;+ unsigned long initial_values; }; -/* Platform data description provided by the arch */+/**+ * struct htc_egpio_platform_data - description provided by the arch+ * @irq_base: beginning of available IRQs (eg, IRQ_BOARD_START)+ * @num_irqs: number of irqs+ * @reg_width: number of bits per register, either 8 or 16 bit+ * @bus_width: alignment of the registers, either 16 or 32 bit+ * @invert_acks: set if chip requires writing '0' to ack an irq, instead of '1'+ * @ack_register: location of the irq/ack register+ * @chip: pointer to array of htc_egpio_chip descriptors+ * @num_chips: number of egpio chip descriptors+ */ struct htc_egpio_platform_data {- /* Beginning of available irqs (eg, IRQ_BOARD_START) */- int irq_base;- /* Beginning of available gpios (eg, GPIO_BASE_INCREMENT) */- int gpio_base;- /* Shift register number by this value (bus_shift=1 for 32bit register alignment) */- int bus_shift;- /* Set if chip requires writing '0' to ack an irq */- int invertAcks;- /* Number of registers (optional if all output pins specified- * below) */- int nrRegs;- /* The location of the irq ack register */- int ackRegister;+ int bus_width;+ int reg_width; - /* List of pin descriptions. One must specify all input pins- * that have a corresponding irq pin and all output pins with- * a non-zero start value. Specifying other pins is- * optional. */- struct htc_egpio_pinInfo *pins;- int nr_pins;+ int irq_base;+ int num_irqs;+ int invert_acks;+ int ack_register;++ struct htc_egpio_chip *chip;+ int num_chips; }; /* Determine the wakeup irq, to be called during early resume */--- /home/ph5/scm/hh.o/linux/kernel26/drivers/mfd/htc-egpio.c 2007-11-18 14:47:55.000000000 +0100+++ drivers/mfd/htc-egpio.c 2007-11-24 21:51:39.000000000 +0100@@ -1,8 +1,9 @@ /*- * Support for the EGPIO chip present on several HTC phones. This+ * Support for the EGPIO chip present on several HTC phones. This * is believed to be related to the CPLD chip present on the board. * * (c) Copyright 2007 Kevin O'Connor <kevin@koconnor.net>+ * Copyright (c) 2007 Philipp Zabel <philipp.zabel@gmail.com> * * This file may be distributed under the terms of the GNU GPL license. */@@ -13,39 +14,49 @@ #include <linux/spinlock.h> /* spinlock_t */ #include <linux/platform_device.h> /* platform_device */ #include <linux/module.h>-#include <linux/gpiodev2.h> #include <linux/mfd/htc-egpio.h> #include <asm/irq.h> /* IRQT_RISING */ #include <asm/io.h> /* ioremap_nocache */ #include <asm/mach/irq.h> /* struct irq_chip */ +struct egpio_chip {+ int reg_start;+ struct gpio_chip chip;++ int cached_values;++ struct device *dev;+};+ struct egpio_info {- spinlock_t lock;- u16 *addrBase;- int bus_shift;+ spinlock_t lock;++ /* iomem info */+ void __iomem *base_addr;+ int bus_shift;+ int reg_width; /* irq info */- int ackRegister;- int ackWrite;- u16 irqsEnabled;- uint irqStart;- uint chainedirq;+ int ack_register;+ int ack_write;+ u16 irqs_enabled;+ uint irq_start;+ int num_irqs;+ uint chainedirq; - /* output info */- int maxRegs;- u16 cached_values[MAX_EGPIO_REGS];+ /* egpio info */+ struct egpio_chip *chip; }; --/****************************************************************- * Irqs- ****************************************************************/+/*+ * IRQs+ */ static inline void ackirqs(struct egpio_info *ei) {- writew(ei->ackWrite, &ei->addrBase[ei->ackRegister << ei->bus_shift]);- /* printk("EGPIO ack\n"); */+ writew(ei->ack_write, ei->base_addr + (ei->ack_register << ei->bus_shift));+ printk("EGPIO ack - write %x to %x\n", ei->ack_write, ei->ack_register << ei->bus_shift); } /* There does not appear to be a way to proactively mask interrupts@@ -54,14 +65,14 @@ static void egpio_mask(unsigned int irq) { struct egpio_info *ei = get_irq_chip_data(irq);- ei->irqsEnabled &= ~(1 << (irq - ei->irqStart));- /* printk("EGPIO mask %d %04x\n", irq, ei->irqsEnabled); */+ ei->irqs_enabled &= ~(1 << (irq - ei->irq_start));+ printk("EGPIO mask %d %04x\n", irq, ei->irqs_enabled); } static void egpio_unmask(unsigned int irq) { struct egpio_info *ei = get_irq_chip_data(irq);- ei->irqsEnabled |= 1 << (irq - ei->irqStart);- /* printk("EGPIO unmask %d %04x\n", irq, ei->irqsEnabled); */+ ei->irqs_enabled |= 1 << (irq - ei->irq_start);+ printk("EGPIO unmask %d %04x\n", irq, ei->irqs_enabled); } static struct irq_chip egpio_muxed_chip = {@@ -76,15 +87,16 @@ int irqpin; /* Read current pins. */- u16 readval = readw(&ei->addrBase[ei->ackRegister << ei->bus_shift]);+ unsigned long readval = readw(ei->base_addr + (ei->ack_register << ei->bus_shift));+ printk("IRQ reg: %x\n", readval); /* Ack/unmask interrupts. */ ackirqs(ei); /* Process all set pins. */- for (irqpin=0; irqpin<MAX_EGPIO_IRQS; irqpin++) {- if (!(readval & ei->irqsEnabled & (1<<irqpin)))- continue;+ readval &= ei->irqs_enabled;+ for_each_bit(irqpin, &readval, ei->num_irqs) { /* Run irq handler */- irq = ei->irqStart + irqpin;+ printk("got IRQ %d\n", irqpin);+ irq = ei->irq_start + irqpin; desc = &irq_desc[irq]; desc->handle_irq(irq, desc); }@@ -93,128 +105,127 @@ int htc_egpio_get_wakeup_irq(struct device *dev) { struct egpio_info *ei = dev_get_drvdata(dev);- int irqpin; /* Read current pins. */- u16 readval = readw(&ei->addrBase[ei->ackRegister << ei->bus_shift]);+ u16 readval = readw(ei->base_addr + (ei->ack_register << ei->bus_shift)); /* Ack/unmask interrupts. */ ackirqs(ei);- /* Process all set pins. */- for (irqpin=0; irqpin<MAX_EGPIO_IRQS; irqpin++) {- if (!(readval & ei->irqsEnabled & (1<<irqpin)))- continue;- /* Return first irq */- return ei->irqStart + irqpin;- }- return 0;+ /* Return first set pin. */+ readval &= ei->irqs_enabled;+ return ei->irq_start + ffs(readval) - 1; } EXPORT_SYMBOL(htc_egpio_get_wakeup_irq); -/****************************************************************+/* * Input pins- ****************************************************************/+ */ -static inline int u16pos(int bit) {- return bit/16;+static inline int egpio_pos(int bit, int reg_width)+{+ return bit/reg_width; }-static inline int u16bit(int bit) {- return 1<<(bit & (16-1));++static inline int egpio_bit(int bit, int reg_width)+{+ return 1<<(bit & (reg_width-1)); } /* Check an input pin to see if it is active. */-static int egpio_get(struct device *dev, unsigned gpio)+static int egpio_get(struct gpio_chip *chip, unsigned offset) {- unsigned bit = gpio & GPIO_BASE_MASK;- struct egpio_info *ei = dev_get_drvdata(dev);- u16 readval = readw(&ei->addrBase[u16pos(bit) << ei->bus_shift]);- return readval & u16bit(bit);+ struct egpio_chip *egpio;+ struct egpio_info *ei;+ unsigned bit;+ int reg;+ int value;++ printk(KERN_INFO "egpio_get_value(%d)\n", chip->base + offset);++ egpio = container_of(chip, struct egpio_chip, chip);+ ei = dev_get_drvdata(egpio->dev);+ bit = egpio_bit(offset, ei->reg_width);+ reg = egpio->reg_start + egpio_pos(offset, ei->reg_width);++ value = readw(ei->base_addr + (reg << ei->bus_shift));+ printk(KERN_INFO "readw(%p + %x) = %x\n", ei->base_addr, reg << ei->bus_shift, value);+ return value & bit; } -static int egpio_to_irq(struct device *dev, unsigned gpio_no)+static int egpio_direction_input(struct gpio_chip *chip, unsigned offset) {- struct egpio_info *ei = dev_get_drvdata(dev);- struct htc_egpio_platform_data *pdata = dev->platform_data;- int i;- for (i=0; i<pdata->nr_pins; i++) {- struct htc_egpio_pinInfo *pi = &pdata->pins[i];- if (pi->type == HTC_EGPIO_TYPE_INPUT- && pi->gpio == gpio_no- && pi->input_irq >= 0)- return (pi->input_irq & 0xf) + ei->irqStart;- }- return -ENODEV;+ return test_bit(offset, chip->is_out) ? -EINVAL : 0; } -/****************************************************************+/* * Output pins- ****************************************************************/+ */ -static void egpio_set(struct device *dev, unsigned gpio, int val)+static void egpio_set(struct gpio_chip *chip, unsigned offset, int value) {- unsigned bit = gpio & GPIO_BASE_MASK;- struct egpio_info *ei = dev_get_drvdata(dev);- int pos = u16pos(bit);- unsigned long flag;+ unsigned long flag;+ struct egpio_chip *egpio;+ struct egpio_info *ei;+ unsigned bit;+ int pos;+ int reg;+ int mask;+ int shift;++ printk(KERN_INFO "egpio_set(%s, %d(%d), %d)\n", chip->label, offset, offset+chip->base, value);++ egpio = container_of(chip, struct egpio_chip, chip);+ ei = dev_get_drvdata(egpio->dev);+ bit = egpio_bit(offset, ei->reg_width);+ pos = egpio_pos(offset, ei->reg_width);+ reg = egpio->reg_start + pos; spin_lock_irqsave(&ei->lock, flag);- if (val) {- ei->cached_values[pos] |= u16bit(bit);- printk("egpio set: reg %d = 0x%04x\n"- , pos, ei->cached_values[pos]);+ if (value) {+ egpio->cached_values |= (1 << offset);+ printk(KERN_INFO "egpio set: reg %d = 0x%04x\n",+ reg, egpio->cached_values); } else {- ei->cached_values[pos] &= ~u16bit(bit);- printk("egpio clear: reg %d = 0x%04x\n"- , pos, ei->cached_values[pos]);+ egpio->cached_values &= ~(1 << offset);+ printk(KERN_INFO "egpio clear: reg %d = 0x%04x\n",+ reg, egpio->cached_values); }- writew(ei->cached_values[pos], &ei->addrBase[pos << ei->bus_shift]);++ mask = ((1 << ei->reg_width) - 1);+ shift = ei->reg_width * pos;+ printk("writew(%x, %p + %x)\n", (egpio->cached_values >> shift) & mask,+ ei->base_addr, (pos << ei->bus_shift));+ writew((egpio->cached_values >> shift) & mask,+ ei->base_addr + (pos << ei->bus_shift)); spin_unlock_irqrestore(&ei->lock, flag); } +static int egpio_direction_output(struct gpio_chip *chip,+ unsigned offset, int value)+{+ if (test_bit(offset, chip->is_out)) {+ egpio_set(chip, offset, value);+ return 0;+ } else {+ return -EINVAL;+ }+}+ /**************************************************************** * Setup ****************************************************************/ -static void setup_pin(struct egpio_info *ei, struct htc_egpio_pinInfo *pi)-{- int pin = pi->gpio & GPIO_BASE_MASK;-- if (pi->gpio < 0 || pin > 16*MAX_EGPIO_REGS) {- printk(KERN_ERR "EGPIO invalid pin %d\n", pi->gpio);- return;- }-- switch (pi->type) {- case HTC_EGPIO_TYPE_INPUT:- if (pi->input_irq < 0)- break;- pin = pi->input_irq & GPIO_BASE_MASK;- if (ei->ackRegister != u16pos(pin)) {- printk(KERN_ERR "EGPIO irq conflict %d vs %d\n"- , ei->ackRegister, u16pos(pin));- return;- }- break;- case HTC_EGPIO_TYPE_OUTPUT:- if (ei->maxRegs < u16pos(pin))- ei->maxRegs = u16pos(pin);- if (pi->output_initial)- ei->cached_values[u16pos(pin)] |= u16bit(pin);- break;- default:- printk(KERN_ERR "EGPIO unknown type %d\n", pi->type);- }-}- static int egpio_probe(struct platform_device *pdev) { struct htc_egpio_platform_data *pdata = pdev->dev.platform_data;- struct resource *res;+ struct resource *res; struct egpio_info *ei;- int irq, i, ret;- struct gpio_ops ops;+ struct gpio_chip *chip;+ int irq;+ int i;+ int ret; /* Initialize ei data structure. */ ei = kzalloc(sizeof(*ei), GFP_KERNEL);@@ -233,33 +244,57 @@ res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) goto fail;- ei->addrBase = (u16 *)ioremap_nocache(res->start, res->end - res->start);- if (!ei->addrBase)+ ei->base_addr = ioremap_nocache(res->start, res->end - res->start);+ if (!ei->base_addr) goto fail;- printk(KERN_NOTICE "EGPIO phys=%08x virt=%p\n"- , res->start, ei->addrBase);- ei->bus_shift = pdata->bus_shift;-+ printk(KERN_NOTICE "EGPIO phys=%08x virt=%p\n",+ res->start, ei->base_addr);+ ei->bus_shift = fls(pdata->bus_width - 1) - 3;+ printk("BUS_SHIFT = %d\n", ei->bus_shift);+ ei->reg_width = pdata->reg_width; platform_set_drvdata(pdev, ei); - ops.get_value = egpio_get;- ops.set_value = egpio_set;- ops.to_irq = egpio_to_irq;- gpiodev_register(pdata->gpio_base, &pdev->dev, &ops);+ ei->chip = kzalloc(sizeof(struct egpio_chip) * pdata->num_chips, GFP_KERNEL);+ if (!ei) {+ ret = -ENOMEM;+ goto fail;+ }+ for (i = 0; i < pdata->num_chips; i++) {+ ei->chip[i].reg_start = pdata->chip[i].reg_start;+ ei->chip[i].cached_values = pdata->chip[i].initial_values;+ ei->chip[i].dev = &(pdev->dev);+ chip = &(ei->chip[i].chip);+ chip->label = "htc-egpio";+ chip->get = egpio_get;+ chip->set = egpio_set;+ chip->direction_input = egpio_direction_input;+ chip->direction_output = egpio_direction_output; - /* Go through list of pins. */- ei->irqStart = pdata->irq_base;- ei->maxRegs = pdata->nrRegs - 1;- ei->ackRegister = pdata->ackRegister;- for (i = 0; i < pdata->nr_pins; i++)- setup_pin(ei, &pdata->pins[i]);+ chip->base = pdata->chip[i].gpio_base;+ chip->ngpio = pdata->chip[i].num_gpios;+ /* only gpiolib is supposed to modify is_out, doesn't stop us */+ chip->is_out[0] = pdata->chip[i].direction;++ gpiochip_add(chip);+ }++#if 0+ /* Setup initial output pin values. */+ if (pdata->chip[i].type == HTC_EGPIO_TYPE_OUTPUT) {+ printk("egpio read: reg %d\n", reg); pdata->chip[i].cached_values+ }+#endif++ ei->irq_start = pdata->irq_base;+ ei->num_irqs = pdata->num_irqs;+ ei->ack_register = pdata->ack_register; if (ei->chainedirq) { /* Setup irq handlers */- ei->ackWrite = 0xFFFF;- if (pdata->invertAcks)- ei->ackWrite = 0;- for (irq = ei->irqStart; irq < ei->irqStart+MAX_EGPIO_IRQS; irq++) {+ ei->ack_write = 0xFFFF;+ if (pdata->invert_acks)+ ei->ack_write = 0;+ for (irq = ei->irq_start; irq < ei->irq_start+ei->num_irqs; irq++) { set_irq_chip(irq, &egpio_muxed_chip); set_irq_chip_data(irq, ei); set_irq_handler(irq, handle_simple_irq);@@ -273,11 +308,6 @@ device_init_wakeup(&pdev->dev, 1); } - /* Setup initial output pin values. */- for (i = 0; i<=ei->maxRegs; i++)- if (i != ei->ackRegister)- writew(ei->cached_values[i], &ei->addrBase[i << ei->bus_shift]);- return 0; fail:@@ -291,7 +321,7 @@ struct egpio_info *ei = platform_get_drvdata(pdev); unsigned int irq; if (ei->chainedirq) {- for (irq = ei->irqStart; irq < ei->irqStart+MAX_EGPIO_IRQS; irq++) {+ for (irq = ei->irq_start; irq < ei->irq_start+ei->num_irqs; irq++) { set_irq_chip(irq, NULL); set_irq_handler(irq, NULL); set_irq_flags(irq, 0);@@ -299,7 +329,8 @@ set_irq_chained_handler(ei->chainedirq, NULL); device_init_wakeup(&pdev->dev, 0); }- iounmap(ei->addrBase);+ iounmap(ei->base_addr);+ kfree(ei->chip); kfree(ei); return 0;@@ -349,11 +380,8 @@ platform_driver_unregister(&egpio_driver); } -#ifdef MODULE-module_init(egpio_init);-#else /* start early for dependencies */+/* start early for dependencies */ subsys_initcall(egpio_init);-#endif module_exit(egpio_exit) MODULE_LICENSE("GPL");