cregit-Linux how code gets into the kernel

Release 4.11 arch/arm/mach-pxa/mfp-pxa2xx.c

/*
 *  linux/arch/arm/mach-pxa/mfp-pxa2xx.c
 *
 *  PXA2xx pin mux configuration support
 *
 *  The GPIOs on PXA2xx can be configured as one of many alternate
 *  functions, this is by concept samilar to the MFP configuration
 *  on PXA3xx,  what's more important, the low power pin state and
 *  wakeup detection are also supported by the same framework.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 */
#include <linux/gpio.h>
#include <linux/gpio-pxa.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/syscore_ops.h>

#include <mach/pxa2xx-regs.h>
#include "mfp-pxa2xx.h"

#include "generic.h"


#define PGSR(x)		__REG2(0x40F00020, (x) << 2)

#define __GAFR(u, x)	__REG2((u) ? 0x40E00058 : 0x40E00054, (x) << 3)

#define GAFR_L(x)	__GAFR(0, x)

#define GAFR_U(x)	__GAFR(1, x)


#define BANK_OFF(n)	(((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2))

#define GPLR(x)		__REG2(0x40E00000, BANK_OFF((x) >> 5))

#define GPDR(x)		__REG2(0x40E00000, BANK_OFF((x) >> 5) + 0x0c)

#define GPSR(x)		__REG2(0x40E00000, BANK_OFF((x) >> 5) + 0x18)

#define GPCR(x)		__REG2(0x40E00000, BANK_OFF((x) >> 5) + 0x24)


#define PWER_WE35	(1 << 24)


struct gpio_desc {
	
unsigned	valid		: 1;
	
unsigned	can_wakeup	: 1;
	
unsigned	keypad_gpio	: 1;
	
unsigned	dir_inverted	: 1;
	
unsigned int	mask; /* bit mask in PWER or PKWR */
	
unsigned int	mux_mask; /* bit mask of muxed gpio bits, 0 if no mux */
	
unsigned long	config;
};


static struct gpio_desc gpio_desc[MFP_PIN_GPIO127 + 1];


static unsigned long gpdr_lpm[4];


