Pin control changes for the v3.11 kernel cycle:

- A large slew of improvements of the Genric pin configuration
   support, and deployment in four different platforms:
   Rockchip, Super-H PFC, ABx500 and TZ1090. Support BIAS_BUS_HOLD,
   get device tree parsing and debugfs support into shape.
 
 - We also have device tree support with generic naming conventions
   for the generic pin configuration.
 
 - Delete the unused and confusing direct pinconf API. Now state
   transitions is *the* way to control pins and multiplexing.
 
 - New drivers for Rockchip, TZ1090, and TZ1090 PDC.
 
 - Two pin control states related to power management are now
   handled in the device core: "sleep" and "idle", removing a lot
   of boilerplate code in drivers. We do not yet know if this is
   the final word for pin PM, but it already make things a lot
   easier to handle.
 
 - Handle sparse GPIO ranges passing a list of disparate pins, and
   utilize these in the new BayTrail (x86 Atom SoC) driver.
 
 - Make the sunxi (AllWinner) driver handle external interrupts.
 
 - Make it possible for pinctrl-single to handle the case where
   several pins are managed by a single register, and augment it to
   handle sleep modes.
 
 - Cleanups and improvements for the abx500 drivers.
 
 - Move Sirf pin control drivers to their own directory, support
   save/restore of context and add support for the SiRFatlas6 SoC.
 
 - PMU muxing for the Dove pinctrl driver.
 
 - Finalization and support for VF610 in the i.MX6 pinctrl driver.
 
 - Smoothen out various Exynos rough edges.
 
 - Generic cleanups of various kinds.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1.4.10 (GNU/Linux)
 
 iQIcBAABAgAGBQJR0Z07AAoJEEEQszewGV1zx+oP/j+bh39e1Fc8ySFNvpwLFFRb
 EbQZx21XsK+d4fUVYQJ1IBh3e5FTqkmvHarbO1aNttqyk7eN5P4EFb3dLExIX+81
 6SJYtldH5ZdvLpJNvSXAX6fUjTD1CtBCDs5z5AvDQjqUArQ2tKlzJJgFXW8MSd3B
 5hd7XdU5g30GbVzFwrPbVUZwRM12YVs/HACkP6uFqDjB8KX6nXpETlqeeFW+ApvW
 RPT7iN/CsFls7gl6mHsPvScdfXar0ilZfu0hTf3EmhlVK1/iPOV6aqAF9z4j2Yxf
 ICL/x3phJ0Q7yNeZslif0KN3iJnrRGbdNvBi6wim35Ds5Uf3lY2SAhSvxNmkjT8n
 DB9oBTvQzr5OEv8fstWJAT+BWIdZ6Z91IqJ5Gy40A91oVUU9NDDBR3ur2gIneEUz
 51kOUhucCzpiht5A/7djAx6MYYOEUwjGNzjOs7tGcxCxz4+Rb2DbAXZ3Cew45ddh
 1QsfL3588A0DTp7ccw7f4QwYveX/cquzia/MD8AtdrUSYFEPfkexEo540/VqMl8j
 aMJ8Uuca9GSnyXDk+ziwkzLg2DjTw+p+6IygNr2GLrXFH2LTAKRpz/SidyLArDsw
 0sTFan0sdU3497rHX5Xc8yCyDY4sXCdQm3/er+TE+Z7V2dS99GuEysCAInIdvM1I
 Wupqaxw4A25YSmbRFVpR
 =EbAf
 -----END PGP SIGNATURE-----

Merge tag 'pinctrl-for-v3.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl

Pull pin control changes from Linus Walleij:

 - A large slew of improvements of the Genric pin configuration support,
   and deployment in four different platforms: Rockchip, Super-H PFC,
   ABx500 and TZ1090.  Support BIAS_BUS_HOLD, get device tree parsing
   and debugfs support into shape.

 - We also have device tree support with generic naming conventions for
   the generic pin configuration.

 - Delete the unused and confusing direct pinconf API.  Now state
   transitions is *the* way to control pins and multiplexing.

 - New drivers for Rockchip, TZ1090, and TZ1090 PDC.

 - Two pin control states related to power management are now handled in
   the device core: "sleep" and "idle", removing a lot of boilerplate
   code in drivers.  We do not yet know if this is the final word for
   pin PM, but it already make things a lot easier to handle.

 - Handle sparse GPIO ranges passing a list of disparate pins, and
   utilize these in the new BayTrail (x86 Atom SoC) driver.

 - Make the sunxi (AllWinner) driver handle external interrupts.

 - Make it possible for pinctrl-single to handle the case where several
   pins are managed by a single register, and augment it to handle sleep
   modes.

 - Cleanups and improvements for the abx500 drivers.

 - Move Sirf pin control drivers to their own directory, support
   save/restore of context and add support for the SiRFatlas6 SoC.

 - PMU muxing for the Dove pinctrl driver.

 - Finalization and support for VF610 in the i.MX6 pinctrl driver.

 - Smoothen out various Exynos rough edges.

 - Generic cleanups of various kinds.

* tag 'pinctrl-for-v3.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl: (82 commits)
  pinctrl: vt8500: wmt: remove redundant dev_err call in wmt_pinctrl_probe()
  pinctrl: remove bindings for pinconf options needing more thought
  pinctrl: remove slew-rate parameter from tz1090
  pinctrl: set unit for debounce time pinconfig to usec
  pinctrl: more clarifications for generic pull configs
  pinctrl: rip out the direct pinconf API
  pinctrl-tz1090-pdc: add TZ1090 PDC pinctrl driver
  pinctrl-tz1090: add TZ1090 pinctrl driver
  pinctrl: samsung: Staticize drvdata_list
  pinctrl: rockchip: Add missing irq_gc_unlock() call before return error
  pinctrl: abx500: rework error path
  pinctrl: abx500: suppress hardcoded value
  pinctrl: abx500: factorize code
  pinctrl: abx500: fix abx500_gpio_get()
  pinctrl: abx500: fix abx500_pin_config_set()
  pinctrl: abx500: Add device tree support
  sh-pfc: Guard DT parsing with #ifdef CONFIG_OF
  pinctrl: add Intel BayTrail GPIO/pinctrl support
  pinctrl: fix pinconf_ops::pin_config_dbg_parse_modify kerneldoc
  pinctrl: Staticize local symbols
  ...

Conflicts:
	drivers/net/ethernet/ti/davinci_mdio.c
	drivers/pinctrl/Makefile
This commit is contained in:
Linus Torvalds 2013-07-03 11:48:03 -07:00
commit 3dbde57ad9
60 changed files with 12447 additions and 2945 deletions

View file

@ -58,6 +58,18 @@ config PINCTRL_AT91
help
Say Y here to enable the at91 pinctrl driver
config PINCTRL_BAYTRAIL
bool "Intel Baytrail GPIO pin control"
depends on GPIOLIB && ACPI && X86
select IRQ_DOMAIN
help
driver for memory mapped GPIO functionality on Intel Baytrail
platforms. Supports 3 banks with 102, 28 and 44 gpios.
Most pins are usually muxed to some other functionality by firmware,
so only a small amount is available for gpio use.
Requires ACPI device enumeration code to set up a platform device.
config PINCTRL_BCM2835
bool
select PINMUX
@ -108,6 +120,14 @@ config PINCTRL_IMX6SL
help
Say Y here to enable the imx6sl pinctrl driver
config PINCTRL_VF610
bool "Freescale Vybrid VF610 pinctrl driver"
depends on OF
depends on SOC_VF610
select PINCTRL_IMX
help
Say Y here to enable the Freescale Vybrid VF610 pinctrl driver
config PINCTRL_LANTIQ
bool
depends on LANTIQ
@ -150,6 +170,12 @@ config PINCTRL_DB8540
bool "DB8540 pin controller driver"
depends on PINCTRL_NOMADIK && ARCH_U8500
config PINCTRL_ROCKCHIP
bool
select PINMUX
select GENERIC_PINCONF
select GENERIC_IRQ_CHIP
config PINCTRL_SINGLE
tristate "One-register-per-pin type device tree based pinctrl driver"
depends on OF
@ -192,6 +218,18 @@ config PINCTRL_TEGRA114
bool
select PINCTRL_TEGRA
config PINCTRL_TZ1090
bool "Toumaz Xenif TZ1090 pin control driver"
depends on SOC_TZ1090
select PINMUX
select GENERIC_PINCONF
config PINCTRL_TZ1090_PDC
bool "Toumaz Xenif TZ1090 PDC pin control driver"
depends on SOC_TZ1090
select PINMUX
select PINCONF
config PINCTRL_U300
bool "U300 pin controller driver"
depends on ARCH_U300

View file

@ -16,12 +16,14 @@ obj-$(CONFIG_PINCTRL_AB9540) += pinctrl-ab9540.o
obj-$(CONFIG_PINCTRL_AB8505) += pinctrl-ab8505.o
obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o
obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o
obj-$(CONFIG_PINCTRL_IMX) += pinctrl-imx.o
obj-$(CONFIG_PINCTRL_IMX35) += pinctrl-imx35.o
obj-$(CONFIG_PINCTRL_IMX51) += pinctrl-imx51.o
obj-$(CONFIG_PINCTRL_IMX53) += pinctrl-imx53.o
obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6q.o
obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6dl.o
obj-$(CONFIG_PINCTRL_IMX6SL) += pinctrl-imx6sl.o
obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o
obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o
obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o
@ -30,13 +32,16 @@ obj-$(CONFIG_PINCTRL_NOMADIK) += pinctrl-nomadik.o
obj-$(CONFIG_PINCTRL_STN8815) += pinctrl-nomadik-stn8815.o
obj-$(CONFIG_PINCTRL_DB8500) += pinctrl-nomadik-db8500.o
obj-$(CONFIG_PINCTRL_DB8540) += pinctrl-nomadik-db8540.o
obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
obj-$(CONFIG_PINCTRL_SIRF) += pinctrl-sirf.o
obj-$(CONFIG_PINCTRL_SIRF) += sirf/
obj-$(CONFIG_PINCTRL_SUNXI) += pinctrl-sunxi.o
obj-$(CONFIG_PINCTRL_TEGRA) += pinctrl-tegra.o
obj-$(CONFIG_PINCTRL_TEGRA20) += pinctrl-tegra20.o
obj-$(CONFIG_PINCTRL_TEGRA30) += pinctrl-tegra30.o
obj-$(CONFIG_PINCTRL_TEGRA114) += pinctrl-tegra114.o
obj-$(CONFIG_PINCTRL_TZ1090) += pinctrl-tz1090.o
obj-$(CONFIG_PINCTRL_TZ1090_PDC) += pinctrl-tz1090-pdc.o
obj-$(CONFIG_PINCTRL_U300) += pinctrl-u300.o
obj-$(CONFIG_PINCTRL_COH901) += pinctrl-coh901.o
obj-$(CONFIG_PINCTRL_SAMSUNG) += pinctrl-samsung.o
@ -47,6 +52,7 @@ obj-$(CONFIG_PINCTRL_S3C64XX) += pinctrl-s3c64xx.o
obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o
obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o
obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
obj-$(CONFIG_PINCTRL_VF610) += pinctrl-vf610.o
obj-$(CONFIG_PLAT_ORION) += mvebu/
obj-$(CONFIG_ARCH_SHMOBILE) += sh-pfc/

View file

@ -41,13 +41,13 @@
static bool pinctrl_dummy_state;
/* Mutex taken to protect pinctrl_list */
DEFINE_MUTEX(pinctrl_list_mutex);
static DEFINE_MUTEX(pinctrl_list_mutex);
/* Mutex taken to protect pinctrl_maps */
DEFINE_MUTEX(pinctrl_maps_mutex);
/* Mutex taken to protect pinctrldev_list */
DEFINE_MUTEX(pinctrldev_list_mutex);
static DEFINE_MUTEX(pinctrldev_list_mutex);
/* Global list of pin control devices (struct pinctrl_dev) */
static LIST_HEAD(pinctrldev_list);
@ -101,20 +101,23 @@ EXPORT_SYMBOL_GPL(pinctrl_dev_get_drvdata);
struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *devname)
{
struct pinctrl_dev *pctldev = NULL;
bool found = false;
if (!devname)
return NULL;
mutex_lock(&pinctrldev_list_mutex);
list_for_each_entry(pctldev, &pinctrldev_list, node) {
if (!strcmp(dev_name(pctldev->dev), devname)) {
/* Matched on device name */
found = true;
break;
mutex_unlock(&pinctrldev_list_mutex);
return pctldev;
}
}
return found ? pctldev : NULL;
mutex_unlock(&pinctrldev_list_mutex);
return NULL;
}
struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np)
@ -279,6 +282,29 @@ static int pinctrl_register_pins(struct pinctrl_dev *pctldev,
return 0;
}
/**
* gpio_to_pin() - GPIO range GPIO number to pin number translation
* @range: GPIO range used for the translation
* @gpio: gpio pin to translate to a pin number
*
* Finds the pin number for a given GPIO using the specified GPIO range
* as a base for translation. The distinction between linear GPIO ranges
* and pin list based GPIO ranges is managed correctly by this function.
*
* This function assumes the gpio is part of the specified GPIO range, use
* only after making sure this is the case (e.g. by calling it on the
* result of successful pinctrl_get_device_gpio_range calls)!
*/
static inline int gpio_to_pin(struct pinctrl_gpio_range *range,
unsigned int gpio)
{
unsigned int offset = gpio - range->base;
if (range->pins)
return range->pins[offset];
else
return range->pin_base + offset;
}
/**
* pinctrl_match_gpio_range() - check if a certain GPIO pin is in range
* @pctldev: pin controller device to check
@ -326,6 +352,8 @@ static bool pinctrl_ready_for_gpio_range(unsigned gpio)
struct pinctrl_gpio_range *range = NULL;
struct gpio_chip *chip = gpio_to_chip(gpio);
mutex_lock(&pinctrldev_list_mutex);
/* Loop over the pin controllers */
list_for_each_entry(pctldev, &pinctrldev_list, node) {
/* Loop over the ranges */
@ -334,9 +362,13 @@ static bool pinctrl_ready_for_gpio_range(unsigned gpio)
if (range->base + range->npins - 1 < chip->base ||
range->base > chip->base + chip->ngpio - 1)
continue;
mutex_unlock(&pinctrldev_list_mutex);
return true;
}
}
mutex_unlock(&pinctrldev_list_mutex);
return false;
}
#else
@ -408,8 +440,6 @@ struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname,
{
struct pinctrl_dev *pctldev;
mutex_lock(&pinctrldev_list_mutex);
pctldev = get_pinctrl_dev_from_devname(devname);
/*
@ -418,13 +448,10 @@ struct pinctrl_dev *pinctrl_find_and_add_gpio_range(const char *devname,
* range need to defer probing.
*/
if (!pctldev) {
mutex_unlock(&pinctrldev_list_mutex);
return ERR_PTR(-EPROBE_DEFER);
}
pinctrl_add_gpio_range(pctldev, range);
mutex_unlock(&pinctrldev_list_mutex);
return pctldev;
}
EXPORT_SYMBOL_GPL(pinctrl_find_and_add_gpio_range);
@ -438,21 +465,26 @@ struct pinctrl_gpio_range *
pinctrl_find_gpio_range_from_pin(struct pinctrl_dev *pctldev,
unsigned int pin)
{
struct pinctrl_gpio_range *range = NULL;
struct pinctrl_gpio_range *range;
mutex_lock(&pctldev->mutex);
/* Loop over the ranges */
list_for_each_entry(range, &pctldev->gpio_ranges, node) {
/* Check if we're in the valid range */
if (pin >= range->pin_base &&
pin < range->pin_base + range->npins) {
mutex_unlock(&pctldev->mutex);
return range;
}
if (range->pins) {
int a;
for (a = 0; a < range->npins; a++) {
if (range->pins[a] == pin)
goto out;
}
} else if (pin >= range->pin_base &&
pin < range->pin_base + range->npins)
goto out;
}
range = NULL;
out:
mutex_unlock(&pctldev->mutex);
return NULL;
return range;
}
EXPORT_SYMBOL_GPL(pinctrl_find_gpio_range_from_pin);
@ -517,22 +549,18 @@ int pinctrl_request_gpio(unsigned gpio)
int ret;
int pin;
mutex_lock(&pinctrldev_list_mutex);
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
if (ret) {
if (pinctrl_ready_for_gpio_range(gpio))
ret = 0;
mutex_unlock(&pinctrldev_list_mutex);
return ret;
}
/* Convert to the pin controllers number space */
pin = gpio - range->base + range->pin_base;
pin = gpio_to_pin(range, gpio);
ret = pinmux_request_gpio(pctldev, range, pin, gpio);
mutex_unlock(&pinctrldev_list_mutex);
return ret;
}
EXPORT_SYMBOL_GPL(pinctrl_request_gpio);
@ -552,22 +580,18 @@ void pinctrl_free_gpio(unsigned gpio)
int ret;
int pin;
mutex_lock(&pinctrldev_list_mutex);
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
if (ret) {
mutex_unlock(&pinctrldev_list_mutex);
return;
}
mutex_lock(&pctldev->mutex);
/* Convert to the pin controllers number space */
pin = gpio - range->base + range->pin_base;
pin = gpio_to_pin(range, gpio);
pinmux_free_gpio(pctldev, pin, range);
mutex_unlock(&pctldev->mutex);
mutex_unlock(&pinctrldev_list_mutex);
}
EXPORT_SYMBOL_GPL(pinctrl_free_gpio);
@ -578,22 +602,18 @@ static int pinctrl_gpio_direction(unsigned gpio, bool input)
int ret;
int pin;
mutex_lock(&pinctrldev_list_mutex);
ret = pinctrl_get_device_gpio_range(gpio, &pctldev, &range);
if (ret) {
mutex_unlock(&pinctrldev_list_mutex);
return ret;
}
mutex_lock(&pctldev->mutex);
/* Convert to the pin controllers number space */
pin = gpio - range->base + range->pin_base;
pin = gpio_to_pin(range, gpio);
ret = pinmux_gpio_direction(pctldev, range, pin, input);
mutex_unlock(&pctldev->mutex);
mutex_unlock(&pinctrldev_list_mutex);
return ret;
}
@ -1204,6 +1224,69 @@ int pinctrl_force_default(struct pinctrl_dev *pctldev)
}
EXPORT_SYMBOL_GPL(pinctrl_force_default);
#ifdef CONFIG_PM
/**
* pinctrl_pm_select_default_state() - select default pinctrl state for PM
* @dev: device to select default state for
*/
int pinctrl_pm_select_default_state(struct device *dev)
{
struct dev_pin_info *pins = dev->pins;
int ret;
if (!pins)
return 0;
if (IS_ERR(pins->default_state))
return 0; /* No default state */
ret = pinctrl_select_state(pins->p, pins->default_state);
if (ret)
dev_err(dev, "failed to activate default pinctrl state\n");
return ret;
}
EXPORT_SYMBOL_GPL(pinctrl_pm_select_default_state);
/**
* pinctrl_pm_select_sleep_state() - select sleep pinctrl state for PM
* @dev: device to select sleep state for
*/
int pinctrl_pm_select_sleep_state(struct device *dev)
{
struct dev_pin_info *pins = dev->pins;
int ret;
if (!pins)
return 0;
if (IS_ERR(pins->sleep_state))
return 0; /* No sleep state */
ret = pinctrl_select_state(pins->p, pins->sleep_state);
if (ret)
dev_err(dev, "failed to activate pinctrl sleep state\n");
return ret;
}
EXPORT_SYMBOL_GPL(pinctrl_pm_select_sleep_state);
/**
* pinctrl_pm_select_idle_state() - select idle pinctrl state for PM
* @dev: device to select idle state for
*/
int pinctrl_pm_select_idle_state(struct device *dev)
{
struct dev_pin_info *pins = dev->pins;
int ret;
if (!pins)
return 0;
if (IS_ERR(pins->idle_state))
return 0; /* No idle state */
ret = pinctrl_select_state(pins->p, pins->idle_state);
if (ret)
dev_err(dev, "failed to activate pinctrl idle state\n");
return ret;
}
EXPORT_SYMBOL_GPL(pinctrl_pm_select_idle_state);
#endif
#ifdef CONFIG_DEBUG_FS
static int pinctrl_pins_show(struct seq_file *s, void *what)
@ -1296,11 +1379,21 @@ static int pinctrl_gpioranges_show(struct seq_file *s, void *what)
/* Loop over the ranges */
list_for_each_entry(range, &pctldev->gpio_ranges, node) {
seq_printf(s, "%u: %s GPIOS [%u - %u] PINS [%u - %u]\n",
range->id, range->name,
range->base, (range->base + range->npins - 1),
range->pin_base,
(range->pin_base + range->npins - 1));
if (range->pins) {
int a;
seq_printf(s, "%u: %s GPIOS [%u - %u] PINS {",
range->id, range->name,
range->base, (range->base + range->npins - 1));
for (a = 0; a < range->npins - 1; a++)
seq_printf(s, "%u, ", range->pins[a]);
seq_printf(s, "%u}\n", range->pins[a]);
}
else
seq_printf(s, "%u: %s GPIOS [%u - %u] PINS [%u - %u]\n",
range->id, range->name,
range->base, (range->base + range->npins - 1),
range->pin_base,
(range->pin_base + range->npins - 1));
}
mutex_unlock(&pctldev->mutex);

View file

