cregit-Linux how code gets into the kernel

Release 4.11 drivers/pinctrl/qcom/pinctrl-msm.c

/*
 * Copyright (c) 2013, Sony Mobile Communications AB.
 * Copyright (c) 2013, The Linux Foundation. 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 version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * 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/delay.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pinctrl/machine.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/reboot.h>
#include <linux/pm.h>
#include <linux/log2.h>

#include "../core.h"
#include "../pinconf.h"
#include "pinctrl-msm.h"
#include "../pinctrl-utils.h"


#define MAX_NR_GPIO 300

#define PS_HOLD_OFFSET 0x820

/**
 * struct msm_pinctrl - state for a pinctrl-msm device
 * @dev:            device handle.
 * @pctrl:          pinctrl handle.
 * @chip:           gpiochip handle.
 * @restart_nb:     restart notifier block.
 * @irq:            parent irq for the TLMM irq_chip.
 * @lock:           Spinlock to protect register resources as well
 *                  as msm_pinctrl data structures.
 * @enabled_irqs:   Bitmap of currently enabled irqs.
 * @dual_edge_irqs: Bitmap of irqs that need sw emulated dual edge
 *                  detection.
 * @soc;            Reference to soc_data of platform specific data.
 * @regs:           Base address for the TLMM register map.
 */

struct msm_pinctrl {
	
struct device *dev;
	
struct pinctrl_dev *pctrl;
	
struct gpio_chip chip;
	
struct notifier_block restart_nb;
	
int irq;

	
raw_spinlock_t lock;

	DECLARE_BITMAP(dual_edge_irqs, MAX_NR_GPIO);
	DECLARE_BITMAP(enabled_irqs, MAX_NR_GPIO);

	
const struct msm_pinctrl_soc_data *soc;
	
void __iomem *regs;
};


static int msm_get_groups_count(struct pinctrl_dev *pctldev) { struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); return pctrl->soc->ngroups; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson28100.00%1100.00%
Total28100.00%1100.00%


static const char *msm_get_group_name(struct pinctrl_dev *pctldev, unsigned group) { struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); return pctrl->soc->groups[group].name; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson38100.00%1100.00%
Total38100.00%1100.00%


static int msm_get_group_pins(struct pinctrl_dev *pctldev, unsigned group, const unsigned **pins, unsigned *num_pins) { struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); *pins = pctrl->soc->groups[group].pins; *num_pins = pctrl->soc->groups[group].npins; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson65100.00%1100.00%
Total65100.00%1100.00%

static const struct pinctrl_ops msm_pinctrl_ops = { .get_groups_count = msm_get_groups_count, .get_group_name = msm_get_group_name, .get_group_pins = msm_get_group_pins, .dt_node_to_map = pinconf_generic_dt_node_to_map_group, .dt_free_map = pinctrl_utils_free_map, };
static int msm_get_functions_count(struct pinctrl_dev *pctldev) { struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); return pctrl->soc->nfunctions; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson28100.00%1100.00%
Total28100.00%1100.00%


static const char *msm_get_function_name(struct pinctrl_dev *pctldev, unsigned function) { struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); return pctrl->soc->functions[function].name; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson38100.00%1100.00%
Total38100.00%1100.00%


static int msm_get_function_groups(struct pinctrl_dev *pctldev, unsigned function, const char * const **groups, unsigned * const num_groups) { struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); *groups = pctrl->soc->functions[function].groups; *num_groups = pctrl->soc->functions[function].ngroups; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson68100.00%1100.00%
Total68100.00%1100.00%


