9
0
Fork 0

Merge branch 'for-next/gpiolib'

This commit is contained in:
Sascha Hauer 2012-09-05 12:59:29 +02:00
commit 978b0739dc
23 changed files with 674 additions and 146 deletions

View File

@ -37,6 +37,7 @@ config ARCH_EP93XX
config ARCH_IMX
bool "Freescale iMX-based"
select GENERIC_GPIO
select GPIOLIB
config ARCH_MXS
bool "Freescale i.MX23/28 (mxs) based"

View File

@ -27,7 +27,8 @@
#include <errno.h>
#include <io.h>
#include <mach/imx-regs.h>
#include <mach/gpio.h>
#include <gpio.h>
#include <init.h>
#if defined CONFIG_ARCH_IMX1 || defined CONFIG_ARCH_IMX21 || defined CONFIG_ARCH_IMX27
#define GPIO_DR 0x1c
@ -48,21 +49,15 @@
#define GPIO_ISR 0x18
#endif
extern void __iomem *imx_gpio_base[];
extern int imx_gpio_count;
struct imx_gpio_chip {
void __iomem *base;
struct gpio_chip chip;
};
static void __iomem *gpio_get_base(unsigned gpio)
static void imx_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
{
if (gpio >= imx_gpio_count)
return NULL;
return imx_gpio_base[gpio / 32];
}
void gpio_set_value(unsigned gpio, int value)
{
void __iomem *base = gpio_get_base(gpio);
int shift = gpio % 32;
struct imx_gpio_chip *imxgpio = container_of(chip, struct imx_gpio_chip, chip);
void __iomem *base = imxgpio->base;
u32 val;
if (!base)
@ -71,59 +66,88 @@ void gpio_set_value(unsigned gpio, int value)
val = readl(base + GPIO_DR);
if (value)
val |= 1 << shift;
val |= 1 << gpio;
else
val &= ~(1 << shift);
val &= ~(1 << gpio);
writel(val, base + GPIO_DR);
}
int gpio_direction_input(unsigned gpio)
static int imx_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
void __iomem *base = gpio_get_base(gpio);
int shift = gpio % 32;
struct imx_gpio_chip *imxgpio = container_of(chip, struct imx_gpio_chip, chip);
void __iomem *base = imxgpio->base;
u32 val;
if (!base)
return -EINVAL;
val = readl(base + GPIO_GDIR);
val &= ~(1 << shift);
val &= ~(1 << gpio);
writel(val, base + GPIO_GDIR);
return 0;
}
int gpio_direction_output(unsigned gpio, int value)
static int imx_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value)
{
void __iomem *base = gpio_get_base(gpio);
int shift = gpio % 32;
struct imx_gpio_chip *imxgpio = container_of(chip, struct imx_gpio_chip, chip);
void __iomem *base = imxgpio->base;
u32 val;
if (!base)
return -EINVAL;
gpio_set_value(gpio, value);
gpio_set_value(gpio + chip->base, value);
val = readl(base + GPIO_GDIR);
val |= 1 << shift;
val |= 1 << gpio;
writel(val, base + GPIO_GDIR);
return 0;
}
int gpio_get_value(unsigned gpio)
static int imx_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
{
void __iomem *base = gpio_get_base(gpio);
int shift = gpio % 32;
struct imx_gpio_chip *imxgpio = container_of(chip, struct imx_gpio_chip, chip);
void __iomem *base = imxgpio->base;
u32 val;
if (!base)
return -EINVAL;
val = readl(base + GPIO_PSR);
return val & (1 << shift) ? 1 : 0;
return val & (1 << gpio) ? 1 : 0;
}
static struct gpio_ops imx_gpio_ops = {
.direction_input = imx_gpio_direction_input,
.direction_output = imx_gpio_direction_output,
.get = imx_gpio_get_value,
.set = imx_gpio_set_value,
};
static int imx_gpio_probe(struct device_d *dev)
{
struct imx_gpio_chip *imxgpio;
imxgpio = xzalloc(sizeof(*imxgpio));
imxgpio->base = dev_request_mem_region(dev, 0);
imxgpio->chip.ops = &imx_gpio_ops;
imxgpio->chip.base = -1;
imxgpio->chip.ngpio = 32;
imxgpio->chip.dev = dev;
gpiochip_add(&imxgpio->chip);
dev_info(dev, "probed gpiochip%d with base %d\n", dev->id, imxgpio->chip.base);
return 0;
}
static struct driver_d imx_gpio_driver = {
.name = "imx-gpio",
.probe = imx_gpio_probe,
};
static int imx_gpio_add(void)
{
register_driver(&imx_gpio_driver);
return 0;
}
coredevice_initcall(imx_gpio_add);