@ -26,6 +26,9 @@
#define DOVE_MPP_VIRT_BASE (DOVE_SB_REGS_VIRT_BASE + 0xd0200)
#define DOVE_PMU_MPP_GENERAL_CTRL (DOVE_MPP_VIRT_BASE + 0x10)
#define DOVE_AU0_AC97_SEL BIT(16)
#define DOVE_PMU_SIGNAL_SELECT_0 (DOVE_SB_REGS_VIRT_BASE + 0xd802C)
#define DOVE_PMU_SIGNAL_SELECT_1 (DOVE_SB_REGS_VIRT_BASE + 0xd8030)
#define DOVE_GLOBAL_CONFIG_1 (DOVE_SB_REGS_VIRT_BASE + 0xe802C)
#define DOVE_GLOBAL_CONFIG_1 (DOVE_SB_REGS_VIRT_BASE + 0xe802C)
#define DOVE_TWSI_ENABLE_OPTION1 BIT(7)
#define DOVE_GLOBAL_CONFIG_2 (DOVE_SB_REGS_VIRT_BASE + 0xe8030)
@ -58,12 +61,16 @@ static int dove_pmu_mpp_ctrl_get(struct mvebu_mpp_ctrl *ctrl,
unsigned off = (ctrl->pid / MPPS_PER_REG) * MPP_BITS;
unsigned shift = (ctrl->pid % MPPS_PER_REG) * MPP_BITS;
unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
unsigned long mpp = readl(DOVE_MPP_VIRT_BASE + off);
unsigned long func;
if (pmu & (1 << ctrl->pid))
*config = CONFIG_PMU;
else
*config = (mpp >> shift) & MPP_MASK;
if (pmu & (1 << ctrl->pid)) {
func = readl(DOVE_PMU_SIGNAL_SELECT_0 + off);
*config = (func >> shift) & MPP_MASK;
*config |= CONFIG_PMU;
} else {
func = readl(DOVE_MPP_VIRT_BASE + off);
*config = (func >> shift) & MPP_MASK;
}
return 0;
}
@ -73,15 +80,20 @@ static int dove_pmu_mpp_ctrl_set(struct mvebu_mpp_ctrl *ctrl,
unsigned off = (ctrl->pid / MPPS_PER_REG) * MPP_BITS;
unsigned shift = (ctrl->pid % MPPS_PER_REG) * MPP_BITS;
unsigned long pmu = readl(DOVE_PMU_MPP_GENERAL_CTRL);
unsigned long mpp = readl(DOVE_MPP_VIRT_BASE + off);
unsigned long func;
if (config == CONFIG_PMU)
if (config & CONFIG_PMU) {
writel(pmu | (1 << ctrl->pid), DOVE_PMU_MPP_GENERAL_CTRL);
else {
func = readl(DOVE_PMU_SIGNAL_SELECT_0 + off);
func &= ~(MPP_MASK << shift);
func |= (config & MPP_MASK) << shift;
writel(func, DOVE_PMU_SIGNAL_SELECT_0 + off);
} else {
writel(pmu & ~(1 << ctrl->pid), DOVE_PMU_MPP_GENERAL_CTRL);
mpp &= ~(MPP_MASK << shift);
mpp |= config << shift;
writel(mpp, DOVE_MPP_VIRT_BASE + off);
func = readl(DOVE_MPP_VIRT_BASE + off);
func &= ~(MPP_MASK << shift);
func |= (config & MPP_MASK) << shift;
writel(func, DOVE_MPP_VIRT_BASE + off);
}
return 0;
}
@ -378,20 +390,53 @@ static struct mvebu_mpp_mode dove_mpp_modes[] = {
MPP_FUNCTION(0x02, "uart2", "rts"),
MPP_FUNCTION(0x03, "sdio0", "cd"),
MPP_FUNCTION(0x0f, "lcd0", "pwm"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(1,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x02, "uart2", "cts"),
MPP_FUNCTION(0x03, "sdio0", "wp"),
MPP_FUNCTION(0x0f, "lcd1", "pwm"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(2,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x01, "sata", "prsnt"),
MPP_FUNCTION(0x02, "uart2", "txd"),
MPP_FUNCTION(0x03, "sdio0", "buspwr"),
MPP_FUNCTION(0x04, "uart1", "rts"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(3,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x01, "sata", "act"),
@ -399,43 +444,131 @@ static struct mvebu_mpp_mode dove_mpp_modes[] = {
MPP_FUNCTION(0x03, "sdio0", "ledctrl"),
MPP_FUNCTION(0x04, "uart1", "cts"),
MPP_FUNCTION(0x0f, "lcd-spi", "cs1"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(4,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x02, "uart3", "rts"),
MPP_FUNCTION(0x03, "sdio1", "cd"),
MPP_FUNCTION(0x04, "spi1", "miso"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(5,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x02, "uart3", "cts"),
MPP_FUNCTION(0x03, "sdio1", "wp"),
MPP_FUNCTION(0x04, "spi1", "cs"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(6,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x02, "uart3", "txd"),
MPP_FUNCTION(0x03, "sdio1", "buspwr"),
MPP_FUNCTION(0x04, "spi1", "mosi"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(7,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x02, "uart3", "rxd"),
MPP_FUNCTION(0x03, "sdio1", "ledctrl"),
MPP_FUNCTION(0x04, "spi1", "sck"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "core-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(8,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x01, "watchdog", "rstout"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(9,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x05, "pex1", "clkreq"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(10,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x05, "ssp", "sclk"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(11,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x01, "sata", "prsnt"),
@ -443,33 +576,88 @@ static struct mvebu_mpp_mode dove_mpp_modes[] = {
MPP_FUNCTION(0x03, "sdio0", "ledctrl"),
MPP_FUNCTION(0x04, "sdio1", "ledctrl"),
MPP_FUNCTION(0x05, "pex0", "clkreq"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(12,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x01, "sata", "act"),
MPP_FUNCTION(0x02, "uart2", "rts"),
MPP_FUNCTION(0x03, "audio0", "extclk"),
MPP_FUNCTION(0x04, "sdio1", "cd"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(13,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x02, "uart2", "cts"),
MPP_FUNCTION(0x03, "audio1", "extclk"),
MPP_FUNCTION(0x04, "sdio1", "wp"),
MPP_FUNCTION(0x05, "ssp", "extclk"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(14,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x02, "uart2", "txd"),
MPP_FUNCTION(0x04, "sdio1", "buspwr"),
MPP_FUNCTION(0x05, "ssp", "rxd"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(15,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x02, "uart2", "rxd"),
MPP_FUNCTION(0x04, "sdio1", "ledctrl"),
MPP_FUNCTION(0x05, "ssp", "sfrm"),
MPP_FUNCTION(0x10, "pmu", NULL)),
MPP_FUNCTION(CONFIG_PMU | 0x0, "pmu-nc", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x1, "pmu-low", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x2, "pmu-high", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x3, "pmic", "sdi"),
MPP_FUNCTION(CONFIG_PMU | 0x4, "cpu-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x5, "standby-pwr-down", NULL),
MPP_FUNCTION(CONFIG_PMU | 0x8, "cpu-pwr-good", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xa, "bat-fault", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xb, "ext0-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xc, "ext1-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xd, "ext2-wakeup", NULL),
MPP_FUNCTION(CONFIG_PMU | 0xe, "pmu-blink", NULL)),
MPP_MODE(16,
MPP_FUNCTION(0x00, "gpio", NULL),
MPP_FUNCTION(0x02, "uart3", "rts"),

View file

@ -21,6 +21,7 @@
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/of.h>
#include "core.h"
#include "pinconf.h"
@ -37,14 +38,18 @@ struct pin_config_item {
static struct pin_config_item conf_items[] = {
PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL),
PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL),
PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL),
PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL),
PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", NULL),
PCONFDUMP(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT,
"input bias pull to pin specific state", NULL),
PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL),
PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL),
PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL),
PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA"),
PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL),
PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL),
PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "time units"),
PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec"),
PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"),
PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL),
PCONFDUMP(PIN_CONFIG_LOW_POWER_MODE, "pin low power", "mode"),
@ -135,3 +140,100 @@ void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
}
EXPORT_SYMBOL_GPL(pinconf_generic_dump_config);
#endif
#ifdef CONFIG_OF
struct pinconf_generic_dt_params {
const char * const property;
enum pin_config_param param;
u32 default_value;
};
static struct pinconf_generic_dt_params dt_params[] = {
{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
{ "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
{ "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
{ "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 1 },
{ "bias-pull-down", PIN_CONFIG_BIAS_PULL_DOWN, 1 },
{ "bias-pull-pin-default", PIN_CONFIG_BIAS_PULL_PIN_DEFAULT, 1 },
{ "drive-push-pull", PIN_CONFIG_DRIVE_PUSH_PULL, 0 },
{ "drive-open-drain", PIN_CONFIG_DRIVE_OPEN_DRAIN, 0 },
{ "drive-open-source", PIN_CONFIG_DRIVE_OPEN_SOURCE, 0 },
{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
{ "input-schmitt-enable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 1 },
{ "input-schmitt-disable", PIN_CONFIG_INPUT_SCHMITT_ENABLE, 0 },
{ "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
{ "low-power-enable", PIN_CONFIG_LOW_POWER_MODE, 1 },
{ "low-power-disable", PIN_CONFIG_LOW_POWER_MODE, 0 },
{ "output-low", PIN_CONFIG_OUTPUT, 0, },
{ "output-high", PIN_CONFIG_OUTPUT, 1, },
};
/**
* pinconf_generic_parse_dt_config()
* parse the config properties into generic pinconfig values.
* @np: node containing the pinconfig properties
* @configs: array with nconfigs entries containing the generic pinconf values
* @nconfigs: umber of configurations
*/
int pinconf_generic_parse_dt_config(struct device_node *np,
unsigned long **configs,
unsigned int *nconfigs)
{
unsigned long *cfg;
unsigned int ncfg = 0;
int ret;
int i;
u32 val;
if (!np)
return -EINVAL;
/* allocate a temporary array big enough to hold one of each option */
cfg = kzalloc(sizeof(*cfg) * ARRAY_SIZE(dt_params), GFP_KERNEL);
if (!cfg)
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
struct pinconf_generic_dt_params *par = &dt_params[i];
ret = of_property_read_u32(np, par->property, &val);
/* property not found */
if (ret == -EINVAL)
continue;
/* use default value, when no value is specified */
if (ret)
val = par->default_value;
pr_debug("found %s with value %u\n", par->property, val);
cfg[ncfg] = pinconf_to_config_packed(par->param, val);
ncfg++;
}
ret = 0;
/* no configs found at all */
if (ncfg == 0) {
*configs = NULL;
*nconfigs = 0;
goto out;
}
/*
* Now limit the number of configs to the real number of
* found properties.
*/
*configs = kzalloc(ncfg * sizeof(unsigned long), GFP_KERNEL);
if (!*configs) {
ret = -ENOMEM;
goto out;
}
memcpy(*configs, cfg, ncfg * sizeof(unsigned long));
*nconfigs = ncfg;
out:
kfree(cfg);
return ret;
}
#endif

View file

@ -75,98 +75,6 @@ int pin_config_get_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
return ops->pin_config_get(pctldev, pin, config);
}
/**
* pin_config_get() - get the configuration of a single pin parameter
* @dev_name: name of the pin controller device for this pin
* @name: name of the pin to get the config for
* @config: the config pointed to by this argument will be filled in with the
* current pin state, it can be used directly by drivers as a numeral, or
* it can be dereferenced to any struct.
*/
int pin_config_get(const char *dev_name, const char *name,
unsigned long *config)
{
struct pinctrl_dev *pctldev;
int pin;
pctldev = get_pinctrl_dev_from_devname(dev_name);
if (!pctldev) {
pin = -EINVAL;
return pin;
}
mutex_lock(&pctldev->mutex);
pin = pin_get_from_name(pctldev, name);
if (pin < 0)
goto unlock;
pin = pin_config_get_for_pin(pctldev, pin, config);
unlock:
mutex_unlock(&pctldev->mutex);
return pin;
}
EXPORT_SYMBOL(pin_config_get);
static int pin_config_set_for_pin(struct pinctrl_dev *pctldev, unsigned pin,
unsigned long config)
{
const struct pinconf_ops *ops = pctldev->desc->confops;
int ret;
if (!ops || !ops->pin_config_set) {
dev_err(pctldev->dev, "cannot configure pin, missing "
"config function in driver\n");
return -EINVAL;
}
ret = ops->pin_config_set(pctldev, pin, config);
if (ret) {
dev_err(pctldev->dev,
"unable to set pin configuration on pin %d\n", pin);
return ret;
}
return 0;
}
/**
* pin_config_set() - set the configuration of a single pin parameter
* @dev_name: name of pin controller device for this pin
* @name: name of the pin to set the config for
* @config: the config in this argument will contain the desired pin state, it
* can be used directly by drivers as a numeral, or it can be dereferenced
* to any struct.
*/
int pin_config_set(const char *dev_name, const char *name,
unsigned long config)
{
struct pinctrl_dev *pctldev;
int pin, ret;
pctldev = get_pinctrl_dev_from_devname(dev_name);
if (!pctldev) {
ret = -EINVAL;
return ret;
}
mutex_lock(&pctldev->mutex);
pin = pin_get_from_name(pctldev, name);
if (pin < 0) {
ret = pin;
goto unlock;
}
ret = pin_config_set_for_pin(pctldev, pin, config);
unlock:
mutex_unlock(&pctldev->mutex);
return ret;
}
EXPORT_SYMBOL(pin_config_set);
int pin_config_group_get(const char *dev_name, const char *pin_group,
unsigned long *config)
{
@ -204,88 +112,6 @@ unlock:
mutex_unlock(&pctldev->mutex);
return ret;
}
EXPORT_SYMBOL(pin_config_group_get);
int pin_config_group_set(const char *dev_name, const char *pin_group,
unsigned long config)
{
struct pinctrl_dev *pctldev;
const struct pinconf_ops *ops;
const struct pinctrl_ops *pctlops;
int selector;
const unsigned *pins;
unsigned num_pins;
int ret;
int i;
pctldev = get_pinctrl_dev_from_devname(dev_name);
if (!pctldev) {
ret = -EINVAL;
return ret;
}
mutex_lock(&pctldev->mutex);
ops = pctldev->desc->confops;
pctlops = pctldev->desc->pctlops;
if (!ops || (!ops->pin_config_group_set && !ops->pin_config_set)) {
dev_err(pctldev->dev, "cannot configure pin group, missing "
"config function in driver\n");
ret = -EINVAL;
goto unlock;
}
selector = pinctrl_get_group_selector(pctldev, pin_group);
if (selector < 0) {
ret = selector;
goto unlock;
}
ret = pctlops->get_group_pins(pctldev, selector, &pins, &num_pins);
if (ret) {
dev_err(pctldev->dev, "cannot configure pin group, error "
"getting pins\n");
goto unlock;
}
/*
* If the pin controller supports handling entire groups we use that
* capability.
*/
if (ops->pin_config_group_set) {
ret = ops->pin_config_group_set(pctldev, selector, config);
/*
* If the pin controller prefer that a certain group be handled
* pin-by-pin as well, it returns -EAGAIN.
*/
if (ret != -EAGAIN)
goto unlock;
}
/*
* If the controller cannot handle entire groups, we configure each pin
* individually.
*/
if (!ops->pin_config_set) {
ret = 0;
goto unlock;
}
for (i = 0; i < num_pins; i++) {
ret = ops->pin_config_set(pctldev, pins[i], config);
if (ret < 0)
goto unlock;
}
ret = 0;
unlock:
mutex_unlock(&pctldev->mutex);
return ret;
}
EXPORT_SYMBOL(pin_config_group_set);
int pinconf_map_to_setting(struct pinctrl_map const *map,
struct pinctrl_setting *setting)

View file

@ -123,3 +123,9 @@ static inline void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
return;
}
#endif
#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_OF)
int pinconf_generic_parse_dt_config(struct device_node *np,
unsigned long **configs,
unsigned int *nconfigs);
#endif

View file

@ -30,8 +30,11 @@
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/machine.h>
#include "pinctrl-abx500.h"
#include "core.h"
#include "pinconf.h"
/*
* The AB9540 and AB8540 GPIO support are extended versions
@ -93,13 +96,15 @@
#define AB8540_GPIOX_VBAT_START 51
#define AB8540_GPIOX_VBAT_END 54
#define ABX500_GPIO_INPUT 0
#define ABX500_GPIO_OUTPUT 1
struct abx500_pinctrl {
struct device *dev;
struct pinctrl_dev *pctldev;
struct abx500_pinctrl_soc_data *soc;
struct gpio_chip chip;
struct ab8500 *parent;
struct mutex lock;
struct abx500_gpio_irq_cluster *irq_cluster;
int irq_cluster_size;
};
@ -129,8 +134,8 @@ static int abx500_gpio_get_bit(struct gpio_chip *chip, u8 reg,
if (ret < 0)
dev_err(pct->dev,
"%s read reg =%x, offset=%x failed\n",
__func__, reg, offset);
"%s read reg =%x, offset=%x failed (%d)\n",
__func__, reg, offset, ret);
return ret;
}
@ -146,7 +151,8 @@ static int abx500_gpio_set_bits(struct gpio_chip *chip, u8 reg,
ret = abx500_mask_and_set_register_interruptible(pct->dev,
AB8500_MISC, reg, BIT(pos), val << pos);
if (ret < 0)
dev_err(pct->dev, "%s write failed\n", __func__);
dev_err(pct->dev, "%s write reg, %x offset %x failed (%d)\n",
__func__, reg, offset, ret);
return ret;
}
@ -160,12 +166,24 @@ static int abx500_gpio_get(struct gpio_chip *chip, unsigned offset)
{
struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
bool bit;
bool is_out;
u8 gpio_offset = offset - 1;
int ret;
ret = abx500_gpio_get_bit(chip, AB8500_GPIO_IN1_REG,
offset, &bit);
ret = abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG,
gpio_offset, &is_out);
if (ret < 0)
goto out;
if (is_out)
ret = abx500_gpio_get_bit(chip, AB8500_GPIO_OUT1_REG,
gpio_offset, &bit);
else
ret = abx500_gpio_get_bit(chip, AB8500_GPIO_IN1_REG,
gpio_offset, &bit);
out:
if (ret < 0) {
dev_err(pct->dev, "%s failed\n", __func__);
dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
return ret;
}
@ -179,11 +197,47 @@ static void abx500_gpio_set(struct gpio_chip *chip, unsigned offset, int val)
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_OUT1_REG, offset, val);
if (ret < 0)
dev_err(pct->dev, "%s write failed\n", __func__);
dev_err(pct->dev, "%s write failed (%d)\n", __func__, ret);
}
static int abx500_config_pull_updown(struct abx500_pinctrl *pct,
int offset, enum abx500_gpio_pull_updown val)
static int abx500_get_pull_updown(struct abx500_pinctrl *pct, int offset,
enum abx500_gpio_pull_updown *pull_updown)
{
u8 pos;
u8 val;
int ret;
struct pullud *pullud;
if (!pct->soc->pullud) {
dev_err(pct->dev, "%s AB chip doesn't support pull up/down feature",
__func__);
ret = -EPERM;
goto out;
}
pullud = pct->soc->pullud;
if ((offset < pullud->first_pin)
|| (offset > pullud->last_pin)) {
ret = -EINVAL;
goto out;
}
ret = abx500_get_register_interruptible(pct->dev,
AB8500_MISC, AB8540_GPIO_PULL_UPDOWN_REG, &val);
pos = (offset - pullud->first_pin) << 1;
*pull_updown = (val >> pos) & AB8540_GPIO_PULL_UPDOWN_MASK;
out:
if (ret < 0)
dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
return ret;
}
static int abx500_set_pull_updown(struct abx500_pinctrl *pct,
int offset, enum abx500_gpio_pull_updown val)
{
u8 pos;
int ret;
@ -203,8 +257,7 @@ static int abx500_config_pull_updown(struct abx500_pinctrl *pct,
ret = -EINVAL;
goto out;
}
pos = offset << 1;
pos = (offset - pullud->first_pin) << 1;
ret = abx500_mask_and_set_register_interruptible(pct->dev,
AB8500_MISC, AB8540_GPIO_PULL_UPDOWN_REG,
@ -217,33 +270,51 @@ out:
return ret;
}
static bool abx500_pullud_supported(struct gpio_chip *chip, unsigned gpio)
{
struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
struct pullud *pullud = pct->soc->pullud;
return (pullud &&
gpio >= pullud->first_pin &&
gpio <= pullud->last_pin);
}
static int abx500_gpio_direction_output(struct gpio_chip *chip,
unsigned offset,
int val)
{
struct abx500_pinctrl *pct = to_abx500_pinctrl(chip);
struct pullud *pullud = pct->soc->pullud;
unsigned gpio;
int ret;
/* set direction as output */
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 1);
ret = abx500_gpio_set_bits(chip,
AB8500_GPIO_DIR1_REG,
offset,
ABX500_GPIO_OUTPUT);
if (ret < 0)
return ret;
goto out;
/* disable pull down */
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG, offset, 1);
ret = abx500_gpio_set_bits(chip,
AB8500_GPIO_PUD1_REG,
offset,
ABX500_GPIO_PULL_NONE);
if (ret < 0)
return ret;
goto out;
/* if supported, disable both pull down and pull up */
gpio = offset + 1;
if (pullud && gpio >= pullud->first_pin && gpio <= pullud->last_pin) {
ret = abx500_config_pull_updown(pct,
if (abx500_pullud_supported(chip, gpio)) {
ret = abx500_set_pull_updown(pct,
gpio,
ABX500_GPIO_PULL_NONE);
if (ret < 0)
return ret;
}
out:
if (ret < 0) {
dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
return ret;
}
/* set the output as 1 or 0 */
@ -253,7 +324,10 @@ static int abx500_gpio_direction_output(struct gpio_chip *chip,
static int abx500_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
/* set the register as input */
return abx500_gpio_set_bits(chip, AB8500_GPIO_DIR1_REG, offset, 0);
return abx500_gpio_set_bits(chip,
AB8500_GPIO_DIR1_REG,
offset,
ABX500_GPIO_INPUT);
}
static int abx500_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
@ -338,10 +412,16 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
if (af.alt_bit1 != UNUSED) {
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
offset, 0);
if (ret < 0)
goto out;
ret = abx500_gpio_set_bits(chip,
AB8500_GPIO_ALTFUN_REG,
af.alt_bit1,
!!(af.alta_val && BIT(0)));
if (ret < 0)
goto out;
if (af.alt_bit2 != UNUSED)
ret = abx500_gpio_set_bits(chip,
AB8500_GPIO_ALTFUN_REG,
@ -355,8 +435,14 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
case ABX500_ALT_B:
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
offset, 0);
if (ret < 0)
goto out;
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
af.alt_bit1, !!(af.altb_val && BIT(0)));
if (ret < 0)
goto out;
if (af.alt_bit2 != UNUSED)
ret = abx500_gpio_set_bits(chip,
AB8500_GPIO_ALTFUN_REG,
@ -367,8 +453,14 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
case ABX500_ALT_C:
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_SEL1_REG,
offset, 0);
if (ret < 0)
goto out;
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
af.alt_bit2, !!(af.altc_val && BIT(0)));
if (ret < 0)
goto out;
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_ALTFUN_REG,
af.alt_bit2, !!(af.altc_val && BIT(1)));
break;
@ -378,11 +470,14 @@ static int abx500_set_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
return -EINVAL;
}
out:
if (ret < 0)
dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
return ret;
}
static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
static int abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
unsigned gpio)
{
u8 mode;
@ -393,6 +488,7 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
struct alternate_functions af = pct->soc->alternate_functions[gpio];
/* on ABx5xx, there is no GPIO0, so adjust the offset */
unsigned offset = gpio - 1;
int ret;
/*
* if gpiosel_bit is set to unused,
@ -402,8 +498,11 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
return ABX500_DEFAULT;
/* read GpioSelx register */
abx500_gpio_get_bit(chip, AB8500_GPIO_SEL1_REG + (offset / 8),
ret = abx500_gpio_get_bit(chip, AB8500_GPIO_SEL1_REG + (offset / 8),
af.gpiosel_bit, &bit_mode);
if (ret < 0)
goto out;
mode = bit_mode;
/* sanity check */
@ -435,14 +534,19 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
* pin use the AlternatFunction register
* read alt_bit1 value
*/
abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG,
ret = abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG,
af.alt_bit1, &alt_bit1);
if (ret < 0)
goto out;
if (af.alt_bit2 != UNUSED)
if (af.alt_bit2 != UNUSED) {
/* read alt_bit2 value */
abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG, af.alt_bit2,
ret = abx500_gpio_get_bit(chip, AB8500_GPIO_ALTFUN_REG,
af.alt_bit2,
&alt_bit2);
else
if (ret < 0)
goto out;
} else
alt_bit2 = 0;
mode = (alt_bit2 << 1) + alt_bit1;
@ -452,6 +556,10 @@ static u8 abx500_get_mode(struct pinctrl_dev *pctldev, struct gpio_chip *chip,
return ABX500_ALT_B;
else
return ABX500_ALT_C;
out:
dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
return ret;
}
#ifdef CONFIG_DEBUG_FS
@ -463,11 +571,14 @@ static void abx500_gpio_dbg_show_one(struct seq_file *s,
struct gpio_chip *chip,
unsigned offset, unsigned gpio)
{
struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
const char *label = gpiochip_is_requested(chip, offset - 1);
u8 gpio_offset = offset - 1;
int mode = -1;
bool is_out;
bool pull;
bool pd;
enum abx500_gpio_pull_updown pud = 0;
int ret;
const char *modes[] = {
[ABX500_DEFAULT] = "default",
@ -476,21 +587,48 @@ static void abx500_gpio_dbg_show_one(struct seq_file *s,
[ABX500_ALT_C] = "altC",
};
abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG, gpio_offset, &is_out);
abx500_gpio_get_bit(chip, AB8500_GPIO_PUD1_REG, gpio_offset, &pull);
const char *pull_up_down[] = {
[ABX500_GPIO_PULL_DOWN] = "pull down",
[ABX500_GPIO_PULL_NONE] = "pull none",
[ABX500_GPIO_PULL_NONE + 1] = "pull none",
[ABX500_GPIO_PULL_UP] = "pull up",
};
ret = abx500_gpio_get_bit(chip, AB8500_GPIO_DIR1_REG,
gpio_offset, &is_out);
if (ret < 0)
goto out;
seq_printf(s, " gpio-%-3d (%-20.20s) %-3s",
gpio, label ?: "(none)",
is_out ? "out" : "in ");
if (!is_out) {
if (abx500_pullud_supported(chip, offset)) {
ret = abx500_get_pull_updown(pct, offset, &pud);
if (ret < 0)
goto out;
seq_printf(s, " %-9s", pull_up_down[pud]);
} else {
ret = abx500_gpio_get_bit(chip, AB8500_GPIO_PUD1_REG,
gpio_offset, &pd);
if (ret < 0)
goto out;
seq_printf(s, " %-9s", pull_up_down[pd]);
}
} else
seq_printf(s, " %-9s", chip->get(chip, offset) ? "hi" : "lo");
if (pctldev)
mode = abx500_get_mode(pctldev, chip, offset);
seq_printf(s, " gpio-%-3d (%-20.20s) %-3s %-9s %s",
gpio, label ?: "(none)",
is_out ? "out" : "in ",
is_out ?
(chip->get
? (chip->get(chip, offset) ? "hi" : "lo")
: "? ")
: (pull ? "pull up" : "pull down"),
(mode < 0) ? "unknown" : modes[mode]);
seq_printf(s, " %s", (mode < 0) ? "unknown" : modes[mode]);
out:
if (ret < 0)
dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
}
static void abx500_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
@ -594,6 +732,9 @@ static int abx500_pmx_enable(struct pinctrl_dev *pctldev, unsigned function,
ret = abx500_set_mode(pctldev, chip, g->pins[i], g->altsetting);
}
if (ret < 0)
dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
return ret;
}
@ -642,10 +783,8 @@ static int abx500_gpio_request_enable(struct pinctrl_dev *pctldev,
ret = abx500_set_mode(pct->pctldev, &pct->chip,
offset, p->altfunc);
if (ret < 0) {
if (ret < 0)
dev_err(pct->dev, "%s setting altfunc failed\n", __func__);
return ret;
}
return ret;
}
@ -704,11 +843,193 @@ static void abx500_pin_dbg_show(struct pinctrl_dev *pctldev,
chip->base + offset - 1);
}
static void abx500_dt_free_map(struct pinctrl_dev *pctldev,
struct pinctrl_map *map, unsigned num_maps)
{
int i;
for (i = 0; i < num_maps; i++)
if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
kfree(map[i].data.configs.configs);
kfree(map);
}
static int abx500_dt_reserve_map(struct pinctrl_map **map,
unsigned *reserved_maps,
unsigned *num_maps,
unsigned reserve)
{
unsigned old_num = *reserved_maps;
unsigned new_num = *num_maps + reserve;
struct pinctrl_map *new_map;
if (old_num >= new_num)
return 0;
new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
if (!new_map)
return -ENOMEM;
memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
*map = new_map;
*reserved_maps = new_num;
return 0;
}
static int abx500_dt_add_map_mux(struct pinctrl_map **map,
unsigned *reserved_maps,
unsigned *num_maps, const char *group,
const char *function)
{
if (*num_maps == *reserved_maps)
return -ENOSPC;
(*map)[*num_maps].type = PIN_MAP_TYPE_MUX_GROUP;
(*map)[*num_maps].data.mux.group = group;
(*map)[*num_maps].data.mux.function = function;
(*num_maps)++;
return 0;
}
static int abx500_dt_add_map_configs(struct pinctrl_map **map,
unsigned *reserved_maps,
unsigned *num_maps, const char *group,
unsigned long *configs, unsigned num_configs)
{
unsigned long *dup_configs;
if (*num_maps == *reserved_maps)
return -ENOSPC;
dup_configs = kmemdup(configs, num_configs * sizeof(*dup_configs),
GFP_KERNEL);
if (!dup_configs)
return -ENOMEM;
(*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_PIN;
(*map)[*num_maps].data.configs.group_or_pin = group;
(*map)[*num_maps].data.configs.configs = dup_configs;
(*map)[*num_maps].data.configs.num_configs = num_configs;
(*num_maps)++;
return 0;
}
static const char *abx500_find_pin_name(struct pinctrl_dev *pctldev,
const char *pin_name)
{
int i, pin_number;
struct abx500_pinctrl *npct = pinctrl_dev_get_drvdata(pctldev);
if (sscanf((char *)pin_name, "GPIO%d", &pin_number) == 1)
for (i = 0; i < npct->soc->npins; i++)
if (npct->soc->pins[i].number == pin_number)
return npct->soc->pins[i].name;
return NULL;
}
static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev,
struct device_node *np,
struct pinctrl_map **map,
unsigned *reserved_maps,
unsigned *num_maps)
{
int ret;
const char *function = NULL;
unsigned long *configs;
unsigned int nconfigs = 0;
bool has_config = 0;
unsigned reserve = 0;
struct property *prop;
const char *group, *gpio_name;
struct device_node *np_config;
ret = of_property_read_string(np, "ste,function", &function);
if (ret >= 0)
reserve = 1;
ret = pinconf_generic_parse_dt_config(np, &configs, &nconfigs);
if (nconfigs)
has_config = 1;
np_config = of_parse_phandle(np, "ste,config", 0);
if (np_config) {
ret = pinconf_generic_parse_dt_config(np_config, &configs,
&nconfigs);
if (ret)
goto exit;
has_config |= nconfigs;
}
ret = of_property_count_strings(np, "ste,pins");
if (ret < 0)
goto exit;
if (has_config)
reserve++;
reserve *= ret;
ret = abx500_dt_reserve_map(map, reserved_maps, num_maps, reserve);
if (ret < 0)
goto exit;
of_property_for_each_string(np, "ste,pins", prop, group) {
if (function) {
ret = abx500_dt_add_map_mux(map, reserved_maps,
num_maps, group, function);
if (ret < 0)
goto exit;
}
if (has_config) {
gpio_name = abx500_find_pin_name(pctldev, group);
ret = abx500_dt_add_map_configs(map, reserved_maps,
num_maps, gpio_name, configs, 1);
if (ret < 0)
goto exit;
}
}
exit:
return ret;
}
static int abx500_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np_config,
struct pinctrl_map **map, unsigned *num_maps)
{
unsigned reserved_maps;
struct device_node *np;
int ret;
reserved_maps = 0;
*map = NULL;
*num_maps = 0;
for_each_child_of_node(np_config, np) {
ret = abx500_dt_subnode_to_map(pctldev, np, map,
&reserved_maps, num_maps);
if (ret < 0) {
abx500_dt_free_map(pctldev, *map, *num_maps);
return ret;
}
}
return 0;
}
static const struct pinctrl_ops abx500_pinctrl_ops = {
.get_groups_count = abx500_get_groups_cnt,
.get_group_name = abx500_get_group_name,
.get_group_pins = abx500_get_group_pins,
.pin_dbg_show = abx500_pin_dbg_show,
.dt_node_to_map = abx500_dt_node_to_map,
.dt_free_map = abx500_dt_free_map,
};
static int abx500_pin_config_get(struct pinctrl_dev *pctldev,
@ -723,10 +1044,9 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev,
unsigned long config)
{
struct abx500_pinctrl *pct = pinctrl_dev_get_drvdata(pctldev);
struct pullud *pullud = pct->soc->pullud;
struct gpio_chip *chip = &pct->chip;
unsigned offset;
int ret;
int ret = -EINVAL;
enum pin_config_param param = pinconf_to_config_param(config);
enum pin_config_param argument = pinconf_to_config_argument(config);
@ -739,12 +1059,10 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev,
offset = pin - 1;
switch (param) {
case PIN_CONFIG_BIAS_PULL_DOWN:
/*
* if argument = 1 set the pull down
* else clear the pull down
*/
case PIN_CONFIG_BIAS_DISABLE:
ret = abx500_gpio_direction_input(chip, offset);
if (ret < 0)
goto out;
/*
* Some chips only support pull down, while some actually
* support both pull up and pull down. Such chips have
@ -752,28 +1070,72 @@ static int abx500_pin_config_set(struct pinctrl_dev *pctldev,
* both features. If the pin is not within that range, we
* fall back to the old bit set that only support pull down.
*/
if (pullud &&
pin >= pullud->first_pin &&
pin <= pullud->last_pin)
ret = abx500_config_pull_updown(pct,
if (abx500_pullud_supported(chip, pin))
ret = abx500_set_pull_updown(pct,
pin,
ABX500_GPIO_PULL_NONE);
else
/* Chip only supports pull down */
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG,
offset, ABX500_GPIO_PULL_NONE);
break;
case PIN_CONFIG_BIAS_PULL_DOWN:
ret = abx500_gpio_direction_input(chip, offset);
if (ret < 0)
goto out;
/*
* if argument = 1 set the pull down
* else clear the pull down
* Some chips only support pull down, while some actually
* support both pull up and pull down. Such chips have
* a "pullud" range specified for the pins that support
* both features. If the pin is not within that range, we
* fall back to the old bit set that only support pull down.
*/
if (abx500_pullud_supported(chip, pin))
ret = abx500_set_pull_updown(pct,
pin,
argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE);
else
/* Chip only supports pull down */
ret = abx500_gpio_set_bits(chip, AB8500_GPIO_PUD1_REG,
offset, argument ? 0 : 1);
offset,
argument ? ABX500_GPIO_PULL_DOWN : ABX500_GPIO_PULL_NONE);
break;
case PIN_CONFIG_BIAS_PULL_UP:
ret = abx500_gpio_direction_input(chip, offset);
if (ret < 0)
goto out;
/*
* if argument = 1 set the pull up
* else clear the pull up
*/
ret = abx500_gpio_direction_input(chip, offset);
/*
* Some chips only support pull down, while some actually
* support both pull up and pull down. Such chips have
* a "pullud" range specified for the pins that support
* both features. If the pin is not within that range, do
* nothing
*/
if (abx500_pullud_supported(chip, pin))
ret = abx500_set_pull_updown(pct,
pin,
argument ? ABX500_GPIO_PULL_UP : ABX500_GPIO_PULL_NONE);
break;
case PIN_CONFIG_OUTPUT:
ret = abx500_gpio_direction_output(chip, offset, argument);
break;
default:
dev_err(chip->dev, "illegal configuration requested\n");
return -EINVAL;
}
out:
if (ret < 0)
dev_err(pct->dev, "%s failed (%d)\n", __func__, ret);
return ret;
}
@ -881,9 +1243,6 @@ static int abx500_gpio_probe(struct platform_device *pdev)
id = (unsigned long)match->data;
}
/* initialize the lock */
mutex_init(&pct->lock);
/* Poke in other ASIC variants here */
switch (id) {
case PINCTRL_AB8500:
@ -900,13 +1259,11 @@ static int abx500_gpio_probe(struct platform_device *pdev)
break;
default:
dev_err(&pdev->dev, "Unsupported pinctrl sub driver (%d)\n", id);
mutex_destroy(&pct->lock);
return -EINVAL;
}
if (!pct->soc) {
dev_err(&pdev->dev, "Invalid SOC data\n");
mutex_destroy(&pct->lock);
return -EINVAL;
}
@ -917,7 +1274,6 @@ static int abx500_gpio_probe(struct platform_device *pdev)
ret = gpiochip_add(&pct->chip);
if (ret) {
dev_err(&pdev->dev, "unable to add gpiochip: %d\n", ret);
mutex_destroy(&pct->lock);
return ret;
}
dev_info(&pdev->dev, "added gpiochip\n");
@ -954,7 +1310,6 @@ out_rem_chip:
if (err)
dev_info(&pdev->dev, "failed to remove gpiochip\n");
mutex_destroy(&pct->lock);
return ret;
}
@ -974,8 +1329,6 @@ static int abx500_gpio_remove(struct platform_device *pdev)
return ret;
}
mutex_destroy(&pct->lock);
return 0;
}

