|
@@ -16,82 +16,275 @@
|
|
|
#ifndef mcfgpio_h
|
|
|
#define mcfgpio_h
|
|
|
|
|
|
-#include <linux/io.h>
|
|
|
+#ifdef CONFIG_GPIOLIB
|
|
|
#include <asm-generic/gpio.h>
|
|
|
+#else
|
|
|
+
|
|
|
+int __mcfgpio_get_value(unsigned gpio);
|
|
|
+void __mcfgpio_set_value(unsigned gpio, int value);
|
|
|
+int __mcfgpio_direction_input(unsigned gpio);
|
|
|
+int __mcfgpio_direction_output(unsigned gpio, int value);
|
|
|
+int __mcfgpio_request(unsigned gpio);
|
|
|
+void __mcfgpio_free(unsigned gpio);
|
|
|
+
|
|
|
+/* our alternate 'gpiolib' functions */
|
|
|
+static inline int __gpio_get_value(unsigned gpio)
|
|
|
+{
|
|
|
+ if (gpio < MCFGPIO_PIN_MAX)
|
|
|
+ return __mcfgpio_get_value(gpio);
|
|
|
+ else
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+static inline void __gpio_set_value(unsigned gpio, int value)
|
|
|
+{
|
|
|
+ if (gpio < MCFGPIO_PIN_MAX)
|
|
|
+ __mcfgpio_set_value(gpio, value);
|
|
|
+}
|
|
|
+
|
|
|
+static inline int __gpio_cansleep(unsigned gpio)
|
|
|
+{
|
|
|
+ if (gpio < MCFGPIO_PIN_MAX)
|
|
|
+ return 0;
|
|
|
+ else
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+static inline int __gpio_to_irq(unsigned gpio)
|
|
|
+{
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+static inline int gpio_direction_input(unsigned gpio)
|
|
|
+{
|
|
|
+ if (gpio < MCFGPIO_PIN_MAX)
|
|
|
+ return __mcfgpio_direction_input(gpio);
|
|
|
+ else
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+static inline int gpio_direction_output(unsigned gpio, int value)
|
|
|
+{
|
|
|
+ if (gpio < MCFGPIO_PIN_MAX)
|
|
|
+ return __mcfgpio_direction_output(gpio, value);
|
|
|
+ else
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+static inline int gpio_request(unsigned gpio, const char *label)
|
|
|
+{
|
|
|
+ if (gpio < MCFGPIO_PIN_MAX)
|
|
|
+ return __mcfgpio_request(gpio);
|
|
|
+ else
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+static inline void gpio_free(unsigned gpio)
|
|
|
+{
|
|
|
+ if (gpio < MCFGPIO_PIN_MAX)
|
|
|
+ __mcfgpio_free(gpio);
|
|
|
+}
|
|
|
+
|
|
|
+#endif /* CONFIG_GPIOLIB */
|
|
|
|
|
|
-struct mcf_gpio_chip {
|
|
|
- struct gpio_chip gpio_chip;
|
|
|
- void __iomem *pddr;
|
|
|
- void __iomem *podr;
|
|
|
- void __iomem *ppdr;
|
|
|
- void __iomem *setr;
|
|
|
- void __iomem *clrr;
|
|
|
- const u8 *gpio_to_pinmux;
|
|
|
-};
|
|
|
-
|
|
|
-extern struct mcf_gpio_chip mcf_gpio_chips[];
|
|
|
-extern unsigned int mcf_gpio_chips_size;
|
|
|
-
|
|
|
-int mcf_gpio_direction_input(struct gpio_chip *, unsigned);
|
|
|
-int mcf_gpio_get_value(struct gpio_chip *, unsigned);
|
|
|
-int mcf_gpio_direction_output(struct gpio_chip *, unsigned, int);
|
|
|
-void mcf_gpio_set_value(struct gpio_chip *, unsigned, int);
|
|
|
-void mcf_gpio_set_value_fast(struct gpio_chip *, unsigned, int);
|
|
|
-int mcf_gpio_request(struct gpio_chip *, unsigned);
|
|
|
-void mcf_gpio_free(struct gpio_chip *, unsigned);
|
|
|
|
|
|
/*
|
|
|
- * Define macros to ease the pain of setting up the GPIO tables. There
|
|
|
- * are two cases we need to deal with here, they cover all currently
|
|
|
- * available ColdFire GPIO hardware. There are of course minor differences
|
|
|
- * in the layout and number of bits in each ColdFire part, but the macros
|
|
|
- * take all that in.
|
|
|
+ * The Freescale Coldfire family is quite varied in how they implement GPIO.
|
|
|
+ * Some parts have 8 bit ports, some have 16bit and some have 32bit; some have
|
|
|
+ * only one port, others have multiple ports; some have a single data latch
|
|
|
+ * for both input and output, others have a separate pin data register to read
|
|
|
+ * input; some require a read-modify-write access to change an output, others
|
|
|
+ * have set and clear registers for some of the outputs; Some have all the
|
|
|
+ * GPIOs in a single control area, others have some GPIOs implemented in
|
|
|
+ * different modules.
|
|
|
*
|
|
|
- * Firstly is the conventional GPIO registers where we toggle individual
|
|
|
- * bits in a register, preserving the other bits in the register. For
|
|
|
- * lack of a better term I have called this the slow method.
|
|
|
+ * This implementation attempts accommodate the differences while presenting
|
|
|
+ * a generic interface that will optimize to as few instructions as possible.
|
|
|
*/
|
|
|
-#define MCFGPS(mlabel, mbase, mngpio, mpddr, mpodr, mppdr) \
|
|
|
- { \
|
|
|
- .gpio_chip = { \
|
|
|
- .label = #mlabel, \
|
|
|
- .request = mcf_gpio_request, \
|
|
|
- .free = mcf_gpio_free, \
|
|
|
- .direction_input = mcf_gpio_direction_input, \
|
|
|
- .direction_output = mcf_gpio_direction_output,\
|
|
|
- .get = mcf_gpio_get_value, \
|
|
|
- .set = mcf_gpio_set_value, \
|
|
|
- .base = mbase, \
|
|
|
- .ngpio = mngpio, \
|
|
|
- }, \
|
|
|
- .pddr = (void __iomem *) mpddr, \
|
|
|
- .podr = (void __iomem *) mpodr, \
|
|
|
- .ppdr = (void __iomem *) mppdr, \
|
|
|
- }
|
|
|
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
|
|
|
+ defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
|
|
|
+ defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
|
|
|
+ defined(CONFIG_M532x) || defined(CONFIG_M54xx)
|
|
|
+
|
|
|
+/* These parts have GPIO organized by 8 bit ports */
|
|
|
+
|
|
|
+#define MCFGPIO_PORTTYPE u8
|
|
|
+#define MCFGPIO_PORTSIZE 8
|
|
|
+#define mcfgpio_read(port) __raw_readb(port)
|
|
|
+#define mcfgpio_write(data, port) __raw_writeb(data, port)
|
|
|
+
|
|
|
+#elif defined(CONFIG_M5307) || defined(CONFIG_M5407) || defined(CONFIG_M5272)
|
|
|
+
|
|
|
+/* These parts have GPIO organized by 16 bit ports */
|
|
|
+
|
|
|
+#define MCFGPIO_PORTTYPE u16
|
|
|
+#define MCFGPIO_PORTSIZE 16
|
|
|
+#define mcfgpio_read(port) __raw_readw(port)
|
|
|
+#define mcfgpio_write(data, port) __raw_writew(data, port)
|
|
|
+
|
|
|
+#elif defined(CONFIG_M5249)
|
|
|
+
|
|
|
+/* These parts have GPIO organized by 32 bit ports */
|
|
|
+
|
|
|
+#define MCFGPIO_PORTTYPE u32
|
|
|
+#define MCFGPIO_PORTSIZE 32
|
|
|
+#define mcfgpio_read(port) __raw_readl(port)
|
|
|
+#define mcfgpio_write(data, port) __raw_writel(data, port)
|
|
|
+
|
|
|
+#endif
|
|
|
|
|
|
+#define mcfgpio_bit(gpio) (1 << ((gpio) % MCFGPIO_PORTSIZE))
|
|
|
+#define mcfgpio_port(gpio) ((gpio) / MCFGPIO_PORTSIZE)
|
|
|
+
|
|
|
+#if defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
|
|
|
+ defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x)
|
|
|
+/*
|
|
|
+ * These parts have an 'Edge' Port module (external interrupt/GPIO) which uses
|
|
|
+ * read-modify-write to change an output and a GPIO module which has separate
|
|
|
+ * set/clr registers to directly change outputs with a single write access.
|
|
|
+ */
|
|
|
+#if defined(CONFIG_M528x)
|
|
|
/*
|
|
|
- * Secondly is the faster case, where we have set and clear registers
|
|
|
- * that allow us to set or clear a bit with a single write, not having
|
|
|
- * to worry about preserving other bits.
|
|
|
+ * The 528x also has GPIOs in other modules (GPT, QADC) which use
|
|
|
+ * read-modify-write as well as those controlled by the EPORT and GPIO modules.
|
|
|
*/
|
|
|
-#define MCFGPF(mlabel, mbase, mngpio) \
|
|
|
- { \
|
|
|
- .gpio_chip = { \
|
|
|
- .label = #mlabel, \
|
|
|
- .request = mcf_gpio_request, \
|
|
|
- .free = mcf_gpio_free, \
|
|
|
- .direction_input = mcf_gpio_direction_input, \
|
|
|
- .direction_output = mcf_gpio_direction_output,\
|
|
|
- .get = mcf_gpio_get_value, \
|
|
|
- .set = mcf_gpio_set_value_fast, \
|
|
|
- .base = mbase, \
|
|
|
- .ngpio = mngpio, \
|
|
|
- }, \
|
|
|
- .pddr = (void __iomem *) MCFGPIO_PDDR_##mlabel, \
|
|
|
- .podr = (void __iomem *) MCFGPIO_PODR_##mlabel, \
|
|
|
- .ppdr = (void __iomem *) MCFGPIO_PPDSDR_##mlabel, \
|
|
|
- .setr = (void __iomem *) MCFGPIO_PPDSDR_##mlabel, \
|
|
|
- .clrr = (void __iomem *) MCFGPIO_PCLRR_##mlabel, \
|
|
|
- }
|
|
|
+#define MCFGPIO_SCR_START 40
|
|
|
+#else
|
|
|
+#define MCFGPIO_SCR_START 8
|
|
|
+#endif
|
|
|
+
|
|
|
+#define MCFGPIO_SETR_PORT(gpio) (MCFGPIO_SETR + \
|
|
|
+ mcfgpio_port(gpio - MCFGPIO_SCR_START))
|
|
|
+
|
|
|
+#define MCFGPIO_CLRR_PORT(gpio) (MCFGPIO_CLRR + \
|
|
|
+ mcfgpio_port(gpio - MCFGPIO_SCR_START))
|
|
|
+#else
|
|
|
+
|
|
|
+#define MCFGPIO_SCR_START MCFGPIO_PIN_MAX
|
|
|
+/* with MCFGPIO_SCR == MCFGPIO_PIN_MAX, these will be optimized away */
|
|
|
+#define MCFGPIO_SETR_PORT(gpio) 0
|
|
|
+#define MCFGPIO_CLRR_PORT(gpio) 0
|
|
|
|
|
|
#endif
|
|
|
+/*
|
|
|
+ * Coldfire specific helper functions
|
|
|
+ */
|
|
|
+
|
|
|
+/* return the port pin data register for a gpio */
|
|
|
+static inline u32 __mcfgpio_ppdr(unsigned gpio)
|
|
|
+{
|
|
|
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
|
|
|
+ defined(CONFIG_M5307) || defined(CONFIG_M5407)
|
|
|
+ return MCFSIM_PADAT;
|
|
|
+#elif defined(CONFIG_M5272)
|
|
|
+ if (gpio < 16)
|
|
|
+ return MCFSIM_PADAT;
|
|
|
+ else if (gpio < 32)
|
|
|
+ return MCFSIM_PBDAT;
|
|
|
+ else
|
|
|
+ return MCFSIM_PCDAT;
|
|
|
+#elif defined(CONFIG_M5249)
|
|
|
+ if (gpio < 32)
|
|
|
+ return MCFSIM2_GPIOREAD;
|
|
|
+ else
|
|
|
+ return MCFSIM2_GPIO1READ;
|
|
|
+#elif defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
|
|
|
+ defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x)
|
|
|
+ if (gpio < 8)
|
|
|
+ return MCFEPORT_EPPDR;
|
|
|
+#if defined(CONFIG_M528x)
|
|
|
+ else if (gpio < 16)
|
|
|
+ return MCFGPTA_GPTPORT;
|
|
|
+ else if (gpio < 24)
|
|
|
+ return MCFGPTB_GPTPORT;
|
|
|
+ else if (gpio < 32)
|
|
|
+ return MCFQADC_PORTQA;
|
|
|
+ else if (gpio < 40)
|
|
|
+ return MCFQADC_PORTQB;
|
|
|
+#endif
|
|
|
+ else
|
|
|
+ return MCFGPIO_PPDR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
|
|
|
+#else
|
|
|
+ return 0;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+/* return the port output data register for a gpio */
|
|
|
+static inline u32 __mcfgpio_podr(unsigned gpio)
|
|
|
+{
|
|
|
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
|
|
|
+ defined(CONFIG_M5307) || defined(CONFIG_M5407)
|
|
|
+ return MCFSIM_PADAT;
|
|
|
+#elif defined(CONFIG_M5272)
|
|
|
+ if (gpio < 16)
|
|
|
+ return MCFSIM_PADAT;
|
|
|
+ else if (gpio < 32)
|
|
|
+ return MCFSIM_PBDAT;
|
|
|
+ else
|
|
|
+ return MCFSIM_PCDAT;
|
|
|
+#elif defined(CONFIG_M5249)
|
|
|
+ if (gpio < 32)
|
|
|
+ return MCFSIM2_GPIOWRITE;
|
|
|
+ else
|
|
|
+ return MCFSIM2_GPIO1WRITE;
|
|
|
+#elif defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
|
|
|
+ defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x)
|
|
|
+ if (gpio < 8)
|
|
|
+ return MCFEPORT_EPDR;
|
|
|
+#if defined(CONFIG_M528x)
|
|
|
+ else if (gpio < 16)
|
|
|
+ return MCFGPTA_GPTPORT;
|
|
|
+ else if (gpio < 24)
|
|
|
+ return MCFGPTB_GPTPORT;
|
|
|
+ else if (gpio < 32)
|
|
|
+ return MCFQADC_PORTQA;
|
|
|
+ else if (gpio < 40)
|
|
|
+ return MCFQADC_PORTQB;
|
|
|
+#endif
|
|
|
+ else
|
|
|
+ return MCFGPIO_PODR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
|
|
|
+#else
|
|
|
+ return 0;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+/* return the port direction data register for a gpio */
|
|
|
+static inline u32 __mcfgpio_pddr(unsigned gpio)
|
|
|
+{
|
|
|
+#if defined(CONFIG_M5206) || defined(CONFIG_M5206e) || \
|
|
|
+ defined(CONFIG_M5307) || defined(CONFIG_M5407)
|
|
|
+ return MCFSIM_PADDR;
|
|
|
+#elif defined(CONFIG_M5272)
|
|
|
+ if (gpio < 16)
|
|
|
+ return MCFSIM_PADDR;
|
|
|
+ else if (gpio < 32)
|
|
|
+ return MCFSIM_PBDDR;
|
|
|
+ else
|
|
|
+ return MCFSIM_PCDDR;
|
|
|
+#elif defined(CONFIG_M5249)
|
|
|
+ if (gpio < 32)
|
|
|
+ return MCFSIM2_GPIOENABLE;
|
|
|
+ else
|
|
|
+ return MCFSIM2_GPIO1ENABLE;
|
|
|
+#elif defined(CONFIG_M520x) || defined(CONFIG_M523x) || \
|
|
|
+ defined(CONFIG_M527x) || defined(CONFIG_M528x) || defined(CONFIG_M532x)
|
|
|
+ if (gpio < 8)
|
|
|
+ return MCFEPORT_EPDDR;
|
|
|
+#if defined(CONFIG_M528x)
|
|
|
+ else if (gpio < 16)
|
|
|
+ return MCFGPTA_GPTDDR;
|
|
|
+ else if (gpio < 24)
|
|
|
+ return MCFGPTB_GPTDDR;
|
|
|
+ else if (gpio < 32)
|
|
|
+ return MCFQADC_DDRQA;
|
|
|
+ else if (gpio < 40)
|
|
|
+ return MCFQADC_DDRQB;
|
|
|
+#endif
|
|
|
+ else
|
|
|
+ return MCFGPIO_PDDR + mcfgpio_port(gpio - MCFGPIO_SCR_START);
|
|
|
+#else
|
|
|
+ return 0;
|
|
|
+#endif
|
|
|
+}
|
|
|
+
|
|
|
+#endif /* mcfgpio_h */
|