View File

@ -1,4 +0,0 @@
extern void *imx_gpio_base[];
extern int imx_gpio_count;

View File

@ -16,16 +16,15 @@
*/
#include <common.h>
#include <init.h>
#include "gpio.h"
void *imx_gpio_base[] = {
(void *)0x0021c000,
(void *)0x0021c100,
(void *)0x0021c200,
(void *)0x0021c300,
};
int imx_gpio_count = ARRAY_SIZE(imx_gpio_base) * 32;
static int imx1_init(void)
{
add_generic_device("imx-gpio", 0, NULL, 0x0021c000, 0x100, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 1, NULL, 0x0021c100, 0x100, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 2, NULL, 0x0021c200, 0x100, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 3, NULL, 0x0021c300, 0x100, IORESOURCE_MEM, NULL);
return 0;
}
coredevice_initcall(imx1_init);

View File

@ -18,8 +18,6 @@
#include <common.h>
#include <mach/imx-regs.h>
#include "gpio.h"
int imx_silicon_revision(void)
{
// Known values:
@ -28,14 +26,15 @@ int imx_silicon_revision(void)
return CID;
}
void *imx_gpio_base[] = {
(void *)0x10015000,
(void *)0x10015100,
(void *)0x10015200,
(void *)0x10015300,
(void *)0x10015400,
(void *)0x10015500,
};
int imx_gpio_count = ARRAY_SIZE(imx_gpio_base) * 32;
static int imx21_init(void)
{
add_generic_device("imx-gpio", 0, NULL, 0x10015000, 0x100, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 1, NULL, 0x10015100, 0x100, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 2, NULL, 0x10015200, 0x100, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 3, NULL, 0x10015300, 0x100, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 4, NULL, 0x10015400, 0x100, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 5, NULL, 0x10015500, 0x100, IORESOURCE_MEM, NULL);
return 0;
}
coredevice_initcall(imx21_init);

View File

@ -22,17 +22,6 @@
#include <io.h>
#include <sizes.h>
#include "gpio.h"
void *imx_gpio_base[] = {
(void *)0x53fcc000,
(void *)0x53fd0000,
(void *)0x53fa4000,
(void *)0x53f9c000,
};
int imx_gpio_count = ARRAY_SIZE(imx_gpio_base) * 32;
u64 imx_uid(void)
{
u64 uid = 0;
@ -59,6 +48,10 @@ static int imx25_init(void)
add_generic_device("imx_iim", 0, NULL, IMX_IIM_BASE, SZ_4K,
IORESOURCE_MEM, &imx25_iim_pdata);
add_generic_device("imx-gpio", 0, NULL, 0x53fcc000, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 1, NULL, 0x53fd0000, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 2, NULL, 0x53fa4000, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 3, NULL, 0x53f9c000, 0x1000, IORESOURCE_MEM, NULL);
return 0;
}
coredevice_initcall(imx25_init);

View File

