cregit-Linux how code gets into the kernel

Release 4.7 drivers/pinctrl/samsung/pinctrl-s3c64xx.c

/*
 * S3C64xx specific support for pinctrl-samsung driver.
 *
 * Copyright (c) 2013 Tomasz Figa <tomasz.figa@gmail.com>
 *
 * Based on pinctrl-exynos.c, please see the file for original copyrights.
 *
 * 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 file contains the Samsung S3C64xx specific information required by the
 * the Samsung pinctrl/gpiolib driver. It also includes the implementation of
 * external gpio and wakeup interrupt support.
 */

#include <linux/module.h>
#include <linux/device.h>
#include <linux/interrupt.h>
#include <linux/irqdomain.h>
#include <linux/irq.h>
#include <linux/of_irq.h>
#include <linux/io.h>
#include <linux/irqchip/chained_irq.h>
#include <linux/slab.h>
#include <linux/err.h>

#include "pinctrl-samsung.h"


#define NUM_EINT0		28

#define NUM_EINT0_IRQ		4

#define EINT_MAX_PER_REG	16

#define EINT_MAX_PER_GROUP	16

/* External GPIO and wakeup interrupt related definitions */

#define SVC_GROUP_SHIFT		4

#define SVC_GROUP_MASK		0xf

#define SVC_NUM_MASK		0xf

#define SVC_GROUP(x)		((x >> SVC_GROUP_SHIFT) & \
                                                SVC_GROUP_MASK)


#define EINT12CON_REG		0x200

#define EINT12MASK_REG		0x240

#define EINT12PEND_REG		0x260


#define EINT_OFFS(i)		((i) % (2 * EINT_MAX_PER_GROUP))

#define EINT_GROUP(i)		((i) / EINT_MAX_PER_GROUP)

#define EINT_REG(g)		(4 * ((g) / 2))


#define EINTCON_REG(i)		(EINT12CON_REG + EINT_REG(EINT_GROUP(i)))

#define EINTMASK_REG(i)		(EINT12MASK_REG + EINT_REG(EINT_GROUP(i)))

#define EINTPEND_REG(i)		(EINT12PEND_REG + EINT_REG(EINT_GROUP(i)))


#define SERVICE_REG		0x284

#define SERVICEPEND_REG		0x288


#define EINT0CON0_REG		0x900

#define EINT0MASK_REG		0x920

#define EINT0PEND_REG		0x924

/* S3C64xx specific external interrupt trigger types */

#define EINT_LEVEL_LOW		0

#define EINT_LEVEL_HIGH		1

#define EINT_EDGE_FALLING	2

#define EINT_EDGE_RISING	4

#define EINT_EDGE_BOTH		6

#define EINT_CON_MASK		0xF

#define EINT_CON_LEN		4


static const struct samsung_pin_bank_type bank_type_4bit_off = {
	.fld_width = { 4, 1, 2, 0, 2, 2, },
	.reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, },
};


static const struct samsung_pin_bank_type bank_type_4bit_alive = {
	.fld_width = { 4, 1, 2, },
	.reg_offset = { 0x00, 0x04, 0x08, },
};


static const struct samsung_pin_bank_type bank_type_4bit2_off = {
	.fld_width = { 4, 1, 2, 0, 2, 2, },
	.reg_offset = { 0x00, 0x08, 0x0c, 0, 0x10, 0x14, },
};


static const struct samsung_pin_bank_type bank_type_4bit2_alive = {
	.fld_width = { 4, 1, 2, },
	.reg_offset = { 0x00, 0x08, 0x0c, },
};


static const struct samsung_pin_bank_type bank_type_2bit_off = {
	.fld_width = { 2, 1, 2, 0, 2, 2, },
	.reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, },
};


static const struct samsung_pin_bank_type bank_type_2bit_alive = {
	.fld_width = { 2, 1, 2, },
	.reg_offset = { 0x00, 0x04, 0x08, },
};