View file

@ -1543,12 +1543,6 @@ static int at91_gpio_probe(struct platform_device *pdev)
goto err;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
ret = -ENOENT;
goto err;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
ret = irq;
@ -1561,6 +1555,7 @@ static int at91_gpio_probe(struct platform_device *pdev)
goto err;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
at91_chip->regbase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(at91_chip->regbase)) {
ret = PTR_ERR(at91_chip->regbase);

View file

@ -0,0 +1,543 @@
/*
* Pinctrl GPIO driver for Intel Baytrail
* Copyright (c) 2012-2013, Intel Corporation.
*
* Author: Mathias Nyman <mathias.nyman@linux.intel.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/gpio.h>
#include <linux/irqdomain.h>
#include <linux/acpi.h>
#include <linux/acpi_gpio.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/io.h>
#include <linux/pm_runtime.h>
#include <linux/pinctrl/pinctrl.h>
/* memory mapped register offsets */
#define BYT_CONF0_REG 0x000
#define BYT_CONF1_REG 0x004
#define BYT_VAL_REG 0x008
#define BYT_DFT_REG 0x00c
#define BYT_INT_STAT_REG 0x800
/* BYT_CONF0_REG register bits */
#define BYT_TRIG_NEG BIT(26)
#define BYT_TRIG_POS BIT(25)
#define BYT_TRIG_LVL BIT(24)
#define BYT_PIN_MUX 0x07
/* BYT_VAL_REG register bits */
#define BYT_INPUT_EN BIT(2) /* 0: input enabled (active low)*/
#define BYT_OUTPUT_EN BIT(1) /* 0: output enabled (active low)*/
#define BYT_LEVEL BIT(0)
#define BYT_DIR_MASK (BIT(1) | BIT(2))
#define BYT_TRIG_MASK (BIT(26) | BIT(25) | BIT(24))
#define BYT_NGPIO_SCORE 102
#define BYT_NGPIO_NCORE 28
#define BYT_NGPIO_SUS 44
/*
* Baytrail gpio controller consist of three separate sub-controllers called
* SCORE, NCORE and SUS. The sub-controllers are identified by their acpi UID.
*
* GPIO numbering is _not_ ordered meaning that gpio # 0 in ACPI namespace does
* _not_ correspond to the first gpio register at controller's gpio base.
* There is no logic or pattern in mapping gpio numbers to registers (pads) so
* each sub-controller needs to have its own mapping table
*/
/* score_pins[gpio_nr] = pad_nr */
static unsigned const score_pins[BYT_NGPIO_SCORE] = {
85, 89, 93, 96, 99, 102, 98, 101, 34, 37,
36, 38, 39, 35, 40, 84, 62, 61, 64, 59,
54, 56, 60, 55, 63, 57, 51, 50, 53, 47,
52, 49, 48, 43, 46, 41, 45, 42, 58, 44,
95, 105, 70, 68, 67, 66, 69, 71, 65, 72,
86, 90, 88, 92, 103, 77, 79, 83, 78, 81,
80, 82, 13, 12, 15, 14, 17, 18, 19, 16,
2, 1, 0, 4, 6, 7, 9, 8, 33, 32,
31, 30, 29, 27, 25, 28, 26, 23, 21, 20,
24, 22, 5, 3, 10, 11, 106, 87, 91, 104,
97, 100,
};
static unsigned const ncore_pins[BYT_NGPIO_NCORE] = {
19, 18, 17, 20, 21, 22, 24, 25, 23, 16,
14, 15, 12, 26, 27, 1, 4, 8, 11, 0,
3, 6, 10, 13, 2, 5, 9, 7,
};
static unsigned const sus_pins[BYT_NGPIO_SUS] = {
29, 33, 30, 31, 32, 34, 36, 35, 38, 37,
18, 7, 11, 20, 17, 1, 8, 10, 19, 12,
0, 2, 23, 39, 28, 27, 22, 21, 24, 25,
26, 51, 56, 54, 49, 55, 48, 57, 50, 58,
52, 53, 59, 40,
};
static struct pinctrl_gpio_range byt_ranges[] = {
{
.name = "1", /* match with acpi _UID in probe */
.npins = BYT_NGPIO_SCORE,
.pins = score_pins,
},
{
.name = "2",
.npins = BYT_NGPIO_NCORE,
.pins = ncore_pins,
},
{
.name = "3",
.npins = BYT_NGPIO_SUS,
.pins = sus_pins,
},
{
},
};
struct byt_gpio {
struct gpio_chip chip;
struct irq_domain *domain;
struct platform_device *pdev;
spinlock_t lock;
void __iomem *reg_base;
struct pinctrl_gpio_range *range;
};
static void __iomem *byt_gpio_reg(struct gpio_chip *chip, unsigned offset,
int reg)
{
struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
u32 reg_offset;
void __iomem *ptr;
if (reg == BYT_INT_STAT_REG)
reg_offset = (offset / 32) * 4;
else
reg_offset = vg->range->pins[offset] * 16;
ptr = (void __iomem *) (vg->reg_base + reg_offset + reg);
return ptr;
}
static int byt_gpio_request(struct gpio_chip *chip, unsigned offset)
{
struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
pm_runtime_get(&vg->pdev->dev);
return 0;
}
static void byt_gpio_free(struct gpio_chip *chip, unsigned offset)
{
struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
u32 value;
/* clear interrupt triggering */
value = readl(reg);
value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
writel(value, reg);
pm_runtime_put(&vg->pdev->dev);
}
static int byt_irq_type(struct irq_data *d, unsigned type)
{
struct byt_gpio *vg = irq_data_get_irq_chip_data(d);
u32 offset = irqd_to_hwirq(d);
u32 value;
unsigned long flags;
void __iomem *reg = byt_gpio_reg(&vg->chip, offset, BYT_CONF0_REG);
if (offset >= vg->chip.ngpio)
return -EINVAL;
spin_lock_irqsave(&vg->lock, flags);
value = readl(reg);
/* For level trigges the BYT_TRIG_POS and BYT_TRIG_NEG bits
* are used to indicate high and low level triggering
*/
value &= ~(BYT_TRIG_POS | BYT_TRIG_NEG | BYT_TRIG_LVL);
switch (type) {
case IRQ_TYPE_LEVEL_HIGH:
value |= BYT_TRIG_LVL;
case IRQ_TYPE_EDGE_RISING:
value |= BYT_TRIG_POS;
break;
case IRQ_TYPE_LEVEL_LOW:
value |= BYT_TRIG_LVL;
case IRQ_TYPE_EDGE_FALLING:
value |= BYT_TRIG_NEG;
break;
case IRQ_TYPE_EDGE_BOTH:
value |= (BYT_TRIG_NEG | BYT_TRIG_POS);
break;
}
writel(value, reg);
spin_unlock_irqrestore(&vg->lock, flags);
return 0;
}
static int byt_gpio_get(struct gpio_chip *chip, unsigned offset)
{
void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
return readl(reg) & BYT_LEVEL;
}
static void byt_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
{
struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
unsigned long flags;
u32 old_val;
spin_lock_irqsave(&vg->lock, flags);
old_val = readl(reg);
if (value)
writel(old_val | BYT_LEVEL, reg);
else
writel(old_val & ~BYT_LEVEL, reg);
spin_unlock_irqrestore(&vg->lock, flags);
}
static int byt_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
void __iomem *reg = byt_gpio_reg(chip, offset, BYT_VAL_REG);
unsigned long flags;
u32 value;
spin_lock_irqsave(&vg->lock, flags);
value = readl(reg) | BYT_DIR_MASK;
value = value & (~BYT_INPUT_EN); /* active low */
writel(value, reg);
spin_unlock_irqrestore(&vg->lock, flags);
return 0;
}
static int byt_gpio_direction_output(struct gpio_chip *chip,
unsigned gpio, int value)
{
struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
void __iomem *reg = byt_gpio_reg(chip, gpio, BYT_VAL_REG);
unsigned long flags;
u32 reg_val;
spin_lock_irqsave(&vg->lock, flags);
reg_val = readl(reg) | (BYT_DIR_MASK | !!value);
reg_val &= ~(BYT_OUTPUT_EN | !value);
writel(reg_val, reg);
spin_unlock_irqrestore(&vg->lock, flags);
return 0;
}
static void byt_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
{
struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
int i;
unsigned long flags;
u32 conf0, val, offs;
spin_lock_irqsave(&vg->lock, flags);
for (i = 0; i < vg->chip.ngpio; i++) {
offs = vg->range->pins[i] * 16;
conf0 = readl(vg->reg_base + offs + BYT_CONF0_REG);
val = readl(vg->reg_base + offs + BYT_VAL_REG);
seq_printf(s,
" gpio-%-3d %s %s %s pad-%-3d offset:0x%03x mux:%d %s%s%s\n",
i,
val & BYT_INPUT_EN ? " " : "in",
val & BYT_OUTPUT_EN ? " " : "out",
val & BYT_LEVEL ? "hi" : "lo",
vg->range->pins[i], offs,
conf0 & 0x7,
conf0 & BYT_TRIG_NEG ? "fall " : "",
conf0 & BYT_TRIG_POS ? "rise " : "",
conf0 & BYT_TRIG_LVL ? "lvl " : "");
}
spin_unlock_irqrestore(&vg->lock, flags);
}
static int byt_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct byt_gpio *vg = container_of(chip, struct byt_gpio, chip);
return irq_create_mapping(vg->domain, offset);
}
static void byt_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
{
struct irq_data *data = irq_desc_get_irq_data(desc);
struct byt_gpio *vg = irq_data_get_irq_handler_data(data);
struct irq_chip *chip = irq_data_get_irq_chip(data);
u32 base, pin, mask;
void __iomem *reg;
u32 pending;
unsigned virq;
int looplimit = 0;
/* check from GPIO controller which pin triggered the interrupt */
for (base = 0; base < vg->chip.ngpio; base += 32) {
reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG);
while ((pending = readl(reg))) {
pin = __ffs(pending);
mask = BIT(pin);
/* Clear before handling so we can't lose an edge */
writel(mask, reg);
virq = irq_find_mapping(vg->domain, base + pin);
generic_handle_irq(virq);
/* In case bios or user sets triggering incorretly a pin
* might remain in "interrupt triggered" state.
*/
if (looplimit++ > 32) {
dev_err(&vg->pdev->dev,
"Gpio %d interrupt flood, disabling\n",
base + pin);
reg = byt_gpio_reg(&vg->chip, base + pin,
BYT_CONF0_REG);
mask = readl(reg);
mask &= ~(BYT_TRIG_NEG | BYT_TRIG_POS |
BYT_TRIG_LVL);
writel(mask, reg);
mask = readl(reg); /* flush */
break;
}
}
}
chip->irq_eoi(data);
}
static void byt_irq_unmask(struct irq_data *d)
{
}
static void byt_irq_mask(struct irq_data *d)
{
}
static struct irq_chip byt_irqchip = {
.name = "BYT-GPIO",
.irq_mask = byt_irq_mask,
.irq_unmask = byt_irq_unmask,
.irq_set_type = byt_irq_type,
};
static void byt_gpio_irq_init_hw(struct byt_gpio *vg)
{
void __iomem *reg;
u32 base, value;
/* clear interrupt status trigger registers */
for (base = 0; base < vg->chip.ngpio; base += 32) {
reg = byt_gpio_reg(&vg->chip, base, BYT_INT_STAT_REG);
writel(0xffffffff, reg);
/* make sure trigger bits are cleared, if not then a pin
might be misconfigured in bios */
value = readl(reg);
if (value)
dev_err(&vg->pdev->dev,
"GPIO interrupt error, pins misconfigured\n");
}
}
static int byt_gpio_irq_map(struct irq_domain *d, unsigned int virq,
irq_hw_number_t hw)
{
struct byt_gpio *vg = d->host_data;
irq_set_chip_and_handler_name(virq, &byt_irqchip, handle_simple_irq,
"demux");
irq_set_chip_data(virq, vg);
irq_set_irq_type(virq, IRQ_TYPE_NONE);
return 0;
}
static const struct irq_domain_ops byt_gpio_irq_ops = {
.map = byt_gpio_irq_map,
};
static int byt_gpio_probe(struct platform_device *pdev)
{
struct byt_gpio *vg;
struct gpio_chip *gc;
struct resource *mem_rc, *irq_rc;
struct device *dev = &pdev->dev;
struct acpi_device *acpi_dev;
struct pinctrl_gpio_range *range;
acpi_handle handle = ACPI_HANDLE(dev);
unsigned hwirq;
int ret;
if (acpi_bus_get_device(handle, &acpi_dev))
return -ENODEV;
vg = devm_kzalloc(dev, sizeof(struct byt_gpio), GFP_KERNEL);
if (!vg) {
dev_err(&pdev->dev, "can't allocate byt_gpio chip data\n");
return -ENOMEM;
}
for (range = byt_ranges; range->name; range++) {
if (!strcmp(acpi_dev->pnp.unique_id, range->name)) {
vg->chip.ngpio = range->npins;
vg->range = range;
break;
}
}
if (!vg->chip.ngpio || !vg->range)
return -ENODEV;
vg->pdev = pdev;
platform_set_drvdata(pdev, vg);
mem_rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
vg->reg_base = devm_ioremap_resource(dev, mem_rc);
if (IS_ERR(vg->reg_base))
return PTR_ERR(vg->reg_base);
spin_lock_init(&vg->lock);
gc = &vg->chip;
gc->label = dev_name(&pdev->dev);
gc->owner = THIS_MODULE;
gc->request = byt_gpio_request;
gc->free = byt_gpio_free;
gc->direction_input = byt_gpio_direction_input;
gc->direction_output = byt_gpio_direction_output;
gc->get = byt_gpio_get;
gc->set = byt_gpio_set;
gc->dbg_show = byt_gpio_dbg_show;
gc->base = -1;
gc->can_sleep = 0;
gc->dev = dev;
ret = gpiochip_add(gc);
if (ret) {
dev_err(&pdev->dev, "failed adding byt-gpio chip\n");
return ret;
}
/* set up interrupts */
irq_rc = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (irq_rc && irq_rc->start) {
hwirq = irq_rc->start;
gc->to_irq = byt_gpio_to_irq;
vg->domain = irq_domain_add_linear(NULL, gc->ngpio,
&byt_gpio_irq_ops, vg);
if (!vg->domain)
return -ENXIO;
byt_gpio_irq_init_hw(vg);
irq_set_handler_data(hwirq, vg);
irq_set_chained_handler(hwirq, byt_gpio_irq_handler);
/* Register interrupt handlers for gpio signaled acpi events */
acpi_gpiochip_request_interrupts(gc);
}
pm_runtime_enable(dev);
return 0;
}
static int byt_gpio_runtime_suspend(struct device *dev)
{
return 0;
}
static int byt_gpio_runtime_resume(struct device *dev)
{
return 0;
}
static const struct dev_pm_ops byt_gpio_pm_ops = {
.runtime_suspend = byt_gpio_runtime_suspend,
.runtime_resume = byt_gpio_runtime_resume,
};
static const struct acpi_device_id byt_gpio_acpi_match[] = {
{ "INT33B2", 0 },
{ }
};
MODULE_DEVICE_TABLE(acpi, byt_gpio_acpi_match);
static int byt_gpio_remove(struct platform_device *pdev)
{
struct byt_gpio *vg = platform_get_drvdata(pdev);
int err;
pm_runtime_disable(&pdev->dev);
err = gpiochip_remove(&vg->chip);
if (err)
dev_warn(&pdev->dev, "failed to remove gpio_chip.\n");
return 0;
}
static struct platform_driver byt_gpio_driver = {
.probe = byt_gpio_probe,
.remove = byt_gpio_remove,
.driver = {
.name = "byt_gpio",
.owner = THIS_MODULE,
.pm = &byt_gpio_pm_ops,
.acpi_match_table = ACPI_PTR(byt_gpio_acpi_match),
},
};
static int __init byt_gpio_init(void)
{
return platform_driver_register(&byt_gpio_driver);
}
subsys_initcall(byt_gpio_init);