@ -21,24 +21,11 @@
#include <init.h>
#include <io.h>
#include "gpio.h"
int imx_silicon_revision(void)
{
return CID >> 28;
}
void *imx_gpio_base[] = {
(void *)0x10015000,
(void *)0x10015100,
(void *)0x10015200,
(void *)0x10015300,
(void *)0x10015400,
(void *)0x10015500,
};
int imx_gpio_count = ARRAY_SIZE(imx_gpio_base) * 32;
/*
* Initialize MAX on i.MX27. necessary to give the DMA engine
* higher priority to the memory than the CPU. Needed for proper
@ -86,6 +73,12 @@ static int imx27_init(void)
imx27_init_max();
add_generic_device("imx-gpio", 0, NULL, 0x10015000, 0x100, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 1, NULL, 0x10015100, 0x100, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 2, NULL, 0x10015200, 0x100, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 3, NULL, 0x10015300, 0x100, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 4, NULL, 0x10015400, 0x100, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 5, NULL, 0x10015500, 0x100, IORESOURCE_MEM, NULL);
return 0;
}
coredevice_initcall(imx27_init);

View File

@ -20,21 +20,15 @@
#include <sizes.h>
#include <mach/imx-regs.h>
#include "gpio.h"
void *imx_gpio_base[] = {
(void *)0x53fcc000,
(void *)0x53fd0000,
(void *)0x53fa4000,
};
int imx_gpio_count = ARRAY_SIZE(imx_gpio_base) * 32;
static int imx31_init(void)
{
add_generic_device("imx_iim", 0, NULL, IMX_IIM_BASE, SZ_4K,
IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 0, NULL, 0x53fcc000, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 1, NULL, 0x53fd0000, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 2, NULL, 0x53fa4000, 0x1000, IORESOURCE_MEM, NULL);
return 0;
}
coredevice_initcall(imx31_init);

View File

@ -23,16 +23,6 @@
#include <mach/iim.h>
#include <mach/generic.h>
#include "gpio.h"
void *imx_gpio_base[] = {
(void *)0x53fcc000,
(void *)0x53fd0000,
(void *)0x53fa4000,
};
int imx_gpio_count = ARRAY_SIZE(imx_gpio_base) * 32;
int imx_silicon_revision()
{
uint32_t reg;
@ -66,6 +56,10 @@ static int imx35_init(void)
add_generic_device("imx_iim", 0, NULL, IMX_IIM_BASE, SZ_4K,
IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 0, NULL, 0x53fcc000, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 1, NULL, 0x53fd0000, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 2, NULL, 0x53fa4000, 0x1000, IORESOURCE_MEM, NULL);
return 0;
}
coredevice_initcall(imx35_init);

View File

@ -24,17 +24,6 @@
#include <mach/imx-regs.h>
#include <mach/clock-imx51_53.h>
#include "gpio.h"
void *imx_gpio_base[] = {
(void *)MX51_GPIO1_BASE_ADDR,
(void *)MX51_GPIO2_BASE_ADDR,
(void *)MX51_GPIO3_BASE_ADDR,
(void *)MX51_GPIO4_BASE_ADDR,
};
int imx_gpio_count = ARRAY_SIZE(imx_gpio_base) * 32;
#define SI_REV 0x48
static u32 mx51_silicon_revision;
@ -89,6 +78,11 @@ static int imx51_init(void)
add_generic_device("imx_iim", 0, NULL, MX51_IIM_BASE_ADDR, SZ_4K,
IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 0, NULL, 0x73f84000, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 1, NULL, 0x73f88000, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 2, NULL, 0x73f8c000, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 3, NULL, 0x73f90000, 0x1000, IORESOURCE_MEM, NULL);
return 0;
}
coredevice_initcall(imx51_init);

View File

@ -24,20 +24,6 @@
#include <mach/imx-regs.h>
#include <mach/clock-imx51_53.h>
#include "gpio.h"
void *imx_gpio_base[] = {
(void *)MX53_GPIO1_BASE_ADDR,
(void *)MX53_GPIO2_BASE_ADDR,
(void *)MX53_GPIO3_BASE_ADDR,
(void *)MX53_GPIO4_BASE_ADDR,
(void *)MX53_GPIO5_BASE_ADDR,
(void *)MX53_GPIO6_BASE_ADDR,
(void *)MX53_GPIO7_BASE_ADDR,
};
int imx_gpio_count = ARRAY_SIZE(imx_gpio_base) * 32;
#define SI_REV 0x48
static u32 mx53_silicon_revision;
@ -88,6 +74,13 @@ static int imx53_init(void)
add_generic_device("imx_iim", 0, NULL, MX53_IIM_BASE_ADDR, SZ_4K,
IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 0, NULL, MX53_GPIO1_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 1, NULL, MX53_GPIO2_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 2, NULL, MX53_GPIO3_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 3, NULL, MX53_GPIO4_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 4, NULL, MX53_GPIO5_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 5, NULL, MX53_GPIO6_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 6, NULL, MX53_GPIO7_BASE_ADDR, 0x1000, IORESOURCE_MEM, NULL);
return 0;
}
coredevice_initcall(imx53_init);

View File

@ -21,20 +21,6 @@
#include <sizes.h>
#include <mach/imx6-regs.h>
#include "gpio.h"
void *imx_gpio_base[] = {
(void *)MX6_GPIO1_BASE_ADDR,
(void *)MX6_GPIO2_BASE_ADDR,
(void *)MX6_GPIO3_BASE_ADDR,
(void *)MX6_GPIO4_BASE_ADDR,
(void *)MX6_GPIO5_BASE_ADDR,
(void *)MX6_GPIO6_BASE_ADDR,
(void *)MX6_GPIO7_BASE_ADDR,
};
int imx_gpio_count = ARRAY_SIZE(imx_gpio_base) * 32;
void imx6_init_lowlevel(void)
{
void __iomem *aips1 = (void *)MX6_AIPS1_ON_BASE_ADDR;
@ -69,3 +55,17 @@ void imx6_init_lowlevel(void)
writel(0xffffffff, 0x020c407c);
writel(0xffffffff, 0x020c4080);
}
static int imx6_init(void)
{
add_generic_device("imx-gpio", 0, NULL, MX6_GPIO1_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 1, NULL, MX6_GPIO2_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 2, NULL, MX6_GPIO3_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 3, NULL, MX6_GPIO4_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 4, NULL, MX6_GPIO5_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 5, NULL, MX6_GPIO6_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
add_generic_device("imx-gpio", 6, NULL, MX6_GPIO7_BASE_ADDR, 0x4000, IORESOURCE_MEM, NULL);
return 0;
}
coredevice_initcall(imx6_init);

View File

@ -18,5 +18,6 @@ source "drivers/input/Kconfig"
source "drivers/watchdog/Kconfig"
source "drivers/pwm/Kconfig"
source "drivers/dma/Kconfig"
source "drivers/gpio/Kconfig"
endmenu

View File

@ -17,3 +17,4 @@ obj-$(CONFIG_PWM) += pwm/
obj-y += input/
obj-y += dma/
obj-y += watchdog/
obj-y += gpio/

13
drivers/gpio/Kconfig Normal file
View File

@ -0,0 +1,13 @@
config GPIOLIB
bool
if GPIOLIB
menu "GPIO "
config GPIO_STMPE
depends on I2C_STMPE
bool "STMPE GPIO Expander"
endmenu
endif

2
drivers/gpio/Makefile Normal file
View File

@ -0,0 +1,2 @@
obj-$(CONFIG_GPIOLIB) += gpio.o
obj-$(CONFIG_GPIO_STMPE) += gpio-stmpe.o

161
drivers/gpio/gpio-stmpe.c Normal file
View File

@ -0,0 +1,161 @@
/*
* Copyright (C) 2012 Pengutronix
* Steffen Trumtrar <s.trumtrar@pengutronix.de>
*
* 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.
*
* This program is distributed in the hope that 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.
*
*/
#include <common.h>
#include <errno.h>
#include <io.h>
#include <gpio.h>
#include <init.h>
#include <mfd/stmpe-i2c.h>
#define GPIO_BASE 0x80
#define GPIO_SET (GPIO_BASE + 0x02)
#define GPIO_CLR (GPIO_BASE + 0x04)
#define GPIO_MP (GPIO_BASE + 0x06)
#define GPIO_SET_DIR (GPIO_BASE + 0x08)
#define GPIO_ED (GPIO_BASE + 0x0a)
#define GPIO_RE (GPIO_BASE + 0x0c)
#define GPIO_FE (GPIO_BASE + 0x0e)
#define GPIO_PULL_UP (GPIO_BASE + 0x10)
#define GPIO_AF (GPIO_BASE + 0x12)
#define GPIO_LT (GPIO_BASE + 0x16)
#define OFFSET(gpio) (0xff & (1 << (gpio)) ? 1 : 0)
struct stmpe_gpio_chip {
struct gpio_chip chip;
struct stmpe_client_info *ci;
};
static void stmpe_gpio_set_value(struct gpio_chip *chip, unsigned gpio, int value)
{
struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip);
struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci;
int ret;
u8 val;
ci->read_reg(ci->stmpe, GPIO_MP + OFFSET(gpio), &val);
val |= 1 << (gpio % 8);
if (value)
ret = ci->write_reg(ci->stmpe, GPIO_SET + OFFSET(gpio), val);
else
ret = ci->write_reg(ci->stmpe, GPIO_CLR + OFFSET(gpio), val);
if (ret)
dev_err(chip->dev, "write failed!\n");
}
static int stmpe_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip);
struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci;
int ret;
u8 val;
ci->read_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), &val);
val &= ~(1 << (gpio % 8));
ret = ci->write_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), val);
if (ret)
dev_err(chip->dev, "couldn't change direction. Write failed!\n");
return ret;
}
static int stmpe_gpio_direction_output(struct gpio_chip *chip, unsigned gpio, int value)
{
struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip);
struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci;
int ret;
u8 val;
ci->read_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), &val);
val |= 1 << (gpio % 8);
ret = ci->write_reg(ci->stmpe, GPIO_SET_DIR + OFFSET(gpio), val);
stmpe_gpio_set_value(chip, gpio, value);
if (ret)
dev_err(chip->dev, "couldn't change direction. Write failed!\n");
return ret;
}
static int stmpe_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
{
struct stmpe_gpio_chip *stmpegpio = container_of(chip, struct stmpe_gpio_chip, chip);
struct stmpe_client_info *ci = (struct stmpe_client_info *)stmpegpio->ci;
u8 val;
int ret;
ret = ci->read_reg(ci->stmpe, GPIO_MP + OFFSET(gpio), &val);
if (ret)
dev_err(chip->dev, "read failed\n");
return val & (1 << (gpio % 8)) ? 1 : 0;
}
static struct gpio_ops stmpe_gpio_ops = {
.direction_input = stmpe_gpio_direction_input,
.direction_output = stmpe_gpio_direction_output,
.get = stmpe_gpio_get_value,
.set = stmpe_gpio_set_value,
};
static int stmpe_gpio_probe(struct device_d *dev)
{
struct stmpe_gpio_chip *stmpegpio;
struct stmpe_client_info *ci;
int ret;
stmpegpio = xzalloc(sizeof(*stmpegpio));
stmpegpio->chip.ops = &stmpe_gpio_ops;
stmpegpio->ci = dev->platform_data;
ci = (struct stmpe_client_info *)stmpegpio->ci;
if (ci->stmpe->pdata->gpio_base)
stmpegpio->chip.base = ci->stmpe->pdata->gpio_base;
else
stmpegpio->chip.base = -1;
stmpegpio->chip.ngpio = 16;
stmpegpio->chip.dev = dev;
ret = gpiochip_add(&stmpegpio->chip);
if (ret) {
dev_err(dev, "couldn't add gpiochip\n");
return ret;
}
dev_info(dev, "probed stmpe gpiochip%d with base %d\n", dev->id, stmpegpio->chip.base);
return 0;
}
static struct driver_d stmpe_gpio_driver = {
.name = "stmpe-gpio",
.probe = stmpe_gpio_probe,
};
static int stmpe_gpio_add(void)
{
return register_driver(&stmpe_gpio_driver);
}
coredevice_initcall(stmpe_gpio_add);