#define PIN_BANK_4BIT(pins, reg, id)			\
	{                                               \
                .type           = &bank_type_4bit_off,  \
                .pctl_offset    = reg,                  \
                .nr_pins        = pins,                 \
                .eint_type      = EINT_TYPE_NONE,       \
                .name           = id                    \
        }


#define PIN_BANK_4BIT_EINTG(pins, reg, id, eoffs)	\
	{                                               \
                .type           = &bank_type_4bit_off,  \
                .pctl_offset    = reg,                  \
                .nr_pins        = pins,                 \
                .eint_type      = EINT_TYPE_GPIO,       \
                .eint_func      = 7,                    \
                .eint_mask      = (1 << (pins)) - 1,    \
                .eint_offset    = eoffs,                \
                .name           = id                    \
        }


#define PIN_BANK_4BIT_EINTW(pins, reg, id, eoffs, emask) \
	{                                               \
                .type           = &bank_type_4bit_alive,\
                .pctl_offset    = reg,                  \
                .nr_pins        = pins,                 \
                .eint_type      = EINT_TYPE_WKUP,       \
                .eint_func      = 3,                    \
                .eint_mask      = emask,                \
                .eint_offset    = eoffs,                \
                .name           = id                    \
        }


#define PIN_BANK_4BIT2_EINTG(pins, reg, id, eoffs)	\
	{                                               \
                .type           = &bank_type_4bit2_off, \
                .pctl_offset    = reg,                  \
                .nr_pins        = pins,                 \
                .eint_type      = EINT_TYPE_GPIO,       \
                .eint_func      = 7,                    \
                .eint_mask      = (1 << (pins)) - 1,    \
                .eint_offset    = eoffs,                \
                .name           = id                    \
        }


#define PIN_BANK_4BIT2_EINTW(pins, reg, id, eoffs, emask) \
	{                                               \
                .type           = &bank_type_4bit2_alive,\
                .pctl_offset    = reg,                  \
                .nr_pins        = pins,                 \
                .eint_type      = EINT_TYPE_WKUP,       \
                .eint_func      = 3,                    \
                .eint_mask      = emask,                \
                .eint_offset    = eoffs,                \
                .name           = id                    \
        }


#define PIN_BANK_4BIT2_ALIVE(pins, reg, id)		\
	{                                               \
                .type           = &bank_type_4bit2_alive,\
                .pctl_offset    = reg,                  \
                .nr_pins        = pins,                 \
                .eint_type      = EINT_TYPE_NONE,       \
                .name           = id                    \
        }


#define PIN_BANK_2BIT(pins, reg, id)			\
	{                                               \
                .type           = &bank_type_2bit_off,  \
                .pctl_offset    = reg,                  \
                .nr_pins        = pins,                 \
                .eint_type      = EINT_TYPE_NONE,       \
                .name           = id                    \
        }


#define PIN_BANK_2BIT_EINTG(pins, reg, id, eoffs, emask) \
	{                                               \
                .type           = &bank_type_2bit_off,  \
                .pctl_offset    = reg,                  \
                .nr_pins        = pins,                 \
                .eint_type      = EINT_TYPE_GPIO,       \
                .eint_func      = 3,                    \
                .eint_mask      = emask,                \
                .eint_offset    = eoffs,                \
                .name           = id                    \
        }


#define PIN_BANK_2BIT_EINTW(pins, reg, id, eoffs)	\
	{                                               \
                .type           = &bank_type_2bit_alive,\
                .pctl_offset    = reg,                  \
                .nr_pins        = pins,                 \
                .eint_type      = EINT_TYPE_WKUP,       \
                .eint_func      = 2,                    \
                .eint_mask      = (1 << (pins)) - 1,    \
                .eint_offset    = eoffs,                \
                .name           = id                    \
        }

/**
 * struct s3c64xx_eint0_data: EINT0 common data
 * @drvdata: pin controller driver data
 * @domains: IRQ domains of particular EINT0 interrupts
 * @pins: pin offsets inside of banks of particular EINT0 interrupts
 */