View file

@ -113,7 +113,7 @@ static struct lock_class_key gpio_lock_class;
/* pins are just named GPIO0..GPIO53 */
#define BCM2835_GPIO_PIN(a) PINCTRL_PIN(a, "gpio" #a)
struct pinctrl_pin_desc bcm2835_gpio_pins[] = {
static struct pinctrl_pin_desc bcm2835_gpio_pins[] = {
BCM2835_GPIO_PIN(0),
BCM2835_GPIO_PIN(1),
BCM2835_GPIO_PIN(2),

View file

@ -853,7 +853,6 @@ static int __exit u300_gpio_remove(struct platform_device *pdev)
}
u300_gpio_free_ports(gpio);
clk_disable_unprepare(gpio->clk);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -50,28 +50,21 @@ static const struct of_device_id exynos_wkup_irq_ids[] = {
{ }
};
static void exynos_gpio_irq_unmask(struct irq_data *irqd)
{
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
struct samsung_pinctrl_drv_data *d = bank->drvdata;
unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset;
unsigned long mask;
mask = readl(d->virt_base + reg_mask);
mask &= ~(1 << irqd->hwirq);
writel(mask, d->virt_base + reg_mask);
}
static void exynos_gpio_irq_mask(struct irq_data *irqd)
{
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
struct samsung_pinctrl_drv_data *d = bank->drvdata;
unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset;
unsigned long mask;
unsigned long flags;
spin_lock_irqsave(&bank->slock, flags);
mask = readl(d->virt_base + reg_mask);
mask |= 1 << irqd->hwirq;
writel(mask, d->virt_base + reg_mask);
spin_unlock_irqrestore(&bank->slock, flags);
}
static void exynos_gpio_irq_ack(struct irq_data *irqd)
@ -83,6 +76,34 @@ static void exynos_gpio_irq_ack(struct irq_data *irqd)
writel(1 << irqd->hwirq, d->virt_base + reg_pend);
}
static void exynos_gpio_irq_unmask(struct irq_data *irqd)
{
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
struct samsung_pinctrl_drv_data *d = bank->drvdata;
unsigned long reg_mask = d->ctrl->geint_mask + bank->eint_offset;
unsigned long mask;
unsigned long flags;
/*
* Ack level interrupts right before unmask
*
* If we don't do this we'll get a double-interrupt. Level triggered
* interrupts must not fire an interrupt if the level is not
* _currently_ active, even if it was active while the interrupt was
* masked.
*/
if (irqd_get_trigger_type(irqd) & IRQ_TYPE_LEVEL_MASK)
exynos_gpio_irq_ack(irqd);
spin_lock_irqsave(&bank->slock, flags);
mask = readl(d->virt_base + reg_mask);
mask &= ~(1 << irqd->hwirq);
writel(mask, d->virt_base + reg_mask);
spin_unlock_irqrestore(&bank->slock, flags);
}
static int exynos_gpio_irq_set_type(struct irq_data *irqd, unsigned int type)
{
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
@ -258,28 +279,21 @@ err_domains:
return ret;
}
static void exynos_wkup_irq_unmask(struct irq_data *irqd)
{
struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd);
struct samsung_pinctrl_drv_data *d = b->drvdata;
unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset;
unsigned long mask;
mask = readl(d->virt_base + reg_mask);
mask &= ~(1 << irqd->hwirq);
writel(mask, d->virt_base + reg_mask);
}
static void exynos_wkup_irq_mask(struct irq_data *irqd)
{
struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd);
struct samsung_pinctrl_drv_data *d = b->drvdata;
unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset;
unsigned long mask;
unsigned long flags;
spin_lock_irqsave(&b->slock, flags);
mask = readl(d->virt_base + reg_mask);
mask |= 1 << irqd->hwirq;
writel(mask, d->virt_base + reg_mask);
spin_unlock_irqrestore(&b->slock, flags);
}
static void exynos_wkup_irq_ack(struct irq_data *irqd)
@ -291,6 +305,34 @@ static void exynos_wkup_irq_ack(struct irq_data *irqd)
writel(1 << irqd->hwirq, d->virt_base + pend);
}
static void exynos_wkup_irq_unmask(struct irq_data *irqd)
{
struct samsung_pin_bank *b = irq_data_get_irq_chip_data(irqd);
struct samsung_pinctrl_drv_data *d = b->drvdata;
unsigned long reg_mask = d->ctrl->weint_mask + b->eint_offset;
unsigned long mask;
unsigned long flags;
/*
* Ack level interrupts right before unmask
*
* If we don't do this we'll get a double-interrupt. Level triggered
* interrupts must not fire an interrupt if the level is not
* _currently_ active, even if it was active while the interrupt was
* masked.
*/
if (irqd_get_trigger_type(irqd) & IRQ_TYPE_LEVEL_MASK)
exynos_wkup_irq_ack(irqd);
spin_lock_irqsave(&b->slock, flags);
mask = readl(d->virt_base + reg_mask);
mask &= ~(1 << irqd->hwirq);
writel(mask, d->virt_base + reg_mask);
spin_unlock_irqrestore(&b->slock, flags);
}
static int exynos_wkup_irq_set_type(struct irq_data *irqd, unsigned int type)
{
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);

View file

