Merge branch 'gpio/next' of git://git.secretlab.ca/git/linux-2.6
* 'gpio/next' of git://git.secretlab.ca/git/linux-2.6: h8300: Move gpio.h to gpio-internal.h gpio: pl061: add DT binding support gpio: fix build error in include/asm-generic/gpio.h gpiolib: Ensure struct gpio is always defined irq: Add EXPORT_SYMBOL_GPL to function of irq generic-chip gpio-ml-ioh: Use NUMA_NO_NODE not GFP_KERNEL gpio-pch: Use NUMA_NO_NODE not GFP_KERNEL gpio: langwell: ensure alternate function is cleared gpio-pch: Support interrupt function gpio-pch: Save register value in suspend() gpio-pch: modify gpio_nums and mask gpio-pch: support ML7223 IOH n-Bus gpio-pch: add spinlock in suspend/resume processing gpio-pch: Delete invalid "restore" code in suspend() gpio-ml-ioh: Fix suspend/resume issue gpio-ml-ioh: Support interrupt function gpio-ml-ioh: Delete unnecessary code gpio/mxc: add chained_irq_enter/exit() to mx3_gpio_irq_handler() gpio/nomadik: use genirq core to track enablement gpio/nomadik: disable clocks when unused
This commit is contained in:
Коммит
41684f67af
|
@ -67,6 +67,9 @@ extern int nmk_gpio_get_mode(int gpio);
|
|||
extern void nmk_gpio_wakeups_suspend(void);
|
||||
extern void nmk_gpio_wakeups_resume(void);
|
||||
|
||||
extern void nmk_gpio_clocks_enable(void);
|
||||
extern void nmk_gpio_clocks_disable(void);
|
||||
|
||||
extern void nmk_gpio_read_pull(int gpio_bank, u32 *pull_up);
|
||||
|
||||
/*
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <asm/traps.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/gpio-internal.h>
|
||||
#include <asm/regs306x.h>
|
||||
|
||||
const int __initdata h8300_saved_vectors[] = {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <asm/traps.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/gpio.h>
|
||||
#include <asm/gpio-internal.h>
|
||||
#include <asm/regs267x.h>
|
||||
|
||||
/* saved vector list */
|
||||
|
|
|
@ -397,6 +397,7 @@ config GPIO_LANGWELL
|
|||
config GPIO_PCH
|
||||
tristate "Intel EG20T PCH / OKI SEMICONDUCTOR ML7223 IOH GPIO"
|
||||
depends on PCI && X86
|
||||
select GENERIC_IRQ_CHIP
|
||||
help
|
||||
This driver is for PCH(Platform controller Hub) GPIO of Intel Topcliff
|
||||
which is an IOH(Input/Output Hub) for x86 embedded processor.
|
||||
|
@ -411,6 +412,7 @@ config GPIO_PCH
|
|||
config GPIO_ML_IOH
|
||||
tristate "OKI SEMICONDUCTOR ML7213 IOH GPIO support"
|
||||
depends on PCI
|
||||
select GENERIC_IRQ_CHIP
|
||||
help
|
||||
ML7213 is companion chip for Intel Atom E6xx series.
|
||||
This driver can be used for OKI SEMICONDUCTOR ML7213 IOH(Input/Output
|
||||
|
|
|
@ -59,6 +59,7 @@ enum GPIO_REG {
|
|||
GRER, /* rising edge detect */
|
||||
GFER, /* falling edge detect */
|
||||
GEDR, /* edge detect result */
|
||||
GAFR, /* alt function */
|
||||
};
|
||||
|
||||
struct lnw_gpio {
|
||||
|
@ -81,6 +82,31 @@ static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset,
|
|||
return ptr;
|
||||
}
|
||||
|
||||
static void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset,
|
||||
enum GPIO_REG reg_type)
|
||||
{
|
||||
struct lnw_gpio *lnw = container_of(chip, struct lnw_gpio, chip);
|
||||
unsigned nreg = chip->ngpio / 32;
|
||||
u8 reg = offset / 16;
|
||||
void __iomem *ptr;
|
||||
|
||||
ptr = (void __iomem *)(lnw->reg_base + reg_type * nreg * 4 + reg * 4);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static int lnw_gpio_request(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR);
|
||||
u32 value = readl(gafr);
|
||||
int shift = (offset % 16) << 1, af = (value >> shift) & 3;
|
||||
|
||||
if (af) {
|
||||
value &= ~(3 << shift);
|
||||
writel(value, gafr);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lnw_gpio_get(struct gpio_chip *chip, unsigned offset)
|
||||
{
|
||||
void __iomem *gplr = gpio_reg(chip, offset, GPLR);
|
||||
|
@ -321,6 +347,7 @@ static int __devinit lnw_gpio_probe(struct pci_dev *pdev,
|
|||
lnw->reg_base = base;
|
||||
lnw->irq_base = irq_base;
|
||||
lnw->chip.label = dev_name(&pdev->dev);
|
||||
lnw->chip.request = lnw_gpio_request;
|
||||
lnw->chip.direction_input = lnw_gpio_direction_input;
|
||||
lnw->chip.direction_output = lnw_gpio_direction_output;
|
||||
lnw->chip.get = lnw_gpio_get;
|
||||
|
|
|
@ -18,6 +18,17 @@
|
|||
#include <linux/slab.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#define IOH_EDGE_FALLING 0
|
||||
#define IOH_EDGE_RISING BIT(0)
|
||||
#define IOH_LEVEL_L BIT(1)
|
||||
#define IOH_LEVEL_H (BIT(0) | BIT(1))
|
||||
#define IOH_EDGE_BOTH BIT(2)
|
||||
#define IOH_IM_MASK (BIT(0) | BIT(1) | BIT(2))
|
||||
|
||||
#define IOH_IRQ_BASE 0
|
||||
|
||||
#define PCI_VENDOR_ID_ROHM 0x10DB
|
||||
|
||||
|
@ -46,12 +57,22 @@ struct ioh_regs {
|
|||
|
||||
/**
|
||||
* struct ioh_gpio_reg_data - The register store data.
|
||||
* @ien_reg To store contents of interrupt enable register.
|
||||
* @imask_reg: To store contents of interrupt mask regist
|
||||
* @po_reg: To store contents of PO register.
|
||||
* @pm_reg: To store contents of PM register.
|
||||
* @im0_reg: To store contents of interrupt mode regist0
|
||||
* @im1_reg: To store contents of interrupt mode regist1
|
||||
* @use_sel_reg: To store contents of GPIO_USE_SEL0~3
|
||||
*/
|
||||
struct ioh_gpio_reg_data {
|
||||
u32 ien_reg;
|
||||
u32 imask_reg;
|
||||
u32 po_reg;
|
||||
u32 pm_reg;
|
||||
u32 im0_reg;
|
||||
u32 im1_reg;
|
||||
u32 use_sel_reg;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -62,7 +83,11 @@ struct ioh_gpio_reg_data {
|
|||
* @gpio: Data for GPIO infrastructure.
|
||||
* @ioh_gpio_reg: Memory mapped Register data is saved here
|
||||
* when suspend.
|
||||
* @gpio_use_sel: Save GPIO_USE_SEL1~4 register for PM
|
||||
* @ch: Indicate GPIO channel
|
||||
* @irq_base: Save base of IRQ number for interrupt
|
||||
* @spinlock: Used for register access protection in
|
||||
* interrupt context ioh_irq_type and PM;
|
||||
*/
|
||||
struct ioh_gpio {
|
||||
void __iomem *base;
|
||||
|
@ -70,8 +95,11 @@ struct ioh_gpio {
|
|||
struct device *dev;
|
||||
struct gpio_chip gpio;
|
||||
struct ioh_gpio_reg_data ioh_gpio_reg;
|
||||
u32 gpio_use_sel;
|
||||
struct mutex lock;
|
||||
int ch;
|
||||
int irq_base;
|
||||
spinlock_t spinlock;
|
||||
};
|
||||
|
||||
static const int num_ports[] = {6, 12, 16, 16, 15, 16, 16, 12};
|
||||
|
@ -145,8 +173,25 @@ static int ioh_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
|||
*/
|
||||
static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip)
|
||||
{
|
||||
chip->ioh_gpio_reg.po_reg = ioread32(&chip->reg->regs[chip->ch].po);
|
||||
chip->ioh_gpio_reg.pm_reg = ioread32(&chip->reg->regs[chip->ch].pm);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i ++, chip++) {
|
||||
chip->ioh_gpio_reg.po_reg =
|
||||
ioread32(&chip->reg->regs[chip->ch].po);
|
||||
chip->ioh_gpio_reg.pm_reg =
|
||||
ioread32(&chip->reg->regs[chip->ch].pm);
|
||||
chip->ioh_gpio_reg.ien_reg =
|
||||
ioread32(&chip->reg->regs[chip->ch].ien);
|
||||
chip->ioh_gpio_reg.imask_reg =
|
||||
ioread32(&chip->reg->regs[chip->ch].imask);
|
||||
chip->ioh_gpio_reg.im0_reg =
|
||||
ioread32(&chip->reg->regs[chip->ch].im_0);
|
||||
chip->ioh_gpio_reg.im1_reg =
|
||||
ioread32(&chip->reg->regs[chip->ch].im_1);
|
||||
if (i < 4)
|
||||
chip->ioh_gpio_reg.use_sel_reg =
|
||||
ioread32(&chip->reg->ioh_sel_reg[i]);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -154,13 +199,34 @@ static void ioh_gpio_save_reg_conf(struct ioh_gpio *chip)
|
|||
*/
|
||||
static void ioh_gpio_restore_reg_conf(struct ioh_gpio *chip)
|
||||
{
|
||||
/* to store contents of PO register */
|
||||
iowrite32(chip->ioh_gpio_reg.po_reg, &chip->reg->regs[chip->ch].po);
|
||||
/* to store contents of PM register */
|
||||
iowrite32(chip->ioh_gpio_reg.pm_reg, &chip->reg->regs[chip->ch].pm);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 8; i ++, chip++) {
|
||||
iowrite32(chip->ioh_gpio_reg.po_reg,
|
||||
&chip->reg->regs[chip->ch].po);
|
||||
iowrite32(chip->ioh_gpio_reg.pm_reg,
|
||||
&chip->reg->regs[chip->ch].pm);
|
||||
iowrite32(chip->ioh_gpio_reg.ien_reg,
|
||||
&chip->reg->regs[chip->ch].ien);
|
||||
iowrite32(chip->ioh_gpio_reg.imask_reg,
|
||||
&chip->reg->regs[chip->ch].imask);
|
||||
iowrite32(chip->ioh_gpio_reg.im0_reg,
|
||||
&chip->reg->regs[chip->ch].im_0);
|
||||
iowrite32(chip->ioh_gpio_reg.im1_reg,
|
||||
&chip->reg->regs[chip->ch].im_1);
|
||||
if (i < 4)
|
||||
iowrite32(chip->ioh_gpio_reg.use_sel_reg,
|
||||
&chip->reg->ioh_sel_reg[i]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static int ioh_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
|
||||
{
|
||||
struct ioh_gpio *chip = container_of(gpio, struct ioh_gpio, gpio);
|
||||
return chip->irq_base + offset;
|
||||
}
|
||||
|
||||
static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port)
|
||||
{
|
||||
struct gpio_chip *gpio = &chip->gpio;
|
||||
|
@ -175,16 +241,148 @@ static void ioh_gpio_setup(struct ioh_gpio *chip, int num_port)
|
|||
gpio->base = -1;
|
||||
gpio->ngpio = num_port;
|
||||
gpio->can_sleep = 0;
|
||||
gpio->to_irq = ioh_gpio_to_irq;
|
||||
}
|
||||
|
||||
static int ioh_irq_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
u32 im;
|
||||
u32 *im_reg;
|
||||
u32 ien;
|
||||
u32 im_pos;
|
||||
int ch;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
int irq = d->irq;
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
struct ioh_gpio *chip = gc->private;
|
||||
|
||||
ch = irq - chip->irq_base;
|
||||
if (irq <= chip->irq_base + 7) {
|
||||
im_reg = &chip->reg->regs[chip->ch].im_0;
|
||||
im_pos = ch;
|
||||
} else {
|
||||
im_reg = &chip->reg->regs[chip->ch].im_1;
|
||||
im_pos = ch - 8;
|
||||
}
|
||||
dev_dbg(chip->dev, "%s:irq=%d type=%d ch=%d pos=%d type=%d\n",
|
||||
__func__, irq, type, ch, im_pos, type);
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
|
||||
switch (type) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
val = IOH_EDGE_RISING;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
val = IOH_EDGE_FALLING;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
val = IOH_EDGE_BOTH;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
val = IOH_LEVEL_H;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
val = IOH_LEVEL_L;
|
||||
break;
|
||||
case IRQ_TYPE_PROBE:
|
||||
goto end;
|
||||
default:
|
||||
dev_warn(chip->dev, "%s: unknown type(%dd)",
|
||||
__func__, type);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Set interrupt mode */
|
||||
im = ioread32(im_reg) & ~(IOH_IM_MASK << (im_pos * 4));
|
||||
iowrite32(im | (val << (im_pos * 4)), im_reg);
|
||||
|
||||
/* iclr */
|
||||
iowrite32(BIT(ch), &chip->reg->regs[chip->ch].iclr);
|
||||
|
||||
/* IMASKCLR */
|
||||
iowrite32(BIT(ch), &chip->reg->regs[chip->ch].imaskclr);
|
||||
|
||||
/* Enable interrupt */
|
||||
ien = ioread32(&chip->reg->regs[chip->ch].ien);
|
||||
iowrite32(ien | BIT(ch), &chip->reg->regs[chip->ch].ien);
|
||||
end:
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ioh_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
struct ioh_gpio *chip = gc->private;
|
||||
|
||||
iowrite32(1 << (d->irq - chip->irq_base),
|
||||
&chip->reg->regs[chip->ch].imaskclr);
|
||||
}
|
||||
|
||||
static void ioh_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
struct ioh_gpio *chip = gc->private;
|
||||
|
||||
iowrite32(1 << (d->irq - chip->irq_base),
|
||||
&chip->reg->regs[chip->ch].imask);
|
||||
}
|
||||
|
||||
static irqreturn_t ioh_gpio_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct ioh_gpio *chip = dev_id;
|
||||
u32 reg_val;
|
||||
int i, j;
|
||||
int ret = IRQ_NONE;
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
reg_val = ioread32(&chip->reg->regs[i].istatus);
|
||||
for (j = 0; j < num_ports[i]; j++) {
|
||||
if (reg_val & BIT(j)) {
|
||||
dev_dbg(chip->dev,
|
||||
"%s:[%d]:irq=%d status=0x%x\n",
|
||||
__func__, j, irq, reg_val);
|
||||
iowrite32(BIT(j),
|
||||
&chip->reg->regs[chip->ch].iclr);
|
||||
generic_handle_irq(chip->irq_base + j);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __devinit void ioh_gpio_alloc_generic_chip(struct ioh_gpio *chip,
|
||||
unsigned int irq_start, unsigned int num)
|
||||
{
|
||||
struct irq_chip_generic *gc;
|
||||
struct irq_chip_type *ct;
|
||||
|
||||
gc = irq_alloc_generic_chip("ioh_gpio", 1, irq_start, chip->base,
|
||||
handle_simple_irq);
|
||||
gc->private = chip;
|
||||
ct = gc->chip_types;
|
||||
|
||||
ct->chip.irq_mask = ioh_irq_mask;
|
||||
ct->chip.irq_unmask = ioh_irq_unmask;
|
||||
ct->chip.irq_set_type = ioh_irq_type;
|
||||
|
||||
irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
|
||||
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
|
||||
}
|
||||
|
||||
static int __devinit ioh_gpio_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
int i, j;
|
||||
struct ioh_gpio *chip;
|
||||
void __iomem *base;
|
||||
void __iomem *chip_save;
|
||||
int irq_base;
|
||||
|
||||
ret = pci_enable_device(pdev);
|
||||
if (ret) {
|
||||
|
@ -228,10 +426,41 @@ static int __devinit ioh_gpio_probe(struct pci_dev *pdev,
|
|||
}
|
||||
|
||||
chip = chip_save;
|
||||
for (j = 0; j < 8; j++, chip++) {
|
||||
irq_base = irq_alloc_descs(-1, IOH_IRQ_BASE, num_ports[j],
|
||||
NUMA_NO_NODE);
|
||||
if (irq_base < 0) {
|
||||
dev_warn(&pdev->dev,
|
||||
"ml_ioh_gpio: Failed to get IRQ base num\n");
|
||||
chip->irq_base = -1;
|
||||
goto err_irq_alloc_descs;
|
||||
}
|
||||
chip->irq_base = irq_base;
|
||||
ioh_gpio_alloc_generic_chip(chip, irq_base, num_ports[j]);
|
||||
}
|
||||
|
||||
chip = chip_save;
|
||||
ret = request_irq(pdev->irq, ioh_gpio_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"%s request_irq failed\n", __func__);
|
||||
goto err_request_irq;
|
||||
}
|
||||
|
||||
pci_set_drvdata(pdev, chip);
|
||||
|
||||
return 0;
|
||||
|
||||
err_request_irq:
|
||||
chip = chip_save;
|
||||
err_irq_alloc_descs:
|
||||
while (--j >= 0) {
|
||||
chip--;
|
||||
irq_free_descs(chip->irq_base, num_ports[j]);
|
||||
}
|
||||
|
||||
chip = chip_save;
|
||||
err_gpiochip_add:
|
||||
while (--i >= 0) {
|
||||
chip--;
|
||||
|
@ -264,7 +493,11 @@ static void __devexit ioh_gpio_remove(struct pci_dev *pdev)
|
|||
void __iomem *chip_save;
|
||||
|
||||
chip_save = chip;
|
||||
|
||||
free_irq(pdev->irq, chip);
|
||||
|
||||
for (i = 0; i < 8; i++, chip++) {
|
||||
irq_free_descs(chip->irq_base, num_ports[i]);
|
||||
err = gpiochip_remove(&chip->gpio);
|
||||
if (err)
|
||||
dev_err(&pdev->dev, "Failed gpiochip_remove\n");
|
||||
|
@ -282,9 +515,11 @@ static int ioh_gpio_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||
{
|
||||
s32 ret;
|
||||
struct ioh_gpio *chip = pci_get_drvdata(pdev);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
ioh_gpio_save_reg_conf(chip);
|
||||
ioh_gpio_restore_reg_conf(chip);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
ret = pci_save_state(pdev);
|
||||
if (ret) {
|
||||
|
@ -304,6 +539,7 @@ static int ioh_gpio_resume(struct pci_dev *pdev)
|
|||
{
|
||||
s32 ret;
|
||||
struct ioh_gpio *chip = pci_get_drvdata(pdev);
|
||||
unsigned long flags;
|
||||
|
||||
ret = pci_enable_wake(pdev, PCI_D0, 0);
|
||||
|
||||
|
@ -315,9 +551,11 @@ static int ioh_gpio_resume(struct pci_dev *pdev)
|
|||
}
|
||||
pci_restore_state(pdev);
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
iowrite32(0x01, &chip->reg->srst);
|
||||
iowrite32(0x00, &chip->reg->srst);
|
||||
ioh_gpio_restore_reg_conf(chip);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <asm-generic/bug.h>
|
||||
#include <asm/mach/irq.h>
|
||||
|
||||
enum mxc_gpio_hwtype {
|
||||
IMX1_GPIO, /* runs on i.mx1 */
|
||||
|
@ -232,10 +233,15 @@ static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc)
|
|||
{
|
||||
u32 irq_stat;
|
||||
struct mxc_gpio_port *port = irq_get_handler_data(irq);
|
||||
struct irq_chip *chip = irq_get_chip(irq);
|
||||
|
||||
chained_irq_enter(chip, desc);
|
||||
|
||||
irq_stat = readl(port->base + GPIO_ISR) & readl(port->base + GPIO_IMR);
|
||||
|
||||
mxc_gpio_irq_handler(port, irq_stat);
|
||||
|
||||
chained_irq_exit(chip, desc);
|
||||
}
|
||||
|
||||
/* MX2 has one interrupt *for all* gpio ports */
|
||||
|
|
|
@ -59,7 +59,6 @@ struct nmk_gpio_chip {
|
|||
u32 rwimsc;
|
||||
u32 fwimsc;
|
||||
u32 slpm;
|
||||
u32 enabled;
|
||||
u32 pull_up;
|
||||
};
|
||||
|
||||
|
@ -277,6 +276,8 @@ static void nmk_gpio_glitch_slpm_init(unsigned int *slpm)
|
|||
if (!chip)
|
||||
break;
|
||||
|
||||
clk_enable(chip->clk);
|
||||
|
||||
slpm[i] = readl(chip->addr + NMK_GPIO_SLPC);
|
||||
writel(temp, chip->addr + NMK_GPIO_SLPC);
|
||||
}
|
||||
|
@ -293,6 +294,8 @@ static void nmk_gpio_glitch_slpm_restore(unsigned int *slpm)
|
|||
break;
|
||||
|
||||
writel(slpm[i], chip->addr + NMK_GPIO_SLPC);
|
||||
|
||||
clk_disable(chip->clk);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -337,10 +340,12 @@ static int __nmk_config_pins(pin_cfg_t *cfgs, int num, bool sleep)
|
|||
break;
|
||||
}
|
||||
|
||||
clk_enable(nmk_chip->clk);
|
||||
spin_lock(&nmk_chip->lock);
|
||||
__nmk_config_pin(nmk_chip, pin - nmk_chip->chip.base,
|
||||
cfgs[i], sleep, glitch ? slpm : NULL);
|
||||
spin_unlock(&nmk_chip->lock);
|
||||
clk_disable(nmk_chip->clk);
|
||||
}
|
||||
|
||||
if (glitch)
|
||||
|
@ -425,6 +430,7 @@ int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
|
|||
if (!nmk_chip)
|
||||
return -EINVAL;
|
||||
|
||||
clk_enable(nmk_chip->clk);
|
||||
spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
|
||||
spin_lock(&nmk_chip->lock);
|
||||
|
||||
|
@ -432,6 +438,7 @@ int nmk_gpio_set_slpm(int gpio, enum nmk_gpio_slpm mode)
|
|||
|
||||
spin_unlock(&nmk_chip->lock);
|
||||
spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
|
||||
clk_disable(nmk_chip->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -458,9 +465,11 @@ int nmk_gpio_set_pull(int gpio, enum nmk_gpio_pull pull)
|
|||
if (!nmk_chip)
|
||||
return -EINVAL;
|
||||
|
||||
clk_enable(nmk_chip->clk);
|
||||
spin_lock_irqsave(&nmk_chip->lock, flags);
|
||||
__nmk_gpio_set_pull(nmk_chip, gpio - nmk_chip->chip.base, pull);
|
||||
spin_unlock_irqrestore(&nmk_chip->lock, flags);
|
||||
clk_disable(nmk_chip->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -484,9 +493,11 @@ int nmk_gpio_set_mode(int gpio, int gpio_mode)
|
|||
if (!nmk_chip)
|
||||
return -EINVAL;
|
||||
|
||||
clk_enable(nmk_chip->clk);
|
||||
spin_lock_irqsave(&nmk_chip->lock, flags);
|
||||
__nmk_gpio_set_mode(nmk_chip, gpio - nmk_chip->chip.base, gpio_mode);
|
||||
spin_unlock_irqrestore(&nmk_chip->lock, flags);
|
||||
clk_disable(nmk_chip->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -503,9 +514,13 @@ int nmk_gpio_get_mode(int gpio)
|
|||
|
||||
bit = 1 << (gpio - nmk_chip->chip.base);
|
||||
|
||||
clk_enable(nmk_chip->clk);
|
||||
|
||||
afunc = readl(nmk_chip->addr + NMK_GPIO_AFSLA) & bit;
|
||||
bfunc = readl(nmk_chip->addr + NMK_GPIO_AFSLB) & bit;
|
||||
|
||||
clk_disable(nmk_chip->clk);
|
||||
|
||||
return (afunc ? NMK_GPIO_ALT_A : 0) | (bfunc ? NMK_GPIO_ALT_B : 0);
|
||||
}
|
||||
EXPORT_SYMBOL(nmk_gpio_get_mode);
|
||||
|
@ -526,7 +541,10 @@ static void nmk_gpio_irq_ack(struct irq_data *d)
|
|||
nmk_chip = irq_data_get_irq_chip_data(d);
|
||||
if (!nmk_chip)
|
||||
return;
|
||||
|
||||
clk_enable(nmk_chip->clk);
|
||||
writel(nmk_gpio_get_bitmask(gpio), nmk_chip->addr + NMK_GPIO_IC);
|
||||
clk_disable(nmk_chip->clk);
|
||||
}
|
||||
|
||||
enum nmk_gpio_irq_type {
|
||||
|
@ -587,11 +605,7 @@ static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable)
|
|||
if (!nmk_chip)
|
||||
return -EINVAL;
|
||||
|
||||
if (enable)
|
||||
nmk_chip->enabled |= bitmask;
|
||||
else
|
||||
nmk_chip->enabled &= ~bitmask;
|
||||
|
||||
clk_enable(nmk_chip->clk);
|
||||
spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
|
||||
spin_lock(&nmk_chip->lock);
|
||||
|
||||
|
@ -602,6 +616,7 @@ static int nmk_gpio_irq_maskunmask(struct irq_data *d, bool enable)
|
|||
|
||||
spin_unlock(&nmk_chip->lock);
|
||||
spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
|
||||
clk_disable(nmk_chip->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -629,10 +644,11 @@ static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
|
|||
return -EINVAL;
|
||||
bitmask = nmk_gpio_get_bitmask(gpio);
|
||||
|
||||
clk_enable(nmk_chip->clk);
|
||||
spin_lock_irqsave(&nmk_gpio_slpm_lock, flags);
|
||||
spin_lock(&nmk_chip->lock);
|
||||
|
||||
if (!(nmk_chip->enabled & bitmask))
|
||||
if (irqd_irq_disabled(d))
|
||||
__nmk_gpio_set_wake(nmk_chip, gpio, on);
|
||||
|
||||
if (on)
|
||||
|
@ -642,13 +658,15 @@ static int nmk_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
|
|||
|
||||
spin_unlock(&nmk_chip->lock);
|
||||
spin_unlock_irqrestore(&nmk_gpio_slpm_lock, flags);
|
||||
clk_disable(nmk_chip->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
bool enabled, wake = irqd_is_wakeup_set(d);
|
||||
bool enabled = !irqd_irq_disabled(d);
|
||||
bool wake = irqd_is_wakeup_set(d);
|
||||
int gpio;
|
||||
struct nmk_gpio_chip *nmk_chip;
|
||||
unsigned long flags;
|
||||
|
@ -665,8 +683,7 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
if (type & IRQ_TYPE_LEVEL_LOW)
|
||||
return -EINVAL;
|
||||
|
||||
enabled = nmk_chip->enabled & bitmask;
|
||||
|
||||
clk_enable(nmk_chip->clk);
|
||||
spin_lock_irqsave(&nmk_chip->lock, flags);
|
||||
|
||||
if (enabled)
|
||||
|
@ -690,10 +707,28 @@ static int nmk_gpio_irq_set_type(struct irq_data *d, unsigned int type)
|
|||
__nmk_gpio_irq_modify(nmk_chip, gpio, WAKE, true);
|
||||
|
||||
spin_unlock_irqrestore(&nmk_chip->lock, flags);
|
||||
clk_disable(nmk_chip->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int nmk_gpio_irq_startup(struct irq_data *d)
|
||||
{
|
||||
struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
|
||||
|
||||
clk_enable(nmk_chip->clk);
|
||||
nmk_gpio_irq_unmask(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void nmk_gpio_irq_shutdown(struct irq_data *d)
|
||||
{
|
||||
struct nmk_gpio_chip *nmk_chip = irq_data_get_irq_chip_data(d);
|
||||
|
||||
nmk_gpio_irq_mask(d);
|
||||
clk_disable(nmk_chip->clk);
|
||||
}
|
||||
|
||||
static struct irq_chip nmk_gpio_irq_chip = {
|
||||
.name = "Nomadik-GPIO",
|
||||
.irq_ack = nmk_gpio_irq_ack,
|
||||
|
@ -701,6 +736,8 @@ static struct irq_chip nmk_gpio_irq_chip = {
|
|||
.irq_unmask = nmk_gpio_irq_unmask,
|
||||
.irq_set_type = nmk_gpio_irq_set_type,
|
||||
.irq_set_wake = nmk_gpio_irq_set_wake,
|
||||
.irq_startup = nmk_gpio_irq_startup,
|
||||
.irq_shutdown = nmk_gpio_irq_shutdown,
|
||||
};
|
||||
|
||||
static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
|
||||
|
@ -727,7 +764,11 @@ static void __nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc,
|
|||
static void nmk_gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
|
||||
{
|
||||
struct nmk_gpio_chip *nmk_chip = irq_get_handler_data(irq);
|
||||
u32 status = readl(nmk_chip->addr + NMK_GPIO_IS);
|
||||
u32 status;
|
||||
|
||||
clk_enable(nmk_chip->clk);
|
||||
status = readl(nmk_chip->addr + NMK_GPIO_IS);
|
||||
clk_disable(nmk_chip->clk);
|
||||
|
||||
__nmk_gpio_irq_handler(irq, desc, status);
|
||||
}
|
||||
|
@ -773,7 +814,12 @@ static int nmk_gpio_make_input(struct gpio_chip *chip, unsigned offset)
|
|||
struct nmk_gpio_chip *nmk_chip =
|
||||
container_of(chip, struct nmk_gpio_chip, chip);
|
||||
|
||||
clk_enable(nmk_chip->clk);
|
||||
|
||||
writel(1 << offset, nmk_chip->addr + NMK_GPIO_DIRC);
|
||||
|
||||
clk_disable(nmk_chip->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -782,8 +828,15 @@ static int nmk_gpio_get_input(struct gpio_chip *chip, unsigned offset)
|
|||
struct nmk_gpio_chip *nmk_chip =
|
||||
container_of(chip, struct nmk_gpio_chip, chip);
|
||||
u32 bit = 1 << offset;
|
||||
int value;
|
||||
|
||||
return (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0;
|
||||
clk_enable(nmk_chip->clk);
|
||||
|
||||
value = (readl(nmk_chip->addr + NMK_GPIO_DAT) & bit) != 0;
|
||||
|
||||
clk_disable(nmk_chip->clk);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
|
||||
|
@ -792,7 +845,11 @@ static void nmk_gpio_set_output(struct gpio_chip *chip, unsigned offset,
|
|||
struct nmk_gpio_chip *nmk_chip =
|
||||
container_of(chip, struct nmk_gpio_chip, chip);
|
||||
|
||||
clk_enable(nmk_chip->clk);
|
||||
|
||||
__nmk_gpio_set_output(nmk_chip, offset, val);
|
||||
|
||||
clk_disable(nmk_chip->clk);
|
||||
}
|
||||
|
||||
static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
|
||||
|
@ -801,8 +858,12 @@ static int nmk_gpio_make_output(struct gpio_chip *chip, unsigned offset,
|
|||
struct nmk_gpio_chip *nmk_chip =
|
||||
container_of(chip, struct nmk_gpio_chip, chip);
|
||||
|
||||
clk_enable(nmk_chip->clk);
|
||||
|
||||
__nmk_gpio_make_output(nmk_chip, offset, val);
|
||||
|
||||
clk_disable(nmk_chip->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -833,6 +894,8 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
|||
[NMK_GPIO_ALT_C] = "altC",
|
||||
};
|
||||
|
||||
clk_enable(nmk_chip->clk);
|
||||
|
||||
for (i = 0; i < chip->ngpio; i++, gpio++) {
|
||||
const char *label = gpiochip_is_requested(chip, i);
|
||||
bool pull;
|
||||
|
@ -877,6 +940,8 @@ static void nmk_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
|
|||
|
||||
seq_printf(s, "\n");
|
||||
}
|
||||
|
||||
clk_disable(nmk_chip->clk);
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -894,6 +959,34 @@ static struct gpio_chip nmk_gpio_template = {
|
|||
.can_sleep = 0,
|
||||
};
|
||||
|
||||
void nmk_gpio_clocks_enable(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_BANKS; i++) {
|
||||
struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
|
||||
|
||||
if (!chip)
|
||||
continue;
|
||||
|
||||
clk_enable(chip->clk);
|
||||
}
|
||||
}
|
||||
|
||||
void nmk_gpio_clocks_disable(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_BANKS; i++) {
|
||||
struct nmk_gpio_chip *chip = nmk_gpio_chips[i];
|
||||
|
||||
if (!chip)
|
||||
continue;
|
||||
|
||||
clk_disable(chip->clk);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Called from the suspend/resume path to only keep the real wakeup interrupts
|
||||
* (those that have had set_irq_wake() called on them) as wakeup interrupts,
|
||||
|
@ -913,6 +1006,8 @@ void nmk_gpio_wakeups_suspend(void)
|
|||
if (!chip)
|
||||
break;
|
||||
|
||||
clk_enable(chip->clk);
|
||||
|
||||
chip->rwimsc = readl(chip->addr + NMK_GPIO_RWIMSC);
|
||||
chip->fwimsc = readl(chip->addr + NMK_GPIO_FWIMSC);
|
||||
|
||||
|
@ -927,6 +1022,8 @@ void nmk_gpio_wakeups_suspend(void)
|
|||
/* 0 -> wakeup enable */
|
||||
writel(~chip->real_wake, chip->addr + NMK_GPIO_SLPC);
|
||||
}
|
||||
|
||||
clk_disable(chip->clk);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -940,11 +1037,15 @@ void nmk_gpio_wakeups_resume(void)
|
|||
if (!chip)
|
||||
break;
|
||||
|
||||
clk_enable(chip->clk);
|
||||
|
||||
writel(chip->rwimsc, chip->addr + NMK_GPIO_RWIMSC);
|
||||
writel(chip->fwimsc, chip->addr + NMK_GPIO_FWIMSC);
|
||||
|
||||
if (chip->sleepmode)
|
||||
writel(chip->slpm, chip->addr + NMK_GPIO_SLPC);
|
||||
|
||||
clk_disable(chip->clk);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1011,8 +1112,6 @@ static int __devinit nmk_gpio_probe(struct platform_device *dev)
|
|||
goto out_release;
|
||||
}
|
||||
|
||||
clk_enable(clk);
|
||||
|
||||
nmk_chip = kzalloc(sizeof(*nmk_chip), GFP_KERNEL);
|
||||
if (!nmk_chip) {
|
||||
ret = -ENOMEM;
|
||||
|
|
|
@ -17,9 +17,17 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/irq.h>
|
||||
|
||||
#define PCH_GPIO_ALL_PINS 0xfff /* Mask for GPIO pins 0 to 11 */
|
||||
#define GPIO_NUM_PINS 12 /* Specifies number of GPIO PINS GPIO0-GPIO11 */
|
||||
#define PCH_EDGE_FALLING 0
|
||||
#define PCH_EDGE_RISING BIT(0)
|
||||
#define PCH_LEVEL_L BIT(1)
|
||||
#define PCH_LEVEL_H (BIT(0) | BIT(1))
|
||||
#define PCH_EDGE_BOTH BIT(2)
|
||||
#define PCH_IM_MASK (BIT(0) | BIT(1) | BIT(2))
|
||||
|
||||
#define PCH_IRQ_BASE 24
|
||||
|
||||
struct pch_regs {
|
||||
u32 ien;
|
||||
|
@ -33,18 +41,43 @@ struct pch_regs {
|
|||
u32 pm;
|
||||
u32 im0;
|
||||
u32 im1;
|
||||
u32 reserved[4];
|
||||
u32 reserved[3];
|
||||
u32 gpio_use_sel;
|
||||
u32 reset;
|
||||
};
|
||||
|
||||
enum pch_type_t {
|
||||
INTEL_EG20T_PCH,
|
||||
OKISEMI_ML7223m_IOH, /* OKISEMI ML7223 IOH PCIe Bus-m */
|
||||
OKISEMI_ML7223n_IOH /* OKISEMI ML7223 IOH PCIe Bus-n */
|
||||
};
|
||||
|
||||
/* Specifies number of GPIO PINS */
|
||||
static int gpio_pins[] = {
|
||||
[INTEL_EG20T_PCH] = 12,
|
||||
[OKISEMI_ML7223m_IOH] = 8,
|
||||
[OKISEMI_ML7223n_IOH] = 8,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct pch_gpio_reg_data - The register store data.
|
||||
* @ien_reg: To store contents of IEN register.
|
||||
* @imask_reg: To store contents of IMASK register.
|
||||
* @po_reg: To store contents of PO register.
|
||||
* @pm_reg: To store contents of PM register.
|
||||
* @im0_reg: To store contents of IM0 register.
|
||||
* @im1_reg: To store contents of IM1 register.
|
||||
* @gpio_use_sel_reg : To store contents of GPIO_USE_SEL register.
|
||||
* (Only ML7223 Bus-n)
|
||||
*/
|
||||
struct pch_gpio_reg_data {
|
||||
u32 ien_reg;
|
||||
u32 imask_reg;
|
||||
u32 po_reg;
|
||||
u32 pm_reg;
|
||||
u32 im0_reg;
|
||||
u32 im1_reg;
|
||||
u32 gpio_use_sel_reg;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -55,6 +88,12 @@ struct pch_gpio_reg_data {
|
|||
* @gpio: Data for GPIO infrastructure.
|
||||
* @pch_gpio_reg: Memory mapped Register data is saved here
|
||||
* when suspend.
|
||||
* @lock: Used for register access protection
|
||||
* @irq_base: Save base of IRQ number for interrupt
|
||||
* @ioh: IOH ID
|
||||
* @spinlock: Used for register access protection in
|
||||
* interrupt context pch_irq_mask,
|
||||
* pch_irq_unmask and pch_irq_type;
|
||||
*/
|
||||
struct pch_gpio {
|
||||
void __iomem *base;
|
||||
|
@ -63,6 +102,9 @@ struct pch_gpio {
|
|||
struct gpio_chip gpio;
|
||||
struct pch_gpio_reg_data pch_gpio_reg;
|
||||
struct mutex lock;
|
||||
int irq_base;
|
||||
enum pch_type_t ioh;
|
||||
spinlock_t spinlock;
|
||||
};
|
||||
|
||||
static void pch_gpio_set(struct gpio_chip *gpio, unsigned nr, int val)
|
||||
|
@ -96,7 +138,7 @@ static int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned nr,
|
|||
u32 reg_val;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
pm = ioread32(&chip->reg->pm) & PCH_GPIO_ALL_PINS;
|
||||
pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
|
||||
pm |= (1 << nr);
|
||||
iowrite32(pm, &chip->reg->pm);
|
||||
|
||||
|
@ -118,7 +160,7 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
|||
u32 pm;
|
||||
|
||||
mutex_lock(&chip->lock);
|
||||
pm = ioread32(&chip->reg->pm) & PCH_GPIO_ALL_PINS; /*bits 0-11*/
|
||||
pm = ioread32(&chip->reg->pm) & ((1 << gpio_pins[chip->ioh]) - 1);
|
||||
pm &= ~(1 << nr);
|
||||
iowrite32(pm, &chip->reg->pm);
|
||||
mutex_unlock(&chip->lock);
|
||||
|
@ -131,8 +173,16 @@ static int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned nr)
|
|||
*/
|
||||
static void pch_gpio_save_reg_conf(struct pch_gpio *chip)
|
||||
{
|
||||
chip->pch_gpio_reg.ien_reg = ioread32(&chip->reg->ien);
|
||||
chip->pch_gpio_reg.imask_reg = ioread32(&chip->reg->imask);
|
||||
chip->pch_gpio_reg.po_reg = ioread32(&chip->reg->po);
|
||||
chip->pch_gpio_reg.pm_reg = ioread32(&chip->reg->pm);
|
||||
chip->pch_gpio_reg.im0_reg = ioread32(&chip->reg->im0);
|
||||
if (chip->ioh == INTEL_EG20T_PCH)
|
||||
chip->pch_gpio_reg.im1_reg = ioread32(&chip->reg->im1);
|
||||
if (chip->ioh == OKISEMI_ML7223n_IOH)
|
||||
chip->pch_gpio_reg.gpio_use_sel_reg =\
|
||||
ioread32(&chip->reg->gpio_use_sel);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -140,10 +190,24 @@ static void pch_gpio_save_reg_conf(struct pch_gpio *chip)
|
|||
*/
|
||||
static void pch_gpio_restore_reg_conf(struct pch_gpio *chip)
|
||||
{
|
||||
iowrite32(chip->pch_gpio_reg.ien_reg, &chip->reg->ien);
|
||||
iowrite32(chip->pch_gpio_reg.imask_reg, &chip->reg->imask);
|
||||
/* to store contents of PO register */
|
||||
iowrite32(chip->pch_gpio_reg.po_reg, &chip->reg->po);
|
||||
/* to store contents of PM register */
|
||||
iowrite32(chip->pch_gpio_reg.pm_reg, &chip->reg->pm);
|
||||
iowrite32(chip->pch_gpio_reg.im0_reg, &chip->reg->im0);
|
||||
if (chip->ioh == INTEL_EG20T_PCH)
|
||||
iowrite32(chip->pch_gpio_reg.im1_reg, &chip->reg->im1);
|
||||
if (chip->ioh == OKISEMI_ML7223n_IOH)
|
||||
iowrite32(chip->pch_gpio_reg.gpio_use_sel_reg,
|
||||
&chip->reg->gpio_use_sel);
|
||||
}
|
||||
|
||||
static int pch_gpio_to_irq(struct gpio_chip *gpio, unsigned offset)
|
||||
{
|
||||
struct pch_gpio *chip = container_of(gpio, struct pch_gpio, gpio);
|
||||
return chip->irq_base + offset;
|
||||
}
|
||||
|
||||
static void pch_gpio_setup(struct pch_gpio *chip)
|
||||
|
@ -158,8 +222,132 @@ static void pch_gpio_setup(struct pch_gpio *chip)
|
|||
gpio->set = pch_gpio_set;
|
||||
gpio->dbg_show = NULL;
|
||||
gpio->base = -1;
|
||||
gpio->ngpio = GPIO_NUM_PINS;
|
||||
gpio->ngpio = gpio_pins[chip->ioh];
|
||||
gpio->can_sleep = 0;
|
||||
gpio->to_irq = pch_gpio_to_irq;
|
||||
}
|
||||
|
||||
static int pch_irq_type(struct irq_data *d, unsigned int type)
|
||||
{
|
||||
u32 im;
|
||||
u32 *im_reg;
|
||||
u32 ien;
|
||||
u32 im_pos;
|
||||
int ch;
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
int irq = d->irq;
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
struct pch_gpio *chip = gc->private;
|
||||
|
||||
ch = irq - chip->irq_base;
|
||||
if (irq <= chip->irq_base + 7) {
|
||||
im_reg = &chip->reg->im0;
|
||||
im_pos = ch;
|
||||
} else {
|
||||
im_reg = &chip->reg->im1;
|
||||
im_pos = ch - 8;
|
||||
}
|
||||
dev_dbg(chip->dev, "%s:irq=%d type=%d ch=%d pos=%d\n",
|
||||
__func__, irq, type, ch, im_pos);
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
|
||||
switch (type) {
|
||||
case IRQ_TYPE_EDGE_RISING:
|
||||
val = PCH_EDGE_RISING;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_FALLING:
|
||||
val = PCH_EDGE_FALLING;
|
||||
break;
|
||||
case IRQ_TYPE_EDGE_BOTH:
|
||||
val = PCH_EDGE_BOTH;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_HIGH:
|
||||
val = PCH_LEVEL_H;
|
||||
break;
|
||||
case IRQ_TYPE_LEVEL_LOW:
|
||||
val = PCH_LEVEL_L;
|
||||
break;
|
||||
case IRQ_TYPE_PROBE:
|
||||
goto end;
|
||||
default:
|
||||
dev_warn(chip->dev, "%s: unknown type(%dd)",
|
||||
__func__, type);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Set interrupt mode */
|
||||
im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4));
|
||||
iowrite32(im | (val << (im_pos * 4)), im_reg);
|
||||
|
||||
/* iclr */
|
||||
iowrite32(BIT(ch), &chip->reg->iclr);
|
||||
|
||||
/* IMASKCLR */
|
||||
iowrite32(BIT(ch), &chip->reg->imaskclr);
|
||||
|
||||
/* Enable interrupt */
|
||||
ien = ioread32(&chip->reg->ien);
|
||||
iowrite32(ien | BIT(ch), &chip->reg->ien);
|
||||
end:
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pch_irq_unmask(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
struct pch_gpio *chip = gc->private;
|
||||
|
||||
iowrite32(1 << (d->irq - chip->irq_base), &chip->reg->imaskclr);
|
||||
}
|
||||
|
||||
static void pch_irq_mask(struct irq_data *d)
|
||||
{
|
||||
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
|
||||
struct pch_gpio *chip = gc->private;
|
||||
|
||||
iowrite32(1 << (d->irq - chip->irq_base), &chip->reg->imask);
|
||||
}
|
||||
|
||||
static irqreturn_t pch_gpio_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct pch_gpio *chip = dev_id;
|
||||
u32 reg_val = ioread32(&chip->reg->istatus);
|
||||
int i;
|
||||
int ret = IRQ_NONE;
|
||||
|
||||
for (i = 0; i < gpio_pins[chip->ioh]; i++) {
|
||||
if (reg_val & BIT(i)) {
|
||||
dev_dbg(chip->dev, "%s:[%d]:irq=%d status=0x%x\n",
|
||||
__func__, i, irq, reg_val);
|
||||
iowrite32(BIT(i), &chip->reg->iclr);
|
||||
generic_handle_irq(chip->irq_base + i);
|
||||
ret = IRQ_HANDLED;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __devinit void pch_gpio_alloc_generic_chip(struct pch_gpio *chip,
|
||||
unsigned int irq_start, unsigned int num)
|
||||
{
|
||||
struct irq_chip_generic *gc;
|
||||
struct irq_chip_type *ct;
|
||||
|
||||
gc = irq_alloc_generic_chip("pch_gpio", 1, irq_start, chip->base,
|
||||
handle_simple_irq);
|
||||
gc->private = chip;
|
||||
ct = gc->chip_types;
|
||||
|
||||
ct->chip.irq_mask = pch_irq_mask;
|
||||
ct->chip.irq_unmask = pch_irq_unmask;
|
||||
ct->chip.irq_set_type = pch_irq_type;
|
||||
|
||||
irq_setup_generic_chip(gc, IRQ_MSK(num), IRQ_GC_INIT_MASK_CACHE,
|
||||
IRQ_NOREQUEST | IRQ_NOPROBE, 0);
|
||||
}
|
||||
|
||||
static int __devinit pch_gpio_probe(struct pci_dev *pdev,
|
||||
|
@ -167,6 +355,7 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev,
|
|||
{
|
||||
s32 ret;
|
||||
struct pch_gpio *chip;
|
||||
int irq_base;
|
||||
|
||||
chip = kzalloc(sizeof(*chip), GFP_KERNEL);
|
||||
if (chip == NULL)
|
||||
|
@ -192,6 +381,13 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev,
|
|||
goto err_iomap;
|
||||
}
|
||||
|
||||
if (pdev->device == 0x8803)
|
||||
chip->ioh = INTEL_EG20T_PCH;
|
||||
else if (pdev->device == 0x8014)
|
||||
chip->ioh = OKISEMI_ML7223m_IOH;
|
||||
else if (pdev->device == 0x8043)
|
||||
chip->ioh = OKISEMI_ML7223n_IOH;
|
||||
|
||||
chip->reg = chip->base;
|
||||
pci_set_drvdata(pdev, chip);
|
||||
mutex_init(&chip->lock);
|
||||
|
@ -202,8 +398,36 @@ static int __devinit pch_gpio_probe(struct pci_dev *pdev,
|
|||
goto err_gpiochip_add;
|
||||
}
|
||||
|
||||
irq_base = irq_alloc_descs(-1, 0, gpio_pins[chip->ioh], NUMA_NO_NODE);
|
||||
if (irq_base < 0) {
|
||||
dev_warn(&pdev->dev, "PCH gpio: Failed to get IRQ base num\n");
|
||||
chip->irq_base = -1;
|
||||
goto end;
|
||||
}
|
||||
chip->irq_base = irq_base;
|
||||
|
||||
ret = request_irq(pdev->irq, pch_gpio_handler,
|
||||
IRQF_SHARED, KBUILD_MODNAME, chip);
|
||||
if (ret != 0) {
|
||||
dev_err(&pdev->dev,
|
||||
"%s request_irq failed\n", __func__);
|
||||
goto err_request_irq;
|
||||
}
|
||||
|
||||
pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]);
|
||||
|
||||
/* Initialize interrupt ien register */
|
||||
iowrite32(0, &chip->reg->ien);
|
||||
end:
|
||||
return 0;
|
||||
|
||||
err_request_irq:
|
||||
irq_free_descs(irq_base, gpio_pins[chip->ioh]);
|
||||
|
||||
ret = gpiochip_remove(&chip->gpio);
|
||||
if (ret)
|
||||
dev_err(&pdev->dev, "%s gpiochip_remove failed\n", __func__);
|
||||
|
||||
err_gpiochip_add:
|
||||
pci_iounmap(pdev, chip->base);
|
||||
|
||||
|
@ -224,6 +448,12 @@ static void __devexit pch_gpio_remove(struct pci_dev *pdev)
|
|||
int err;
|
||||
struct pch_gpio *chip = pci_get_drvdata(pdev);
|
||||
|
||||
if (chip->irq_base != -1) {
|
||||
free_irq(pdev->irq, chip);
|
||||
|
||||
irq_free_descs(chip->irq_base, gpio_pins[chip->ioh]);
|
||||
}
|
||||
|
||||
err = gpiochip_remove(&chip->gpio);
|
||||
if (err)
|
||||
dev_err(&pdev->dev, "Failed gpiochip_remove\n");
|
||||
|
@ -239,9 +469,11 @@ static int pch_gpio_suspend(struct pci_dev *pdev, pm_message_t state)
|
|||
{
|
||||
s32 ret;
|
||||
struct pch_gpio *chip = pci_get_drvdata(pdev);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
pch_gpio_save_reg_conf(chip);
|
||||
pch_gpio_restore_reg_conf(chip);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
ret = pci_save_state(pdev);
|
||||
if (ret) {
|
||||
|
@ -261,6 +493,7 @@ static int pch_gpio_resume(struct pci_dev *pdev)
|
|||
{
|
||||
s32 ret;
|
||||
struct pch_gpio *chip = pci_get_drvdata(pdev);
|
||||
unsigned long flags;
|
||||
|
||||
ret = pci_enable_wake(pdev, PCI_D0, 0);
|
||||
|
||||
|
@ -272,9 +505,11 @@ static int pch_gpio_resume(struct pci_dev *pdev)
|
|||
}
|
||||
pci_restore_state(pdev);
|
||||
|
||||
spin_lock_irqsave(&chip->spinlock, flags);
|
||||
iowrite32(0x01, &chip->reg->reset);
|
||||
iowrite32(0x00, &chip->reg->reset);
|
||||
pch_gpio_restore_reg_conf(chip);
|
||||
spin_unlock_irqrestore(&chip->spinlock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -287,6 +522,7 @@ static int pch_gpio_resume(struct pci_dev *pdev)
|
|||
static DEFINE_PCI_DEVICE_TABLE(pch_gpio_pcidev_id) = {
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014) },
|
||||
{ PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8043) },
|
||||
{ 0, }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, pch_gpio_pcidev_id);
|
||||
|
|
|
@ -118,7 +118,7 @@ static int pl061_to_irq(struct gpio_chip *gc, unsigned offset)
|
|||
{
|
||||
struct pl061_gpio *chip = container_of(gc, struct pl061_gpio, gc);
|
||||
|
||||
if (chip->irq_base == (unsigned) -1)
|
||||
if (chip->irq_base == NO_IRQ)
|
||||
return -EINVAL;
|
||||
|
||||
return chip->irq_base + offset;
|
||||
|
@ -246,6 +246,18 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
|
|||
if (chip == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
pdata = dev->dev.platform_data;
|
||||
if (pdata) {
|
||||
chip->gc.base = pdata->gpio_base;
|
||||
chip->irq_base = pdata->irq_base;
|
||||
} else if (dev->dev.of_node) {
|
||||
chip->gc.base = -1;
|
||||
chip->irq_base = NO_IRQ;
|
||||
} else {
|
||||
ret = -ENODEV;
|
||||
goto free_mem;
|
||||
}
|
||||
|
||||
if (!request_mem_region(dev->res.start,
|
||||
resource_size(&dev->res), "pl061")) {
|
||||
ret = -EBUSY;
|
||||
|
@ -267,14 +279,11 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
|
|||
chip->gc.get = pl061_get_value;
|
||||
chip->gc.set = pl061_set_value;
|
||||
chip->gc.to_irq = pl061_to_irq;
|
||||
chip->gc.base = pdata->gpio_base;
|
||||
chip->gc.ngpio = PL061_GPIO_NR;
|
||||
chip->gc.label = dev_name(&dev->dev);
|
||||
chip->gc.dev = &dev->dev;
|
||||
chip->gc.owner = THIS_MODULE;
|
||||
|
||||
chip->irq_base = pdata->irq_base;
|
||||
|
||||
ret = gpiochip_add(&chip->gc);
|
||||
if (ret)
|
||||
goto iounmap;
|
||||
|
@ -283,7 +292,7 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
|
|||
* irq_chip support
|
||||
*/
|
||||
|
||||
if (chip->irq_base == (unsigned) -1)
|
||||
if (chip->irq_base == NO_IRQ)
|
||||
return 0;
|
||||
|
||||
writeb(0, chip->base + GPIOIE); /* disable irqs */
|
||||
|
@ -307,11 +316,13 @@ static int pl061_probe(struct amba_device *dev, const struct amba_id *id)
|
|||
list_add(&chip->list, chip_list);
|
||||
|
||||
for (i = 0; i < PL061_GPIO_NR; i++) {
|
||||
if (pdata->directions & (1 << i))
|
||||
pl061_direction_output(&chip->gc, i,
|
||||
pdata->values & (1 << i));
|
||||
else
|
||||
pl061_direction_input(&chip->gc, i);
|
||||
if (pdata) {
|
||||
if (pdata->directions & (1 << i))
|
||||
pl061_direction_output(&chip->gc, i,
|
||||
pdata->values & (1 << i));
|
||||
else
|
||||
pl061_direction_input(&chip->gc, i);
|
||||
}
|
||||
|
||||
irq_set_chip_and_handler(i + chip->irq_base, &pl061_irqchip,
|
||||
handle_simple_irq);
|
||||
|
|
|
@ -41,6 +41,7 @@ static inline bool gpio_is_valid(int number)
|
|||
}
|
||||
|
||||
struct device;
|
||||
struct gpio;
|
||||
struct seq_file;
|
||||
struct module;
|
||||
struct device_node;
|
||||
|
@ -170,18 +171,6 @@ extern int __gpio_cansleep(unsigned gpio);
|
|||
|
||||
extern int __gpio_to_irq(unsigned gpio);
|
||||
|
||||
/**
|
||||
* struct gpio - a structure describing a GPIO with configuration
|
||||
* @gpio: the GPIO number
|
||||
* @flags: GPIO configuration as specified by GPIOF_*
|
||||
* @label: a literal description string of this GPIO
|
||||
*/
|
||||
struct gpio {
|
||||
unsigned gpio;
|
||||
unsigned long flags;
|
||||
const char *label;
|
||||
};
|
||||
|
||||
extern int gpio_request_one(unsigned gpio, unsigned long flags, const char *label);
|
||||
extern int gpio_request_array(const struct gpio *array, size_t num);
|
||||
extern void gpio_free_array(const struct gpio *array, size_t num);
|
||||
|
@ -220,13 +209,13 @@ static inline int gpio_cansleep(unsigned gpio)
|
|||
static inline int gpio_get_value_cansleep(unsigned gpio)
|
||||
{
|
||||
might_sleep();
|
||||
return gpio_get_value(gpio);
|
||||
return __gpio_get_value(gpio);
|
||||
}
|
||||
|
||||
static inline void gpio_set_value_cansleep(unsigned gpio, int value)
|
||||
{
|
||||
might_sleep();
|
||||
gpio_set_value(gpio, value);
|
||||
__gpio_set_value(gpio, value);
|
||||
}
|
||||
|
||||
#endif /* !CONFIG_GPIOLIB */
|
||||
|
|
|
@ -7,8 +7,7 @@ struct pl061_platform_data {
|
|||
unsigned gpio_base;
|
||||
|
||||
/* number of the first IRQ.
|
||||
* If the IRQ functionality in not desired this must be set to
|
||||
* (unsigned) -1.
|
||||
* If the IRQ functionality in not desired this must be set to NO_IRQ.
|
||||
*/
|
||||
unsigned irq_base;
|
||||
|
||||
|
|
|
@ -14,6 +14,18 @@
|
|||
#define GPIOF_OUT_INIT_LOW (GPIOF_DIR_OUT | GPIOF_INIT_LOW)
|
||||
#define GPIOF_OUT_INIT_HIGH (GPIOF_DIR_OUT | GPIOF_INIT_HIGH)
|
||||
|
||||
/**
|
||||
* struct gpio - a structure describing a GPIO with configuration
|
||||
* @gpio: the GPIO number
|
||||
* @flags: GPIO configuration as specified by GPIOF_*
|
||||
* @label: a literal description string of this GPIO
|
||||
*/
|
||||
struct gpio {
|
||||
unsigned gpio;
|
||||
unsigned long flags;
|
||||
const char *label;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_GENERIC_GPIO
|
||||
#include <asm/gpio.h>
|
||||
|
||||
|
@ -24,18 +36,8 @@
|
|||
#include <linux/errno.h>
|
||||
|
||||
struct device;
|
||||
struct gpio;
|
||||
struct gpio_chip;
|
||||
|
||||
/*
|
||||
* Some platforms don't support the GPIO programming interface.
|
||||
*
|
||||
* In case some driver uses it anyway (it should normally have
|
||||
* depended on GENERIC_GPIO), these routines help the compiler
|
||||
* optimize out much GPIO-related code ... or trigger a runtime
|
||||
* warning when something is wrongly called.
|
||||
*/
|
||||
|
||||
static inline bool gpio_is_valid(int number)
|
||||
{
|
||||
return false;
|
||||
|
|
|
@ -211,6 +211,7 @@ irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base,
|
|||
}
|
||||
return gc;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_alloc_generic_chip);
|
||||
|
||||
/*
|
||||
* Separate lockdep class for interrupt chip which can nest irq_desc
|
||||
|
@ -258,6 +259,7 @@ void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk,
|
|||
}
|
||||
gc->irq_cnt = i - gc->irq_base;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_setup_generic_chip);
|
||||
|
||||
/**
|
||||
* irq_setup_alt_chip - Switch to alternative chip
|
||||
|
@ -281,6 +283,7 @@ int irq_setup_alt_chip(struct irq_data *d, unsigned int type)
|
|||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_setup_alt_chip);
|
||||
|
||||
/**
|
||||
* irq_remove_generic_chip - Remove a chip
|
||||
|
@ -311,6 +314,7 @@ void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk,
|
|||
irq_modify_status(i, clr, set);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(irq_remove_generic_chip);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
static int irq_gc_suspend(void)
|
||||
|
|
Загрузка…
Ссылка в новой задаче