static int msm_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function, unsigned group) { struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); const struct msm_pingroup *g; unsigned long flags; u32 val, mask; int i; g = &pctrl->soc->groups[group]; mask = GENMASK(g->mux_bit + order_base_2(g->nfuncs) - 1, g->mux_bit); for (i = 0; i < g->nfuncs; i++) { if (g->funcs[i] == function) break; } if (WARN_ON(i == g->nfuncs)) return -EINVAL; raw_spin_lock_irqsave(&pctrl->lock, flags); val = readl(pctrl->regs + g->ctl_reg); val &= ~mask; val |= i << g->mux_bit; writel(val, pctrl->regs + g->ctl_reg); raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson15684.32%233.33%
Stephen Boyd2513.51%116.67%
Julia Cartwright21.08%116.67%
John Crispin10.54%116.67%
Linus Walleij10.54%116.67%
Total185100.00%6100.00%

static const struct pinmux_ops msm_pinmux_ops = { .get_functions_count = msm_get_functions_count, .get_function_name = msm_get_function_name, .get_function_groups = msm_get_function_groups, .set_mux = msm_pinmux_set_mux, };
static int msm_config_reg(struct msm_pinctrl *pctrl, const struct msm_pingroup *g, unsigned param, unsigned *mask, unsigned *bit) { switch (param) { case PIN_CONFIG_BIAS_DISABLE: case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_BUS_HOLD: case PIN_CONFIG_BIAS_PULL_UP: *bit = g->pull_bit; *mask = 3; break; case PIN_CONFIG_DRIVE_STRENGTH: *bit = g->drv_bit; *mask = 7; break; case PIN_CONFIG_OUTPUT: case PIN_CONFIG_INPUT_ENABLE: *bit = g->oe_bit; *mask = 1; break; default: return -ENOTSUPP; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson9694.12%250.00%
Stanimir Varbanov32.94%125.00%
Andy Gross32.94%125.00%
Total102100.00%4100.00%

#define MSM_NO_PULL 0 #define MSM_PULL_DOWN 1 #define MSM_KEEPER 2 #define MSM_PULL_UP 3
static unsigned msm_regval_to_drive(u32 val) { return (val + 1) * 2; }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Boyd1161.11%150.00%
Björn Andersson738.89%150.00%
Total18100.00%2100.00%


static int msm_config_group_get(struct pinctrl_dev *pctldev, unsigned int group, unsigned long *config) { const struct msm_pingroup *g; struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); unsigned param = pinconf_to_config_param(*config); unsigned mask; unsigned arg; unsigned bit; int ret; u32 val; g = &pctrl->soc->groups[group]; ret = msm_config_reg(pctrl, g, param, &mask, &bit); if (ret < 0) return ret; val = readl(pctrl->regs + g->ctl_reg); arg = (val >> bit) & mask; /* Convert register value to pinconf value */ switch (param) { case PIN_CONFIG_BIAS_DISABLE: arg = arg == MSM_NO_PULL; break; case PIN_CONFIG_BIAS_PULL_DOWN: arg = arg == MSM_PULL_DOWN; break; case PIN_CONFIG_BIAS_BUS_HOLD: arg = arg == MSM_KEEPER; break; case PIN_CONFIG_BIAS_PULL_UP: arg = arg == MSM_PULL_UP; break; case PIN_CONFIG_DRIVE_STRENGTH: arg = msm_regval_to_drive(arg); break; case PIN_CONFIG_OUTPUT: /* Pin is not output */ if (!arg) return -EINVAL; val = readl(pctrl->regs + g->io_reg); arg = !!(val & BIT(g->in_bit)); break; case PIN_CONFIG_INPUT_ENABLE: /* Pin is output */ if (arg) return -EINVAL; arg = 1; break; default: return -ENOTSUPP; } *config = pinconf_to_config_packed(param, arg); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson22387.11%228.57%
Stanimir Varbanov187.03%228.57%
Andy Gross103.91%114.29%
Stephen Boyd51.95%228.57%
Total256100.00%7100.00%


static int msm_config_group_set(struct pinctrl_dev *pctldev, unsigned group, unsigned long *configs, unsigned num_configs) { const struct msm_pingroup *g; struct msm_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); unsigned long flags; unsigned param; unsigned mask; unsigned arg; unsigned bit; int ret; u32 val; int i; g = &pctrl->soc->groups[group]; for (i = 0; i < num_configs; i++) { param = pinconf_to_config_param(configs[i]); arg = pinconf_to_config_argument(configs[i]); ret = msm_config_reg(pctrl, g, param, &mask, &bit); if (ret < 0) return ret; /* Convert pinconf values to register values */ switch (param) { case PIN_CONFIG_BIAS_DISABLE: arg = MSM_NO_PULL; break; case PIN_CONFIG_BIAS_PULL_DOWN: arg = MSM_PULL_DOWN; break; case PIN_CONFIG_BIAS_BUS_HOLD: arg = MSM_KEEPER; break; case PIN_CONFIG_BIAS_PULL_UP: arg = MSM_PULL_UP; break; case PIN_CONFIG_DRIVE_STRENGTH: /* Check for invalid values */ if (arg > 16 || arg < 2 || (arg % 2) != 0) arg = -1; else arg = (arg / 2) - 1; break; case PIN_CONFIG_OUTPUT: /* set output value */ raw_spin_lock_irqsave(&pctrl->lock, flags); val = readl(pctrl->regs + g->io_reg); if (arg) val |= BIT(g->out_bit); else val &= ~BIT(g->out_bit); writel(val, pctrl->regs + g->io_reg); raw_spin_unlock_irqrestore(&pctrl->lock, flags); /* enable output */ arg = 1; break; case PIN_CONFIG_INPUT_ENABLE: /* disable output */ arg = 0; break; default: dev_err(pctrl->dev, "Unsupported config parameter: %x\n", param); return -EINVAL; } /* Range-check user-supplied value */ if (arg & ~mask) { dev_err(pctrl->dev, "config %x: %x is invalid\n", param, arg); return -EINVAL; } raw_spin_lock_irqsave(&pctrl->lock, flags); val = readl(pctrl->regs + g->ctl_reg); val &= ~(mask << bit); val |= arg << bit; writel(val, pctrl->regs + g->ctl_reg); raw_spin_unlock_irqrestore(&pctrl->lock, flags); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson36388.54%228.57%
Stephen Boyd266.34%228.57%
Stanimir Varbanov92.20%114.29%
Andy Gross81.95%114.29%
Julia Cartwright40.98%114.29%
Total410100.00%7100.00%

static const struct pinconf_ops msm_pinconf_ops = { .is_generic = true, .pin_config_group_get = msm_config_group_get, .pin_config_group_set = msm_config_group_set, }; static struct pinctrl_desc msm_pinctrl_desc = { .pctlops = &msm_pinctrl_ops, .pmxops = &msm_pinmux_ops, .confops = &msm_pinconf_ops, .owner = THIS_MODULE, };
static int msm_gpio_direction_input(struct gpio_chip *chip, unsigned offset) { const struct msm_pingroup *g; struct msm_pinctrl *pctrl = gpiochip_get_data(chip); unsigned long flags; u32 val; g = &pctrl->soc->groups[offset]; raw_spin_lock_irqsave(&pctrl->lock, flags); val = readl(pctrl->regs + g->ctl_reg); val &= ~BIT(g->oe_bit); writel(val, pctrl->regs + g->ctl_reg); raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson10597.22%133.33%
Julia Cartwright21.85%133.33%
Linus Walleij10.93%133.33%
Total108100.00%3100.00%


static int msm_gpio_direction_output(struct gpio_chip *chip, unsigned offset, int value) { const struct msm_pingroup *g; struct msm_pinctrl *pctrl = gpiochip_get_data(chip); unsigned long flags; u32 val; g = &pctrl->soc->groups[offset]; raw_spin_lock_irqsave(&pctrl->lock, flags); val = readl(pctrl->regs + g->io_reg); if (value) val |= BIT(g->out_bit); else val &= ~BIT(g->out_bit); writel(val, pctrl->regs + g->io_reg); val = readl(pctrl->regs + g->ctl_reg); val |= BIT(g->oe_bit); writel(val, pctrl->regs + g->ctl_reg); raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson12578.12%125.00%
Axel Lin3220.00%125.00%
Julia Cartwright21.25%125.00%
Linus Walleij10.62%125.00%
Total160100.00%4100.00%


static int msm_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { struct msm_pinctrl *pctrl = gpiochip_get_data(chip); const struct msm_pingroup *g; u32 val; g = &pctrl->soc->groups[offset]; val = readl(pctrl->regs + g->ctl_reg); /* 0 = output, 1 = input */ return val & BIT(g->oe_bit) ? 0 : 1; }

Contributors

PersonTokensPropCommitsCommitProp
Timur Tabi74100.00%1100.00%
Total74100.00%1100.00%


static int msm_gpio_get(struct gpio_chip *chip, unsigned offset) { const struct msm_pingroup *g; struct msm_pinctrl *pctrl = gpiochip_get_data(chip); u32 val; g = &pctrl->soc->groups[offset]; val = readl(pctrl->regs + g->io_reg); return !!(val & BIT(g->in_bit)); }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson7198.61%150.00%
Linus Walleij11.39%150.00%
Total72100.00%2100.00%


static void msm_gpio_set(struct gpio_chip *chip, unsigned offset, int value) { const struct msm_pingroup *g; struct msm_pinctrl *pctrl = gpiochip_get_data(chip); unsigned long flags; u32 val; g = &pctrl->soc->groups[offset]; raw_spin_lock_irqsave(&pctrl->lock, flags); val = readl(pctrl->regs + g->io_reg); if (value) val |= BIT(g->out_bit); else val &= ~BIT(g->out_bit); writel(val, pctrl->regs + g->io_reg); raw_spin_unlock_irqrestore(&pctrl->lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson10485.25%125.00%
Axel Lin1512.30%125.00%
Julia Cartwright21.64%125.00%
Linus Walleij10.82%125.00%
Total122100.00%4100.00%

#ifdef CONFIG_DEBUG_FS #include <linux/seq_file.h>
static void msm_gpio_dbg_show_one(struct seq_file *s, struct pinctrl_dev *pctldev, struct gpio_chip *chip, unsigned offset, unsigned gpio) { const struct msm_pingroup *g; struct msm_pinctrl *pctrl = gpiochip_get_data(chip); unsigned func; int is_out; int drive; int pull; u32 ctl_reg; static const char * const pulls[] = { "no pull", "pull down", "keeper", "pull up" }; g = &pctrl->soc->groups[offset]; ctl_reg = readl(pctrl->regs + g->ctl_reg); is_out = !!(ctl_reg & BIT(g->oe_bit)); func = (ctl_reg >> g->mux_bit) & 7; drive = (ctl_reg >> g->drv_bit) & 7; pull = (ctl_reg >> g->pull_bit) & 3; seq_printf(s, " %-8s: %-3s %d", g->name, is_out ? "out" : "in", func); seq_printf(s, " %dmA", msm_regval_to_drive(drive)); seq_printf(s, " %s", pulls[pull]); }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson19298.46%250.00%
Stephen Boyd21.03%125.00%
Linus Walleij10.51%125.00%
Total195100.00%4100.00%


static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) { unsigned gpio = chip->base; unsigned i; for (i = 0; i < chip->ngpio; i++, gpio++) { msm_gpio_dbg_show_one(s, NULL, chip, i, gpio); seq_puts(s, "\n"); } }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson66100.00%2100.00%
Total66100.00%2100.00%

#else #define msm_gpio_dbg_show NULL #endif static struct gpio_chip msm_gpio_template = { .direction_input = msm_gpio_direction_input, .direction_output = msm_gpio_direction_output, .get_direction = msm_gpio_get_direction, .get = msm_gpio_get, .set = msm_gpio_set, .request = gpiochip_generic_request, .free = gpiochip_generic_free, .dbg_show = msm_gpio_dbg_show, }; /* For dual-edge interrupts in software, since some hardware has no * such support: * * At appropriate moments, this function may be called to flip the polarity * settings of both-edge irq lines to try and catch the next edge. * * The attempt is considered successful if: * - the status bit goes high, indicating that an edge was caught, or * - the input value of the gpio doesn't change during the attempt. * If the value changes twice during the process, that would cause the first * test to fail but would force the second, as two opposite * transitions would cause a detection no matter the polarity setting. * * The do-loop tries to sledge-hammer closed the timing hole between * the initial value-read and the polarity-write - if the line value changes * during that window, an interrupt is lost, the new polarity setting is * incorrect, and the first success test will fail, causing a retry. * * Algorithm comes from Google's msmgpio driver. */
static void msm_gpio_update_dual_edge_pos(struct msm_pinctrl *pctrl, const struct msm_pingroup *g, struct irq_data *d) { int loop_limit = 100; unsigned val, val2, intstat; unsigned pol; do { val = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit); pol = readl(pctrl->regs + g->intr_cfg_reg); pol ^= BIT(g->intr_polarity_bit); writel(pol, pctrl->regs + g->intr_cfg_reg); val2 = readl(pctrl->regs + g->io_reg) & BIT(g->in_bit); intstat = readl(pctrl->regs + g->intr_status_reg); if (intstat || (val == val2)) return; } while (loop_limit-- > 0); dev_err(pctrl->dev, "dual-edge irq failed to stabilize, %#08x != %#08x\n", val, val2); }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson160100.00%1100.00%
Total160100.00%1100.00%


static void msm_gpio_irq_mask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); const struct msm_pingroup *g; unsigned long flags; u32 val; g = &pctrl->soc->groups[d->hwirq]; raw_spin_lock_irqsave(&pctrl->lock, flags); val = readl(pctrl->regs + g->intr_cfg_reg); val &= ~BIT(g->intr_enable_bit); writel(val, pctrl->regs + g->intr_cfg_reg); clear_bit(d->hwirq, pctrl->enabled_irqs); raw_spin_unlock_irqrestore(&pctrl->lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson10584.00%125.00%
Linus Walleij1814.40%250.00%
Julia Cartwright21.60%125.00%
Total125100.00%4100.00%


static void msm_gpio_irq_unmask(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); const struct msm_pingroup *g; unsigned long flags; u32 val; g = &pctrl->soc->groups[d->hwirq]; raw_spin_lock_irqsave(&pctrl->lock, flags); val = readl(pctrl->regs + g->intr_cfg_reg); val |= BIT(g->intr_enable_bit); writel(val, pctrl->regs + g->intr_cfg_reg); set_bit(d->hwirq, pctrl->enabled_irqs); raw_spin_unlock_irqrestore(&pctrl->lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson10483.87%125.00%
Linus Walleij1814.52%250.00%
Julia Cartwright21.61%125.00%
Total124100.00%4100.00%


static void msm_gpio_irq_ack(struct irq_data *d) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); const struct msm_pingroup *g; unsigned long flags; u32 val; g = &pctrl->soc->groups[d->hwirq]; raw_spin_lock_irqsave(&pctrl->lock, flags); val = readl(pctrl->regs + g->intr_status_reg); if (g->intr_ack_high) val |= BIT(g->intr_status_bit); else val &= ~BIT(g->intr_status_bit); writel(val, pctrl->regs + g->intr_status_reg); if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) msm_gpio_update_dual_edge_pos(pctrl, g, d); raw_spin_unlock_irqrestore(&pctrl->lock, flags); }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson13286.84%240.00%
Linus Walleij1811.84%240.00%
Julia Cartwright21.32%120.00%
Total152100.00%5100.00%


static int msm_gpio_irq_set_type(struct irq_data *d, unsigned int type) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); const struct msm_pingroup *g; unsigned long flags; u32 val; g = &pctrl->soc->groups[d->hwirq]; raw_spin_lock_irqsave(&pctrl->lock, flags); /* * For hw without possibility of detecting both edges */ if (g->intr_detection_width == 1 && type == IRQ_TYPE_EDGE_BOTH) set_bit(d->hwirq, pctrl->dual_edge_irqs); else clear_bit(d->hwirq, pctrl->dual_edge_irqs); /* Route interrupts to application cpu */ val = readl(pctrl->regs + g->intr_target_reg); val &= ~(7 << g->intr_target_bit); val |= g->intr_target_kpss_val << g->intr_target_bit; writel(val, pctrl->regs + g->intr_target_reg); /* Update configuration for gpio. * RAW_STATUS_EN is left on for all gpio irqs. Due to the * internal circuitry of TLMM, toggling the RAW_STATUS * could cause the INTR_STATUS to be set for EDGE interrupts. */ val = readl(pctrl->regs + g->intr_cfg_reg); val |= BIT(g->intr_raw_status_bit); if (g->intr_detection_width == 2) { val &= ~(3 << g->intr_detection_bit); val &= ~(1 << g->intr_polarity_bit); switch (type) { case IRQ_TYPE_EDGE_RISING: val |= 1 << g->intr_detection_bit; val |= BIT(g->intr_polarity_bit); break; case IRQ_TYPE_EDGE_FALLING: val |= 2 << g->intr_detection_bit; val |= BIT(g->intr_polarity_bit); break; case IRQ_TYPE_EDGE_BOTH: val |= 3 << g->intr_detection_bit; val |= BIT(g->intr_polarity_bit); break; case IRQ_TYPE_LEVEL_LOW: break; case IRQ_TYPE_LEVEL_HIGH: val |= BIT(g->intr_polarity_bit); break; } } else if (g->intr_detection_width == 1) { val &= ~(1 << g->intr_detection_bit); val &= ~(1 << g->intr_polarity_bit); switch (type) { case IRQ_TYPE_EDGE_RISING: val |= BIT(g->intr_detection_bit); val |= BIT(g->intr_polarity_bit); break; case IRQ_TYPE_EDGE_FALLING: val |= BIT(g->intr_detection_bit); break; case IRQ_TYPE_EDGE_BOTH: val |= BIT(g->intr_detection_bit); val |= BIT(g->intr_polarity_bit); break; case IRQ_TYPE_LEVEL_LOW: break; case IRQ_TYPE_LEVEL_HIGH: val |= BIT(g->intr_polarity_bit); break; } } else { BUG(); } writel(val, pctrl->regs + g->intr_cfg_reg); if (test_bit(d->hwirq, pctrl->dual_edge_irqs)) msm_gpio_update_dual_edge_pos(pctrl, g, d); raw_spin_unlock_irqrestore(&pctrl->lock, flags); if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) irq_set_handler_locked(d, handle_level_irq); else if (type & (IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING)) irq_set_handler_locked(d, handle_edge_irq); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson47494.99%228.57%
Linus Walleij183.61%228.57%
Georgi Djakov30.60%114.29%
Julia Cartwright20.40%114.29%
Thomas Gleixner20.40%114.29%
Total499100.00%7100.00%


static int msm_gpio_irq_set_wake(struct irq_data *d, unsigned int on) { struct gpio_chip *gc = irq_data_get_irq_chip_data(d); struct msm_pinctrl *pctrl = gpiochip_get_data(gc); unsigned long flags; raw_spin_lock_irqsave(&pctrl->lock, flags); irq_set_irq_wake(pctrl->irq, on); raw_spin_unlock_irqrestore(&pctrl->lock, flags); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson5273.24%120.00%
Linus Walleij1521.13%240.00%
Julia Cartwright45.63%240.00%
Total71100.00%5100.00%

static struct irq_chip msm_gpio_irq_chip = { .name = "msmgpio", .irq_mask = msm_gpio_irq_mask, .irq_unmask = msm_gpio_irq_unmask, .irq_ack = msm_gpio_irq_ack, .irq_set_type = msm_gpio_irq_set_type, .irq_set_wake = msm_gpio_irq_set_wake, };
static void msm_gpio_irq_handler(struct irq_desc *desc) { struct gpio_chip *gc = irq_desc_get_handler_data(desc); const struct msm_pingroup *g; struct msm_pinctrl *pctrl = gpiochip_get_data(gc); struct irq_chip *chip = irq_desc_get_chip(desc); int irq_pin; int handled = 0; u32 val; int i; chained_irq_enter(chip, desc); /* * Each pin has it's own IRQ status register, so use * enabled_irq bitmap to limit the number of reads. */ for_each_set_bit(i, pctrl->enabled_irqs, pctrl->chip.ngpio) { g = &pctrl->soc->groups[i]; val = readl(pctrl->regs + g->intr_status_reg); if (val & BIT(g->intr_status_bit)) { irq_pin = irq_find_mapping(gc->irqdomain, i); generic_handle_irq(irq_pin); handled++; } } /* No interrupts were flagged */ if (handled == 0) handle_bad_irq(desc); chained_irq_exit(chip, desc); }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson13989.68%240.00%
Linus Walleij149.03%240.00%
Jiang Liu21.29%120.00%
Total155100.00%5100.00%


static int msm_gpio_init(struct msm_pinctrl *pctrl) { struct gpio_chip *chip; int ret; unsigned ngpio = pctrl->soc->ngpios; if (WARN_ON(ngpio > MAX_NR_GPIO)) return -EINVAL; chip = &pctrl->chip; chip->base = 0; chip->ngpio = ngpio; chip->label = dev_name(pctrl->dev); chip->parent = pctrl->dev; chip->owner = THIS_MODULE; chip->of_node = pctrl->dev->of_node; ret = gpiochip_add_data(&pctrl->chip, pctrl); if (ret) { dev_err(pctrl->dev, "Failed register gpiochip\n"); return ret; } ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev), 0, 0, chip->ngpio); if (ret) { dev_err(pctrl->dev, "Failed to add pin range\n"); gpiochip_remove(&pctrl->chip); return ret; } ret = gpiochip_irqchip_add(chip, &msm_gpio_irq_chip, 0, handle_edge_irq, IRQ_TYPE_NONE); if (ret) { dev_err(pctrl->dev, "Failed to add irqchip to gpiochip\n"); gpiochip_remove(&pctrl->chip); return -ENOSYS; } gpiochip_set_chained_irqchip(chip, &msm_gpio_irq_chip, pctrl->irq, msm_gpio_irq_handler); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson18176.69%116.67%
Stephen Boyd239.75%116.67%
Linus Walleij166.78%350.00%
Pramod Gurav166.78%116.67%
Total236100.00%6100.00%


static int msm_ps_hold_restart(struct notifier_block *nb, unsigned long action, void *data) { struct msm_pinctrl *pctrl = container_of(nb, struct msm_pinctrl, restart_nb); writel(0, pctrl->regs + PS_HOLD_OFFSET); mdelay(1000); return NOTIFY_DONE; }

Contributors

PersonTokensPropCommitsCommitProp
Julia Cartwright3667.92%150.00%
Pramod Gurav1732.08%150.00%
Total53100.00%2100.00%

static struct msm_pinctrl *poweroff_pctrl;
static void msm_ps_hold_poweroff(void) { msm_ps_hold_restart(&poweroff_pctrl->restart_nb, 0, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
Stephen Boyd20100.00%1100.00%
Total20100.00%1100.00%


static void msm_pinctrl_setup_pm_reset(struct msm_pinctrl *pctrl) { int i; const struct msm_function *func = pctrl->soc->functions; for (i = 0; i < pctrl->soc->nfunctions; i++) if (!strcmp(func[i].name, "ps_hold")) { pctrl->restart_nb.notifier_call = msm_ps_hold_restart; pctrl->restart_nb.priority = 128; if (register_restart_handler(&pctrl->restart_nb)) dev_err(pctrl->dev, "failed to setup restart handler.\n"); poweroff_pctrl = pctrl; pm_power_off = msm_ps_hold_poweroff; break; } }

Contributors

PersonTokensPropCommitsCommitProp
Pramod Gurav6158.65%125.00%
Julia Cartwright3129.81%125.00%
Stephen Boyd1211.54%250.00%
Total104100.00%4100.00%


int msm_pinctrl_probe(struct platform_device *pdev, const struct msm_pinctrl_soc_data *soc_data) { struct msm_pinctrl *pctrl; struct resource *res; int ret; pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL); if (!pctrl) { dev_err(&pdev->dev, "Can't allocate msm_pinctrl\n"); return -ENOMEM; } pctrl->dev = &pdev->dev; pctrl->soc = soc_data; pctrl->chip = msm_gpio_template; raw_spin_lock_init(&pctrl->lock); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); pctrl->regs = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(pctrl->regs)) return PTR_ERR(pctrl->regs); msm_pinctrl_setup_pm_reset(pctrl); pctrl->irq = platform_get_irq(pdev, 0); if (pctrl->irq < 0) { dev_err(&pdev->dev, "No interrupt defined for msmgpio\n"); return pctrl->irq; } msm_pinctrl_desc.name = dev_name(&pdev->dev); msm_pinctrl_desc.pins = pctrl->soc->pins; msm_pinctrl_desc.npins = pctrl->soc->npins; pctrl->pctrl = devm_pinctrl_register(&pdev->dev, &msm_pinctrl_desc, pctrl); if (IS_ERR(pctrl->pctrl)) { dev_err(&pdev->dev, "Couldn't register pinctrl driver\n"); return PTR_ERR(pctrl->pctrl); } ret = msm_gpio_init(pctrl); if (ret) return ret; platform_set_drvdata(pdev, pctrl); dev_dbg(&pdev->dev, "Probed Qualcomm pinctrl driver\n"); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson27393.49%233.33%
Masahiro Yamada93.08%116.67%
Pramod Gurav51.71%116.67%
Laxman Dewangan41.37%116.67%
Julia Cartwright10.34%116.67%
Total292100.00%6100.00%

EXPORT_SYMBOL(msm_pinctrl_probe);
int msm_pinctrl_remove(struct platform_device *pdev) { struct msm_pinctrl *pctrl = platform_get_drvdata(pdev); gpiochip_remove(&pctrl->chip); unregister_restart_handler(&pctrl->restart_nb); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson3179.49%266.67%
Julia Cartwright820.51%133.33%
Total39100.00%3100.00%

EXPORT_SYMBOL(msm_pinctrl_remove);

Overall Contributors

PersonTokensPropCommitsCommitProp
Björn Andersson374984.47%719.44%
Stephen Boyd1363.06%616.67%
Linus Walleij1282.88%513.89%
Pramod Gurav1082.43%25.56%
Julia Cartwright1072.41%38.33%
Timur Tabi791.78%12.78%
Axel Lin471.06%12.78%
Stanimir Varbanov350.79%25.56%
Andy Gross250.56%12.78%
Masahiro Yamada90.20%12.78%
Laxman Dewangan40.09%12.78%
Georgi Djakov30.07%12.78%
Jiang Liu20.05%12.78%
Thomas Gleixner20.05%12.78%
Jonas Gorski20.05%12.78%
Irina Tirdea10.02%12.78%
John Crispin10.02%12.78%
Total4438100.00%36100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.