struct s3c64xx_eint0_data {
	
struct samsung_pinctrl_drv_data *drvdata;
	
struct irq_domain *domains[NUM_EINT0];
	
u8 pins[NUM_EINT0];
};

/**
 * struct s3c64xx_eint0_domain_data: EINT0 per-domain data
 * @bank: pin bank related to the domain
 * @eints: EINT0 interrupts related to the domain
 */

struct s3c64xx_eint0_domain_data {
	
struct samsung_pin_bank *bank;
	
u8 eints[];
};

/**
 * struct s3c64xx_eint_gpio_data: GPIO EINT data
 * @drvdata: pin controller driver data
 * @domains: array of domains related to EINT interrupt groups
 */

struct s3c64xx_eint_gpio_data {
	
struct samsung_pinctrl_drv_data *drvdata;
	
struct irq_domain *domains[];
};

/*
 * Common functions for S3C64xx EINT configuration
 */


static int s3c64xx_irq_get_trigger(unsigned int type) { int trigger; switch (type) { case IRQ_TYPE_EDGE_RISING: trigger = EINT_EDGE_RISING; break; case IRQ_TYPE_EDGE_FALLING: trigger = EINT_EDGE_FALLING; break; case IRQ_TYPE_EDGE_BOTH: trigger = EINT_EDGE_BOTH; break; case IRQ_TYPE_LEVEL_HIGH: trigger = EINT_LEVEL_HIGH; break; case IRQ_TYPE_LEVEL_LOW: trigger = EINT_LEVEL_LOW; break; default: return -EINVAL; } return trigger; }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa67100.00%1100.00%
Total67100.00%1100.00%