134
drivers/gpio/gpio.c Normal file
View File

@ -0,0 +1,134 @@
#include <common.h>
#include <gpio.h>
#include <errno.h>
static LIST_HEAD(chip_list);
#define ARCH_NR_GPIOS 256
static struct gpio_chip *gpio_desc[ARCH_NR_GPIOS];
static int gpio_is_valid(unsigned gpio)
{
if (gpio < ARCH_NR_GPIOS)
return 1;
return 0;
}
void gpio_set_value(unsigned gpio, int value)
{
struct gpio_chip *chip = gpio_desc[gpio];
if (!gpio_is_valid(gpio))
return;
if (!chip)
return;
if (!chip->ops->set)
return;
chip->ops->set(chip, gpio - chip->base, value);
}
EXPORT_SYMBOL(gpio_set_value);
int gpio_get_value(unsigned gpio)
{
struct gpio_chip *chip = gpio_desc[gpio];
if (!gpio_is_valid(gpio))
return -EINVAL;
if (!chip)
return -ENODEV;
if (!chip->ops->get)
return -ENOSYS;
return chip->ops->get(chip, gpio - chip->base);
}
EXPORT_SYMBOL(gpio_get_value);
int gpio_direction_output(unsigned gpio, int value)
{
struct gpio_chip *chip = gpio_desc[gpio];
if (!gpio_is_valid(gpio))
return -EINVAL;
if (!chip)
return -ENODEV;
if (!chip->ops->direction_output)
return -ENOSYS;
return chip->ops->direction_output(chip, gpio - chip->base, value);
}
EXPORT_SYMBOL(gpio_direction_output);
int gpio_direction_input(unsigned gpio)
{
struct gpio_chip *chip = gpio_desc[gpio];
if (!gpio_is_valid(gpio))
return -EINVAL;
if (!chip)
return -ENODEV;
if (!chip->ops->direction_input)
return -ENOSYS;
return chip->ops->direction_input(chip, gpio - chip->base);
}
EXPORT_SYMBOL(gpio_direction_input);
static int gpiochip_find_base(int start, int ngpio)
{
int i;
int spare = 0;
int base = -ENOSPC;
if (start < 0)
start = 0;
for (i = start; i < ARCH_NR_GPIOS; i++) {
struct gpio_chip *chip = gpio_desc[i];
if (!chip) {
spare++;
if (spare == ngpio) {
base = i + 1 - ngpio;
break;
}
} else {
spare = 0;
i += chip->ngpio - 1;
}
}
if (gpio_is_valid(base))
debug("%s: found new base at %d\n", __func__, base);
return base;
}
int gpiochip_add(struct gpio_chip *chip)
{
int base, i;
base = gpiochip_find_base(chip->base, chip->ngpio);
if (base < 0)
return base;
if (chip->base >= 0 && chip->base != base)
return -EBUSY;
chip->base = base;
list_add_tail(&chip->list, &chip_list);
for (i = chip->base; i < chip->base + chip->ngpio; i++)
gpio_desc[i] = chip;
return 0;
}
int gpio_get_num(struct device_d *dev, int gpio)
{
struct gpio_chip *chip;
list_for_each_entry(chip, &chip_list, list) {
if (chip->dev == dev)
return chip->base + gpio;
}
return -ENODEV;
}

