diff options
author | lars <lars@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2009-09-21 18:29:46 +0000 |
---|---|---|
committer | lars <lars@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2009-09-21 18:29:46 +0000 |
commit | e2813918b96b7e6d5f5a37811e507246e604747f (patch) | |
tree | c656b15f93b7b083730061833ec95619662ce47a /target/linux/s3c24xx/files-2.6.31/drivers/mfd/glamo/glamo-gpio2.c | |
parent | dac1d868d3131c0a9b579ccc07833faa208d2d08 (diff) |
[s3c24xx] Add 2.6.31 patches
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@17665 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'target/linux/s3c24xx/files-2.6.31/drivers/mfd/glamo/glamo-gpio2.c')
-rw-r--r-- | target/linux/s3c24xx/files-2.6.31/drivers/mfd/glamo/glamo-gpio2.c | 250 |
1 files changed, 250 insertions, 0 deletions
diff --git a/target/linux/s3c24xx/files-2.6.31/drivers/mfd/glamo/glamo-gpio2.c b/target/linux/s3c24xx/files-2.6.31/drivers/mfd/glamo/glamo-gpio2.c new file mode 100644 index 000000000..dc03c49f7 --- /dev/null +++ b/target/linux/s3c24xx/files-2.6.31/drivers/mfd/glamo/glamo-gpio2.c @@ -0,0 +1,250 @@ +/* Smedia Glamo 336x/337x gpio driver + * + * (C) 2009 Lars-Peter Clausen + * All rights reserved. + * + * 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. + * + * 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., 59 Temple Place, Suite 330, Boston, + * MA 02111-1307 USA + */ + +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/io.h> +#include <linux/platform_device.h> + +#include <linux/gpio.h> +#include <linux/mfd/glamo.h> + +#include "glamo-core.h" +#include "glamo-regs.h" + +#define GLAMO_NR_GPIOS 21 +#define GLAMO_NR_GPIO_REGS DIV_ROUND_UP(GLAMO_NR_GPIOS, 4) + +#define GLAMO_REG_GPIO(x) (((x) * 2) + GLAMO_REG_GPIO_GEN1) + +struct glamo_gpio { + struct glamo_core *glamo; + struct gpio_chip chip; + uint16_t saved_regs[GLAMO_NR_GPIO_REGS]; +}; + +#define REG_OF_GPIO(gpio) (GLAMO_REG_GPIO(gpio >> 2)) +#define NUM_OF_GPIO(gpio) (gpio & 0x3) +#define DIRECTION_BIT(gpio) BIT(NUM_OF_GPIO(gpio) + 0) +#define OUTPUT_BIT(gpio) BIT(NUM_OF_GPIO(gpio) + 4) +#define OUTPUT_VALUE(gpio, value) (value << (NUM_OF_GPIO(gpio) + 4)) +#define INPUT_BIT(gpio) BIT(NUM_OF_GPIO(gpio) + 8) +#define FUNC_BIT(gpio) BIT(NUM_OF_GPIO(gpio) + 12) + + +static inline struct glamo_core *chip_to_glamo(struct gpio_chip *chip) +{ + return container_of(chip, struct glamo_gpio, chip)->glamo; +} + +static void glamo_gpio_set(struct gpio_chip *chip, unsigned offset, int value) +{ + struct glamo_core *glamo = chip_to_glamo(chip); + unsigned int reg = REG_OF_GPIO(offset); + + glamo_reg_set_bit_mask(reg, OUTPUT_VALUE(offset, !!value), OUTPUT_BIT(offset)); +} + +static int glamo_gpio_get(struct gpio_chip *chip, unsigned offset) +{ + struct glamo_core *glamo = chip_to_glamo(chip); + return !!(glamo_reg_read(glamo, REG_OF_GPIO(offset)) & INPUT_BIT(offset)); +} + +static int glamo_gpio_request(struct gpio_chip *chip, unsigned offset) +{ + struct glamo_core *glamo = chip_to_glamo(chip); + unsigned int reg = REG_OF_GPIO(offset); + + glamo_reg_set_bit(glamo, reg, FUNC_BIT(offset)); + + return 0; +} + +static void glamo_gpio_free(struct gpio_chip *chip, unsigned offset) +{ + struct glamo_core *glamo = chip_to_glamo(chip); + unsigned int reg = REG_OF_GPIO(offset); + + glamo_reg_clear_bit(glamo, reg, FUNC_BIT(offset)); +} + +static int glamo_gpio_direction_output(struct gpio_chip *chip, unsigned offset, + int value) +{ + struct glamo_core *glamo = chip_to_glamo(chip); + unsigned int reg = REG_OF_GPIO(offset); + uint16_t mask = DIRECTION_BIT(offset) | OUTPUT_BIT(offset); + uint16_t value = DIRECTION_BIT(offset); + + if (value) + value |= OUTPUT_BIT(offset); + + glamo_reg_set_bit_mask(glamo, reg, mask, value); + + return 0; +} + +static int glamo_gpio_direction_input(struct gpio_chip *chip, unsigned offset) +{ + struct glamo_core *glamo = chip_to_glamo(chip); + unsigned int reg = REG_OF_GPIO(offset); + + glamo_reg_set_bit(glamo, reg, DIRECTION_BIT(offset)); + + return 0; +} + +static const struct __devinit gpio_chip glamo_gpio_chip = { + .label = "glamo", + .request = glamo_gpio_request, + .free = glamo_gpio_free, + .direction_input = glamo_gpio_direction_input, + .get = glamo_gpio_get, + .direction_output = glamo_gpio_direction_output, + .set = glamo_gpio_set, + .base = -1, + .ngpio = GLAMO_NR_GPIOS, + .can_sleep = 0, + .owner = THIS_MODULE, +}; + +static int __devinit glamo_gpio_probe(struct platform_device *pdev) +{ + struct glamo_platform_data *pdata = pdev->dev.parent->platform_data; + struct glamo_gpio *glamo_gpio; + int ret; + + glamo_gpio = kzalloc(sizeof(struct glamo_gpio), GFP_KERNEL); + if (!glamo_gpio) + return -ENOMEM; + + glamo_gpio->glamo = dev_get_drvdata(pdev->dev.parent); + glamo_gpio->chip = glamo_gpio_chip; + glamo_gpio->chip.dev = &pdev->dev; + if (pdata) + glamo_gpio->chip.base = pdata->gpio_base; + + ret = gpiochip_add(&glamo_gpio->chip); + + if (ret) { + dev_err(&pdev->dev, "Could not register gpio chip: %d\n", ret); + goto err; + } + + platform_set_drvdata(pdev, glamo_gpio); + return 0; +err: + kfree(glamo_gpio); + return ret; +} + +static int __devexit glamo_gpio_remove(struct platform_device *pdev) +{ + struct glamo_gpio *glamo_gpio = platform_get_drvdata(pdev); + int ret; + + ret = gpiochip_remove(&glamo_gpio->chip); + if (!ret) + goto done; + + platform_set_drvdata(pdev, NULL); + kfree(glamo_gpio); + +done: + return ret; +} + +#ifdef CONFIG_PM + +static int glamo_gpio_suspend(struct device *dev) +{ + struct glamo_gpio *glamo_gpio = dev_get_drvdata(dev); + struct glamo_core *glamo = glamo_gpio->glamo; + uint16_t *saved_regs = glamo_gpio->saved_regs; + int i; + + spin_lock(&glamo->lock); + for (i = 0; i < GLAMO_NR_GPIO_REGS; ++i) + saved_regs[i] = readw(glamo->base + GLAMO_REG_GPIO(i)); + spin_unlock(&glamo->lock); + + return 0; +} + +static int glamo_gpio_resume(struct device *dev) +{ + struct glamo_gpio *glamo_gpio = dev_get_drvdata(dev); + struct glamo_core *glamo = glamo_gpio->glamo; + uint16_t *saved_regs = glamo_gpio->saved_regs; + int i; + + spin_lock(&glamo->lock); + for (i = 0; i < GLAMO_NR_GPIO_REGS; ++i) + writew(saved_regs[i], glamo->base + GLAMO_REG_GPIO(i)); + spin_unlock(&glamo->lock); + + printk("glamo-gpio resume\n"); + return 0; +} + +static const struct dev_pm_ops glamo_pm_ops = { + .suspend = glamo_gpio_suspend, + .resume = glamo_gpio_resume, + .freeze = glamo_gpio_suspend, + .thaw = glamo_gpio_resume, +}; + +#define GLAMO_GPIO_PM_OPS (&glamo_pm_ops) + +#else +#define GLAMO_GPIO_PM_OPS NULL +#endif + +static struct platform_driver glamo_gpio_driver = { + .driver = { + .name = "glamo-gpio", + .owner = THIS_MODULE, + .pm = GLAMO_GPIO_PM_OPS, + }, + .probe = glamo_gpio_probe, + .remove = __devexit_p(glamo_gpio_remove), +}; + +static int __devinit glamo_gpio_init(void) +{ + return platform_driver_register(&glamo_gpio_driver); +} + +static void __exit glamo_gpio_exit(void) +{ + platform_driver_unregister(&glamo_gpio_driver); +} + +module_init(glamo_gpio_init); +module_exit(glamo_gpio_exit); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("GPIO interface for the Glamo multimedia device"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:glamo-gpio"); |