static void s3c64xx_irq_set_handler(struct irq_data *d, unsigned int type) { /* Edge- and level-triggered interrupts need different handlers */ if (type & IRQ_TYPE_EDGE_BOTH) irq_set_handler_locked(d, handle_edge_irq); else irq_set_handler_locked(d, handle_level_irq); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa2978.38%150.00%
thomas gleixnerthomas gleixner821.62%150.00%
Total37100.00%2100.00%


static void s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data *d, struct samsung_pin_bank *bank, int pin) { const struct samsung_pin_bank_type *bank_type = bank->type; unsigned long flags; void __iomem *reg; u8 shift; u32 mask; u32 val; /* Make sure that pin is configured as interrupt */ reg = d->virt_base + bank->pctl_offset; shift = pin; if (bank_type->fld_width[PINCFG_TYPE_FUNC] * shift >= 32) { /* 4-bit bank type with 2 con regs */ reg += 4; shift -= 8; } shift = shift * bank_type->fld_width[PINCFG_TYPE_FUNC]; mask = (1 << bank_type->fld_width[PINCFG_TYPE_FUNC]) - 1; spin_lock_irqsave(&bank->slock, flags); val = readl(reg); val &= ~(mask << shift); val |= bank->eint_func << shift; writel(val, reg); spin_unlock_irqrestore(&bank->slock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa163100.00%2100.00%
Total163100.00%2100.00%

/* * Functions for EINT GPIO configuration (EINT groups 1-9) */
static inline void s3c64xx_gpio_irq_set_mask(struct irq_data *irqd, bool mask) { struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned char index = EINT_OFFS(bank->eint_offset) + irqd->hwirq; void __iomem *reg = d->virt_base + EINTMASK_REG(bank->eint_offset); u32 val; val = readl(reg); if (mask) val |= 1 << index; else val &= ~(1 << index); writel(val, reg); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa102100.00%1100.00%
Total102100.00%1100.00%


static void s3c64xx_gpio_irq_unmask(struct irq_data *irqd) { s3c64xx_gpio_irq_set_mask(irqd, false); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa18100.00%1100.00%
Total18100.00%1100.00%


static void s3c64xx_gpio_irq_mask(struct irq_data *irqd) { s3c64xx_gpio_irq_set_mask(irqd, true); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa18100.00%1100.00%
Total18100.00%1100.00%


static void s3c64xx_gpio_irq_ack(struct irq_data *irqd) { struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); struct samsung_pinctrl_drv_data *d = bank->drvdata; unsigned char index = EINT_OFFS(bank->eint_offset) + irqd->hwirq; void __iomem *reg = d->virt_base + EINTPEND_REG(bank->eint_offset); writel(1 << index, reg); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa70100.00%1100.00%
Total70100.00%1100.00%


static int s3c64xx_gpio_irq_set_type(struct irq_data *irqd, unsigned int type) { struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd); struct samsung_pinctrl_drv_data *d = bank->drvdata; void __iomem *reg; int trigger; u8 shift; u32 val; trigger = s3c64xx_irq_get_trigger(type); if (trigger < 0) { pr_err("unsupported external interrupt type\n"); return -EINVAL; } s3c64xx_irq_set_handler(irqd, type); /* Set up interrupt trigger */ reg = d->virt_base + EINTCON_REG(bank->eint_offset); shift = EINT_OFFS(bank->eint_offset) + irqd->hwirq; shift = 4 * (shift / 4); /* 4 EINTs per trigger selector */ val = readl(reg); val &= ~(EINT_CON_MASK << shift); val |= trigger << shift; writel(val, reg); s3c64xx_irq_set_function(d, bank, irqd->hwirq); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa160100.00%1100.00%
Total160100.00%1100.00%

/* * irq_chip for gpio interrupts. */ static struct irq_chip s3c64xx_gpio_irq_chip = { .name = "GPIO", .irq_unmask = s3c64xx_gpio_irq_unmask, .irq_mask = s3c64xx_gpio_irq_mask, .irq_ack = s3c64xx_gpio_irq_ack, .irq_set_type = s3c64xx_gpio_irq_set_type, };
static int s3c64xx_gpio_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct samsung_pin_bank *bank = h->host_data; if (!(bank->eint_mask & (1 << hw))) return -EINVAL; irq_set_chip_and_handler(virq, &s3c64xx_gpio_irq_chip, handle_level_irq); irq_set_chip_data(virq, bank); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa66100.00%1100.00%
Total66100.00%1100.00%

/* * irq domain callbacks for external gpio interrupt controller. */ static const struct irq_domain_ops s3c64xx_gpio_irqd_ops = { .map = s3c64xx_gpio_irq_map, .xlate = irq_domain_xlate_twocell, };
static void s3c64xx_eint_gpio_irq(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct s3c64xx_eint_gpio_data *data = irq_desc_get_handler_data(desc); struct samsung_pinctrl_drv_data *drvdata = data->drvdata; chained_irq_enter(chip, desc); do { unsigned int svc; unsigned int group; unsigned int pin; unsigned int virq; svc = readl(drvdata->virt_base + SERVICE_REG); group = SVC_GROUP(svc); pin = svc & SVC_NUM_MASK; if (!group) break; /* Group 1 is used for two pin banks */ if (group == 1) { if (pin < 8) group = 0; else pin -= 8; } virq = irq_linear_revmap(data->domains[group], pin); /* * Something must be really wrong if an unmapped EINT * was unmasked... */ BUG_ON(!virq); generic_handle_irq(virq); } while (1); chained_irq_exit(chip, desc); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa15497.47%150.00%
jiang liujiang liu42.53%150.00%
Total158100.00%2100.00%

/** * s3c64xx_eint_gpio_init() - setup handling of external gpio interrupts. * @d: driver data of samsung pinctrl driver. */
static int s3c64xx_eint_gpio_init(struct samsung_pinctrl_drv_data *d) { struct s3c64xx_eint_gpio_data *data; struct samsung_pin_bank *bank; struct device *dev = d->dev; unsigned int nr_domains; unsigned int i; if (!d->irq) { dev_err(dev, "irq number not available\n"); return -EINVAL; } nr_domains = 0; bank = d->pin_banks; for (i = 0; i < d->nr_banks; ++i, ++bank) { unsigned int nr_eints; unsigned int mask; if (bank->eint_type != EINT_TYPE_GPIO) continue; mask = bank->eint_mask; nr_eints = fls(mask); bank->irq_domain = irq_domain_add_linear(bank->of_node, nr_eints, &s3c64xx_gpio_irqd_ops, bank); if (!bank->irq_domain) { dev_err(dev, "gpio irq domain add failed\n"); return -ENXIO; } ++nr_domains; } data = devm_kzalloc(dev, sizeof(*data) + nr_domains * sizeof(*data->domains), GFP_KERNEL); if (!data) { dev_err(dev, "failed to allocate handler data\n"); return -ENOMEM; } data->drvdata = d; bank = d->pin_banks; nr_domains = 0; for (i = 0; i < d->nr_banks; ++i, ++bank) { if (bank->eint_type != EINT_TYPE_GPIO) continue; data->domains[nr_domains++] = bank->irq_domain; } irq_set_chained_handler_and_data(d->irq, s3c64xx_eint_gpio_irq, data); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa27299.63%150.00%
thomas gleixnerthomas gleixner10.37%150.00%
Total273100.00%2100.00%

/* * Functions for configuration of EINT0 wake-up interrupts */
static inline void s3c64xx_eint0_irq_set_mask(struct irq_data *irqd, bool mask) { struct s3c64xx_eint0_domain_data *ddata = irq_data_get_irq_chip_data(irqd); struct samsung_pinctrl_drv_data *d = ddata->bank->drvdata; u32 val; val = readl(d->virt_base + EINT0MASK_REG); if (mask) val |= 1 << ddata->eints[irqd->hwirq]; else val &= ~(1 << ddata->eints[irqd->hwirq]); writel(val, d->virt_base + EINT0MASK_REG); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa95100.00%1100.00%
Total95100.00%1100.00%


static void s3c64xx_eint0_irq_unmask(struct irq_data *irqd) { s3c64xx_eint0_irq_set_mask(irqd, false); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa18100.00%1100.00%
Total18100.00%1100.00%


static void s3c64xx_eint0_irq_mask(struct irq_data *irqd) { s3c64xx_eint0_irq_set_mask(irqd, true); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa18100.00%1100.00%
Total18100.00%1100.00%


static void s3c64xx_eint0_irq_ack(struct irq_data *irqd) { struct s3c64xx_eint0_domain_data *ddata = irq_data_get_irq_chip_data(irqd); struct samsung_pinctrl_drv_data *d = ddata->bank->drvdata; writel(1 << ddata->eints[irqd->hwirq], d->virt_base + EINT0PEND_REG); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa52100.00%1100.00%
Total52100.00%1100.00%


static int s3c64xx_eint0_irq_set_type(struct irq_data *irqd, unsigned int type) { struct s3c64xx_eint0_domain_data *ddata = irq_data_get_irq_chip_data(irqd); struct samsung_pin_bank *bank = ddata->bank; struct samsung_pinctrl_drv_data *d = bank->drvdata; void __iomem *reg; int trigger; u8 shift; u32 val; trigger = s3c64xx_irq_get_trigger(type); if (trigger < 0) { pr_err("unsupported external interrupt type\n"); return -EINVAL; } s3c64xx_irq_set_handler(irqd, type); /* Set up interrupt trigger */ reg = d->virt_base + EINT0CON0_REG; shift = ddata->eints[irqd->hwirq]; if (shift >= EINT_MAX_PER_REG) { reg += 4; shift -= EINT_MAX_PER_REG; } shift = EINT_CON_LEN * (shift / 2); val = readl(reg); val &= ~(EINT_CON_MASK << shift); val |= trigger << shift; writel(val, reg); s3c64xx_irq_set_function(d, bank, irqd->hwirq); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa177100.00%1100.00%
Total177100.00%1100.00%

/* * irq_chip for wakeup interrupts */ static struct irq_chip s3c64xx_eint0_irq_chip = { .name = "EINT0", .irq_unmask = s3c64xx_eint0_irq_unmask, .irq_mask = s3c64xx_eint0_irq_mask, .irq_ack = s3c64xx_eint0_irq_ack, .irq_set_type = s3c64xx_eint0_irq_set_type, };
static inline void s3c64xx_irq_demux_eint(struct irq_desc *desc, u32 range) { struct irq_chip *chip = irq_desc_get_chip(desc); struct s3c64xx_eint0_data *data = irq_desc_get_handler_data(desc); struct samsung_pinctrl_drv_data *drvdata = data->drvdata; unsigned int pend, mask; chained_irq_enter(chip, desc); pend = readl(drvdata->virt_base + EINT0PEND_REG); mask = readl(drvdata->virt_base + EINT0MASK_REG); pend = pend & range & ~mask; pend &= range; while (pend) { unsigned int virq, irq; irq = fls(pend) - 1; pend &= ~(1 << irq); virq = irq_linear_revmap(data->domains[irq], data->pins[irq]); /* * Something must be really wrong if an unmapped EINT * was unmasked... */ BUG_ON(!virq); generic_handle_irq(virq); } chained_irq_exit(chip, desc); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa15496.25%150.00%
jiang liujiang liu63.75%150.00%
Total160100.00%2100.00%


static void s3c64xx_demux_eint0_3(struct irq_desc *desc) { s3c64xx_irq_demux_eint(desc, 0xf); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa18100.00%1100.00%
Total18100.00%1100.00%


static void s3c64xx_demux_eint4_11(struct irq_desc *desc) { s3c64xx_irq_demux_eint(desc, 0xff0); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa18100.00%1100.00%
Total18100.00%1100.00%


static void s3c64xx_demux_eint12_19(struct irq_desc *desc) { s3c64xx_irq_demux_eint(desc, 0xff000); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa18100.00%1100.00%
Total18100.00%1100.00%


static void s3c64xx_demux_eint20_27(struct irq_desc *desc) { s3c64xx_irq_demux_eint(desc, 0xff00000); }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa18100.00%1100.00%
Total18100.00%1100.00%

static irq_flow_handler_t s3c64xx_eint0_handlers[NUM_EINT0_IRQ] = { s3c64xx_demux_eint0_3, s3c64xx_demux_eint4_11, s3c64xx_demux_eint12_19, s3c64xx_demux_eint20_27, };
static int s3c64xx_eint0_irq_map(struct irq_domain *h, unsigned int virq, irq_hw_number_t hw) { struct s3c64xx_eint0_domain_data *ddata = h->host_data; struct samsung_pin_bank *bank = ddata->bank; if (!(bank->eint_mask & (1 << hw))) return -EINVAL; irq_set_chip_and_handler(virq, &s3c64xx_eint0_irq_chip, handle_level_irq); irq_set_chip_data(virq, ddata); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa75100.00%1100.00%
Total75100.00%1100.00%

/* * irq domain callbacks for external wakeup interrupt controller. */ static const struct irq_domain_ops s3c64xx_eint0_irqd_ops = { .map = s3c64xx_eint0_irq_map, .xlate = irq_domain_xlate_twocell, }; /* list of external wakeup controllers supported */ static const struct of_device_id s3c64xx_eint0_irq_ids[] = { { .compatible = "samsung,s3c64xx-wakeup-eint", }, { } }; /** * s3c64xx_eint_eint0_init() - setup handling of external wakeup interrupts. * @d: driver data of samsung pinctrl driver. */
static int s3c64xx_eint_eint0_init(struct samsung_pinctrl_drv_data *d) { struct device *dev = d->dev; struct device_node *eint0_np = NULL; struct device_node *np; struct samsung_pin_bank *bank; struct s3c64xx_eint0_data *data; unsigned int i; for_each_child_of_node(dev->of_node, np) { if (of_match_node(s3c64xx_eint0_irq_ids, np)) { eint0_np = np; break; } } if (!eint0_np) return -ENODEV; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); if (!data) { dev_err(dev, "could not allocate memory for wkup eint data\n"); return -ENOMEM; } data->drvdata = d; for (i = 0; i < NUM_EINT0_IRQ; ++i) { unsigned int irq; irq = irq_of_parse_and_map(eint0_np, i); if (!irq) { dev_err(dev, "failed to get wakeup EINT IRQ %d\n", i); return -ENXIO; } irq_set_chained_handler_and_data(irq, s3c64xx_eint0_handlers[i], data); } bank = d->pin_banks; for (i = 0; i < d->nr_banks; ++i, ++bank) { struct s3c64xx_eint0_domain_data *ddata; unsigned int nr_eints; unsigned int mask; unsigned int irq; unsigned int pin; if (bank->eint_type != EINT_TYPE_WKUP) continue; mask = bank->eint_mask; nr_eints = fls(mask); ddata = devm_kzalloc(dev, sizeof(*ddata) + nr_eints, GFP_KERNEL); if (!ddata) { dev_err(dev, "failed to allocate domain data\n"); return -ENOMEM; } ddata->bank = bank; bank->irq_domain = irq_domain_add_linear(bank->of_node, nr_eints, &s3c64xx_eint0_irqd_ops, ddata); if (!bank->irq_domain) { dev_err(dev, "wkup irq domain add failed\n"); return -ENXIO; } irq = bank->eint_offset; mask = bank->eint_mask; for (pin = 0; mask; ++pin, mask >>= 1) { if (!(mask & 1)) continue; data->domains[irq] = bank->irq_domain; data->pins[irq] = pin; ddata->eints[pin] = irq; ++irq; } } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa39999.75%150.00%
thomas gleixnerthomas gleixner10.25%150.00%
Total400100.00%2100.00%

/* pin banks of s3c64xx pin-controller 0 */ static const struct samsung_pin_bank_data s3c64xx_pin_banks0[] __initconst = { PIN_BANK_4BIT_EINTG(8, 0x000, "gpa", 0), PIN_BANK_4BIT_EINTG(7, 0x020, "gpb", 8), PIN_BANK_4BIT_EINTG(8, 0x040, "gpc", 16), PIN_BANK_4BIT_EINTG(5, 0x060, "gpd", 32), PIN_BANK_4BIT(5, 0x080, "gpe"), PIN_BANK_2BIT_EINTG(16, 0x0a0, "gpf", 48, 0x3fff), PIN_BANK_4BIT_EINTG(7, 0x0c0, "gpg", 64), PIN_BANK_4BIT2_EINTG(10, 0x0e0, "gph", 80), PIN_BANK_2BIT(16, 0x100, "gpi"), PIN_BANK_2BIT(12, 0x120, "gpj"), PIN_BANK_4BIT2_ALIVE(16, 0x800, "gpk"), PIN_BANK_4BIT2_EINTW(15, 0x810, "gpl", 16, 0x7f00), PIN_BANK_4BIT_EINTW(6, 0x820, "gpm", 23, 0x1f), PIN_BANK_2BIT_EINTW(16, 0x830, "gpn", 0), PIN_BANK_2BIT_EINTG(16, 0x140, "gpo", 96, 0xffff), PIN_BANK_2BIT_EINTG(15, 0x160, "gpp", 112, 0x7fff), PIN_BANK_2BIT_EINTG(9, 0x180, "gpq", 128, 0x1ff), }; /* * Samsung pinctrl driver data for S3C64xx SoC. S3C64xx SoC includes * one gpio/pin-mux/pinconfig controller. */ const struct samsung_pin_ctrl s3c64xx_pin_ctrl[] __initconst = { { /* pin-controller instance 1 data */ .pin_banks = s3c64xx_pin_banks0, .nr_banks = ARRAY_SIZE(s3c64xx_pin_banks0), .eint_gpio_init = s3c64xx_eint_gpio_init, .eint_wkup_init = s3c64xx_eint_eint0_init, }, };

Overall Contributors

PersonTokensPropCommitsCommitProp
tomasz figatomasz figa313499.37%562.50%
thomas gleixnerthomas gleixner100.32%225.00%
jiang liujiang liu100.32%112.50%
Total3154100.00%8100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}