7e5b2db77b
Pull MIPS updates from Ralf Baechle: "The whole series has been sitting in -next for quite a while with no complaints. The last change to the series was before the weekend the removal of an SPI patch which Grant - even though previously acked by himself - appeared to raise objections. So I removed it until the situation is clarified. Other than that all the patches have the acks from their respective maintainers, all MIPS and x86 defconfigs are building fine and I'm not aware of any problems introduced by this series. Among the key features for this patch series is a sizable patchset for Lantiq which among other things introduces support for Lantiq's flagship product, the FALCON SOC. It also means that the opensource developers behind this patchset have overtaken Lantiq's competing inhouse development team that was working behind closed doors. Less noteworthy the ath79 patchset which adds support for a few more chip variants, cleanups and fixes. Finally the usual dose of tweaking of generic code." Fix up trivial conflicts in arch/mips/lantiq/xway/gpio_{ebu,stp}.c where printk spelling fixes clashed with file move and eventual removal of the printk. * 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus: (81 commits) MIPS: lantiq: remove orphaned code MIPS: Remove all -Wall and almost all -Werror usage from arch/mips. MIPS: lantiq: implement support for FALCON soc MTD: MIPS: lantiq: verify that the NOR interface is available on falcon soc MTD: MIPS: lantiq: implement OF support watchdog: MIPS: lantiq: implement OF support and minor fixes SERIAL: MIPS: lantiq: implement OF support GPIO: MIPS: lantiq: convert gpio-stp-xway to OF GPIO: MIPS: lantiq: convert gpio-mm-lantiq to OF and of_mm_gpio GPIO: MIPS: lantiq: move gpio-stp and gpio-ebu to the subsystem folder MIPS: pci: convert lantiq driver to OF MIPS: lantiq: convert dma to platform driver MIPS: lantiq: implement support for clkdev api MIPS: lantiq: drop ltq_gpio_request() and gpio_to_irq() OF: MIPS: lantiq: implement irq_domain support OF: MIPS: lantiq: implement OF support MIPS: lantiq: drop mips_machine support OF: PCI: const usage needed by MIPS MIPS: Cavium: Remove smp_reserve_lock. MIPS: Move cache setup to setup_arch(). ...
183 lines
4.9 KiB
C
183 lines
4.9 KiB
C
/*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 as published
|
|
* by the Free Software Foundation.
|
|
*
|
|
* Copyright (C) 2010 John Crispin <blogic@openwrt.org>
|
|
*/
|
|
|
|
#include <linux/slab.h>
|
|
#include <linux/export.h>
|
|
#include <linux/platform_device.h>
|
|
#include <linux/gpio.h>
|
|
#include <linux/ioport.h>
|
|
#include <linux/io.h>
|
|
|
|
#include <lantiq_soc.h>
|
|
|
|
#define LTQ_GPIO_OUT 0x00
|
|
#define LTQ_GPIO_IN 0x04
|
|
#define LTQ_GPIO_DIR 0x08
|
|
#define LTQ_GPIO_ALTSEL0 0x0C
|
|
#define LTQ_GPIO_ALTSEL1 0x10
|
|
#define LTQ_GPIO_OD 0x14
|
|
|
|
#define PINS_PER_PORT 16
|
|
#define MAX_PORTS 3
|
|
|
|
#define ltq_gpio_getbit(m, r, p) (!!(ltq_r32(m + r) & (1 << p)))
|
|
#define ltq_gpio_setbit(m, r, p) ltq_w32_mask(0, (1 << p), m + r)
|
|
#define ltq_gpio_clearbit(m, r, p) ltq_w32_mask((1 << p), 0, m + r)
|
|
|
|
struct ltq_gpio {
|
|
void __iomem *membase;
|
|
struct gpio_chip chip;
|
|
};
|
|
|
|
static struct ltq_gpio ltq_gpio_port[MAX_PORTS];
|
|
|
|
int ltq_gpio_request(unsigned int pin, unsigned int alt0,
|
|
unsigned int alt1, unsigned int dir, const char *name)
|
|
{
|
|
int id = 0;
|
|
|
|
if (pin >= (MAX_PORTS * PINS_PER_PORT))
|
|
return -EINVAL;
|
|
if (gpio_request(pin, name)) {
|
|
pr_err("failed to setup lantiq gpio: %s\n", name);
|
|
return -EBUSY;
|
|
}
|
|
if (dir)
|
|
gpio_direction_output(pin, 1);
|
|
else
|
|
gpio_direction_input(pin);
|
|
while (pin >= PINS_PER_PORT) {
|
|
pin -= PINS_PER_PORT;
|
|
id++;
|
|
}
|
|
if (alt0)
|
|
ltq_gpio_setbit(ltq_gpio_port[id].membase,
|
|
LTQ_GPIO_ALTSEL0, pin);
|
|
else
|
|
ltq_gpio_clearbit(ltq_gpio_port[id].membase,
|
|
LTQ_GPIO_ALTSEL0, pin);
|
|
if (alt1)
|
|
ltq_gpio_setbit(ltq_gpio_port[id].membase,
|
|
LTQ_GPIO_ALTSEL1, pin);
|
|
else
|
|
ltq_gpio_clearbit(ltq_gpio_port[id].membase,
|
|
LTQ_GPIO_ALTSEL1, pin);
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(ltq_gpio_request);
|
|
|
|
static void ltq_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)
|
|
{
|
|
struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
|
|
|
|
if (value)
|
|
ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset);
|
|
else
|
|
ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OUT, offset);
|
|
}
|
|
|
|
static int ltq_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
|
{
|
|
struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
|
|
|
|
return ltq_gpio_getbit(ltq_gpio->membase, LTQ_GPIO_IN, offset);
|
|
}
|
|
|
|
static int ltq_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
|
|
{
|
|
struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
|
|
|
|
ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
|
|
ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ltq_gpio_direction_output(struct gpio_chip *chip,
|
|
unsigned int offset, int value)
|
|
{
|
|
struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
|
|
|
|
ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_OD, offset);
|
|
ltq_gpio_setbit(ltq_gpio->membase, LTQ_GPIO_DIR, offset);
|
|
ltq_gpio_set(chip, offset, value);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ltq_gpio_req(struct gpio_chip *chip, unsigned offset)
|
|
{
|
|
struct ltq_gpio *ltq_gpio = container_of(chip, struct ltq_gpio, chip);
|
|
|
|
ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL0, offset);
|
|
ltq_gpio_clearbit(ltq_gpio->membase, LTQ_GPIO_ALTSEL1, offset);
|
|
return 0;
|
|
}
|
|
|
|
static int ltq_gpio_probe(struct platform_device *pdev)
|
|
{
|
|
struct resource *res;
|
|
|
|
if (pdev->id >= MAX_PORTS) {
|
|
dev_err(&pdev->dev, "invalid gpio port %d\n",
|
|
pdev->id);
|
|
return -EINVAL;
|
|
}
|
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
|
if (!res) {
|
|
dev_err(&pdev->dev, "failed to get memory for gpio port %d\n",
|
|
pdev->id);
|
|
return -ENOENT;
|
|
}
|
|
res = devm_request_mem_region(&pdev->dev, res->start,
|
|
resource_size(res), dev_name(&pdev->dev));
|
|
if (!res) {
|
|
dev_err(&pdev->dev,
|
|
"failed to request memory for gpio port %d\n",
|
|
pdev->id);
|
|
return -EBUSY;
|
|
}
|
|
ltq_gpio_port[pdev->id].membase = devm_ioremap_nocache(&pdev->dev,
|
|
res->start, resource_size(res));
|
|
if (!ltq_gpio_port[pdev->id].membase) {
|
|
dev_err(&pdev->dev, "failed to remap memory for gpio port %d\n",
|
|
pdev->id);
|
|
return -ENOMEM;
|
|
}
|
|
ltq_gpio_port[pdev->id].chip.label = "ltq_gpio";
|
|
ltq_gpio_port[pdev->id].chip.direction_input = ltq_gpio_direction_input;
|
|
ltq_gpio_port[pdev->id].chip.direction_output =
|
|
ltq_gpio_direction_output;
|
|
ltq_gpio_port[pdev->id].chip.get = ltq_gpio_get;
|
|
ltq_gpio_port[pdev->id].chip.set = ltq_gpio_set;
|
|
ltq_gpio_port[pdev->id].chip.request = ltq_gpio_req;
|
|
ltq_gpio_port[pdev->id].chip.base = PINS_PER_PORT * pdev->id;
|
|
ltq_gpio_port[pdev->id].chip.ngpio = PINS_PER_PORT;
|
|
platform_set_drvdata(pdev, <q_gpio_port[pdev->id]);
|
|
return gpiochip_add(<q_gpio_port[pdev->id].chip);
|
|
}
|
|
|
|
static struct platform_driver
|
|
ltq_gpio_driver = {
|
|
.probe = ltq_gpio_probe,
|
|
.driver = {
|
|
.name = "ltq_gpio",
|
|
.owner = THIS_MODULE,
|
|
},
|
|
};
|
|
|
|
int __init ltq_gpio_init(void)
|
|
{
|
|
int ret = platform_driver_register(<q_gpio_driver);
|
|
|
|
if (ret)
|
|
pr_info("ltq_gpio : Error registering platform driver!");
|
|
return ret;
|
|
}
|
|
|
|
postcore_initcall(ltq_gpio_init);
|