Commit 6879c2d3 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull pin control fixes from Linus Walleij:
 "Nothing special, just driver fixes:

   - Fix IRQ wakeup and pins for UFS and SDC2 issues on the Qualcomm
     SC8180x

   - Fix the Rockchip driver to support interrupt on both rising and
     falling edges.

   - Name the Allwinner A100 R_PIO properly

   - Fix several issues with the Ocelot interrupts"

* tag 'pinctrl-v6.0-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-pinctrl:
  pinctrl: ocelot: Fix interrupt controller
  pinctrl: sunxi: Fix name for A100 R_PIO
  pinctrl: rockchip: Enhance support for IRQ_TYPE_EDGE_BOTH
  pinctrl: qcom: sc8180x: Fix wrong pin numbers
  pinctrl: qcom: sc8180x: Fix gpio_wakeirq_map
parents 68e777e4 c297561b
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -419,11 +419,11 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
			goto out;
		} else {
			bank->toggle_edge_mode |= mask;
			level |= mask;
			level &= ~mask;

			/*
			 * Determine gpio state. If 1 next interrupt should be
			 * falling otherwise rising.
			 * low otherwise high.
			 */
			data = readl(bank->reg_base + bank->gpio_regs->ext_port);
			if (data & mask)
+97 −14
Original line number Diff line number Diff line
@@ -331,6 +331,7 @@ struct ocelot_pinctrl {
	const struct ocelot_pincfg_data *pincfg_data;
	struct ocelot_pmx_func func[FUNC_MAX];
	u8 stride;
	struct workqueue_struct *wq;
};

struct ocelot_match_data {
@@ -338,6 +339,11 @@ struct ocelot_match_data {
	struct ocelot_pincfg_data pincfg_data;
};

struct ocelot_irq_work {
	struct work_struct irq_work;
	struct irq_desc *irq_desc;
};

#define LUTON_P(p, f0, f1)						\
static struct ocelot_pin_caps luton_pin_##p = {				\
	.pin = p,							\
@@ -1813,6 +1819,75 @@ static void ocelot_irq_mask(struct irq_data *data)
	gpiochip_disable_irq(chip, gpio);
}

static void ocelot_irq_work(struct work_struct *work)
{
	struct ocelot_irq_work *w = container_of(work, struct ocelot_irq_work, irq_work);
	struct irq_chip *parent_chip = irq_desc_get_chip(w->irq_desc);
	struct gpio_chip *chip = irq_desc_get_chip_data(w->irq_desc);
	struct irq_data *data = irq_desc_get_irq_data(w->irq_desc);
	unsigned int gpio = irqd_to_hwirq(data);

	local_irq_disable();
	chained_irq_enter(parent_chip, w->irq_desc);
	generic_handle_domain_irq(chip->irq.domain, gpio);
	chained_irq_exit(parent_chip, w->irq_desc);
	local_irq_enable();

	kfree(w);
}

static void ocelot_irq_unmask_level(struct irq_data *data)
{
	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
	struct ocelot_pinctrl *info = gpiochip_get_data(chip);
	struct irq_desc *desc = irq_data_to_desc(data);
	unsigned int gpio = irqd_to_hwirq(data);
	unsigned int bit = BIT(gpio % 32);
	bool ack = false, active = false;
	u8 trigger_level;
	int val;

	trigger_level = irqd_get_trigger_type(data);

	/* Check if the interrupt line is still active. */
	regmap_read(info->map, REG(OCELOT_GPIO_IN, info, gpio), &val);
	if ((!(val & bit) && trigger_level == IRQ_TYPE_LEVEL_LOW) ||
	      (val & bit && trigger_level == IRQ_TYPE_LEVEL_HIGH))
		active = true;

	/*
	 * Check if the interrupt controller has seen any changes in the
	 * interrupt line.
	 */
	regmap_read(info->map, REG(OCELOT_GPIO_INTR, info, gpio), &val);
	if (val & bit)
		ack = true;

	/* Enable the interrupt now */
	gpiochip_enable_irq(chip, gpio);
	regmap_update_bits(info->map, REG(OCELOT_GPIO_INTR_ENA, info, gpio),
			   bit, bit);

	/*
	 * In case the interrupt line is still active and the interrupt
	 * controller has not seen any changes in the interrupt line, then it
	 * means that there happen another interrupt while the line was active.
	 * So we missed that one, so we need to kick the interrupt again
	 * handler.
	 */
	if (active && !ack) {
		struct ocelot_irq_work *work;

		work = kmalloc(sizeof(*work), GFP_ATOMIC);
		if (!work)
			return;

		work->irq_desc = desc;
		INIT_WORK(&work->irq_work, ocelot_irq_work);
		queue_work(info->wq, &work->irq_work);
	}
}

static void ocelot_irq_unmask(struct irq_data *data)
{
	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
@@ -1836,13 +1911,12 @@ static void ocelot_irq_ack(struct irq_data *data)

static int ocelot_irq_set_type(struct irq_data *data, unsigned int type);

static struct irq_chip ocelot_eoi_irqchip = {
static struct irq_chip ocelot_level_irqchip = {
	.name		= "gpio",
	.irq_mask	= ocelot_irq_mask,
	.irq_eoi	= ocelot_irq_ack,
	.irq_unmask	= ocelot_irq_unmask,
	.flags          = IRQCHIP_EOI_THREADED | IRQCHIP_EOI_IF_HANDLED |
			  IRQCHIP_IMMUTABLE,
	.irq_ack	= ocelot_irq_ack,
	.irq_unmask	= ocelot_irq_unmask_level,
	.flags		= IRQCHIP_IMMUTABLE,
	.irq_set_type	= ocelot_irq_set_type,
	GPIOCHIP_IRQ_RESOURCE_HELPERS
};
@@ -1859,14 +1933,9 @@ static struct irq_chip ocelot_irqchip = {

static int ocelot_irq_set_type(struct irq_data *data, unsigned int type)
{
	type &= IRQ_TYPE_SENSE_MASK;

	if (!(type & (IRQ_TYPE_EDGE_BOTH | IRQ_TYPE_LEVEL_HIGH)))
		return -EINVAL;

	if (type & IRQ_TYPE_LEVEL_HIGH)
		irq_set_chip_handler_name_locked(data, &ocelot_eoi_irqchip,
						 handle_fasteoi_irq, NULL);
	if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
		irq_set_chip_handler_name_locked(data, &ocelot_level_irqchip,
						 handle_level_irq, NULL);
	if (type & IRQ_TYPE_EDGE_BOTH)
		irq_set_chip_handler_name_locked(data, &ocelot_irqchip,
						 handle_edge_irq, NULL);
@@ -1996,6 +2065,10 @@ static int ocelot_pinctrl_probe(struct platform_device *pdev)
	if (!info->desc)
		return -ENOMEM;

	info->wq = alloc_ordered_workqueue("ocelot_ordered", 0);
	if (!info->wq)
		return -ENOMEM;

	info->pincfg_data = &data->pincfg_data;

	reset = devm_reset_control_get_optional_shared(dev, "switch");
@@ -2018,7 +2091,7 @@ static int ocelot_pinctrl_probe(struct platform_device *pdev)
		dev_err(dev, "Failed to create regmap\n");
		return PTR_ERR(info->map);
	}
	dev_set_drvdata(dev, info->map);
	dev_set_drvdata(dev, info);
	info->dev = dev;

	/* Pinconf registers */
@@ -2043,6 +2116,15 @@ static int ocelot_pinctrl_probe(struct platform_device *pdev)
	return 0;
}

static int ocelot_pinctrl_remove(struct platform_device *pdev)
{
	struct ocelot_pinctrl *info = platform_get_drvdata(pdev);

	destroy_workqueue(info->wq);

	return 0;
}

static struct platform_driver ocelot_pinctrl_driver = {
	.driver = {
		.name = "pinctrl-ocelot",
@@ -2050,6 +2132,7 @@ static struct platform_driver ocelot_pinctrl_driver = {
		.suppress_bind_attrs = true,
	},
	.probe = ocelot_pinctrl_probe,
	.remove = ocelot_pinctrl_remove,
};
module_platform_driver(ocelot_pinctrl_driver);
MODULE_LICENSE("Dual MIT/GPL");
+5 −5
Original line number Diff line number Diff line
@@ -530,10 +530,10 @@ DECLARE_MSM_GPIO_PINS(187);
DECLARE_MSM_GPIO_PINS(188);
DECLARE_MSM_GPIO_PINS(189);

static const unsigned int sdc2_clk_pins[] = { 190 };
static const unsigned int sdc2_cmd_pins[] = { 191 };
static const unsigned int sdc2_data_pins[] = { 192 };
static const unsigned int ufs_reset_pins[] = { 193 };
static const unsigned int ufs_reset_pins[] = { 190 };
static const unsigned int sdc2_clk_pins[] = { 191 };
static const unsigned int sdc2_cmd_pins[] = { 192 };
static const unsigned int sdc2_data_pins[] = { 193 };

enum sc8180x_functions {
	msm_mux_adsp_ext,
@@ -1582,7 +1582,7 @@ static const int sc8180x_acpi_reserved_gpios[] = {
static const struct msm_gpio_wakeirq_map sc8180x_pdc_map[] = {
	{ 3, 31 }, { 5, 32 }, { 8, 33 }, { 9, 34 }, { 10, 100 }, { 12, 104 },
	{ 24, 37 }, { 26, 38 }, { 27, 41 }, { 28, 42 }, { 30, 39 }, { 36, 43 },
	{ 37, 43 }, { 38, 45 }, { 39, 118 }, { 39, 125 }, { 41, 47 },
	{ 37, 44 }, { 38, 45 }, { 39, 118 }, { 39, 125 }, { 41, 47 },
	{ 42, 48 }, { 46, 50 }, { 47, 49 }, { 48, 51 }, { 49, 53 }, { 50, 52 },
	{ 51, 116 }, { 51, 123 }, { 53, 54 }, { 54, 55 }, { 55, 56 },
	{ 56, 57 }, { 58, 58 }, { 60, 60 }, { 68, 62 }, { 70, 63 }, { 76, 86 },
+1 −1
Original line number Diff line number Diff line
@@ -99,7 +99,7 @@ MODULE_DEVICE_TABLE(of, a100_r_pinctrl_match);
static struct platform_driver a100_r_pinctrl_driver = {
	.probe	= a100_r_pinctrl_probe,
	.driver	= {
		.name		= "sun50iw10p1-r-pinctrl",
		.name		= "sun50i-a100-r-pinctrl",
		.of_match_table	= a100_r_pinctrl_match,
	},
};