@ -220,7 +220,7 @@ static int exynos5440_dt_node_to_map(struct pinctrl_dev *pctldev,
dev_err(dev, "failed to alloc memory for group name\n");
goto free_map;
}
sprintf(gname, "%s%s", np->name, GROUP_SUFFIX);
snprintf(gname, strlen(np->name) + 4, "%s%s", np->name, GROUP_SUFFIX);
/*
* don't have config options? then skip over to creating function
@ -259,7 +259,8 @@ skip_cfgs:
dev_err(dev, "failed to alloc memory for func name\n");
goto free_cfg;
}
sprintf(fname, "%s%s", np->name, FUNCTION_SUFFIX);
snprintf(fname, strlen(np->name) + 4, "%s%s", np->name,
FUNCTION_SUFFIX);
map[*nmaps].data.mux.group = gname;
map[*nmaps].data.mux.function = fname;
@ -713,7 +714,8 @@ static int exynos5440_pinctrl_parse_dt(struct platform_device *pdev,
dev_err(dev, "failed to alloc memory for group name\n");
return -ENOMEM;
}
sprintf(gname, "%s%s", cfg_np->name, GROUP_SUFFIX);
snprintf(gname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name,
GROUP_SUFFIX);
grp->name = gname;
grp->pins = pin_list;
@ -733,7 +735,8 @@ skip_to_pin_function:
dev_err(dev, "failed to alloc memory for func name\n");
return -ENOMEM;
}
sprintf(fname, "%s%s", cfg_np->name, FUNCTION_SUFFIX);
snprintf(fname, strlen(cfg_np->name) + 4, "%s%s", cfg_np->name,
FUNCTION_SUFFIX);
func->name = fname;
func->groups = devm_kzalloc(dev, sizeof(char *), GFP_KERNEL);
@ -806,7 +809,7 @@ static int exynos5440_pinctrl_register(struct platform_device *pdev,
/* for each pin, set the name of the pin */
for (pin = 0; pin < ctrldesc->npins; pin++) {
sprintf(pin_names, "gpio%02d", pin);
snprintf(pin_names, 6, "gpio%02d", pin);
pdesc = pindesc + pin;
pdesc->name = pin_names;
pin_names += PIN_NAME_LENGTH;

View file

@ -221,13 +221,21 @@ static int imx_pmx_enable(struct pinctrl_dev *pctldev, unsigned selector,
pin_id = pins[i];
pin_reg = &info->pin_regs[pin_id];
if (!pin_reg->mux_reg) {
if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->mux_reg) {
dev_err(ipctl->dev, "Pin(%s) does not support mux function\n",
info->pins[pin_id].name);
return -EINVAL;
}
writel(mux[i], ipctl->base + pin_reg->mux_reg);
if (info->flags & SHARE_MUX_CONF_REG) {
u32 reg;
reg = readl(ipctl->base + pin_reg->mux_reg);
reg &= ~(0x7 << 20);
reg |= (mux[i] << 20);
writel(reg, ipctl->base + pin_reg->mux_reg);
} else {
writel(mux[i], ipctl->base + pin_reg->mux_reg);
}
dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%x\n",
pin_reg->mux_reg, mux[i]);
@ -287,7 +295,7 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev,
const struct imx_pinctrl_soc_info *info = ipctl->info;
const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
if (!pin_reg->conf_reg) {
if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->conf_reg) {
dev_err(info->dev, "Pin(%s) does not support config function\n",
info->pins[pin_id].name);
return -EINVAL;
@ -295,6 +303,9 @@ static int imx_pinconf_get(struct pinctrl_dev *pctldev,
*config = readl(ipctl->base + pin_reg->conf_reg);
if (info->flags & SHARE_MUX_CONF_REG)
*config &= 0xffff;
return 0;
}
@ -305,7 +316,7 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev,
const struct imx_pinctrl_soc_info *info = ipctl->info;
const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
if (!pin_reg->conf_reg) {
if (!(info->flags & ZERO_OFFSET_VALID) && !pin_reg->conf_reg) {
dev_err(info->dev, "Pin(%s) does not support config function\n",
info->pins[pin_id].name);
return -EINVAL;
@ -314,7 +325,15 @@ static int imx_pinconf_set(struct pinctrl_dev *pctldev,
dev_dbg(ipctl->dev, "pinconf set pin %s\n",
info->pins[pin_id].name);
writel(config, ipctl->base + pin_reg->conf_reg);
if (info->flags & SHARE_MUX_CONF_REG) {
u32 reg;
reg = readl(ipctl->base + pin_reg->conf_reg);
reg &= ~0xffff;
reg |= config;
writel(reg, ipctl->base + pin_reg->conf_reg);
} else {
writel(config, ipctl->base + pin_reg->conf_reg);
}
dev_dbg(ipctl->dev, "write: offset 0x%x val 0x%lx\n",
pin_reg->conf_reg, config);
@ -381,19 +400,24 @@ static struct pinctrl_desc imx_pinctrl_desc = {
* 1 u32 CONFIG, so 24 types in total for each pin.
*/
#define FSL_PIN_SIZE 24
#define SHARE_FSL_PIN_SIZE 20
static int imx_pinctrl_parse_groups(struct device_node *np,
struct imx_pin_group *grp,
struct imx_pinctrl_soc_info *info,
u32 index)
{
int size;
int size, pin_size;
const __be32 *list;
int i;
u32 config;
dev_dbg(info->dev, "group(%d): %s\n", index, np->name);
if (info->flags & SHARE_MUX_CONF_REG)
pin_size = SHARE_FSL_PIN_SIZE;
else
pin_size = FSL_PIN_SIZE;
/* Initialise group */
grp->name = np->name;
@ -403,12 +427,12 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
*/
list = of_get_property(np, "fsl,pins", &size);
/* we do not check return since it's safe node passed down */
if (!size || size % FSL_PIN_SIZE) {
if (!size || size % pin_size) {
dev_err(info->dev, "Invalid fsl,pins property\n");
return -EINVAL;
}
grp->npins = size / FSL_PIN_SIZE;
grp->npins = size / pin_size;
grp->pins = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
GFP_KERNEL);
grp->mux_mode = devm_kzalloc(info->dev, grp->npins * sizeof(unsigned int),
@ -421,10 +445,17 @@ static int imx_pinctrl_parse_groups(struct device_node *np,
GFP_KERNEL);
for (i = 0; i < grp->npins; i++) {
u32 mux_reg = be32_to_cpu(*list++);
u32 conf_reg = be32_to_cpu(*list++);
unsigned int pin_id = mux_reg ? mux_reg / 4 : conf_reg / 4;
struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
u32 conf_reg;
unsigned int pin_id;
struct imx_pin_reg *pin_reg;
if (info->flags & SHARE_MUX_CONF_REG)
conf_reg = mux_reg;
else
conf_reg = be32_to_cpu(*list++);
pin_id = mux_reg ? mux_reg / 4 : conf_reg / 4;
pin_reg = &info->pin_regs[pin_id];
grp->pins[i] = pin_id;
pin_reg->mux_reg = mux_reg;
pin_reg->conf_reg = conf_reg;

View file

@ -74,8 +74,12 @@ struct imx_pinctrl_soc_info {
unsigned int ngroups;
struct imx_pmx_func *functions;
unsigned int nfunctions;
unsigned int flags;
};
#define ZERO_OFFSET_VALID 0x1
#define SHARE_MUX_CONF_REG 0x2
#define NO_MUX 0x0
#define NO_PAD 0x0

View file

@ -515,7 +515,6 @@ int mxs_pinctrl_probe(struct platform_device *pdev,
return 0;
err:
platform_set_drvdata(pdev, NULL);
iounmap(d->base);
return ret;
}
@ -525,7 +524,6 @@ int mxs_pinctrl_remove(struct platform_device *pdev)
{
struct mxs_pinctrl_data *d = platform_get_drvdata(pdev);
platform_set_drvdata(pdev, NULL);
pinctrl_unregister(d->pctl);
iounmap(d->base);

View file

@ -1309,7 +1309,7 @@ static int nmk_gpio_irq_map(struct irq_domain *d, unsigned int irq,
return 0;
}
const struct irq_domain_ops nmk_gpio_irq_simple_ops = {
static const struct irq_domain_ops nmk_gpio_irq_simple_ops = {
.map = nmk_gpio_irq_map,
.xlate = irq_domain_xlate_twocell,
};
@ -1681,7 +1681,7 @@ static bool nmk_pinctrl_dt_get_config(struct device_node *np,
return has_config;
}
int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
struct device_node *np,
struct pinctrl_map **map,
unsigned *reserved_maps,
@ -1740,7 +1740,7 @@ exit:
return ret;
}
int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
static int nmk_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np_config,
struct pinctrl_map **map, unsigned *num_maps)
{

File diff suppressed because it is too large Load diff

View file

@ -50,7 +50,7 @@ static struct pin_config {
};
/* Global list of devices (struct samsung_pinctrl_drv_data) */
LIST_HEAD(drvdata_list);
static LIST_HEAD(drvdata_list);
static unsigned int pin_base;

View file

@ -30,7 +30,7 @@
#define DRIVER_NAME "pinctrl-single"
#define PCS_MUX_PINS_NAME "pinctrl-single,pins"
#define PCS_MUX_BITS_NAME "pinctrl-single,bits"
#define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 1)
#define PCS_REG_NAME_LEN ((sizeof(unsigned long) * 2) + 3)
#define PCS_OFF_DISABLED ~0U
/**
@ -163,6 +163,7 @@ struct pcs_name {
* @foff: value to turn mux off
* @fmax: max number of functions in fmask
* @is_pinconf: whether supports pinconf
* @bits_per_pin:number of bits per pin
* @names: array of register names for pins
* @pins: physical pins on the SoC
* @pgtree: pingroup index radix tree
@ -190,6 +191,7 @@ struct pcs_device {
unsigned fmax;
bool bits_per_mux;
bool is_pinconf;
unsigned bits_per_pin;
struct pcs_name *names;
struct pcs_data pins;
struct radix_tree_root pgtree;
@ -431,10 +433,11 @@ static int pcs_enable(struct pinctrl_dev *pctldev, unsigned fselector,
vals = &func->vals[i];
val = pcs->read(vals->reg);
if (!vals->mask)
mask = pcs->fmask;
if (pcs->bits_per_mux)
mask = vals->mask;
else
mask = pcs->fmask & vals->mask;
mask = pcs->fmask;
val &= ~mask;
val |= (vals->val & mask);
@ -741,7 +744,8 @@ static const struct pinconf_ops pcs_pinconf_ops = {
* @pcs: pcs driver instance
* @offset: register offset from base
*/
static int pcs_add_pin(struct pcs_device *pcs, unsigned offset)
static int pcs_add_pin(struct pcs_device *pcs, unsigned offset,
unsigned pin_pos)
{
struct pinctrl_pin_desc *pin;
struct pcs_name *pn;
@ -756,8 +760,8 @@ static int pcs_add_pin(struct pcs_device *pcs, unsigned offset)
pin = &pcs->pins.pa[i];
pn = &pcs->names[i];
sprintf(pn->name, "%lx",
(unsigned long)pcs->res->start + offset);
sprintf(pn->name, "%lx.%d",
(unsigned long)pcs->res->start + offset, pin_pos);
pin->name = pn->name;
pin->number = i;
pcs->pins.cur++;
@ -777,9 +781,17 @@ static int pcs_add_pin(struct pcs_device *pcs, unsigned offset)
static int pcs_allocate_pin_table(struct pcs_device *pcs)
{
int mux_bytes, nr_pins, i;
int num_pins_in_register = 0;
mux_bytes = pcs->width / BITS_PER_BYTE;
nr_pins = pcs->size / mux_bytes;
if (pcs->bits_per_mux) {
pcs->bits_per_pin = fls(pcs->fmask);
nr_pins = (pcs->size * BITS_PER_BYTE) / pcs->bits_per_pin;
num_pins_in_register = pcs->width / pcs->bits_per_pin;
} else {
nr_pins = pcs->size / mux_bytes;
}
dev_dbg(pcs->dev, "allocating %i pins\n", nr_pins);
pcs->pins.pa = devm_kzalloc(pcs->dev,
@ -800,9 +812,17 @@ static int pcs_allocate_pin_table(struct pcs_device *pcs)
for (i = 0; i < pcs->desc.npins; i++) {
unsigned offset;
int res;
int byte_num;
int pin_pos = 0;
offset = i * mux_bytes;
res = pcs_add_pin(pcs, offset);
if (pcs->bits_per_mux) {
byte_num = (pcs->bits_per_pin * i) / BITS_PER_BYTE;
offset = (byte_num / mux_bytes) * mux_bytes;
pin_pos = i % num_pins_in_register;
} else {
offset = i * mux_bytes;
}
res = pcs_add_pin(pcs, offset, pin_pos);
if (res < 0) {
dev_err(pcs->dev, "error adding pins: %i\n", res);
return res;
@ -919,7 +939,10 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset)
return -EINVAL;
}
index = offset / (pcs->width / BITS_PER_BYTE);
if (pcs->bits_per_mux)
index = (offset * BITS_PER_BYTE) / pcs->bits_per_pin;
else
index = offset / (pcs->width / BITS_PER_BYTE);
return index;
}
@ -1097,29 +1120,18 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
{
struct pcs_func_vals *vals;
const __be32 *mux;
int size, params, rows, *pins, index = 0, found = 0, res = -ENOMEM;
int size, rows, *pins, index = 0, found = 0, res = -ENOMEM;
struct pcs_function *function;
if (pcs->bits_per_mux) {
params = 3;
mux = of_get_property(np, PCS_MUX_BITS_NAME, &size);
} else {
params = 2;
mux = of_get_property(np, PCS_MUX_PINS_NAME, &size);
}
if (!mux) {
dev_err(pcs->dev, "no valid property for %s\n", np->name);
return -EINVAL;
}
if (size < (sizeof(*mux) * params)) {
dev_err(pcs->dev, "bad data for %s\n", np->name);
mux = of_get_property(np, PCS_MUX_PINS_NAME, &size);
if ((!mux) || (size < sizeof(*mux) * 2)) {
dev_err(pcs->dev, "bad data for mux %s\n",
np->name);
return -EINVAL;
}
size /= sizeof(*mux); /* Number of elements in array */
rows = size / params;
rows = size / 2;
vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows, GFP_KERNEL);
if (!vals)
@ -1137,10 +1149,6 @@ static int pcs_parse_one_pinctrl_entry(struct pcs_device *pcs,
val = be32_to_cpup(mux + index++);
vals[found].reg = pcs->base + offset;
vals[found].val = val;
if (params == 3) {
val = be32_to_cpup(mux + index++);
vals[found].mask = val;
}
pin = pcs_get_pin_by_offset(pcs, offset);
if (pin < 0) {
@ -1184,6 +1192,125 @@ free_function:
free_pins:
devm_kfree(pcs->dev, pins);
free_vals:
devm_kfree(pcs->dev, vals);
return res;
}
#define PARAMS_FOR_BITS_PER_MUX 3
static int pcs_parse_bits_in_pinctrl_entry(struct pcs_device *pcs,
struct device_node *np,
struct pinctrl_map **map,
unsigned *num_maps,
const char **pgnames)
{
struct pcs_func_vals *vals;
const __be32 *mux;
int size, rows, *pins, index = 0, found = 0, res = -ENOMEM;
int npins_in_row;
struct pcs_function *function;
mux = of_get_property(np, PCS_MUX_BITS_NAME, &size);
if (!mux) {
dev_err(pcs->dev, "no valid property for %s\n", np->name);
return -EINVAL;
}
if (size < (sizeof(*mux) * PARAMS_FOR_BITS_PER_MUX)) {
dev_err(pcs->dev, "bad data for %s\n", np->name);
return -EINVAL;
}
/* Number of elements in array */
size /= sizeof(*mux);
rows = size / PARAMS_FOR_BITS_PER_MUX;
npins_in_row = pcs->width / pcs->bits_per_pin;
vals = devm_kzalloc(pcs->dev, sizeof(*vals) * rows * npins_in_row,
GFP_KERNEL);
if (!vals)
return -ENOMEM;
pins = devm_kzalloc(pcs->dev, sizeof(*pins) * rows * npins_in_row,
GFP_KERNEL);
if (!pins)
goto free_vals;
while (index < size) {
unsigned offset, val;
unsigned mask, bit_pos, val_pos, mask_pos, submask;
unsigned pin_num_from_lsb;
int pin;
offset = be32_to_cpup(mux + index++);
val = be32_to_cpup(mux + index++);
mask = be32_to_cpup(mux + index++);
/* Parse pins in each row from LSB */
while (mask) {
bit_pos = ffs(mask);
pin_num_from_lsb = bit_pos / pcs->bits_per_pin;
mask_pos = ((pcs->fmask) << (bit_pos - 1));
val_pos = val & mask_pos;
submask = mask & mask_pos;
mask &= ~mask_pos;
if (submask != mask_pos) {
dev_warn(pcs->dev,
"Invalid submask 0x%x for %s at 0x%x\n",
submask, np->name, offset);
continue;
}
vals[found].mask = submask;
vals[found].reg = pcs->base + offset;
vals[found].val = val_pos;
pin = pcs_get_pin_by_offset(pcs, offset);
if (pin < 0) {
dev_err(pcs->dev,
"could not add functions for %s %ux\n",
np->name, offset);
break;
}
pins[found++] = pin + pin_num_from_lsb;
}
}
pgnames[0] = np->name;
function = pcs_add_function(pcs, np, np->name, vals, found, pgnames, 1);
if (!function)
goto free_pins;
res = pcs_add_pingroup(pcs, np, np->name, pins, found);
if (res < 0)
goto free_function;
(*map)->type = PIN_MAP_TYPE_MUX_GROUP;
(*map)->data.mux.group = np->name;
(*map)->data.mux.function = np->name;
if (pcs->is_pinconf) {
dev_err(pcs->dev, "pinconf not supported\n");
goto free_pingroups;
}
*num_maps = 1;
return 0;
free_pingroups:
pcs_free_pingroups(pcs);
*num_maps = 1;
free_function:
pcs_remove_function(pcs, function);
free_pins:
devm_kfree(pcs->dev, pins);
free_vals:
devm_kfree(pcs->dev, vals);
@ -1219,12 +1346,22 @@ static int pcs_dt_node_to_map(struct pinctrl_dev *pctldev,
goto free_map;
}
ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map, num_maps,
pgnames);
if (ret < 0) {
dev_err(pcs->dev, "no pins entries for %s\n",
np_config->name);
goto free_pgnames;
if (pcs->bits_per_mux) {
ret = pcs_parse_bits_in_pinctrl_entry(pcs, np_config, map,
num_maps, pgnames);
if (ret < 0) {
dev_err(pcs->dev, "no pins entries for %s\n",
np_config->name);
goto free_pgnames;
}
} else {
ret = pcs_parse_one_pinctrl_entry(pcs, np_config, map,
num_maps, pgnames);
if (ret < 0) {
dev_err(pcs->dev, "no pins entries for %s\n",
np_config->name);
goto free_pgnames;
}
}
return 0;
@ -1346,6 +1483,29 @@ static int pcs_add_gpio_func(struct device_node *node, struct pcs_device *pcs)
return ret;
}
static int pinctrl_single_suspend(struct platform_device *pdev,
pm_message_t state)
{
struct pcs_device *pcs;
pcs = platform_get_drvdata(pdev);
if (!pcs)
return -EINVAL;
return pinctrl_force_sleep(pcs->pctl);
}
static int pinctrl_single_resume(struct platform_device *pdev)
{
struct pcs_device *pcs;
pcs = platform_get_drvdata(pdev);
if (!pcs)
return -EINVAL;
return pinctrl_force_default(pcs->pctl);
}
static int pcs_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@ -1494,6 +1654,10 @@ static struct platform_driver pcs_driver = {
.name = DRIVER_NAME,
.of_match_table = pcs_of_match,
},
#ifdef CONFIG_PM
.suspend = pinctrl_single_suspend,
.resume = pinctrl_single_resume,
#endif
};
module_platform_driver(pcs_driver);

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -344,9 +344,31 @@
#define PULL_PINS_BITS 2
#define PULL_PINS_MASK 0x03
#define SUNXI_IRQ_NUMBER 32
#define IRQ_CFG_REG 0x200
#define IRQ_CFG_IRQ_PER_REG 8
#define IRQ_CFG_IRQ_BITS 4
#define IRQ_CFG_IRQ_MASK ((1 << IRQ_CFG_IRQ_BITS) - 1)
#define IRQ_CTRL_REG 0x210
#define IRQ_CTRL_IRQ_PER_REG 32
#define IRQ_CTRL_IRQ_BITS 1
#define IRQ_CTRL_IRQ_MASK ((1 << IRQ_CTRL_IRQ_BITS) - 1)
#define IRQ_STATUS_REG 0x214
#define IRQ_STATUS_IRQ_PER_REG 32
#define IRQ_STATUS_IRQ_BITS 1
#define IRQ_STATUS_IRQ_MASK ((1 << IRQ_STATUS_IRQ_BITS) - 1)
#define IRQ_EDGE_RISING 0x00
#define IRQ_EDGE_FALLING 0x01
#define IRQ_LEVEL_HIGH 0x02
#define IRQ_LEVEL_LOW 0x03
#define IRQ_EDGE_BOTH 0x04
struct sunxi_desc_function {
const char *name;
u8 muxval;
u8 irqnum;
};
struct sunxi_desc_pin {
@ -378,10 +400,13 @@ struct sunxi_pinctrl {
struct gpio_chip *chip;
struct sunxi_pinctrl_desc *desc;
struct device *dev;
struct irq_domain *domain;
struct sunxi_pinctrl_function *functions;
unsigned nfunctions;
struct sunxi_pinctrl_group *groups;
unsigned ngroups;
int irq;
int irq_array[SUNXI_IRQ_NUMBER];
struct pinctrl_dev *pctl_dev;
};
@ -398,6 +423,13 @@ struct sunxi_pinctrl {
.muxval = _val, \
}
#define SUNXI_FUNCTION_IRQ(_val, _irq) \
{ \
.name = "irq", \
.muxval = _val, \
.irqnum = _irq, \
}
/*
* The sunXi PIO registers are organized as is:
* 0x00 - 0x0c Muxing values.
@ -475,4 +507,40 @@ static inline u32 sunxi_pull_offset(u16 pin)
return pin_num * PULL_PINS_BITS;
}
static inline u32 sunxi_irq_cfg_reg(u16 irq)
{
u8 reg = irq / IRQ_CFG_IRQ_PER_REG;
return reg + IRQ_CFG_REG;
}
static inline u32 sunxi_irq_cfg_offset(u16 irq)
{
u32 irq_num = irq % IRQ_CFG_IRQ_PER_REG;
return irq_num * IRQ_CFG_IRQ_BITS;
}
static inline u32 sunxi_irq_ctrl_reg(u16 irq)
{
u8 reg = irq / IRQ_CTRL_IRQ_PER_REG;
return reg + IRQ_CTRL_REG;
}
static inline u32 sunxi_irq_ctrl_offset(u16 irq)
{
u32 irq_num = irq % IRQ_CTRL_IRQ_PER_REG;
return irq_num * IRQ_CTRL_IRQ_BITS;
}
static inline u32 sunxi_irq_status_reg(u16 irq)
{
u8 reg = irq / IRQ_STATUS_IRQ_PER_REG;
return reg + IRQ_STATUS_REG;
}
static inline u32 sunxi_irq_status_offset(u16 irq)
{
u32 irq_num = irq % IRQ_STATUS_IRQ_PER_REG;
return irq_num * IRQ_STATUS_IRQ_BITS;
}
#endif /* __PINCTRL_SUNXI_H */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1100,7 +1100,6 @@ static int u300_pmx_remove(struct platform_device *pdev)
struct u300_pmx *upmx = platform_get_drvdata(pdev);
pinctrl_unregister(upmx->pctl);
platform_set_drvdata(pdev, NULL);
return 0;
}

View file

@ -0,0 +1,338 @@
/*
* VF610 pinctrl driver based on imx pinmux and pinconf core
*
* Copyright 2013 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
#include <linux/err.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/pinctrl.h>
#include "pinctrl-imx.h"
enum vf610_pads {
VF610_PAD_PTA6 = 0,
VF610_PAD_PTA8 = 1,
VF610_PAD_PTA9 = 2,
VF610_PAD_PTA10 = 3,
VF610_PAD_PTA11 = 4,
VF610_PAD_PTA12 = 5,
VF610_PAD_PTA16 = 6,
VF610_PAD_PTA17 = 7,
VF610_PAD_PTA18 = 8,
VF610_PAD_PTA19 = 9,
VF610_PAD_PTA20 = 10,
VF610_PAD_PTA21 = 11,
VF610_PAD_PTA22 = 12,
VF610_PAD_PTA23 = 13,
VF610_PAD_PTA24 = 14,
VF610_PAD_PTA25 = 15,
VF610_PAD_PTA26 = 16,
VF610_PAD_PTA27 = 17,
VF610_PAD_PTA28 = 18,
VF610_PAD_PTA29 = 19,
VF610_PAD_PTA30 = 20,
VF610_PAD_PTA31 = 21,
VF610_PAD_PTB0 = 22,
VF610_PAD_PTB1 = 23,
VF610_PAD_PTB2 = 24,
VF610_PAD_PTB3 = 25,
VF610_PAD_PTB4 = 26,
VF610_PAD_PTB5 = 27,
VF610_PAD_PTB6 = 28,
VF610_PAD_PTB7 = 29,
VF610_PAD_PTB8 = 30,
VF610_PAD_PTB9 = 31,
VF610_PAD_PTB10 = 32,
VF610_PAD_PTB11 = 33,
VF610_PAD_PTB12 = 34,
VF610_PAD_PTB13 = 35,
VF610_PAD_PTB14 = 36,
VF610_PAD_PTB15 = 37,
VF610_PAD_PTB16 = 38,
VF610_PAD_PTB17 = 39,
VF610_PAD_PTB18 = 40,
VF610_PAD_PTB19 = 41,
VF610_PAD_PTB20 = 42,
VF610_PAD_PTB21 = 43,
VF610_PAD_PTB22 = 44,
VF610_PAD_PTC0 = 45,
VF610_PAD_PTC1 = 46,
VF610_PAD_PTC2 = 47,
VF610_PAD_PTC3 = 48,
VF610_PAD_PTC4 = 49,
VF610_PAD_PTC5 = 50,
VF610_PAD_PTC6 = 51,
VF610_PAD_PTC7 = 52,
VF610_PAD_PTC8 = 53,
VF610_PAD_PTC9 = 54,
VF610_PAD_PTC10 = 55,
VF610_PAD_PTC11 = 56,
VF610_PAD_PTC12 = 57,
VF610_PAD_PTC13 = 58,
VF610_PAD_PTC14 = 59,
VF610_PAD_PTC15 = 60,
VF610_PAD_PTC16 = 61,
VF610_PAD_PTC17 = 62,
VF610_PAD_PTD31 = 63,
VF610_PAD_PTD30 = 64,
VF610_PAD_PTD29 = 65,
VF610_PAD_PTD28 = 66,
VF610_PAD_PTD27 = 67,
VF610_PAD_PTD26 = 68,
VF610_PAD_PTD25 = 69,
VF610_PAD_PTD24 = 70,
VF610_PAD_PTD23 = 71,
VF610_PAD_PTD22 = 72,
VF610_PAD_PTD21 = 73,
VF610_PAD_PTD20 = 74,
VF610_PAD_PTD19 = 75,
VF610_PAD_PTD18 = 76,
VF610_PAD_PTD17 = 77,
VF610_PAD_PTD16 = 78,
VF610_PAD_PTD0 = 79,
VF610_PAD_PTD1 = 80,
VF610_PAD_PTD2 = 81,
VF610_PAD_PTD3 = 82,
VF610_PAD_PTD4 = 83,
VF610_PAD_PTD5 = 84,
VF610_PAD_PTD6 = 85,
VF610_PAD_PTD7 = 86,
VF610_PAD_PTD8 = 87,
VF610_PAD_PTD9 = 88,
VF610_PAD_PTD10 = 89,
VF610_PAD_PTD11 = 90,
VF610_PAD_PTD12 = 91,
VF610_PAD_PTD13 = 92,
VF610_PAD_PTB23 = 93,
VF610_PAD_PTB24 = 94,
VF610_PAD_PTB25 = 95,
VF610_PAD_PTB26 = 96,
VF610_PAD_PTB27 = 97,
VF610_PAD_PTB28 = 98,
VF610_PAD_PTC26 = 99,
VF610_PAD_PTC27 = 100,
VF610_PAD_PTC28 = 101,
VF610_PAD_PTC29 = 102,
VF610_PAD_PTC30 = 103,
VF610_PAD_PTC31 = 104,
VF610_PAD_PTE0 = 105,
VF610_PAD_PTE1 = 106,
VF610_PAD_PTE2 = 107,
VF610_PAD_PTE3 = 108,
VF610_PAD_PTE4 = 109,
VF610_PAD_PTE5 = 110,
VF610_PAD_PTE6 = 111,
VF610_PAD_PTE7 = 112,
VF610_PAD_PTE8 = 113,
VF610_PAD_PTE9 = 114,
VF610_PAD_PTE10 = 115,
VF610_PAD_PTE11 = 116,
VF610_PAD_PTE12 = 117,
VF610_PAD_PTE13 = 118,
VF610_PAD_PTE14 = 119,
VF610_PAD_PTE15 = 120,
VF610_PAD_PTE16 = 121,
VF610_PAD_PTE17 = 122,
VF610_PAD_PTE18 = 123,
VF610_PAD_PTE19 = 124,
VF610_PAD_PTE20 = 125,
VF610_PAD_PTE21 = 126,
VF610_PAD_PTE22 = 127,
VF610_PAD_PTE23 = 128,
VF610_PAD_PTE24 = 129,
VF610_PAD_PTE25 = 130,
VF610_PAD_PTE26 = 131,
VF610_PAD_PTE27 = 132,
VF610_PAD_PTE28 = 133,
VF610_PAD_PTA7 = 134,
};
/* Pad names for the pinmux subsystem */
static const struct pinctrl_pin_desc vf610_pinctrl_pads[] = {
IMX_PINCTRL_PIN(VF610_PAD_PTA6),
IMX_PINCTRL_PIN(VF610_PAD_PTA8),
IMX_PINCTRL_PIN(VF610_PAD_PTA9),
IMX_PINCTRL_PIN(VF610_PAD_PTA10),
IMX_PINCTRL_PIN(VF610_PAD_PTA11),
IMX_PINCTRL_PIN(VF610_PAD_PTA12),
IMX_PINCTRL_PIN(VF610_PAD_PTA16),
IMX_PINCTRL_PIN(VF610_PAD_PTA17),
IMX_PINCTRL_PIN(VF610_PAD_PTA18),
IMX_PINCTRL_PIN(VF610_PAD_PTA19),
IMX_PINCTRL_PIN(VF610_PAD_PTA20),
IMX_PINCTRL_PIN(VF610_PAD_PTA21),
IMX_PINCTRL_PIN(VF610_PAD_PTA22),
IMX_PINCTRL_PIN(VF610_PAD_PTA23),
IMX_PINCTRL_PIN(VF610_PAD_PTA24),
IMX_PINCTRL_PIN(VF610_PAD_PTA25),
IMX_PINCTRL_PIN(VF610_PAD_PTA26),
IMX_PINCTRL_PIN(VF610_PAD_PTA27),
IMX_PINCTRL_PIN(VF610_PAD_PTA28),
IMX_PINCTRL_PIN(VF610_PAD_PTA29),
IMX_PINCTRL_PIN(VF610_PAD_PTA30),
IMX_PINCTRL_PIN(VF610_PAD_PTA31),
IMX_PINCTRL_PIN(VF610_PAD_PTB0),
IMX_PINCTRL_PIN(VF610_PAD_PTB1),
IMX_PINCTRL_PIN(VF610_PAD_PTB2),
IMX_PINCTRL_PIN(VF610_PAD_PTB3),
IMX_PINCTRL_PIN(VF610_PAD_PTB4),
IMX_PINCTRL_PIN(VF610_PAD_PTB5),
IMX_PINCTRL_PIN(VF610_PAD_PTB6),
IMX_PINCTRL_PIN(VF610_PAD_PTB7),
IMX_PINCTRL_PIN(VF610_PAD_PTB8),
IMX_PINCTRL_PIN(VF610_PAD_PTB9),
IMX_PINCTRL_PIN(VF610_PAD_PTB10),
IMX_PINCTRL_PIN(VF610_PAD_PTB11),
IMX_PINCTRL_PIN(VF610_PAD_PTB12),
IMX_PINCTRL_PIN(VF610_PAD_PTB13),
IMX_PINCTRL_PIN(VF610_PAD_PTB14),
IMX_PINCTRL_PIN(VF610_PAD_PTB15),
IMX_PINCTRL_PIN(VF610_PAD_PTB16),
IMX_PINCTRL_PIN(VF610_PAD_PTB17),
IMX_PINCTRL_PIN(VF610_PAD_PTB18),
IMX_PINCTRL_PIN(VF610_PAD_PTB19),
IMX_PINCTRL_PIN(VF610_PAD_PTB20),
IMX_PINCTRL_PIN(VF610_PAD_PTB21),
IMX_PINCTRL_PIN(VF610_PAD_PTB22),
IMX_PINCTRL_PIN(VF610_PAD_PTC0),
IMX_PINCTRL_PIN(VF610_PAD_PTC1),
IMX_PINCTRL_PIN(VF610_PAD_PTC2),
IMX_PINCTRL_PIN(VF610_PAD_PTC3),
IMX_PINCTRL_PIN(VF610_PAD_PTC4),
IMX_PINCTRL_PIN(VF610_PAD_PTC5),
IMX_PINCTRL_PIN(VF610_PAD_PTC6),
IMX_PINCTRL_PIN(VF610_PAD_PTC7),
IMX_PINCTRL_PIN(VF610_PAD_PTC8),
IMX_PINCTRL_PIN(VF610_PAD_PTC9),
IMX_PINCTRL_PIN(VF610_PAD_PTC10),
IMX_PINCTRL_PIN(VF610_PAD_PTC11),
IMX_PINCTRL_PIN(VF610_PAD_PTC12),
IMX_PINCTRL_PIN(VF610_PAD_PTC13),
IMX_PINCTRL_PIN(VF610_PAD_PTC14),
IMX_PINCTRL_PIN(VF610_PAD_PTC15),
IMX_PINCTRL_PIN(VF610_PAD_PTC16),
IMX_PINCTRL_PIN(VF610_PAD_PTC17),
IMX_PINCTRL_PIN(VF610_PAD_PTD31),
IMX_PINCTRL_PIN(VF610_PAD_PTD30),
IMX_PINCTRL_PIN(VF610_PAD_PTD29),
IMX_PINCTRL_PIN(VF610_PAD_PTD28),
IMX_PINCTRL_PIN(VF610_PAD_PTD27),
IMX_PINCTRL_PIN(VF610_PAD_PTD26),
IMX_PINCTRL_PIN(VF610_PAD_PTD25),
IMX_PINCTRL_PIN(VF610_PAD_PTD24),
IMX_PINCTRL_PIN(VF610_PAD_PTD23),
IMX_PINCTRL_PIN(VF610_PAD_PTD22),
IMX_PINCTRL_PIN(VF610_PAD_PTD21),
IMX_PINCTRL_PIN(VF610_PAD_PTD20),
IMX_PINCTRL_PIN(VF610_PAD_PTD19),
IMX_PINCTRL_PIN(VF610_PAD_PTD18),
IMX_PINCTRL_PIN(VF610_PAD_PTD17),
IMX_PINCTRL_PIN(VF610_PAD_PTD16),
IMX_PINCTRL_PIN(VF610_PAD_PTD0),
IMX_PINCTRL_PIN(VF610_PAD_PTD1),
IMX_PINCTRL_PIN(VF610_PAD_PTD2),
IMX_PINCTRL_PIN(VF610_PAD_PTD3),
IMX_PINCTRL_PIN(VF610_PAD_PTD4),
IMX_PINCTRL_PIN(VF610_PAD_PTD5),
IMX_PINCTRL_PIN(VF610_PAD_PTD6),
IMX_PINCTRL_PIN(VF610_PAD_PTD7),
IMX_PINCTRL_PIN(VF610_PAD_PTD8),
IMX_PINCTRL_PIN(VF610_PAD_PTD9),
IMX_PINCTRL_PIN(VF610_PAD_PTD10),
IMX_PINCTRL_PIN(VF610_PAD_PTD11),
IMX_PINCTRL_PIN(VF610_PAD_PTD12),
IMX_PINCTRL_PIN(VF610_PAD_PTD13),
IMX_PINCTRL_PIN(VF610_PAD_PTB23),
IMX_PINCTRL_PIN(VF610_PAD_PTB24),
IMX_PINCTRL_PIN(VF610_PAD_PTB25),
IMX_PINCTRL_PIN(VF610_PAD_PTB26),
IMX_PINCTRL_PIN(VF610_PAD_PTB27),
IMX_PINCTRL_PIN(VF610_PAD_PTB28),
IMX_PINCTRL_PIN(VF610_PAD_PTC26),
IMX_PINCTRL_PIN(VF610_PAD_PTC27),
IMX_PINCTRL_PIN(VF610_PAD_PTC28),
IMX_PINCTRL_PIN(VF610_PAD_PTC29),
IMX_PINCTRL_PIN(VF610_PAD_PTC30),
IMX_PINCTRL_PIN(VF610_PAD_PTC31),
IMX_PINCTRL_PIN(VF610_PAD_PTE0),
IMX_PINCTRL_PIN(VF610_PAD_PTE1),
IMX_PINCTRL_PIN(VF610_PAD_PTE2),
IMX_PINCTRL_PIN(VF610_PAD_PTE3),
IMX_PINCTRL_PIN(VF610_PAD_PTE4),
IMX_PINCTRL_PIN(VF610_PAD_PTE5),
IMX_PINCTRL_PIN(VF610_PAD_PTE6),
IMX_PINCTRL_PIN(VF610_PAD_PTE7),
IMX_PINCTRL_PIN(VF610_PAD_PTE8),
IMX_PINCTRL_PIN(VF610_PAD_PTE9),
IMX_PINCTRL_PIN(VF610_PAD_PTE10),
IMX_PINCTRL_PIN(VF610_PAD_PTE11),
IMX_PINCTRL_PIN(VF610_PAD_PTE12),
IMX_PINCTRL_PIN(VF610_PAD_PTE13),
IMX_PINCTRL_PIN(VF610_PAD_PTE14),
IMX_PINCTRL_PIN(VF610_PAD_PTE15),
IMX_PINCTRL_PIN(VF610_PAD_PTE16),
IMX_PINCTRL_PIN(VF610_PAD_PTE17),
IMX_PINCTRL_PIN(VF610_PAD_PTE18),
IMX_PINCTRL_PIN(VF610_PAD_PTE19),
IMX_PINCTRL_PIN(VF610_PAD_PTE20),
IMX_PINCTRL_PIN(VF610_PAD_PTE21),
IMX_PINCTRL_PIN(VF610_PAD_PTE22),
IMX_PINCTRL_PIN(VF610_PAD_PTE23),
IMX_PINCTRL_PIN(VF610_PAD_PTE24),
IMX_PINCTRL_PIN(VF610_PAD_PTE25),
IMX_PINCTRL_PIN(VF610_PAD_PTE26),
IMX_PINCTRL_PIN(VF610_PAD_PTE27),
IMX_PINCTRL_PIN(VF610_PAD_PTE28),
IMX_PINCTRL_PIN(VF610_PAD_PTA7),
};
static struct imx_pinctrl_soc_info vf610_pinctrl_info = {
.pins = vf610_pinctrl_pads,
.npins = ARRAY_SIZE(vf610_pinctrl_pads),
.flags = ZERO_OFFSET_VALID | SHARE_MUX_CONF_REG,
};
static struct of_device_id vf610_pinctrl_of_match[] = {
{ .compatible = "fsl,vf610-iomuxc", },
{ /* sentinel */ }
};
static int vf610_pinctrl_probe(struct platform_device *pdev)
{
return imx_pinctrl_probe(pdev, &vf610_pinctrl_info);
}
static struct platform_driver vf610_pinctrl_driver = {
.driver = {
.name = "vf610-pinctrl",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(vf610_pinctrl_of_match),
},
.probe = vf610_pinctrl_probe,
.remove = imx_pinctrl_remove,
};
static int __init vf610_pinctrl_init(void)
{
return platform_driver_register(&vf610_pinctrl_driver);
}
arch_initcall(vf610_pinctrl_init);
static void __exit vf610_pinctrl_exit(void)
{
platform_driver_unregister(&vf610_pinctrl_driver);
}
module_exit(vf610_pinctrl_exit);
MODULE_DESCRIPTION("Freescale VF610 pinctrl driver");
MODULE_LICENSE("GPL v2");

View file

@ -18,6 +18,8 @@
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/pinctrl/machine.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
@ -348,14 +350,72 @@ int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type)
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id sh_pfc_of_table[] = {
#ifdef CONFIG_PINCTRL_PFC_R8A73A4
{
.compatible = "renesas,pfc-r8a73a4",
.data = &r8a73a4_pinmux_info,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7740
{
.compatible = "renesas,pfc-r8a7740",
.data = &r8a7740_pinmux_info,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7778
{
.compatible = "renesas,pfc-r8a7778",
.data = &r8a7778_pinmux_info,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7779
{
.compatible = "renesas,pfc-r8a7779",
.data = &r8a7779_pinmux_info,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_R8A7790
{
.compatible = "renesas,pfc-r8a7790",
.data = &r8a7790_pinmux_info,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_SH7372
{
.compatible = "renesas,pfc-sh7372",
.data = &sh7372_pinmux_info,
},
#endif
#ifdef CONFIG_PINCTRL_PFC_SH73A0
{
.compatible = "renesas,pfc-sh73a0",
.data = &sh73a0_pinmux_info,
},
#endif
{ },
};
MODULE_DEVICE_TABLE(of, sh_pfc_of_table);
#endif
static int sh_pfc_probe(struct platform_device *pdev)
{
const struct platform_device_id *platid = platform_get_device_id(pdev);
#ifdef CONFIG_OF
struct device_node *np = pdev->dev.of_node;
#endif
const struct sh_pfc_soc_info *info;
struct sh_pfc *pfc;
int ret;
info = pdev->id_entry->driver_data
? (void *)pdev->id_entry->driver_data : pdev->dev.platform_data;
#ifdef CONFIG_OF
if (np)
info = of_match_device(sh_pfc_of_table, &pdev->dev)->data;
else
#endif
info = platid ? (const void *)platid->driver_data : NULL;
if (info == NULL)
return -ENODEV;
@ -501,6 +561,7 @@ static struct platform_driver sh_pfc_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(sh_pfc_of_table),
},
};

View file

@ -14,7 +14,9 @@
#include <linux/err.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/pinctrl/pinctrl.h>
@ -72,11 +74,214 @@ static void sh_pfc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
seq_printf(s, "%s", DRV_NAME);
}
#ifdef CONFIG_OF
static int sh_pfc_map_add_config(struct pinctrl_map *map,
const char *group_or_pin,
enum pinctrl_map_type type,
unsigned long *configs,
unsigned int num_configs)
{
unsigned long *cfgs;
cfgs = kmemdup(configs, num_configs * sizeof(*cfgs),
GFP_KERNEL);
if (cfgs == NULL)
return -ENOMEM;
map->type = type;
map->data.configs.group_or_pin = group_or_pin;
map->data.configs.configs = cfgs;
map->data.configs.num_configs = num_configs;
return 0;
}
static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
struct pinctrl_map **map,
unsigned int *num_maps, unsigned int *index)
{
struct pinctrl_map *maps = *map;
unsigned int nmaps = *num_maps;
unsigned int idx = *index;
unsigned int num_configs;
const char *function = NULL;
unsigned long *configs;
struct property *prop;
unsigned int num_groups;
unsigned int num_pins;
const char *group;
const char *pin;
int ret;
/* Parse the function and configuration properties. At least a function
* or one configuration must be specified.
*/
ret = of_property_read_string(np, "renesas,function", &function);
if (ret < 0 && ret != -EINVAL) {
dev_err(dev, "Invalid function in DT\n");
return ret;
}
ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs);
if (ret < 0)
return ret;
if (!function && num_configs == 0) {
dev_err(dev,
"DT node must contain at least a function or config\n");
goto done;
}
/* Count the number of pins and groups and reallocate mappings. */
ret = of_property_count_strings(np, "renesas,pins");
if (ret == -EINVAL) {
num_pins = 0;
} else if (ret < 0) {
dev_err(dev, "Invalid pins list in DT\n");
goto done;
} else {
num_pins = ret;
}
ret = of_property_count_strings(np, "renesas,groups");
if (ret == -EINVAL) {
num_groups = 0;
} else if (ret < 0) {
dev_err(dev, "Invalid pin groups list in DT\n");
goto done;
} else {
num_groups = ret;
}
if (!num_pins && !num_groups) {
dev_err(dev, "No pin or group provided in DT node\n");
ret = -ENODEV;
goto done;
}
if (function)
nmaps += num_groups;
if (configs)
nmaps += num_pins + num_groups;
maps = krealloc(maps, sizeof(*maps) * nmaps, GFP_KERNEL);
if (maps == NULL) {
ret = -ENOMEM;
goto done;
}
*map = maps;
*num_maps = nmaps;
/* Iterate over pins and groups and create the mappings. */
of_property_for_each_string(np, "renesas,groups", prop, group) {
if (function) {
maps[idx].type = PIN_MAP_TYPE_MUX_GROUP;
maps[idx].data.mux.group = group;
maps[idx].data.mux.function = function;
idx++;
}
if (configs) {
ret = sh_pfc_map_add_config(&maps[idx], group,
PIN_MAP_TYPE_CONFIGS_GROUP,
configs, num_configs);
if (ret < 0)
goto done;
idx++;
}
}
if (!configs) {
ret = 0;
goto done;
}
of_property_for_each_string(np, "renesas,pins", prop, pin) {
ret = sh_pfc_map_add_config(&maps[idx], pin,
PIN_MAP_TYPE_CONFIGS_PIN,
configs, num_configs);
if (ret < 0)
goto done;
idx++;
}
done:
*index = idx;
kfree(configs);
return ret;
}
static void sh_pfc_dt_free_map(struct pinctrl_dev *pctldev,
struct pinctrl_map *map, unsigned num_maps)
{
unsigned int i;
if (map == NULL)
return;
for (i = 0; i < num_maps; ++i) {
if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP ||
map[i].type == PIN_MAP_TYPE_CONFIGS_PIN)
kfree(map[i].data.configs.configs);
}
kfree(map);
}
static int sh_pfc_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np,
struct pinctrl_map **map, unsigned *num_maps)
{
struct sh_pfc_pinctrl *pmx = pinctrl_dev_get_drvdata(pctldev);
struct device *dev = pmx->pfc->dev;
struct device_node *child;
unsigned int index;
int ret;
*map = NULL;
*num_maps = 0;
index = 0;
for_each_child_of_node(np, child) {
ret = sh_pfc_dt_subnode_to_map(dev, child, map, num_maps,
&index);
if (ret < 0)
goto done;
}
/* If no mapping has been found in child nodes try the config node. */
if (*num_maps == 0) {
ret = sh_pfc_dt_subnode_to_map(dev, np, map, num_maps, &index);
if (ret < 0)
goto done;
}
if (*num_maps)
return 0;
dev_err(dev, "no mapping found in node %s\n", np->full_name);
ret = -EINVAL;
done:
if (ret < 0)
sh_pfc_dt_free_map(pctldev, *map, *num_maps);
return ret;
}
#endif /* CONFIG_OF */
static const struct pinctrl_ops sh_pfc_pinctrl_ops = {
.get_groups_count = sh_pfc_get_groups_count,
.get_group_name = sh_pfc_get_group_name,
.get_group_pins = sh_pfc_get_group_pins,
.pin_dbg_show = sh_pfc_pin_dbg_show,
#ifdef CONFIG_OF
.dt_node_to_map = sh_pfc_dt_node_to_map,
.dt_free_map = sh_pfc_dt_free_map,
#endif
};
static int sh_pfc_get_functions_count(struct pinctrl_dev *pctldev)

View file

@ -0,0 +1,5 @@
# CSR SiRFsoc pinmux support
obj-y += pinctrl-sirf.o
obj-y += pinctrl-prima2.o
obj-y += pinctrl-atlas6.o

View file

@ -0,0 +1,947 @@
/*
* pinctrl pads, groups, functions for CSR SiRFatlasVI
*
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
#include <linux/pinctrl/pinctrl.h>
#include <linux/bitops.h>
#include "pinctrl-sirf.h"
/*
* pad list for the pinmux subsystem
* refer to atlasVI_io_table_v0.93.xls
*/
static const struct pinctrl_pin_desc sirfsoc_pads[] = {
PINCTRL_PIN(0, "gpio0-0"),
PINCTRL_PIN(1, "gpio0-1"),
PINCTRL_PIN(2, "gpio0-2"),
PINCTRL_PIN(3, "gpio0-3"),
PINCTRL_PIN(4, "pwm0"),
PINCTRL_PIN(5, "pwm1"),
PINCTRL_PIN(6, "pwm2"),
PINCTRL_PIN(7, "pwm3"),
PINCTRL_PIN(8, "warm_rst_b"),
PINCTRL_PIN(9, "odo_0"),
PINCTRL_PIN(10, "odo_1"),
PINCTRL_PIN(11, "dr_dir"),
PINCTRL_PIN(12, "rts_0"),
PINCTRL_PIN(13, "scl_1"),
PINCTRL_PIN(14, "ntrst"),
PINCTRL_PIN(15, "sda_1"),
PINCTRL_PIN(16, "x_ldd[16]"),
PINCTRL_PIN(17, "x_ldd[17]"),
PINCTRL_PIN(18, "x_ldd[18]"),
PINCTRL_PIN(19, "x_ldd[19]"),
PINCTRL_PIN(20, "x_ldd[20]"),
PINCTRL_PIN(21, "x_ldd[21]"),
PINCTRL_PIN(22, "x_ldd[22]"),
PINCTRL_PIN(23, "x_ldd[23]"),
PINCTRL_PIN(24, "gps_sgn"),
PINCTRL_PIN(25, "gps_mag"),
PINCTRL_PIN(26, "gps_clk"),
PINCTRL_PIN(27, "sd_cd_b_2"),
PINCTRL_PIN(28, "sd_vcc_on_2"),
PINCTRL_PIN(29, "sd_wp_b_2"),
PINCTRL_PIN(30, "sd_clk_3"),
PINCTRL_PIN(31, "sd_cmd_3"),
PINCTRL_PIN(32, "x_sd_dat_3[0]"),
PINCTRL_PIN(33, "x_sd_dat_3[1]"),
PINCTRL_PIN(34, "x_sd_dat_3[2]"),
PINCTRL_PIN(35, "x_sd_dat_3[3]"),
PINCTRL_PIN(36, "usb_clk"),
PINCTRL_PIN(37, "usb_dir"),
PINCTRL_PIN(38, "usb_nxt"),
PINCTRL_PIN(39, "usb_stp"),
PINCTRL_PIN(40, "usb_dat[7]"),
PINCTRL_PIN(41, "usb_dat[6]"),
PINCTRL_PIN(42, "x_cko_1"),
PINCTRL_PIN(43, "spi_clk_1"),
PINCTRL_PIN(44, "spi_dout_1"),
PINCTRL_PIN(45, "spi_din_1"),
PINCTRL_PIN(46, "spi_en_1"),
PINCTRL_PIN(47, "x_txd_1"),
PINCTRL_PIN(48, "x_txd_2"),
PINCTRL_PIN(49, "x_rxd_1"),
PINCTRL_PIN(50, "x_rxd_2"),
PINCTRL_PIN(51, "x_usclk_0"),
PINCTRL_PIN(52, "x_utxd_0"),
PINCTRL_PIN(53, "x_urxd_0"),
PINCTRL_PIN(54, "x_utfs_0"),
PINCTRL_PIN(55, "x_urfs_0"),
PINCTRL_PIN(56, "usb_dat5"),
PINCTRL_PIN(57, "usb_dat4"),
PINCTRL_PIN(58, "usb_dat3"),
PINCTRL_PIN(59, "usb_dat2"),
PINCTRL_PIN(60, "usb_dat1"),
PINCTRL_PIN(61, "usb_dat0"),
PINCTRL_PIN(62, "x_ldd[14]"),
PINCTRL_PIN(63, "x_ldd[15]"),
PINCTRL_PIN(64, "x_gps_gpio"),
PINCTRL_PIN(65, "x_ldd[13]"),
PINCTRL_PIN(66, "x_df_we_b"),
PINCTRL_PIN(67, "x_df_re_b"),
PINCTRL_PIN(68, "x_txd_0"),
PINCTRL_PIN(69, "x_rxd_0"),
PINCTRL_PIN(70, "x_l_lck"),
PINCTRL_PIN(71, "x_l_fck"),
PINCTRL_PIN(72, "x_l_de"),
PINCTRL_PIN(73, "x_ldd[0]"),
PINCTRL_PIN(74, "x_ldd[1]"),
PINCTRL_PIN(75, "x_ldd[2]"),
PINCTRL_PIN(76, "x_ldd[3]"),
PINCTRL_PIN(77, "x_ldd[4]"),
PINCTRL_PIN(78, "x_cko_0"),
PINCTRL_PIN(79, "x_ldd[5]"),
PINCTRL_PIN(80, "x_ldd[6]"),
PINCTRL_PIN(81, "x_ldd[7]"),
PINCTRL_PIN(82, "x_ldd[8]"),
PINCTRL_PIN(83, "x_ldd[9]"),
PINCTRL_PIN(84, "x_ldd[10]"),
PINCTRL_PIN(85, "x_ldd[11]"),
PINCTRL_PIN(86, "x_ldd[12]"),
PINCTRL_PIN(87, "x_vip_vsync"),
PINCTRL_PIN(88, "x_vip_hsync"),
PINCTRL_PIN(89, "x_vip_pxclk"),
PINCTRL_PIN(90, "x_sda_0"),
PINCTRL_PIN(91, "x_scl_0"),
PINCTRL_PIN(92, "x_df_ry_by"),
PINCTRL_PIN(93, "x_df_cs_b[1]"),
PINCTRL_PIN(94, "x_df_cs_b[0]"),
PINCTRL_PIN(95, "x_l_pclk"),
PINCTRL_PIN(96, "x_df_dqs"),
PINCTRL_PIN(97, "x_df_wp_b"),
PINCTRL_PIN(98, "ac97_sync"),
PINCTRL_PIN(99, "ac97_bit_clk "),
PINCTRL_PIN(100, "ac97_dout"),
PINCTRL_PIN(101, "ac97_din"),
PINCTRL_PIN(102, "x_rtc_io"),
};
static const struct sirfsoc_muxmask lcd_16bits_sirfsoc_muxmask[] = {
{
.group = 1,
.mask = BIT(30) | BIT(31),
}, {
.group = 2,
.mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) |
BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) |
BIT(20) | BIT(21) | BIT(22) | BIT(31),
},
};
static const struct sirfsoc_padmux lcd_16bits_padmux = {
.muxmask_counts = ARRAY_SIZE(lcd_16bits_sirfsoc_muxmask),
.muxmask = lcd_16bits_sirfsoc_muxmask,
.funcmask = BIT(4),
.funcval = 0,
};
static const unsigned lcd_16bits_pins[] = { 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83,
84, 85, 86, 95 };
static const struct sirfsoc_muxmask lcd_18bits_muxmask[] = {
{
.group = 2,
.mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) |
BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) |
BIT(20) | BIT(21) | BIT(22) | BIT(31),
}, {
.group = 1,
.mask = BIT(30) | BIT(31),
}, {
.group = 0,
.mask = BIT(16) | BIT(17),
},
};
static const struct sirfsoc_padmux lcd_18bits_padmux = {
.muxmask_counts = ARRAY_SIZE(lcd_18bits_muxmask),
.muxmask = lcd_18bits_muxmask,
.funcmask = BIT(4) | BIT(15),
.funcval = 0,
};
static const unsigned lcd_18bits_pins[] = { 16, 17, 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83,
84, 85, 86, 95 };
static const struct sirfsoc_muxmask lcd_24bits_muxmask[] = {
{
.group = 2,
.mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) |
BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) |
BIT(20) | BIT(21) | BIT(22) | BIT(31),
}, {
.group = 1,
.mask = BIT(30) | BIT(31),
}, {
.group = 0,
.mask = BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20) | BIT(21) | BIT(22) | BIT(23),
},
};
static const struct sirfsoc_padmux lcd_24bits_padmux = {
.muxmask_counts = ARRAY_SIZE(lcd_24bits_muxmask),
.muxmask = lcd_24bits_muxmask,
.funcmask = BIT(4) | BIT(15),
.funcval = 0,
};
static const unsigned lcd_24bits_pins[] = { 16, 17, 18, 19, 20, 21, 22, 23, 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79,
80, 81, 82, 83, 84, 85, 86, 95};
static const struct sirfsoc_muxmask lcdrom_muxmask[] = {
{
.group = 2,
.mask = BIT(1) | BIT(6) | BIT(7) | BIT(8) | BIT(9) | BIT(10) | BIT(11) |
BIT(12) | BIT(13) | BIT(15) | BIT(16) | BIT(17) | BIT(18) | BIT(19) |
BIT(20) | BIT(21) | BIT(22) | BIT(31),
}, {
.group = 1,
.mask = BIT(30) | BIT(31),
}, {
.group = 0,
.mask = BIT(8),
},
};
static const struct sirfsoc_padmux lcdrom_padmux = {
.muxmask_counts = ARRAY_SIZE(lcdrom_muxmask),
.muxmask = lcdrom_muxmask,
.funcmask = BIT(4),
.funcval = BIT(4),
};
static const unsigned lcdrom_pins[] = { 8, 62, 63, 65, 70, 71, 72, 73, 74, 75, 76, 77, 79, 80, 81, 82, 83,
84, 85, 86, 95};
static const struct sirfsoc_muxmask uart0_muxmask[] = {
{
.group = 0,
.mask = BIT(12),
}, {
.group = 1,
.mask = BIT(23),
}, {
.group = 2,
.mask = BIT(4) | BIT(5),
},
};
static const struct sirfsoc_padmux uart0_padmux = {
.muxmask_counts = ARRAY_SIZE(uart0_muxmask),
.muxmask = uart0_muxmask,
.funcmask = BIT(9),
.funcval = BIT(9),
};
static const unsigned uart0_pins[] = { 12, 55, 68, 69 };
static const struct sirfsoc_muxmask uart0_nostreamctrl_muxmask[] = {
{
.group = 2,
.mask = BIT(4) | BIT(5),
},
};
static const struct sirfsoc_padmux uart0_nostreamctrl_padmux = {
.muxmask_counts = ARRAY_SIZE(uart0_nostreamctrl_muxmask),
.muxmask = uart0_nostreamctrl_muxmask,
};
static const unsigned uart0_nostreamctrl_pins[] = { 68, 69 };
static const struct sirfsoc_muxmask uart1_muxmask[] = {
{
.group = 1,
.mask = BIT(15) | BIT(17),
},
};
static const struct sirfsoc_padmux uart1_padmux = {
.muxmask_counts = ARRAY_SIZE(uart1_muxmask),
.muxmask = uart1_muxmask,
};
static const unsigned uart1_pins[] = { 47, 49 };
static const struct sirfsoc_muxmask uart2_muxmask[] = {
{
.group = 0,
.mask = BIT(10) | BIT(14),
}, {
.group = 1,
.mask = BIT(16) | BIT(18),
},
};
static const struct sirfsoc_padmux uart2_padmux = {
.muxmask_counts = ARRAY_SIZE(uart2_muxmask),
.muxmask = uart2_muxmask,
.funcmask = BIT(10),
.funcval = BIT(10),
};
static const unsigned uart2_pins[] = { 10, 14, 48, 50 };
static const struct sirfsoc_muxmask uart2_nostreamctrl_muxmask[] = {
{
.group = 1,
.mask = BIT(16) | BIT(18),
},
};
static const struct sirfsoc_padmux uart2_nostreamctrl_padmux = {
.muxmask_counts = ARRAY_SIZE(uart2_nostreamctrl_muxmask),
.muxmask = uart2_nostreamctrl_muxmask,
};
static const unsigned uart2_nostreamctrl_pins[] = { 48, 50 };
static const struct sirfsoc_muxmask sdmmc3_muxmask[] = {
{
.group = 0,
.mask = BIT(30) | BIT(31),
}, {
.group = 1,
.mask = BIT(0) | BIT(1) | BIT(2) | BIT(3),
},
};
static const struct sirfsoc_padmux sdmmc3_padmux = {
.muxmask_counts = ARRAY_SIZE(sdmmc3_muxmask),
.muxmask = sdmmc3_muxmask,
.funcmask = BIT(7),
.funcval = 0,
};
static const unsigned sdmmc3_pins[] = { 30, 31, 32, 33, 34, 35 };
static const struct sirfsoc_muxmask spi0_muxmask[] = {
{
.group = 0,
.mask = BIT(30),
}, {
.group = 1,
.mask = BIT(0) | BIT(2) | BIT(3),
},
};
static const struct sirfsoc_padmux spi0_padmux = {
.muxmask_counts = ARRAY_SIZE(spi0_muxmask),
.muxmask = spi0_muxmask,
.funcmask = BIT(7),
.funcval = BIT(7),
};
static const unsigned spi0_pins[] = { 30, 32, 34, 35 };
static const struct sirfsoc_muxmask cko1_muxmask[] = {
{
.group = 1,
.mask = BIT(10),
},
};
static const struct sirfsoc_padmux cko1_padmux = {
.muxmask_counts = ARRAY_SIZE(cko1_muxmask),
.muxmask = cko1_muxmask,
.funcmask = BIT(3),
.funcval = 0,
};
static const unsigned cko1_pins[] = { 42 };
static const struct sirfsoc_muxmask i2s_muxmask[] = {
{
.group = 1,
.mask = BIT(10),
}, {
.group = 3,
.mask = BIT(2) | BIT(3) | BIT(4) | BIT(5),
},
};
static const struct sirfsoc_padmux i2s_padmux = {
.muxmask_counts = ARRAY_SIZE(i2s_muxmask),
.muxmask = i2s_muxmask,
.funcmask = BIT(3),
.funcval = BIT(3),
};
static const unsigned i2s_pins[] = { 42, 98, 99, 100, 101 };
static const struct sirfsoc_muxmask i2s_no_din_muxmask[] = {
{
.group = 1,
.mask = BIT(10),
}, {
.group = 3,
.mask = BIT(2) | BIT(3) | BIT(4),
},
};
static const struct sirfsoc_padmux i2s_no_din_padmux = {
.muxmask_counts = ARRAY_SIZE(i2s_no_din_muxmask),
.muxmask = i2s_no_din_muxmask,
.funcmask = BIT(3),
.funcval = BIT(3),
};
static const unsigned i2s_no_din_pins[] = { 42, 98, 99, 100 };
static const struct sirfsoc_muxmask i2s_6chn_muxmask[] = {
{
.group = 1,
.mask = BIT(10) | BIT(20) | BIT(23),
}, {
.group = 3,
.mask = BIT(2) | BIT(3) | BIT(4) | BIT(5),
},
};
static const struct sirfsoc_padmux i2s_6chn_padmux = {
.muxmask_counts = ARRAY_SIZE(i2s_6chn_muxmask),
.muxmask = i2s_6chn_muxmask,
.funcmask = BIT(1) | BIT(3) | BIT(9),
.funcval = BIT(1) | BIT(3) | BIT(9),
};
static const unsigned i2s_6chn_pins[] = { 42, 52, 55, 98, 99, 100, 101 };
static const struct sirfsoc_muxmask ac97_muxmask[] = {
{
.group = 3,
.mask = BIT(2) | BIT(3) | BIT(4) | BIT(5),
},
};
static const struct sirfsoc_padmux ac97_padmux = {
.muxmask_counts = ARRAY_SIZE(ac97_muxmask),
.muxmask = ac97_muxmask,
};
static const unsigned ac97_pins[] = { 98, 99, 100, 101 };
static const struct sirfsoc_muxmask spi1_muxmask[] = {
{
.group = 1,
.mask = BIT(11) | BIT(12) | BIT(13) | BIT(14),
},
};
static const struct sirfsoc_padmux spi1_padmux = {
.muxmask_counts = ARRAY_SIZE(spi1_muxmask),
.muxmask = spi1_muxmask,
.funcmask = BIT(16),
.funcval = 0,
};
static const unsigned spi1_pins[] = { 43, 44, 45, 46 };
static const struct sirfsoc_muxmask sdmmc1_muxmask[] = {
{
.group = 2,
.mask = BIT(2) | BIT(3),
},
};
static const struct sirfsoc_padmux sdmmc1_padmux = {
.muxmask_counts = ARRAY_SIZE(sdmmc1_muxmask),
.muxmask = sdmmc1_muxmask,
.funcmask = BIT(5),
.funcval = BIT(5),
};
static const unsigned sdmmc1_pins[] = { 66, 67 };
static const struct sirfsoc_muxmask gps_muxmask[] = {
{
.group = 0,
.mask = BIT(24) | BIT(25) | BIT(26),
},
};
static const struct sirfsoc_padmux gps_padmux = {
.muxmask_counts = ARRAY_SIZE(gps_muxmask),
.muxmask = gps_muxmask,
.funcmask = BIT(13),
.funcval = 0,
};
static const unsigned gps_pins[] = { 24, 25, 26 };
static const struct sirfsoc_muxmask sdmmc5_muxmask[] = {
{
.group = 0,
.mask = BIT(24) | BIT(25) | BIT(26),
},
};
static const struct sirfsoc_padmux sdmmc5_padmux = {
.muxmask_counts = ARRAY_SIZE(sdmmc5_muxmask),
.muxmask = sdmmc5_muxmask,
.funcmask = BIT(13),
.funcval = BIT(13),
};
static const unsigned sdmmc5_pins[] = { 24, 25, 26 };
static const struct sirfsoc_muxmask usp0_muxmask[] = {
{
.group = 1,
.mask = BIT(19) | BIT(20) | BIT(21) | BIT(22),
},
};
static const struct sirfsoc_padmux usp0_padmux = {
.muxmask_counts = ARRAY_SIZE(usp0_muxmask),
.muxmask = usp0_muxmask,
.funcmask = BIT(1) | BIT(2) | BIT(9),
.funcval = 0,
};
static const unsigned usp0_pins[] = { 51, 52, 53, 54 };
static const struct sirfsoc_muxmask usp1_muxmask[] = {
{
.group = 0,
.mask = BIT(15),
}, {
.group = 1,
.mask = BIT(11) | BIT(12) | BIT(13) | BIT(14),
},
};
static const struct sirfsoc_padmux usp1_padmux = {
.muxmask_counts = ARRAY_SIZE(usp1_muxmask),
.muxmask = usp1_muxmask,
.funcmask = BIT(16),
.funcval = BIT(16),
};
static const unsigned usp1_pins[] = { 15, 43, 44, 45, 46 };
static const struct sirfsoc_muxmask nand_muxmask[] = {
{
.group = 2,
.mask = BIT(2) | BIT(3) | BIT(28) | BIT(29) | BIT(30),
}, {
.group = 3,
.mask = BIT(0) | BIT(1),
},
};
static const struct sirfsoc_padmux nand_padmux = {
.muxmask_counts = ARRAY_SIZE(nand_muxmask),
.muxmask = nand_muxmask,
.funcmask = BIT(5) | BIT(19),
.funcval = 0,
};
static const unsigned nand_pins[] = { 66, 67, 92, 93, 94, 96, 97 };
static const struct sirfsoc_muxmask sdmmc0_muxmask[] = {
{
.group = 3,
.mask = BIT(1),
},
};
static const struct sirfsoc_padmux sdmmc0_padmux = {
.muxmask_counts = ARRAY_SIZE(sdmmc0_muxmask),
.muxmask = sdmmc0_muxmask,
.funcmask = BIT(5) | BIT(19),
.funcval = BIT(19),
};
static const unsigned sdmmc0_pins[] = { 97 };
static const struct sirfsoc_muxmask sdmmc2_muxmask[] = {
{
.group = 0,
.mask = BIT(27) | BIT(28) | BIT(29),
},
};
static const struct sirfsoc_padmux sdmmc2_padmux = {
.muxmask_counts = ARRAY_SIZE(sdmmc2_muxmask),
.muxmask = sdmmc2_muxmask,
.funcmask = BIT(11),
.funcval = 0,
};
static const unsigned sdmmc2_pins[] = { 27, 28, 29 };
static const struct sirfsoc_muxmask sdmmc2_nowp_muxmask[] = {
{
.group = 0,
.mask = BIT(27) | BIT(28),
},
};
static const struct sirfsoc_padmux sdmmc2_nowp_padmux = {
.muxmask_counts = ARRAY_SIZE(sdmmc2_nowp_muxmask),
.muxmask = sdmmc2_nowp_muxmask,
.funcmask = BIT(11),
.funcval = 0,
};
static const unsigned sdmmc2_nowp_pins[] = { 27, 28 };
static const struct sirfsoc_muxmask cko0_muxmask[] = {
{
.group = 2,
.mask = BIT(14),
},
};
static const struct sirfsoc_padmux cko0_padmux = {
.muxmask_counts = ARRAY_SIZE(cko0_muxmask),
.muxmask = cko0_muxmask,
};
static const unsigned cko0_pins[] = { 78 };
static const struct sirfsoc_muxmask vip_muxmask[] = {
{
.group = 1,
.mask = BIT(4) | BIT(5) | BIT(6) | BIT(8) | BIT(9)
| BIT(24) | BIT(25) | BIT(26) | BIT(27) | BIT(28) |
BIT(29),
},
};
static const struct sirfsoc_padmux vip_padmux = {
.muxmask_counts = ARRAY_SIZE(vip_muxmask),
.muxmask = vip_muxmask,
.funcmask = BIT(18),
.funcval = BIT(18),
};
static const unsigned vip_pins[] = { 36, 37, 38, 40, 41, 56, 57, 58, 59, 60, 61 };
static const struct sirfsoc_muxmask vip_noupli_muxmask[] = {
{
.group = 0,
.mask = BIT(16) | BIT(17) | BIT(18) | BIT(19) | BIT(20)
| BIT(21) | BIT(22) | BIT(23),
}, {
.group = 2,
.mask = BIT(23) | BIT(24) | BIT(25),
},
};
static const struct sirfsoc_padmux vip_noupli_padmux = {
.muxmask_counts = ARRAY_SIZE(vip_noupli_muxmask),
.muxmask = vip_noupli_muxmask,
.funcmask = BIT(15),
.funcval = BIT(15),
};
static const unsigned vip_noupli_pins[] = { 16, 17, 18, 19, 20, 21, 22, 23, 87, 88, 89 };
static const struct sirfsoc_muxmask i2c0_muxmask[] = {
{
.group = 2,
.mask = BIT(26) | BIT(27),
},
};
static const struct sirfsoc_padmux i2c0_padmux = {
.muxmask_counts = ARRAY_SIZE(i2c0_muxmask),
.muxmask = i2c0_muxmask,
};
static const unsigned i2c0_pins[] = { 90, 91 };
static const struct sirfsoc_muxmask i2c1_muxmask[] = {
{
.group = 0,
.mask = BIT(13) | BIT(15),
},
};
static const struct sirfsoc_padmux i2c1_padmux = {
.muxmask_counts = ARRAY_SIZE(i2c1_muxmask),
.muxmask = i2c1_muxmask,
.funcmask = BIT(16),
.funcval = 0,
};
static const unsigned i2c1_pins[] = { 13, 15 };
static const struct sirfsoc_muxmask pwm0_muxmask[] = {
{
.group = 0,
.mask = BIT(4),
},
};
static const struct sirfsoc_padmux pwm0_padmux = {
.muxmask_counts = ARRAY_SIZE(pwm0_muxmask),
.muxmask = pwm0_muxmask,
.funcmask = BIT(12),
.funcval = 0,
};
static const unsigned pwm0_pins[] = { 4 };
static const struct sirfsoc_muxmask pwm1_muxmask[] = {
{
.group = 0,
.mask = BIT(5),
},
};
static const struct sirfsoc_padmux pwm1_padmux = {
.muxmask_counts = ARRAY_SIZE(pwm1_muxmask),
.muxmask = pwm1_muxmask,
};
static const unsigned pwm1_pins[] = { 5 };
static const struct sirfsoc_muxmask pwm2_muxmask[] = {
{
.group = 0,
.mask = BIT(6),
},
};
static const struct sirfsoc_padmux pwm2_padmux = {
.muxmask_counts = ARRAY_SIZE(pwm2_muxmask),
.muxmask = pwm2_muxmask,
};
static const unsigned pwm2_pins[] = { 6 };
static const struct sirfsoc_muxmask pwm3_muxmask[] = {
{
.group = 0,
.mask = BIT(7),
},
};
static const struct sirfsoc_padmux pwm3_padmux = {
.muxmask_counts = ARRAY_SIZE(pwm3_muxmask),
.muxmask = pwm3_muxmask,
};
static const unsigned pwm3_pins[] = { 7 };
static const struct sirfsoc_muxmask pwm4_muxmask[] = {
{
.group = 2,
.mask = BIT(14),
},
};
static const struct sirfsoc_padmux pwm4_padmux = {
.muxmask_counts = ARRAY_SIZE(pwm4_muxmask),
.muxmask = pwm4_muxmask,
};
static const unsigned pwm4_pins[] = { 78 };
static const struct sirfsoc_muxmask warm_rst_muxmask[] = {
{
.group = 0,
.mask = BIT(8),
},
};
static const struct sirfsoc_padmux warm_rst_padmux = {
.muxmask_counts = ARRAY_SIZE(warm_rst_muxmask),
.muxmask = warm_rst_muxmask,
.funcmask = BIT(4),
.funcval = 0,
};
static const unsigned warm_rst_pins[] = { 8 };
static const struct sirfsoc_muxmask usb0_upli_drvbus_muxmask[] = {
{
.group = 1,
.mask = BIT(4) | BIT(5) | BIT(6) | BIT(7) | BIT(8)
| BIT(9) | BIT(24) | BIT(25) | BIT(26) |
BIT(27) | BIT(28) | BIT(29),
},
};
static const struct sirfsoc_padmux usb0_upli_drvbus_padmux = {
.muxmask_counts = ARRAY_SIZE(usb0_upli_drvbus_muxmask),
.muxmask = usb0_upli_drvbus_muxmask,
.funcmask = BIT(18),
.funcval = 0,
};
static const unsigned usb0_upli_drvbus_pins[] = { 36, 37, 38, 39, 40, 41, 56, 57, 58, 59, 60, 61 };
static const struct sirfsoc_muxmask usb1_utmi_drvbus_muxmask[] = {
{
.group = 0,
.mask = BIT(28),
},
};
static const struct sirfsoc_padmux usb1_utmi_drvbus_padmux = {
.muxmask_counts = ARRAY_SIZE(usb1_utmi_drvbus_muxmask),
.muxmask = usb1_utmi_drvbus_muxmask,
.funcmask = BIT(11),
.funcval = BIT(11), /* refer to PAD_UTMI_DRVVBUS1_ENABLE */
};
static const unsigned usb1_utmi_drvbus_pins[] = { 28 };
static const struct sirfsoc_muxmask pulse_count_muxmask[] = {
{
.group = 0,
.mask = BIT(9) | BIT(10) | BIT(11),
},
};
static const struct sirfsoc_padmux pulse_count_padmux = {
.muxmask_counts = ARRAY_SIZE(pulse_count_muxmask),
.muxmask = pulse_count_muxmask,
};
static const unsigned pulse_count_pins[] = { 9, 10, 11 };
static const struct sirfsoc_pin_group sirfsoc_pin_groups[] = {
SIRFSOC_PIN_GROUP("lcd_16bitsgrp", lcd_16bits_pins),
SIRFSOC_PIN_GROUP("lcd_18bitsgrp", lcd_18bits_pins),
SIRFSOC_PIN_GROUP("lcd_24bitsgrp", lcd_24bits_pins),
SIRFSOC_PIN_GROUP("lcdrom_grp", lcdrom_pins),
SIRFSOC_PIN_GROUP("uart0grp", uart0_pins),
SIRFSOC_PIN_GROUP("uart1grp", uart1_pins),
SIRFSOC_PIN_GROUP("uart2grp", uart2_pins),
SIRFSOC_PIN_GROUP("uart2_nostreamctrlgrp", uart2_nostreamctrl_pins),
SIRFSOC_PIN_GROUP("usp0grp", usp0_pins),
SIRFSOC_PIN_GROUP("usp1grp", usp1_pins),
SIRFSOC_PIN_GROUP("i2c0grp", i2c0_pins),
SIRFSOC_PIN_GROUP("i2c1grp", i2c1_pins),
SIRFSOC_PIN_GROUP("pwm0grp", pwm0_pins),
SIRFSOC_PIN_GROUP("pwm1grp", pwm1_pins),
SIRFSOC_PIN_GROUP("pwm2grp", pwm2_pins),
SIRFSOC_PIN_GROUP("pwm3grp", pwm3_pins),
SIRFSOC_PIN_GROUP("pwm4grp", pwm4_pins),
SIRFSOC_PIN_GROUP("vipgrp", vip_pins),
SIRFSOC_PIN_GROUP("vip_noupligrp", vip_noupli_pins),
SIRFSOC_PIN_GROUP("warm_rstgrp", warm_rst_pins),
SIRFSOC_PIN_GROUP("cko0grp", cko0_pins),
SIRFSOC_PIN_GROUP("cko1grp", cko1_pins),
SIRFSOC_PIN_GROUP("sdmmc0grp", sdmmc0_pins),
SIRFSOC_PIN_GROUP("sdmmc1grp", sdmmc1_pins),
SIRFSOC_PIN_GROUP("sdmmc2grp", sdmmc2_pins),
SIRFSOC_PIN_GROUP("sdmmc2_nowpgrp", sdmmc2_nowp_pins),
SIRFSOC_PIN_GROUP("sdmmc3grp", sdmmc3_pins),
SIRFSOC_PIN_GROUP("sdmmc5grp", sdmmc5_pins),
SIRFSOC_PIN_GROUP("usb0_upli_drvbusgrp", usb0_upli_drvbus_pins),
SIRFSOC_PIN_GROUP("usb1_utmi_drvbusgrp", usb1_utmi_drvbus_pins),
SIRFSOC_PIN_GROUP("pulse_countgrp", pulse_count_pins),
SIRFSOC_PIN_GROUP("i2sgrp", i2s_pins),
SIRFSOC_PIN_GROUP("i2s_no_dingrp", i2s_no_din_pins),
SIRFSOC_PIN_GROUP("i2s_6chngrp", i2s_6chn_pins),
SIRFSOC_PIN_GROUP("ac97grp", ac97_pins),
SIRFSOC_PIN_GROUP("nandgrp", nand_pins),
SIRFSOC_PIN_GROUP("spi0grp", spi0_pins),
SIRFSOC_PIN_GROUP("spi1grp", spi1_pins),
SIRFSOC_PIN_GROUP("gpsgrp", gps_pins),
};
static const char * const lcd_16bitsgrp[] = { "lcd_16bitsgrp" };
static const char * const lcd_18bitsgrp[] = { "lcd_18bitsgrp" };
static const char * const lcd_24bitsgrp[] = { "lcd_24bitsgrp" };
static const char * const lcdromgrp[] = { "lcdromgrp" };
static const char * const uart0grp[] = { "uart0grp" };
static const char * const uart1grp[] = { "uart1grp" };
static const char * const uart2grp[] = { "uart2grp" };
static const char * const uart2_nostreamctrlgrp[] = { "uart2_nostreamctrlgrp" };
static const char * const usp0grp[] = { "usp0grp" };
static const char * const usp1grp[] = { "usp1grp" };
static const char * const i2c0grp[] = { "i2c0grp" };
static const char * const i2c1grp[] = { "i2c1grp" };
static const char * const pwm0grp[] = { "pwm0grp" };
static const char * const pwm1grp[] = { "pwm1grp" };
static const char * const pwm2grp[] = { "pwm2grp" };
static const char * const pwm3grp[] = { "pwm3grp" };
static const char * const pwm4grp[] = { "pwm4grp" };
static const char * const vipgrp[] = { "vipgrp" };
static const char * const vip_noupligrp[] = { "vip_noupligrp" };
static const char * const warm_rstgrp[] = { "warm_rstgrp" };
static const char * const cko0grp[] = { "cko0grp" };
static const char * const cko1grp[] = { "cko1grp" };
static const char * const sdmmc0grp[] = { "sdmmc0grp" };
static const char * const sdmmc1grp[] = { "sdmmc1grp" };
static const char * const sdmmc2grp[] = { "sdmmc2grp" };
static const char * const sdmmc3grp[] = { "sdmmc3grp" };
static const char * const sdmmc5grp[] = { "sdmmc5grp" };
static const char * const sdmmc2_nowpgrp[] = { "sdmmc2_nowpgrp" };
static const char * const usb0_upli_drvbusgrp[] = { "usb0_upli_drvbusgrp" };
static const char * const usb1_utmi_drvbusgrp[] = { "usb1_utmi_drvbusgrp" };
static const char * const pulse_countgrp[] = { "pulse_countgrp" };
static const char * const i2sgrp[] = { "i2sgrp" };
static const char * const i2s_no_dingrp[] = { "i2s_no_dingrp" };
static const char * const i2s_6chngrp[] = { "i2s_6chngrp" };
static const char * const ac97grp[] = { "ac97grp" };
static const char * const nandgrp[] = { "nandgrp" };
static const char * const spi0grp[] = { "spi0grp" };
static const char * const spi1grp[] = { "spi1grp" };
static const char * const gpsgrp[] = { "gpsgrp" };
static const struct sirfsoc_pmx_func sirfsoc_pmx_functions[] = {
SIRFSOC_PMX_FUNCTION("lcd_16bits", lcd_16bitsgrp, lcd_16bits_padmux),
SIRFSOC_PMX_FUNCTION("lcd_18bits", lcd_18bitsgrp, lcd_18bits_padmux),
SIRFSOC_PMX_FUNCTION("lcd_24bits", lcd_24bitsgrp, lcd_24bits_padmux),
SIRFSOC_PMX_FUNCTION("lcdrom", lcdromgrp, lcdrom_padmux),
SIRFSOC_PMX_FUNCTION("uart0", uart0grp, uart0_padmux),
SIRFSOC_PMX_FUNCTION("uart1", uart1grp, uart1_padmux),
SIRFSOC_PMX_FUNCTION("uart2", uart2grp, uart2_padmux),
SIRFSOC_PMX_FUNCTION("uart2_nostreamctrl", uart2_nostreamctrlgrp, uart2_nostreamctrl_padmux),
SIRFSOC_PMX_FUNCTION("usp0", usp0grp, usp0_padmux),
SIRFSOC_PMX_FUNCTION("usp1", usp1grp, usp1_padmux),
SIRFSOC_PMX_FUNCTION("i2c0", i2c0grp, i2c0_padmux),
SIRFSOC_PMX_FUNCTION("i2c1", i2c1grp, i2c1_padmux),
SIRFSOC_PMX_FUNCTION("pwm0", pwm0grp, pwm0_padmux),
SIRFSOC_PMX_FUNCTION("pwm1", pwm1grp, pwm1_padmux),
SIRFSOC_PMX_FUNCTION("pwm2", pwm2grp, pwm2_padmux),
SIRFSOC_PMX_FUNCTION("pwm3", pwm3grp, pwm3_padmux),
SIRFSOC_PMX_FUNCTION("pwm4", pwm4grp, pwm4_padmux),
SIRFSOC_PMX_FUNCTION("vip", vipgrp, vip_padmux),
SIRFSOC_PMX_FUNCTION("vip_noupli", vip_noupligrp, vip_noupli_padmux),
SIRFSOC_PMX_FUNCTION("warm_rst", warm_rstgrp, warm_rst_padmux),
SIRFSOC_PMX_FUNCTION("cko0", cko0grp, cko0_padmux),
SIRFSOC_PMX_FUNCTION("cko1", cko1grp, cko1_padmux),
SIRFSOC_PMX_FUNCTION("sdmmc0", sdmmc0grp, sdmmc0_padmux),
SIRFSOC_PMX_FUNCTION("sdmmc1", sdmmc1grp, sdmmc1_padmux),
SIRFSOC_PMX_FUNCTION("sdmmc2", sdmmc2grp, sdmmc2_padmux),
SIRFSOC_PMX_FUNCTION("sdmmc3", sdmmc3grp, sdmmc3_padmux),
SIRFSOC_PMX_FUNCTION("sdmmc5", sdmmc5grp, sdmmc5_padmux),
SIRFSOC_PMX_FUNCTION("sdmmc2_nowp", sdmmc2_nowpgrp, sdmmc2_nowp_padmux),
SIRFSOC_PMX_FUNCTION("usb0_upli_drvbus", usb0_upli_drvbusgrp, usb0_upli_drvbus_padmux),
SIRFSOC_PMX_FUNCTION("usb1_utmi_drvbus", usb1_utmi_drvbusgrp, usb1_utmi_drvbus_padmux),
SIRFSOC_PMX_FUNCTION("pulse_count", pulse_countgrp, pulse_count_padmux),
SIRFSOC_PMX_FUNCTION("i2s", i2sgrp, i2s_padmux),
SIRFSOC_PMX_FUNCTION("i2s_no_din", i2s_no_dingrp, i2s_no_din_padmux),
SIRFSOC_PMX_FUNCTION("i2s_6chn", i2s_6chngrp, i2s_6chn_padmux),
SIRFSOC_PMX_FUNCTION("ac97", ac97grp, ac97_padmux),
SIRFSOC_PMX_FUNCTION("nand", nandgrp, nand_padmux),
SIRFSOC_PMX_FUNCTION("spi0", spi0grp, spi0_padmux),
SIRFSOC_PMX_FUNCTION("spi1", spi1grp, spi1_padmux),
SIRFSOC_PMX_FUNCTION("gps", gpsgrp, gps_padmux),
};
struct sirfsoc_pinctrl_data atlas6_pinctrl_data = {
(struct pinctrl_pin_desc *)sirfsoc_pads,
ARRAY_SIZE(sirfsoc_pads),
(struct sirfsoc_pin_group *)sirfsoc_pin_groups,
ARRAY_SIZE(sirfsoc_pin_groups),
(struct sirfsoc_pmx_func *)sirfsoc_pmx_functions,
ARRAY_SIZE(sirfsoc_pmx_functions),
};

View file

@ -0,0 +1,929 @@
/*
* pinmux driver for CSR SiRFprimaII
*
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/irqdomain.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/machine.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/bitops.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <asm/mach/irq.h>
#include "pinctrl-sirf.h"
#define DRIVER_NAME "pinmux-sirf"
struct sirfsoc_gpio_bank {
struct of_mm_gpio_chip chip;
struct irq_domain *domain;
int id;
int parent_irq;
spinlock_t lock;
bool is_marco; /* for marco, some registers are different with prima2 */
};
static struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS];
static DEFINE_SPINLOCK(sgpio_lock);
static struct sirfsoc_pin_group *sirfsoc_pin_groups;
static int sirfsoc_pingrp_cnt;
static int sirfsoc_get_groups_count(struct pinctrl_dev *pctldev)
{
return sirfsoc_pingrp_cnt;
}
static const char *sirfsoc_get_group_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
return sirfsoc_pin_groups[selector].name;
}
static int sirfsoc_get_group_pins(struct pinctrl_dev *pctldev, unsigned selector,
const unsigned **pins,
unsigned *num_pins)
{
*pins = sirfsoc_pin_groups[selector].pins;
*num_pins = sirfsoc_pin_groups[selector].num_pins;
return 0;
}
static void sirfsoc_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
unsigned offset)
{
seq_printf(s, " " DRIVER_NAME);
}
static int sirfsoc_dt_node_to_map(struct pinctrl_dev *pctldev,
struct device_node *np_config,
struct pinctrl_map **map, unsigned *num_maps)
{
struct sirfsoc_pmx *spmx = pinctrl_dev_get_drvdata(pctldev);
struct device_node *np;
struct property *prop;
const char *function, *group;
int ret, index = 0, count = 0;
/* calculate number of maps required */
for_each_child_of_node(np_config, np) {
ret = of_property_read_string(np, "sirf,function", &function);
if (ret < 0)
return ret;
ret = of_property_count_strings(np, "sirf,pins");
if (ret < 0)
return ret;
count += ret;
}
if (!count) {
dev_err(spmx->dev, "No child nodes passed via DT\n");
return -ENODEV;
}
*map = kzalloc(sizeof(**map) * count, GFP_KERNEL);
if (!*map)
return -ENOMEM;
for_each_child_of_node(np_config, np) {
of_property_read_string(np, "sirf,function", &function);
of_property_for_each_string(np, "sirf,pins", prop, group) {
(*map)[index].type = PIN_MAP_TYPE_MUX_GROUP;
(*map)[index].data.mux.group = group;
(*map)[index].data.mux.function = function;
index++;
}
}
*num_maps = count;
return 0;
}
static void sirfsoc_dt_free_map(struct pinctrl_dev *pctldev,
struct pinctrl_map *map, unsigned num_maps)
{
kfree(map);
}
static struct pinctrl_ops sirfsoc_pctrl_ops = {
.get_groups_count = sirfsoc_get_groups_count,
.get_group_name = sirfsoc_get_group_name,
.get_group_pins = sirfsoc_get_group_pins,
.pin_dbg_show = sirfsoc_pin_dbg_show,
.dt_node_to_map = sirfsoc_dt_node_to_map,
.dt_free_map = sirfsoc_dt_free_map,
};
static struct sirfsoc_pmx_func *sirfsoc_pmx_functions;
static int sirfsoc_pmxfunc_cnt;
static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx, unsigned selector,
bool enable)
{
int i;
const struct sirfsoc_padmux *mux = sirfsoc_pmx_functions[selector].padmux;
const struct sirfsoc_muxmask *mask = mux->muxmask;
for (i = 0; i < mux->muxmask_counts; i++) {
u32 muxval;
if (!spmx->is_marco) {
muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
if (enable)
muxval = muxval & ~mask[i].mask;
else
muxval = muxval | mask[i].mask;
writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(mask[i].group));
} else {
if (enable)
writel(mask[i].mask, spmx->gpio_virtbase +
SIRFSOC_GPIO_PAD_EN_CLR(mask[i].group));
else
writel(mask[i].mask, spmx->gpio_virtbase +
SIRFSOC_GPIO_PAD_EN(mask[i].group));
}
}
if (mux->funcmask && enable) {
u32 func_en_val;
func_en_val =
readl(spmx->rsc_virtbase + SIRFSOC_RSC_PIN_MUX);
func_en_val =
(func_en_val & ~mux->funcmask) | (mux->
funcval);
writel(func_en_val, spmx->rsc_virtbase + SIRFSOC_RSC_PIN_MUX);
}
}
static int sirfsoc_pinmux_enable(struct pinctrl_dev *pmxdev, unsigned selector,
unsigned group)
{
struct sirfsoc_pmx *spmx;
spmx = pinctrl_dev_get_drvdata(pmxdev);
sirfsoc_pinmux_endisable(spmx, selector, true);
return 0;
}
static void sirfsoc_pinmux_disable(struct pinctrl_dev *pmxdev, unsigned selector,
unsigned group)
{
struct sirfsoc_pmx *spmx;
spmx = pinctrl_dev_get_drvdata(pmxdev);
sirfsoc_pinmux_endisable(spmx, selector, false);
}
static int sirfsoc_pinmux_get_funcs_count(struct pinctrl_dev *pmxdev)
{
return sirfsoc_pmxfunc_cnt;
}
static const char *sirfsoc_pinmux_get_func_name(struct pinctrl_dev *pctldev,
unsigned selector)
{
return sirfsoc_pmx_functions[selector].name;
}
static int sirfsoc_pinmux_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
const char * const **groups,
unsigned * const num_groups)
{
*groups = sirfsoc_pmx_functions[selector].groups;
*num_groups = sirfsoc_pmx_functions[selector].num_groups;
return 0;
}
static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
struct pinctrl_gpio_range *range, unsigned offset)
{
struct sirfsoc_pmx *spmx;
int group = range->id;
u32 muxval;
spmx = pinctrl_dev_get_drvdata(pmxdev);
if (!spmx->is_marco) {
muxval = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
muxval = muxval | (1 << (offset - range->pin_base));
writel(muxval, spmx->gpio_virtbase + SIRFSOC_GPIO_PAD_EN(group));
} else {
writel(1 << (offset - range->pin_base), spmx->gpio_virtbase +
SIRFSOC_GPIO_PAD_EN(group));
}
return 0;
}
static struct pinmux_ops sirfsoc_pinmux_ops = {
.enable = sirfsoc_pinmux_enable,
.disable = sirfsoc_pinmux_disable,
.get_functions_count = sirfsoc_pinmux_get_funcs_count,
.get_function_name = sirfsoc_pinmux_get_func_name,
.get_function_groups = sirfsoc_pinmux_get_groups,
.gpio_request_enable = sirfsoc_pinmux_request_gpio,
};
static struct pinctrl_desc sirfsoc_pinmux_desc = {
.name = DRIVER_NAME,
.pctlops = &sirfsoc_pctrl_ops,
.pmxops = &sirfsoc_pinmux_ops,
.owner = THIS_MODULE,
};
/*
* Todo: bind irq_chip to every pinctrl_gpio_range
*/
static struct pinctrl_gpio_range sirfsoc_gpio_ranges[] = {
{
.name = "sirfsoc-gpio*",
.id = 0,
.base = 0,
.pin_base = 0,
.npins = 32,
}, {
.name = "sirfsoc-gpio*",
.id = 1,
.base = 32,
.pin_base = 32,
.npins = 32,
}, {
.name = "sirfsoc-gpio*",
.id = 2,
.base = 64,
.pin_base = 64,
.npins = 32,
}, {
.name = "sirfsoc-gpio*",
.id = 3,
.base = 96,
.pin_base = 96,
.npins = 19,
},
};
static void __iomem *sirfsoc_rsc_of_iomap(void)
{
const struct of_device_id rsc_ids[] = {
{ .compatible = "sirf,prima2-rsc" },
{ .compatible = "sirf,marco-rsc" },
{}
};
struct device_node *np;
np = of_find_matching_node(NULL, rsc_ids);
if (!np)
panic("unable to find compatible rsc node in dtb\n");
return of_iomap(np, 0);
}
static int sirfsoc_gpio_of_xlate(struct gpio_chip *gc,
const struct of_phandle_args *gpiospec,
u32 *flags)
{
if (gpiospec->args[0] > SIRFSOC_GPIO_NO_OF_BANKS * SIRFSOC_GPIO_BANK_SIZE)
return -EINVAL;
if (gc != &sgpio_bank[gpiospec->args[0] / SIRFSOC_GPIO_BANK_SIZE].chip.gc)
return -EINVAL;
if (flags)
*flags = gpiospec->args[1];
return gpiospec->args[0] % SIRFSOC_GPIO_BANK_SIZE;
}
static const struct of_device_id pinmux_ids[] = {
{ .compatible = "sirf,prima2-pinctrl", .data = &prima2_pinctrl_data, },
{ .compatible = "sirf,atlas6-pinctrl", .data = &atlas6_pinctrl_data, },
{ .compatible = "sirf,marco-pinctrl", .data = &prima2_pinctrl_data, },
{}
};
static int sirfsoc_pinmux_probe(struct platform_device *pdev)
{
int ret;
struct sirfsoc_pmx *spmx;
struct device_node *np = pdev->dev.of_node;
const struct sirfsoc_pinctrl_data *pdata;
int i;
/* Create state holders etc for this driver */
spmx = devm_kzalloc(&pdev->dev, sizeof(*spmx), GFP_KERNEL);
if (!spmx)
return -ENOMEM;
spmx->dev = &pdev->dev;
platform_set_drvdata(pdev, spmx);
spmx->gpio_virtbase = of_iomap(np, 0);
if (!spmx->gpio_virtbase) {
dev_err(&pdev->dev, "can't map gpio registers\n");
return -ENOMEM;
}
spmx->rsc_virtbase = sirfsoc_rsc_of_iomap();
if (!spmx->rsc_virtbase) {
ret = -ENOMEM;
dev_err(&pdev->dev, "can't map rsc registers\n");
goto out_no_rsc_remap;
}
if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
spmx->is_marco = 1;
pdata = of_match_node(pinmux_ids, np)->data;
sirfsoc_pin_groups = pdata->grps;
sirfsoc_pingrp_cnt = pdata->grps_cnt;
sirfsoc_pmx_functions = pdata->funcs;
sirfsoc_pmxfunc_cnt = pdata->funcs_cnt;
sirfsoc_pinmux_desc.pins = pdata->pads;
sirfsoc_pinmux_desc.npins = pdata->pads_cnt;
/* Now register the pin controller and all pins it handles */
spmx->pmx = pinctrl_register(&sirfsoc_pinmux_desc, &pdev->dev, spmx);
if (!spmx->pmx) {
dev_err(&pdev->dev, "could not register SIRFSOC pinmux driver\n");
ret = -EINVAL;
goto out_no_pmx;
}
for (i = 0; i < ARRAY_SIZE(sirfsoc_gpio_ranges); i++) {
sirfsoc_gpio_ranges[i].gc = &sgpio_bank[i].chip.gc;
pinctrl_add_gpio_range(spmx->pmx, &sirfsoc_gpio_ranges[i]);
}
dev_info(&pdev->dev, "initialized SIRFSOC pinmux driver\n");
return 0;
out_no_pmx:
iounmap(spmx->rsc_virtbase);
out_no_rsc_remap:
iounmap(spmx->gpio_virtbase);
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int sirfsoc_pinmux_suspend_noirq(struct device *dev)
{
int i, j;
struct sirfsoc_pmx *spmx = dev_get_drvdata(dev);
for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
for (j = 0; j < SIRFSOC_GPIO_BANK_SIZE; j++) {
spmx->gpio_regs[i][j] = readl(spmx->gpio_virtbase +
SIRFSOC_GPIO_CTRL(i, j));
}
spmx->ints_regs[i] = readl(spmx->gpio_virtbase +
SIRFSOC_GPIO_INT_STATUS(i));
spmx->paden_regs[i] = readl(spmx->gpio_virtbase +
SIRFSOC_GPIO_PAD_EN(i));
}
spmx->dspen_regs = readl(spmx->gpio_virtbase + SIRFSOC_GPIO_DSP_EN0);
for (i = 0; i < 3; i++)
spmx->rsc_regs[i] = readl(spmx->rsc_virtbase + 4 * i);
return 0;
}
static int sirfsoc_pinmux_resume_noirq(struct device *dev)
{
int i, j;
struct sirfsoc_pmx *spmx = dev_get_drvdata(dev);
for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
for (j = 0; j < SIRFSOC_GPIO_BANK_SIZE; j++) {
writel(spmx->gpio_regs[i][j], spmx->gpio_virtbase +
SIRFSOC_GPIO_CTRL(i, j));
}
writel(spmx->ints_regs[i], spmx->gpio_virtbase +
SIRFSOC_GPIO_INT_STATUS(i));
writel(spmx->paden_regs[i], spmx->gpio_virtbase +
SIRFSOC_GPIO_PAD_EN(i));
}
writel(spmx->dspen_regs, spmx->gpio_virtbase + SIRFSOC_GPIO_DSP_EN0);
for (i = 0; i < 3; i++)
writel(spmx->rsc_regs[i], spmx->rsc_virtbase + 4 * i);
return 0;
}
static const struct dev_pm_ops sirfsoc_pinmux_pm_ops = {
.suspend_noirq = sirfsoc_pinmux_suspend_noirq,
.resume_noirq = sirfsoc_pinmux_resume_noirq,
};
#endif
static struct platform_driver sirfsoc_pinmux_driver = {
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = pinmux_ids,
#ifdef CONFIG_PM_SLEEP
.pm = &sirfsoc_pinmux_pm_ops,
#endif
},
.probe = sirfsoc_pinmux_probe,
};
static int __init sirfsoc_pinmux_init(void)
{
return platform_driver_register(&sirfsoc_pinmux_driver);
}
arch_initcall(sirfsoc_pinmux_init);
static inline int sirfsoc_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
{
struct sirfsoc_gpio_bank *bank = container_of(to_of_mm_gpio_chip(chip),
struct sirfsoc_gpio_bank, chip);
return irq_create_mapping(bank->domain, offset);
}
static inline int sirfsoc_gpio_to_offset(unsigned int gpio)
{
return gpio % SIRFSOC_GPIO_BANK_SIZE;
}
static inline struct sirfsoc_gpio_bank *sirfsoc_gpio_to_bank(unsigned int gpio)
{
return &sgpio_bank[gpio / SIRFSOC_GPIO_BANK_SIZE];
}
static inline struct sirfsoc_gpio_bank *sirfsoc_irqchip_to_bank(struct gpio_chip *chip)
{
return container_of(to_of_mm_gpio_chip(chip), struct sirfsoc_gpio_bank, chip);
}
static void sirfsoc_gpio_irq_ack(struct irq_data *d)
{
struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE;
u32 val, offset;
unsigned long flags;
offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
spin_lock_irqsave(&sgpio_lock, flags);
val = readl(bank->chip.regs + offset);
writel(val, bank->chip.regs + offset);
spin_unlock_irqrestore(&sgpio_lock, flags);
}
static void __sirfsoc_gpio_irq_mask(struct sirfsoc_gpio_bank *bank, int idx)
{
u32 val, offset;
unsigned long flags;
offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
spin_lock_irqsave(&sgpio_lock, flags);
val = readl(bank->chip.regs + offset);
val &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK;
val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK;
writel(val, bank->chip.regs + offset);
spin_unlock_irqrestore(&sgpio_lock, flags);
}
static void sirfsoc_gpio_irq_mask(struct irq_data *d)
{
struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
__sirfsoc_gpio_irq_mask(bank, d->hwirq % SIRFSOC_GPIO_BANK_SIZE);
}
static void sirfsoc_gpio_irq_unmask(struct irq_data *d)
{
struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE;
u32 val, offset;
unsigned long flags;
offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
spin_lock_irqsave(&sgpio_lock, flags);
val = readl(bank->chip.regs + offset);
val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK;
val |= SIRFSOC_GPIO_CTL_INTR_EN_MASK;
writel(val, bank->chip.regs + offset);
spin_unlock_irqrestore(&sgpio_lock, flags);
}
static int sirfsoc_gpio_irq_type(struct irq_data *d, unsigned type)
{
struct sirfsoc_gpio_bank *bank = irq_data_get_irq_chip_data(d);
int idx = d->hwirq % SIRFSOC_GPIO_BANK_SIZE;
u32 val, offset;
unsigned long flags;
offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
spin_lock_irqsave(&sgpio_lock, flags);
val = readl(bank->chip.regs + offset);
val &= ~SIRFSOC_GPIO_CTL_INTR_STS_MASK;
switch (type) {
case IRQ_TYPE_NONE:
break;
case IRQ_TYPE_EDGE_RISING:
val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK;
val &= ~SIRFSOC_GPIO_CTL_INTR_LOW_MASK;
break;
case IRQ_TYPE_EDGE_FALLING:
val &= ~SIRFSOC_GPIO_CTL_INTR_HIGH_MASK;
val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK;
break;
case IRQ_TYPE_EDGE_BOTH:
val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_LOW_MASK |
SIRFSOC_GPIO_CTL_INTR_TYPE_MASK;
break;
case IRQ_TYPE_LEVEL_LOW:
val &= ~(SIRFSOC_GPIO_CTL_INTR_HIGH_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK);
val |= SIRFSOC_GPIO_CTL_INTR_LOW_MASK;
break;
case IRQ_TYPE_LEVEL_HIGH:
val |= SIRFSOC_GPIO_CTL_INTR_HIGH_MASK;
val &= ~(SIRFSOC_GPIO_CTL_INTR_LOW_MASK | SIRFSOC_GPIO_CTL_INTR_TYPE_MASK);
break;
}
writel(val, bank->chip.regs + offset);
spin_unlock_irqrestore(&sgpio_lock, flags);
return 0;
}
static struct irq_chip sirfsoc_irq_chip = {
.name = "sirf-gpio-irq",
.irq_ack = sirfsoc_gpio_irq_ack,
.irq_mask = sirfsoc_gpio_irq_mask,
.irq_unmask = sirfsoc_gpio_irq_unmask,
.irq_set_type = sirfsoc_gpio_irq_type,
};
static void sirfsoc_gpio_handle_irq(unsigned int irq, struct irq_desc *desc)
{
struct sirfsoc_gpio_bank *bank = irq_get_handler_data(irq);
u32 status, ctrl;
int idx = 0;
struct irq_chip *chip = irq_get_chip(irq);
chained_irq_enter(chip, desc);
status = readl(bank->chip.regs + SIRFSOC_GPIO_INT_STATUS(bank->id));
if (!status) {
printk(KERN_WARNING
"%s: gpio id %d status %#x no interrupt is flaged\n",
__func__, bank->id, status);
handle_bad_irq(irq, desc);
return;
}
while (status) {
ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, idx));
/*
* Here we must check whether the corresponding GPIO's interrupt
* has been enabled, otherwise just skip it
*/
if ((status & 0x1) && (ctrl & SIRFSOC_GPIO_CTL_INTR_EN_MASK)) {
pr_debug("%s: gpio id %d idx %d happens\n",
__func__, bank->id, idx);
generic_handle_irq(irq_find_mapping(bank->domain, idx));
}
idx++;
status = status >> 1;
}
chained_irq_exit(chip, desc);
}
static inline void sirfsoc_gpio_set_input(struct sirfsoc_gpio_bank *bank, unsigned ctrl_offset)
{
u32 val;
val = readl(bank->chip.regs + ctrl_offset);
val &= ~SIRFSOC_GPIO_CTL_OUT_EN_MASK;
writel(val, bank->chip.regs + ctrl_offset);
}
static int sirfsoc_gpio_request(struct gpio_chip *chip, unsigned offset)
{
struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
unsigned long flags;
if (pinctrl_request_gpio(chip->base + offset))
return -ENODEV;
spin_lock_irqsave(&bank->lock, flags);
/*
* default status:
* set direction as input and mask irq
*/
sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->id, offset));
__sirfsoc_gpio_irq_mask(bank, offset);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
}
static void sirfsoc_gpio_free(struct gpio_chip *chip, unsigned offset)
{
struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
__sirfsoc_gpio_irq_mask(bank, offset);
sirfsoc_gpio_set_input(bank, SIRFSOC_GPIO_CTRL(bank->id, offset));
spin_unlock_irqrestore(&bank->lock, flags);
pinctrl_free_gpio(chip->base + offset);
}
static int sirfsoc_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
int idx = sirfsoc_gpio_to_offset(gpio);
unsigned long flags;
unsigned offset;
offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
spin_lock_irqsave(&bank->lock, flags);
sirfsoc_gpio_set_input(bank, offset);
spin_unlock_irqrestore(&bank->lock, flags);
return 0;
}
static inline void sirfsoc_gpio_set_output(struct sirfsoc_gpio_bank *bank, unsigned offset,
int value)
{
u32 out_ctrl;
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
out_ctrl = readl(bank->chip.regs + offset);
if (value)
out_ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK;
else
out_ctrl &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK;
out_ctrl &= ~SIRFSOC_GPIO_CTL_INTR_EN_MASK;
out_ctrl |= SIRFSOC_GPIO_CTL_OUT_EN_MASK;
writel(out_ctrl, bank->chip.regs + offset);
spin_unlock_irqrestore(&bank->lock, flags);
}
static int sirfsoc_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value)
{
struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
int idx = sirfsoc_gpio_to_offset(gpio);
u32 offset;
unsigned long flags;
offset = SIRFSOC_GPIO_CTRL(bank->id, idx);
spin_lock_irqsave(&sgpio_lock, flags);
sirfsoc_gpio_set_output(bank, offset, value);
spin_unlock_irqrestore(&sgpio_lock, flags);
return 0;
}
static int sirfsoc_gpio_get_value(struct gpio_chip *chip, unsigned offset)
{
struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
u32 val;
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
val = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset));
spin_unlock_irqrestore(&bank->lock, flags);
return !!(val & SIRFSOC_GPIO_CTL_DATAIN_MASK);
}
static void sirfsoc_gpio_set_value(struct gpio_chip *chip, unsigned offset,
int value)
{
struct sirfsoc_gpio_bank *bank = sirfsoc_irqchip_to_bank(chip);
u32 ctrl;
unsigned long flags;
spin_lock_irqsave(&bank->lock, flags);
ctrl = readl(bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset));
if (value)
ctrl |= SIRFSOC_GPIO_CTL_DATAOUT_MASK;
else
ctrl &= ~SIRFSOC_GPIO_CTL_DATAOUT_MASK;
writel(ctrl, bank->chip.regs + SIRFSOC_GPIO_CTRL(bank->id, offset));
spin_unlock_irqrestore(&bank->lock, flags);
}
static int sirfsoc_gpio_irq_map(struct irq_domain *d, unsigned int irq,
irq_hw_number_t hwirq)
{
struct sirfsoc_gpio_bank *bank = d->host_data;
if (!bank)
return -EINVAL;
irq_set_chip(irq, &sirfsoc_irq_chip);
irq_set_handler(irq, handle_level_irq);
irq_set_chip_data(irq, bank);
set_irq_flags(irq, IRQF_VALID);
return 0;
}
static const struct irq_domain_ops sirfsoc_gpio_irq_simple_ops = {
.map = sirfsoc_gpio_irq_map,
.xlate = irq_domain_xlate_twocell,
};
static void sirfsoc_gpio_set_pullup(const u32 *pullups)
{
int i, n;
const unsigned long *p = (const unsigned long *)pullups;
for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
for_each_set_bit(n, p + i, BITS_PER_LONG) {
u32 offset = SIRFSOC_GPIO_CTRL(i, n);
u32 val = readl(sgpio_bank[i].chip.regs + offset);
val |= SIRFSOC_GPIO_CTL_PULL_MASK;
val |= SIRFSOC_GPIO_CTL_PULL_HIGH;
writel(val, sgpio_bank[i].chip.regs + offset);
}
}
}
static void sirfsoc_gpio_set_pulldown(const u32 *pulldowns)
{
int i, n;
const unsigned long *p = (const unsigned long *)pulldowns;
for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
for_each_set_bit(n, p + i, BITS_PER_LONG) {
u32 offset = SIRFSOC_GPIO_CTRL(i, n);
u32 val = readl(sgpio_bank[i].chip.regs + offset);
val |= SIRFSOC_GPIO_CTL_PULL_MASK;
val &= ~SIRFSOC_GPIO_CTL_PULL_HIGH;
writel(val, sgpio_bank[i].chip.regs + offset);
}
}
}
static int sirfsoc_gpio_probe(struct device_node *np)
{
int i, err = 0;
struct sirfsoc_gpio_bank *bank;
void *regs;
struct platform_device *pdev;
bool is_marco = false;
u32 pullups[SIRFSOC_GPIO_NO_OF_BANKS], pulldowns[SIRFSOC_GPIO_NO_OF_BANKS];
pdev = of_find_device_by_node(np);
if (!pdev)
return -ENODEV;
regs = of_iomap(np, 0);
if (!regs)
return -ENOMEM;
if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
is_marco = 1;
for (i = 0; i < SIRFSOC_GPIO_NO_OF_BANKS; i++) {
bank = &sgpio_bank[i];
spin_lock_init(&bank->lock);
bank->chip.gc.request = sirfsoc_gpio_request;
bank->chip.gc.free = sirfsoc_gpio_free;
bank->chip.gc.direction_input = sirfsoc_gpio_direction_input;
bank->chip.gc.get = sirfsoc_gpio_get_value;
bank->chip.gc.direction_output = sirfsoc_gpio_direction_output;
bank->chip.gc.set = sirfsoc_gpio_set_value;
bank->chip.gc.to_irq = sirfsoc_gpio_to_irq;
bank->chip.gc.base = i * SIRFSOC_GPIO_BANK_SIZE;
bank->chip.gc.ngpio = SIRFSOC_GPIO_BANK_SIZE;
bank->chip.gc.label = kstrdup(np->full_name, GFP_KERNEL);
bank->chip.gc.of_node = np;
bank->chip.gc.of_xlate = sirfsoc_gpio_of_xlate;
bank->chip.gc.of_gpio_n_cells = 2;
bank->chip.regs = regs;
bank->id = i;
bank->is_marco = is_marco;
bank->parent_irq = platform_get_irq(pdev, i);
if (bank->parent_irq < 0) {
err = bank->parent_irq;
goto out;
}
err = gpiochip_add(&bank->chip.gc);
if (err) {
pr_err("%s: error in probe function with status %d\n",
np->full_name, err);
goto out;
}
bank->domain = irq_domain_add_linear(np, SIRFSOC_GPIO_BANK_SIZE,
&sirfsoc_gpio_irq_simple_ops, bank);
if (!bank->domain) {
pr_err("%s: Failed to create irqdomain\n", np->full_name);
err = -ENOSYS;
goto out;
}
irq_set_chained_handler(bank->parent_irq, sirfsoc_gpio_handle_irq);
irq_set_handler_data(bank->parent_irq, bank);
}
if (!of_property_read_u32_array(np, "sirf,pullups", pullups,
SIRFSOC_GPIO_NO_OF_BANKS))
sirfsoc_gpio_set_pullup(pullups);
if (!of_property_read_u32_array(np, "sirf,pulldowns", pulldowns,
SIRFSOC_GPIO_NO_OF_BANKS))
sirfsoc_gpio_set_pulldown(pulldowns);
return 0;
out:
iounmap(regs);
return err;
}
static int __init sirfsoc_gpio_init(void)
{
struct device_node *np;
np = of_find_matching_node(NULL, pinmux_ids);
if (!np)
return -ENODEV;
return sirfsoc_gpio_probe(np);
}
subsys_initcall(sirfsoc_gpio_init);
MODULE_AUTHOR("Rongjun Ying <[email protected]>, "
"Yuping Luo <[email protected]>, "
"Barry Song <[email protected]>");
MODULE_DESCRIPTION("SIRFSOC pin control driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,116 @@
/*
* pinmux driver shared headfile for CSR SiRFsoc
*
* Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
*
* Licensed under GPLv2 or later.
*/
#ifndef __PINMUX_SIRF_H__
#define __PINMUX_SIRF_H__
#define SIRFSOC_NUM_PADS 622
#define SIRFSOC_RSC_PIN_MUX 0x4
#define SIRFSOC_GPIO_PAD_EN(g) ((g)*0x100 + 0x84)
#define SIRFSOC_GPIO_PAD_EN_CLR(g) ((g)*0x100 + 0x90)
#define SIRFSOC_GPIO_CTRL(g, i) ((g)*0x100 + (i)*4)
#define SIRFSOC_GPIO_DSP_EN0 (0x80)
#define SIRFSOC_GPIO_INT_STATUS(g) ((g)*0x100 + 0x8C)
#define SIRFSOC_GPIO_CTL_INTR_LOW_MASK 0x1
#define SIRFSOC_GPIO_CTL_INTR_HIGH_MASK 0x2
#define SIRFSOC_GPIO_CTL_INTR_TYPE_MASK 0x4
#define SIRFSOC_GPIO_CTL_INTR_EN_MASK 0x8
#define SIRFSOC_GPIO_CTL_INTR_STS_MASK 0x10
#define SIRFSOC_GPIO_CTL_OUT_EN_MASK 0x20
#define SIRFSOC_GPIO_CTL_DATAOUT_MASK 0x40
#define SIRFSOC_GPIO_CTL_DATAIN_MASK 0x80
#define SIRFSOC_GPIO_CTL_PULL_MASK 0x100
#define SIRFSOC_GPIO_CTL_PULL_HIGH 0x200
#define SIRFSOC_GPIO_CTL_DSP_INT 0x400
#define SIRFSOC_GPIO_NO_OF_BANKS 5
#define SIRFSOC_GPIO_BANK_SIZE 32
#define SIRFSOC_GPIO_NUM(bank, index) (((bank)*(32)) + (index))
/**
* @dev: a pointer back to containing device
* @virtbase: the offset to the controller in virtual memory
*/
struct sirfsoc_pmx {
struct device *dev;
struct pinctrl_dev *pmx;
void __iomem *gpio_virtbase;
void __iomem *rsc_virtbase;
u32 gpio_regs[SIRFSOC_GPIO_NO_OF_BANKS][SIRFSOC_GPIO_BANK_SIZE];
u32 ints_regs[SIRFSOC_GPIO_NO_OF_BANKS];
u32 paden_regs[SIRFSOC_GPIO_NO_OF_BANKS];
u32 dspen_regs;
u32 rsc_regs[3];
bool is_marco;
};
/* SIRFSOC_GPIO_PAD_EN set */
struct sirfsoc_muxmask {
unsigned long group;
unsigned long mask;
};
struct sirfsoc_padmux {
unsigned long muxmask_counts;
const struct sirfsoc_muxmask *muxmask;
/* RSC_PIN_MUX set */
unsigned long funcmask;
unsigned long funcval;
};
/**
* struct sirfsoc_pin_group - describes a SiRFprimaII pin group
* @name: the name of this specific pin group
* @pins: an array of discrete physical pins used in this group, taken
* from the driver-local pin enumeration space
* @num_pins: the number of pins in this group array, i.e. the number of
* elements in .pins so we can iterate over that array
*/
struct sirfsoc_pin_group {
const char *name;
const unsigned int *pins;
const unsigned num_pins;
};
#define SIRFSOC_PIN_GROUP(n, p) \
{ \
.name = n, \
.pins = p, \
.num_pins = ARRAY_SIZE(p), \
}
struct sirfsoc_pmx_func {
const char *name;
const char * const *groups;
const unsigned num_groups;
const struct sirfsoc_padmux *padmux;
};
#define SIRFSOC_PMX_FUNCTION(n, g, m) \
{ \
.name = n, \
.groups = g, \
.num_groups = ARRAY_SIZE(g), \
.padmux = &m, \
}
struct sirfsoc_pinctrl_data {
struct pinctrl_pin_desc *pads;
int pads_cnt;
struct sirfsoc_pin_group *grps;
int grps_cnt;
struct sirfsoc_pmx_func *funcs;
int funcs_cnt;
};
extern struct sirfsoc_pinctrl_data prima2_pinctrl_data;
extern struct sirfsoc_pinctrl_data atlas6_pinctrl_data;
#endif

View file

@ -441,7 +441,7 @@ static int spear310_p2o(int pin)
return offset;
}
int spear310_o2p(int offset)
static int spear310_o2p(int offset)
{
if (offset <= 3)
return 101 - offset;
@ -528,18 +528,13 @@ static int plgpio_probe(struct platform_device *pdev)
struct resource *res;
int ret, irq, i;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "invalid IORESOURCE_MEM\n");
return -EBUSY;
}
plgpio = devm_kzalloc(&pdev->dev, sizeof(*plgpio), GFP_KERNEL);
if (!plgpio) {
dev_err(&pdev->dev, "memory allocation fail\n");
return -ENOMEM;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
plgpio->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(plgpio->base))
return PTR_ERR(plgpio->base);

View file

@ -569,11 +569,9 @@ int wmt_pinctrl_probe(struct platform_device *pdev,
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->base = devm_request_and_ioremap(&pdev->dev, res);
if (!data->base) {
dev_err(&pdev->dev, "failed to map memory resource\n");
return -EBUSY;
}
data->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(data->base))
return PTR_ERR(data->base);
wmt_desc.pins = data->pins;
wmt_desc.npins = data->npins;