static int __mfp_config_gpio(unsigned gpio, unsigned long c) { unsigned long gafr, mask = GPIO_bit(gpio); int bank = gpio_to_bank(gpio); int uorl = !!(gpio & 0x10); /* GAFRx_U or GAFRx_L ? */ int shft = (gpio & 0xf) << 1; int fn = MFP_AF(c); int is_out = (c & MFP_DIR_OUT) ? 1 : 0; if (fn > 3) return -EINVAL; /* alternate function and direction at run-time */ gafr = (uorl == 0) ? GAFR_L(bank) : GAFR_U(bank); gafr = (gafr & ~(0x3 << shft)) | (fn << shft); if (uorl == 0) GAFR_L(bank) = gafr; else GAFR_U(bank) = gafr; if (is_out ^ gpio_desc[gpio].dir_inverted) GPDR(gpio) |= mask; else GPDR(gpio) &= ~mask; /* alternate function and direction at low power mode */ switch (c & MFP_LPM_STATE_MASK) { case MFP_LPM_DRIVE_HIGH: PGSR(bank) |= mask; is_out = 1; break; case MFP_LPM_DRIVE_LOW: PGSR(bank) &= ~mask; is_out = 1; break; case MFP_LPM_INPUT: case MFP_LPM_DEFAULT: break; default: /* warning and fall through, treat as MFP_LPM_DEFAULT */ pr_warn("%s: GPIO%d: unsupported low power mode\n", __func__, gpio); break; } if (is_out ^ gpio_desc[gpio].dir_inverted) gpdr_lpm[bank] |= mask; else gpdr_lpm[bank] &= ~mask; /* give early warning if MFP_LPM_CAN_WAKEUP is set on the * configurations of those pins not able to wakeup */ if ((c & MFP_LPM_CAN_WAKEUP) && !gpio_desc[gpio].can_wakeup) { pr_warn("%s: GPIO%d unable to wakeup\n", __func__, gpio); return -EINVAL; } if ((c & MFP_LPM_CAN_WAKEUP) && is_out) { pr_warn("%s: output GPIO%d unable to wakeup\n", __func__, gpio); return -EINVAL; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Miao31599.06%685.71%
Joe Perches30.94%114.29%
Total318100.00%7100.00%


static inline int __mfp_validate(int mfp) { int gpio = mfp_to_gpio(mfp); if ((mfp > MFP_PIN_GPIO127) || !gpio_desc[gpio].valid) { pr_warn("%s: GPIO%d is invalid pin\n", __func__, gpio); return -1; } return gpio; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Miao5198.08%150.00%
Joe Perches11.92%150.00%
Total52100.00%2100.00%


void pxa2xx_mfp_config(unsigned long *mfp_cfgs, int num) { unsigned long flags; unsigned long *c; int i, gpio; for (i = 0, c = mfp_cfgs; i < num; i++, c++) { gpio = __mfp_validate(MFP_PIN(*c)); if (gpio < 0) continue; local_irq_save(flags); gpio_desc[gpio].config = *c; __mfp_config_gpio(gpio, *c); local_irq_restore(flags); } }

Contributors

PersonTokensPropCommitsCommitProp
Eric Miao95100.00%2100.00%
Total95100.00%2100.00%


void pxa2xx_mfp_set_lpm(int mfp, unsigned long lpm) { unsigned long flags, c; int gpio; gpio = __mfp_validate(mfp); if (gpio < 0) return; local_irq_save(flags); c = gpio_desc[gpio].config; c = (c & ~MFP_LPM_STATE_MASK) | lpm; __mfp_config_gpio(gpio, c); local_irq_restore(flags); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Miao72100.00%2100.00%
Total72100.00%2100.00%


int gpio_set_wake(unsigned int gpio, unsigned int on) { struct gpio_desc *d; unsigned long c, mux_taken; if (gpio > mfp_to_gpio(MFP_PIN_GPIO127)) return -EINVAL; d = &gpio_desc[gpio]; c = d->config; if (!d->valid) return -EINVAL; /* Allow keypad GPIOs to wakeup system when * configured as generic GPIOs. */ if (d->keypad_gpio && (MFP_AF(d->config) == 0) && (d->config & MFP_LPM_CAN_WAKEUP)) { if (on) PKWR |= d->mask; else PKWR &= ~d->mask; return 0; } mux_taken = (PWER & d->mux_mask) & (~d->mask); if (on && mux_taken) return -EBUSY; if (d->can_wakeup && (c & MFP_LPM_CAN_WAKEUP)) { if (on) { PWER = (PWER & ~d->mux_mask) | d->mask; if (c & MFP_LPM_EDGE_RISE) PRER |= d->mask; else PRER &= ~d->mask; if (c & MFP_LPM_EDGE_FALL) PFER |= d->mask; else PFER &= ~d->mask; } else { PWER &= ~d->mask; PRER &= ~d->mask; PFER &= ~d->mask; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Miao20183.75%266.67%
Robert Jarzmik3916.25%133.33%
Total240100.00%3100.00%

#ifdef CONFIG_PXA25x
static void __init pxa25x_mfp_init(void) { int i; /* running before pxa_gpio_probe() */ #ifdef CONFIG_CPU_PXA26x pxa_last_gpio = 89; #else pxa_last_gpio = 84; #endif for (i = 0; i <= pxa_last_gpio; i++) gpio_desc[i].valid = 1; for (i = 0; i <= 15; i++) { gpio_desc[i].can_wakeup = 1; gpio_desc[i].mask = GPIO_bit(i); } /* PXA26x has additional 4 GPIOs (86/87/88/89) which has the * direction bit inverted in GPDR2. See PXA26x DM 4.1.1. */ for (i = 86; i <= pxa_last_gpio; i++) gpio_desc[i].dir_inverted = 1; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Miao9385.32%480.00%
Haojian Zhuang1614.68%120.00%
Total109100.00%5100.00%

#else
static inline void pxa25x_mfp_init(void) {}

Contributors

PersonTokensPropCommitsCommitProp
Eric Miao8100.00%2100.00%
Total8100.00%2100.00%

#endif /* CONFIG_PXA25x */ #ifdef CONFIG_PXA27x static int pxa27x_pkwr_gpio[] = { 13, 16, 17, 34, 36, 37, 38, 39, 90, 91, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102 };
int keypad_set_wake(unsigned int on) { unsigned int i, gpio, mask = 0; struct gpio_desc *d; for (i = 0; i < ARRAY_SIZE(pxa27x_pkwr_gpio); i++) { gpio = pxa27x_pkwr_gpio[i]; d = &gpio_desc[gpio]; /* skip if configured as generic GPIO */ if (MFP_AF(d->config) == 0) continue; if (d->config & MFP_LPM_CAN_WAKEUP) mask |= gpio_desc[gpio].mask; } if (on) PKWR |= mask; else PKWR &= ~mask; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Miao104100.00%2100.00%
Total104100.00%2100.00%

#define PWER_WEMUX2_GPIO38 (1 << 16) #define PWER_WEMUX2_GPIO53 (2 << 16) #define PWER_WEMUX2_GPIO40 (3 << 16) #define PWER_WEMUX2_GPIO36 (4 << 16) #define PWER_WEMUX2_MASK (7 << 16) #define PWER_WEMUX3_GPIO31 (1 << 19) #define PWER_WEMUX3_GPIO113 (2 << 19) #define PWER_WEMUX3_MASK (3 << 19) #define INIT_GPIO_DESC_MUXED(mux, gpio) \ do { \ gpio_desc[(gpio)].can_wakeup = 1; \ gpio_desc[(gpio)].mask = PWER_ ## mux ## _GPIO ##gpio; \ gpio_desc[(gpio)].mux_mask = PWER_ ## mux ## _MASK; \ } while (0)
static void __init pxa27x_mfp_init(void) { int i, gpio; pxa_last_gpio = 120; /* running before pxa_gpio_probe() */ for (i = 0; i <= pxa_last_gpio; i++) { /* skip GPIO2, 5, 6, 7, 8, they are not * valid pins allow configuration */ if (i == 2 || i == 5 || i == 6 || i == 7 || i == 8) continue; gpio_desc[i].valid = 1; } /* Keypad GPIOs */ for (i = 0; i < ARRAY_SIZE(pxa27x_pkwr_gpio); i++) { gpio = pxa27x_pkwr_gpio[i]; gpio_desc[gpio].can_wakeup = 1; gpio_desc[gpio].keypad_gpio = 1; gpio_desc[gpio].mask = 1 << i; } /* Overwrite GPIO13 as a PWER wakeup source */ for (i = 0; i <= 15; i++) { /* skip GPIO2, 5, 6, 7, 8 */ if (GPIO_bit(i) & 0x1e4) continue; gpio_desc[i].can_wakeup = 1; gpio_desc[i].mask = GPIO_bit(i); } gpio_desc[35].can_wakeup = 1; gpio_desc[35].mask = PWER_WE35; INIT_GPIO_DESC_MUXED(WEMUX3, 31); INIT_GPIO_DESC_MUXED(WEMUX3, 113); INIT_GPIO_DESC_MUXED(WEMUX2, 38); INIT_GPIO_DESC_MUXED(WEMUX2, 53); INIT_GPIO_DESC_MUXED(WEMUX2, 40); INIT_GPIO_DESC_MUXED(WEMUX2, 36); }

Contributors

PersonTokensPropCommitsCommitProp
Eric Miao18379.57%360.00%
Robert Jarzmik4218.26%120.00%
Haojian Zhuang52.17%120.00%
Total230100.00%5100.00%

#else
static inline void pxa27x_mfp_init(void) {}

Contributors

PersonTokensPropCommitsCommitProp
Eric Miao8100.00%1100.00%
Total8100.00%1100.00%

#endif /* CONFIG_PXA27x */ #ifdef CONFIG_PM static unsigned long saved_gafr[2][4]; static unsigned long saved_gpdr[4]; static unsigned long saved_gplr[4]; static unsigned long saved_pgsr[4];
static int pxa2xx_mfp_suspend(void) { int i; /* set corresponding PGSR bit of those marked MFP_LPM_KEEP_OUTPUT */ for (i = 0; i < pxa_last_gpio; i++) { if ((gpio_desc[i].config & MFP_LPM_KEEP_OUTPUT) && (GPDR(i) & GPIO_bit(i))) { if (GPLR(i) & GPIO_bit(i)) PGSR(gpio_to_bank(i)) |= GPIO_bit(i); else PGSR(gpio_to_bank(i)) &= ~GPIO_bit(i); } } for (i = 0; i <= gpio_to_bank(pxa_last_gpio); i++) { saved_gafr[0][i] = GAFR_L(i); saved_gafr[1][i] = GAFR_U(i); saved_gpdr[i] = GPDR(i * 32); saved_gplr[i] = GPLR(i * 32); saved_pgsr[i] = PGSR(i); GPSR(i * 32) = PGSR(i); GPCR(i * 32) = ~PGSR(i); } /* set GPDR bits taking into account MFP_LPM_KEEP_OUTPUT */ for (i = 0; i < pxa_last_gpio; i++) { if ((gpdr_lpm[gpio_to_bank(i)] & GPIO_bit(i)) || ((gpio_desc[i].config & MFP_LPM_KEEP_OUTPUT) && (saved_gpdr[gpio_to_bank(i)] & GPIO_bit(i)))) GPDR(i) |= GPIO_bit(i); else GPDR(i) &= ~GPIO_bit(i); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Miao15354.06%444.44%
Igor Grinberg11339.93%222.22%
Daniel Ribeiro103.53%111.11%
Paul Parsons62.12%111.11%
Rafael J. Wysocki10.35%111.11%
Total283100.00%9100.00%


static void pxa2xx_mfp_resume(void) { int i; for (i = 0; i <= gpio_to_bank(pxa_last_gpio); i++) { GAFR_L(i) = saved_gafr[0][i]; GAFR_U(i) = saved_gafr[1][i]; GPSR(i * 32) = saved_gplr[i]; GPCR(i * 32) = ~saved_gplr[i]; GPDR(i * 32) = saved_gpdr[i]; PGSR(i) = saved_pgsr[i]; } PSSR = PSSR_RDH | PSSR_PH; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Miao7165.74%350.00%
Igor Grinberg2523.15%116.67%
Daniel Ribeiro109.26%116.67%
Rafael J. Wysocki21.85%116.67%
Total108100.00%6100.00%

#else #define pxa2xx_mfp_suspend NULL #define pxa2xx_mfp_resume NULL #endif struct syscore_ops pxa2xx_mfp_syscore_ops = { .suspend = pxa2xx_mfp_suspend, .resume = pxa2xx_mfp_resume, };
static int __init pxa2xx_mfp_init(void) { int i; if (!cpu_is_pxa2xx()) return 0; if (cpu_is_pxa25x()) pxa25x_mfp_init(); if (cpu_is_pxa27x()) pxa27x_mfp_init(); /* clear RDH bit to enable GPIO receivers after reset/sleep exit */ PSSR = PSSR_RDH; /* initialize gafr_run[], pgsr_lpm[] from existing values */ for (i = 0; i <= gpio_to_bank(pxa_last_gpio); i++) gpdr_lpm[i] = GPDR(i * 32); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric Miao6891.89%360.00%
Timothy Clacy56.76%120.00%
Rafael J. Wysocki11.35%120.00%
Total74100.00%5100.00%

postcore_initcall(pxa2xx_mfp_init);

Overall Contributors

PersonTokensPropCommitsCommitProp
Eric Miao164080.63%1142.31%
Igor Grinberg1607.87%27.69%
Robert Jarzmik1286.29%13.85%
Haojian Zhuang452.21%27.69%
Daniel Ribeiro281.38%13.85%
Russell King80.39%311.54%
Rafael J. Wysocki60.29%13.85%
Paul Parsons60.29%13.85%
Timothy Clacy50.25%13.85%
Joe Perches40.20%13.85%
Rob Herring30.15%13.85%
Arnd Bergmann10.05%13.85%
Total2034100.00%26100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.