add gpiolib support to ucb1x00
The old access methods to the gpios will be removed when all users has been converted. (mainly ucb1x00-ts)
This commit is contained in:
parent
cc64717279
commit
9ca3dc805c
|
@ -16,6 +16,7 @@ struct mcp_plat_data {
|
||||||
u32 mccr0;
|
u32 mccr0;
|
||||||
u32 mccr1;
|
u32 mccr1;
|
||||||
unsigned int sclk_rate;
|
unsigned int sclk_rate;
|
||||||
|
int gpio_base;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -163,6 +163,7 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
|
||||||
mcp->dma_audio_wr = DMA_Ser4MCP0Wr;
|
mcp->dma_audio_wr = DMA_Ser4MCP0Wr;
|
||||||
mcp->dma_telco_rd = DMA_Ser4MCP1Rd;
|
mcp->dma_telco_rd = DMA_Ser4MCP1Rd;
|
||||||
mcp->dma_telco_wr = DMA_Ser4MCP1Wr;
|
mcp->dma_telco_wr = DMA_Ser4MCP1Wr;
|
||||||
|
mcp->gpio_base = data->gpio_base;
|
||||||
|
|
||||||
platform_set_drvdata(pdev, mcp);
|
platform_set_drvdata(pdev, mcp);
|
||||||
|
|
||||||
|
|
|
@ -26,11 +26,11 @@
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/mfd/ucb1x00.h>
|
#include <linux/mfd/ucb1x00.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
|
||||||
#include <mach/dma.h>
|
#include <mach/dma.h>
|
||||||
#include <mach/hardware.h>
|
#include <mach/hardware.h>
|
||||||
|
|
||||||
|
|
||||||
static DEFINE_MUTEX(ucb1x00_mutex);
|
static DEFINE_MUTEX(ucb1x00_mutex);
|
||||||
static LIST_HEAD(ucb1x00_drivers);
|
static LIST_HEAD(ucb1x00_drivers);
|
||||||
static LIST_HEAD(ucb1x00_devices);
|
static LIST_HEAD(ucb1x00_devices);
|
||||||
|
@ -108,6 +108,60 @@ unsigned int ucb1x00_io_read(struct ucb1x00 *ucb)
|
||||||
return ucb1x00_reg_read(ucb, UCB_IO_DATA);
|
return ucb1x00_reg_read(ucb, UCB_IO_DATA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
|
||||||
|
{
|
||||||
|
struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ucb->io_lock, flags);
|
||||||
|
if (value)
|
||||||
|
ucb->io_out |= 1 << offset;
|
||||||
|
else
|
||||||
|
ucb->io_out &= ~(1 << offset);
|
||||||
|
|
||||||
|
ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
|
||||||
|
spin_unlock_irqrestore(&ucb->io_lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||||
|
{
|
||||||
|
struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
|
||||||
|
return ucb1x00_reg_read(ucb, UCB_IO_DATA) & (1 << offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
|
||||||
|
{
|
||||||
|
struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ucb->io_lock, flags);
|
||||||
|
ucb->io_dir &= ~(1 << offset);
|
||||||
|
ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
|
||||||
|
spin_unlock_irqrestore(&ucb->io_lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
|
||||||
|
, int value)
|
||||||
|
{
|
||||||
|
struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&ucb->io_lock, flags);
|
||||||
|
ucb->io_dir |= (1 << offset);
|
||||||
|
ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
|
||||||
|
|
||||||
|
if (value)
|
||||||
|
ucb->io_out |= 1 << offset;
|
||||||
|
else
|
||||||
|
ucb->io_out &= ~(1 << offset);
|
||||||
|
ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
|
||||||
|
spin_unlock_irqrestore(&ucb->io_lock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* UCB1300 data sheet says we must:
|
* UCB1300 data sheet says we must:
|
||||||
* 1. enable ADC => 5us (including reference startup time)
|
* 1. enable ADC => 5us (including reference startup time)
|
||||||
|
@ -476,6 +530,7 @@ static int ucb1x00_probe(struct mcp *mcp)
|
||||||
struct ucb1x00_driver *drv;
|
struct ucb1x00_driver *drv;
|
||||||
unsigned int id;
|
unsigned int id;
|
||||||
int ret = -ENODEV;
|
int ret = -ENODEV;
|
||||||
|
int temp;
|
||||||
|
|
||||||
mcp_enable(mcp);
|
mcp_enable(mcp);
|
||||||
id = mcp_reg_read(mcp, UCB_ID);
|
id = mcp_reg_read(mcp, UCB_ID);
|
||||||
|
@ -508,12 +563,27 @@ static int ucb1x00_probe(struct mcp *mcp)
|
||||||
goto err_free;
|
goto err_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ucb->gpio.base = -1;
|
||||||
|
if (mcp->gpio_base != 0) {
|
||||||
|
ucb->gpio.label = dev_name(&ucb->dev);
|
||||||
|
ucb->gpio.base = mcp->gpio_base;
|
||||||
|
ucb->gpio.ngpio = 10;
|
||||||
|
ucb->gpio.set = ucb1x00_gpio_set;
|
||||||
|
ucb->gpio.get = ucb1x00_gpio_get;
|
||||||
|
ucb->gpio.direction_input = ucb1x00_gpio_direction_input;
|
||||||
|
ucb->gpio.direction_output = ucb1x00_gpio_direction_output;
|
||||||
|
ret = gpiochip_add(&ucb->gpio);
|
||||||
|
if (ret)
|
||||||
|
goto err_free;
|
||||||
|
} else
|
||||||
|
dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
|
||||||
|
|
||||||
ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
|
ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
|
||||||
"UCB1x00", ucb);
|
"UCB1x00", ucb);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
|
printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
|
||||||
ucb->irq, ret);
|
ucb->irq, ret);
|
||||||
goto err_free;
|
goto err_gpio;
|
||||||
}
|
}
|
||||||
|
|
||||||
mcp_set_drvdata(mcp, ucb);
|
mcp_set_drvdata(mcp, ucb);
|
||||||
|
@ -522,6 +592,7 @@ static int ucb1x00_probe(struct mcp *mcp)
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_irq;
|
goto err_irq;
|
||||||
|
|
||||||
|
|
||||||
INIT_LIST_HEAD(&ucb->devs);
|
INIT_LIST_HEAD(&ucb->devs);
|
||||||
mutex_lock(&ucb1x00_mutex);
|
mutex_lock(&ucb1x00_mutex);
|
||||||
list_add(&ucb->node, &ucb1x00_devices);
|
list_add(&ucb->node, &ucb1x00_devices);
|
||||||
|
@ -529,10 +600,14 @@ static int ucb1x00_probe(struct mcp *mcp)
|
||||||
ucb1x00_add_dev(ucb, drv);
|
ucb1x00_add_dev(ucb, drv);
|
||||||
}
|
}
|
||||||
mutex_unlock(&ucb1x00_mutex);
|
mutex_unlock(&ucb1x00_mutex);
|
||||||
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
err_irq:
|
err_irq:
|
||||||
free_irq(ucb->irq, ucb);
|
free_irq(ucb->irq, ucb);
|
||||||
|
err_gpio:
|
||||||
|
if (ucb->gpio.base != -1)
|
||||||
|
temp = gpiochip_remove(&ucb->gpio);
|
||||||
err_free:
|
err_free:
|
||||||
kfree(ucb);
|
kfree(ucb);
|
||||||
err_disable:
|
err_disable:
|
||||||
|
@ -545,6 +620,7 @@ static void ucb1x00_remove(struct mcp *mcp)
|
||||||
{
|
{
|
||||||
struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
|
struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
|
||||||
struct list_head *l, *n;
|
struct list_head *l, *n;
|
||||||
|
int ret;
|
||||||
|
|
||||||
mutex_lock(&ucb1x00_mutex);
|
mutex_lock(&ucb1x00_mutex);
|
||||||
list_del(&ucb->node);
|
list_del(&ucb->node);
|
||||||
|
@ -554,6 +630,12 @@ static void ucb1x00_remove(struct mcp *mcp)
|
||||||
}
|
}
|
||||||
mutex_unlock(&ucb1x00_mutex);
|
mutex_unlock(&ucb1x00_mutex);
|
||||||
|
|
||||||
|
if (ucb->gpio.base != -1) {
|
||||||
|
ret = gpiochip_remove(&ucb->gpio);
|
||||||
|
if (ret)
|
||||||
|
dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret);
|
||||||
|
}
|
||||||
|
|
||||||
free_irq(ucb->irq, ucb);
|
free_irq(ucb->irq, ucb);
|
||||||
device_unregister(&ucb->dev);
|
device_unregister(&ucb->dev);
|
||||||
}
|
}
|
||||||
|
@ -604,6 +686,7 @@ static int ucb1x00_resume(struct mcp *mcp)
|
||||||
struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
|
struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
|
||||||
struct ucb1x00_dev *dev;
|
struct ucb1x00_dev *dev;
|
||||||
|
|
||||||
|
ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
|
||||||
mutex_lock(&ucb1x00_mutex);
|
mutex_lock(&ucb1x00_mutex);
|
||||||
list_for_each_entry(dev, &ucb->devs, dev_node) {
|
list_for_each_entry(dev, &ucb->devs, dev_node) {
|
||||||
if (dev->drv->resume)
|
if (dev->drv->resume)
|
||||||
|
|
|
@ -26,6 +26,7 @@ struct mcp {
|
||||||
dma_device_t dma_telco_rd;
|
dma_device_t dma_telco_rd;
|
||||||
dma_device_t dma_telco_wr;
|
dma_device_t dma_telco_wr;
|
||||||
struct device attached_device;
|
struct device attached_device;
|
||||||
|
int gpio_base;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mcp_ops {
|
struct mcp_ops {
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#define UCB1200_H
|
#define UCB1200_H
|
||||||
|
|
||||||
#include <linux/mfd/mcp.h>
|
#include <linux/mfd/mcp.h>
|
||||||
|
#include <linux/gpio.h>
|
||||||
|
|
||||||
#define UCB_IO_DATA 0x00
|
#define UCB_IO_DATA 0x00
|
||||||
#define UCB_IO_DIR 0x01
|
#define UCB_IO_DIR 0x01
|
||||||
|
|
||||||
|
@ -123,6 +125,7 @@ struct ucb1x00 {
|
||||||
struct device dev;
|
struct device dev;
|
||||||
struct list_head node;
|
struct list_head node;
|
||||||
struct list_head devs;
|
struct list_head devs;
|
||||||
|
struct gpio_chip gpio;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ucb1x00_driver;
|
struct ucb1x00_driver;
|
||||||
|
|
Loading…
Reference in New Issue