View File

@ -33,4 +33,8 @@ config I2C_TWL6030
select I2C_TWLCORE
bool "TWL6030 driver"
config I2C_STMPE
depends on I2C
bool "STMPE-i2c driver"
endmenu

View File

@ -6,3 +6,4 @@ obj-$(CONFIG_I2C_LP3972) += lp3972.o
obj-$(CONFIG_I2C_TWLCORE) += twl-core.o
obj-$(CONFIG_I2C_TWL4030) += twl4030.o
obj-$(CONFIG_I2C_TWL6030) += twl6030.o
obj-$(CONFIG_I2C_STMPE) += stmpe-i2c.o

153
drivers/mfd/stmpe-i2c.c Normal file
View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2012 Pengutronix
* Steffen Trumtrar <s.trumtrar@pengutronix.de>
*
* 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.
*
* This program is distributed in the hope that 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.
*
*/
#include <common.h>
#include <init.h>
#include <driver.h>
#include <xfuncs.h>
#include <errno.h>
#include <i2c/i2c.h>
#include <mfd/stmpe-i2c.h>
#define DRIVERNAME "stmpe-i2c"
#define to_stmpe(a) container_of(a, struct stmpe, cdev)
int stmpe_reg_read(struct stmpe *stmpe, u32 reg, u8 *val)
{
int ret;
ret = i2c_read_reg(stmpe->client, reg, val, 1);
return ret == 1 ? 0 : ret;
}
EXPORT_SYMBOL(stmpe_reg_read)
int stmpe_reg_write(struct stmpe *stmpe, u32 reg, u8 val)
{
int ret;
ret = i2c_write_reg(stmpe->client, reg, &val, 1);
return ret == 1 ? 0 : ret;
}
EXPORT_SYMBOL(stmpe_reg_write)
int stmpe_set_bits(struct stmpe *stmpe, u32 reg, u8 mask, u8 val)
{
u8 tmp;
int err;
err = stmpe_reg_read(stmpe, reg, &tmp);
tmp = (tmp & ~mask) | val;
if (!err)
err = stmpe_reg_write(stmpe, reg, tmp);
return err;
}
EXPORT_SYMBOL(stmpe_set_bits);
static ssize_t stmpe_read(struct cdev *cdev, void *_buf, size_t count, loff_t offset, ulong flags)
{
struct stmpe *stmpe = to_stmpe(cdev);
u8 *buf = _buf;
size_t i = count;
int err;
while (i) {
err = stmpe_reg_read(stmpe, offset, buf);
if (err)
return (ssize_t)err;
buf++;
i--;
offset++;
}
return count;
}
static ssize_t stmpe_write(struct cdev *cdev, const void *_buf, size_t count, loff_t offset, ulong flags)
{
struct stmpe *stmpe = to_stmpe(cdev);
const u8 *buf = _buf;
size_t i = count;
int err;
while (i) {
err = stmpe_reg_write(stmpe, offset, *buf);
if (err)
return (ssize_t)err;
buf++;
i--;
offset++;
}
return count;
}
static struct file_operations stmpe_fops = {
.lseek = dev_lseek_default,
.read = stmpe_read,
.write = stmpe_write,
};
static int stmpe_probe(struct device_d *dev)
{
struct stmpe_platform_data *pdata = dev->platform_data;
struct stmpe *stmpe_dev;
struct stmpe_client_info *i2c_ci;
if (!pdata) {
dev_dbg(dev, "no platform data\n");
return -ENODEV;
}
stmpe_dev = xzalloc(sizeof(struct stmpe));
stmpe_dev->cdev.name = DRIVERNAME;
stmpe_dev->client = to_i2c_client(dev);
stmpe_dev->cdev.size = 191; /* 191 known registers */
stmpe_dev->cdev.dev = dev;
stmpe_dev->cdev.ops = &stmpe_fops;
stmpe_dev->pdata = pdata;
dev->priv = stmpe_dev;
i2c_ci = xzalloc(sizeof(struct stmpe_client_info));
i2c_ci->stmpe = stmpe_dev;
i2c_ci->read_reg = stmpe_reg_read;
i2c_ci->write_reg = stmpe_reg_write;
if (pdata->blocks &= STMPE_BLOCK_GPIO)
add_generic_device("stmpe-gpio", DEVICE_ID_DYNAMIC, NULL, 0, 0, IORESOURCE_MEM, i2c_ci);
devfs_create(&stmpe_dev->cdev);
return 0;
}
static struct driver_d stmpe_driver = {
.name = DRIVERNAME,
.probe = stmpe_probe,
};
static int stmpe_init(void)
{
register_driver(&stmpe_driver);
return 0;
}
device_initcall(stmpe_init);

