mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-18 18:23:53 +08:00
Staging: dream: add gpio and pmem support
This adds generic_gpio and pmem support, both are needed for other dream drivers. Signed-off-by: Pavel Machek <pavel@ucw.cz> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
parent
7e9bdd0af0
commit
9b84375747
274
drivers/staging/dream/generic_gpio.c
Normal file
274
drivers/staging/dream/generic_gpio.c
Normal file
@ -0,0 +1,274 @@
|
||||
/* arch/arm/mach-msm/generic_gpio.c
|
||||
*
|
||||
* Copyright (C) 2007 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* 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 <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <asm/gpio.h>
|
||||
#include "gpio_chip.h"
|
||||
|
||||
#define GPIO_NUM_TO_CHIP_INDEX(gpio) ((gpio)>>5)
|
||||
|
||||
struct gpio_state {
|
||||
unsigned long flags;
|
||||
int refcount;
|
||||
};
|
||||
|
||||
static DEFINE_SPINLOCK(gpio_chips_lock);
|
||||
static LIST_HEAD(gpio_chip_list);
|
||||
static struct gpio_chip **gpio_chip_array;
|
||||
static unsigned long gpio_chip_array_size;
|
||||
|
||||
int register_gpio_chip(struct gpio_chip *new_gpio_chip)
|
||||
{
|
||||
int err = 0;
|
||||
struct gpio_chip *gpio_chip;
|
||||
int i;
|
||||
unsigned long irq_flags;
|
||||
unsigned int chip_array_start_index, chip_array_end_index;
|
||||
|
||||
new_gpio_chip->state = kzalloc((new_gpio_chip->end + 1 - new_gpio_chip->start) * sizeof(new_gpio_chip->state[0]), GFP_KERNEL);
|
||||
if (new_gpio_chip->state == NULL) {
|
||||
printk(KERN_ERR "register_gpio_chip: failed to allocate state\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&gpio_chips_lock, irq_flags);
|
||||
chip_array_start_index = GPIO_NUM_TO_CHIP_INDEX(new_gpio_chip->start);
|
||||
chip_array_end_index = GPIO_NUM_TO_CHIP_INDEX(new_gpio_chip->end);
|
||||
if (chip_array_end_index >= gpio_chip_array_size) {
|
||||
struct gpio_chip **new_gpio_chip_array;
|
||||
unsigned long new_gpio_chip_array_size = chip_array_end_index + 1;
|
||||
|
||||
new_gpio_chip_array = kmalloc(new_gpio_chip_array_size * sizeof(new_gpio_chip_array[0]), GFP_ATOMIC);
|
||||
if (new_gpio_chip_array == NULL) {
|
||||
printk(KERN_ERR "register_gpio_chip: failed to allocate array\n");
|
||||
err = -ENOMEM;
|
||||
goto failed;
|
||||
}
|
||||
for (i = 0; i < gpio_chip_array_size; i++)
|
||||
new_gpio_chip_array[i] = gpio_chip_array[i];
|
||||
for (i = gpio_chip_array_size; i < new_gpio_chip_array_size; i++)
|
||||
new_gpio_chip_array[i] = NULL;
|
||||
gpio_chip_array = new_gpio_chip_array;
|
||||
gpio_chip_array_size = new_gpio_chip_array_size;
|
||||
}
|
||||
list_for_each_entry(gpio_chip, &gpio_chip_list, list) {
|
||||
if (gpio_chip->start > new_gpio_chip->end) {
|
||||
list_add_tail(&new_gpio_chip->list, &gpio_chip->list);
|
||||
goto added;
|
||||
}
|
||||
if (gpio_chip->end >= new_gpio_chip->start) {
|
||||
printk(KERN_ERR "register_gpio_source %u-%u overlaps with %u-%u\n",
|
||||
new_gpio_chip->start, new_gpio_chip->end,
|
||||
gpio_chip->start, gpio_chip->end);
|
||||
err = -EBUSY;
|
||||
goto failed;
|
||||
}
|
||||
}
|
||||
list_add_tail(&new_gpio_chip->list, &gpio_chip_list);
|
||||
added:
|
||||
for (i = chip_array_start_index; i <= chip_array_end_index; i++) {
|
||||
if (gpio_chip_array[i] == NULL || gpio_chip_array[i]->start > new_gpio_chip->start)
|
||||
gpio_chip_array[i] = new_gpio_chip;
|
||||
}
|
||||
failed:
|
||||
spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
|
||||
if (err)
|
||||
kfree(new_gpio_chip->state);
|
||||
return err;
|
||||
}
|
||||
|
||||
static struct gpio_chip *get_gpio_chip_locked(unsigned int gpio)
|
||||
{
|
||||
unsigned long i;
|
||||
struct gpio_chip *chip;
|
||||
|
||||
i = GPIO_NUM_TO_CHIP_INDEX(gpio);
|
||||
if (i >= gpio_chip_array_size)
|
||||
return NULL;
|
||||
chip = gpio_chip_array[i];
|
||||
if (chip == NULL)
|
||||
return NULL;
|
||||
list_for_each_entry_from(chip, &gpio_chip_list, list) {
|
||||
if (gpio < chip->start)
|
||||
return NULL;
|
||||
if (gpio <= chip->end)
|
||||
return chip;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int request_gpio(unsigned int gpio, unsigned long flags)
|
||||
{
|
||||
int err = 0;
|
||||
struct gpio_chip *chip;
|
||||
unsigned long irq_flags;
|
||||
unsigned long chip_index;
|
||||
|
||||
spin_lock_irqsave(&gpio_chips_lock, irq_flags);
|
||||
chip = get_gpio_chip_locked(gpio);
|
||||
if (chip == NULL) {
|
||||
err = -EINVAL;
|
||||
goto err;
|
||||
}
|
||||
chip_index = gpio - chip->start;
|
||||
if (chip->state[chip_index].refcount == 0) {
|
||||
chip->configure(chip, gpio, flags);
|
||||
chip->state[chip_index].flags = flags;
|
||||
chip->state[chip_index].refcount++;
|
||||
} else if ((flags & IRQF_SHARED) && (chip->state[chip_index].flags & IRQF_SHARED))
|
||||
chip->state[chip_index].refcount++;
|
||||
else
|
||||
err = -EBUSY;
|
||||
err:
|
||||
spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
|
||||
return err;
|
||||
}
|
||||
|
||||
int gpio_request(unsigned gpio, const char *label)
|
||||
{
|
||||
return request_gpio(gpio, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_request);
|
||||
|
||||
void gpio_free(unsigned gpio)
|
||||
{
|
||||
struct gpio_chip *chip;
|
||||
unsigned long irq_flags;
|
||||
unsigned long chip_index;
|
||||
|
||||
spin_lock_irqsave(&gpio_chips_lock, irq_flags);
|
||||
chip = get_gpio_chip_locked(gpio);
|
||||
if (chip) {
|
||||
chip_index = gpio - chip->start;
|
||||
chip->state[chip_index].refcount--;
|
||||
}
|
||||
spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_free);
|
||||
|
||||
static int gpio_get_irq_num(unsigned int gpio, unsigned int *irqp, unsigned long *irqnumflagsp)
|
||||
{
|
||||
int ret = -ENOTSUPP;
|
||||
struct gpio_chip *chip;
|
||||
unsigned long irq_flags;
|
||||
|
||||
spin_lock_irqsave(&gpio_chips_lock, irq_flags);
|
||||
chip = get_gpio_chip_locked(gpio);
|
||||
if (chip && chip->get_irq_num)
|
||||
ret = chip->get_irq_num(chip, gpio, irqp, irqnumflagsp);
|
||||
spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gpio_to_irq(unsigned gpio)
|
||||
{
|
||||
int ret, irq;
|
||||
ret = gpio_get_irq_num(gpio, &irq, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
return irq;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_to_irq);
|
||||
|
||||
int gpio_configure(unsigned int gpio, unsigned long flags)
|
||||
{
|
||||
int ret = -ENOTSUPP;
|
||||
struct gpio_chip *chip;
|
||||
unsigned long irq_flags;
|
||||
|
||||
spin_lock_irqsave(&gpio_chips_lock, irq_flags);
|
||||
chip = get_gpio_chip_locked(gpio);
|
||||
if (chip)
|
||||
ret = chip->configure(chip, gpio, flags);
|
||||
spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_configure);
|
||||
|
||||
int gpio_direction_input(unsigned gpio)
|
||||
{
|
||||
return gpio_configure(gpio, GPIOF_INPUT);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_direction_input);
|
||||
|
||||
int gpio_direction_output(unsigned gpio, int value)
|
||||
{
|
||||
gpio_set_value(gpio, value);
|
||||
return gpio_configure(gpio, GPIOF_DRIVE_OUTPUT);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_direction_output);
|
||||
|
||||
int gpio_get_value(unsigned gpio)
|
||||
{
|
||||
int ret = -ENOTSUPP;
|
||||
struct gpio_chip *chip;
|
||||
unsigned long irq_flags;
|
||||
|
||||
spin_lock_irqsave(&gpio_chips_lock, irq_flags);
|
||||
chip = get_gpio_chip_locked(gpio);
|
||||
if (chip && chip->read)
|
||||
ret = chip->read(chip, gpio);
|
||||
spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_get_value);
|
||||
|
||||
void gpio_set_value(unsigned gpio, int on)
|
||||
{
|
||||
int ret = -ENOTSUPP;
|
||||
struct gpio_chip *chip;
|
||||
unsigned long irq_flags;
|
||||
|
||||
spin_lock_irqsave(&gpio_chips_lock, irq_flags);
|
||||
chip = get_gpio_chip_locked(gpio);
|
||||
if (chip && chip->write)
|
||||
ret = chip->write(chip, gpio, on);
|
||||
spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_set_value);
|
||||
|
||||
int gpio_read_detect_status(unsigned int gpio)
|
||||
{
|
||||
int ret = -ENOTSUPP;
|
||||
struct gpio_chip *chip;
|
||||
unsigned long irq_flags;
|
||||
|
||||
spin_lock_irqsave(&gpio_chips_lock, irq_flags);
|
||||
chip = get_gpio_chip_locked(gpio);
|
||||
if (chip && chip->read_detect_status)
|
||||
ret = chip->read_detect_status(chip, gpio);
|
||||
spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_read_detect_status);
|
||||
|
||||
int gpio_clear_detect_status(unsigned int gpio)
|
||||
{
|
||||
int ret = -ENOTSUPP;
|
||||
struct gpio_chip *chip;
|
||||
unsigned long irq_flags;
|
||||
|
||||
spin_lock_irqsave(&gpio_chips_lock, irq_flags);
|
||||
chip = get_gpio_chip_locked(gpio);
|
||||
if (chip && chip->clear_detect_status)
|
||||
ret = chip->clear_detect_status(chip, gpio);
|
||||
spin_unlock_irqrestore(&gpio_chips_lock, irq_flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(gpio_clear_detect_status);
|
1335
drivers/staging/dream/pmem.c
Normal file
1335
drivers/staging/dream/pmem.c
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user