View File

@ -5,10 +5,35 @@
static inline int gpio_request(unsigned gpio, const char *label)
{
return 0;
return 0;
}
static inline void gpio_free(unsigned gpio)
{
}
struct gpio_chip;
struct gpio_ops {
int (*direction_input)(struct gpio_chip *chip, unsigned offset);
int (*direction_output)(struct gpio_chip *chip, unsigned offset, int value);
int (*get)(struct gpio_chip *chip, unsigned offset);
void (*set)(struct gpio_chip *chip, unsigned offset, int value);
};
struct gpio_chip {
struct device_d *dev;
int base;
int ngpio;
struct gpio_ops *ops;
struct list_head list;
};
int gpiochip_add(struct gpio_chip *chip);
int gpio_get_num(struct device_d *dev, int gpio);
#endif /* __GPIO_H */

53
include/mfd/stmpe-i2c.h Normal file
View File

@ -0,0 +1,53 @@
/*
* Copyright (C) 2012 Pengutronix
* Steffen Trumtrar <s.trumtrar@pengutronix.de>
*
* This file is released under the GPLv2
*
*/
#ifndef __ASM_ARCH_STMPE_H
#define __ASM_ARCH_STMPE_H
enum stmpe_revision {
STMPE610,
STMPE801,
STMPE811,
STMPE1601,
STMPE2401,
STMPE2403,
STMPE_NBR_PARTS
};
enum stmpe_blocks {
STMPE_BLOCK_GPIO = 1 << 0,
STMPE_BLOCK_KEYPAD = 1 << 1,
STMPE_BLOCK_TOUCHSCREEN = 1 << 2,
STMPE_BLOCK_ADC = 1 << 3,
STMPE_BLOCK_PWM = 1 << 4,
STMPE_BLOCK_ROTATOR = 1 << 5,
};
struct stmpe_platform_data {
enum stmpe_revision revision;
enum stmpe_blocks blocks;
int gpio_base;
};
struct stmpe {
struct cdev cdev;
struct i2c_client *client;
struct stmpe_platform_data *pdata;
};
struct stmpe_client_info {
struct stmpe *stmpe;
int (*read_reg)(struct stmpe *stmpe, u32 reg, u8 *val);
int (*write_reg)(struct stmpe *stmpe, u32 reg, u8 val);
};
int stmpe_reg_read(struct stmpe *priv, u32 reg, u8 *val);
int stmpe_reg_write(struct stmpe *priv, u32 reg, u8 val);
int stmpe_set_bits(struct stmpe *priv, u32 reg, u8 mask, u8 val);
#endif /* __ASM_ARCH_STMPE_H */