brintos

brintos / linux-shallow public Read only

0
0
Text · 8.9 KiB · 97d345b Raw
356 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Faraday Technolog FTGPIO010 gpiochip and interrupt routines4 * Copyright (C) 2017 Linus Walleij <linus.walleij@linaro.org>5 *6 * Based on arch/arm/mach-gemini/gpio.c:7 * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@teltonika.lt>8 *9 * Based on plat-mxc/gpio.c:10 * MXC GPIO support. (c) 2008 Daniel Mack <daniel@caiaq.de>11 * Copyright 2008 Juergen Beisert, kernel@pengutronix.de12 */13#include <linux/gpio/driver.h>14#include <linux/io.h>15#include <linux/interrupt.h>16#include <linux/platform_device.h>17#include <linux/bitops.h>18#include <linux/clk.h>19 20/* GPIO registers definition */21#define GPIO_DATA_OUT		0x0022#define GPIO_DATA_IN		0x0423#define GPIO_DIR		0x0824#define GPIO_BYPASS_IN		0x0C25#define GPIO_DATA_SET		0x1026#define GPIO_DATA_CLR		0x1427#define GPIO_PULL_EN		0x1828#define GPIO_PULL_TYPE		0x1C29#define GPIO_INT_EN		0x2030#define GPIO_INT_STAT_RAW	0x2431#define GPIO_INT_STAT_MASKED	0x2832#define GPIO_INT_MASK		0x2C33#define GPIO_INT_CLR		0x3034#define GPIO_INT_TYPE		0x3435#define GPIO_INT_BOTH_EDGE	0x3836#define GPIO_INT_LEVEL		0x3C37#define GPIO_DEBOUNCE_EN	0x4038#define GPIO_DEBOUNCE_PRESCALE	0x4439 40/**41 * struct ftgpio_gpio - Gemini GPIO state container42 * @dev: containing device for this instance43 * @gc: gpiochip for this instance44 * @base: remapped I/O-memory base45 * @clk: silicon clock46 */47struct ftgpio_gpio {48	struct device *dev;49	struct gpio_chip gc;50	void __iomem *base;51	struct clk *clk;52};53 54static void ftgpio_gpio_ack_irq(struct irq_data *d)55{56	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);57	struct ftgpio_gpio *g = gpiochip_get_data(gc);58 59	writel(BIT(irqd_to_hwirq(d)), g->base + GPIO_INT_CLR);60}61 62static void ftgpio_gpio_mask_irq(struct irq_data *d)63{64	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);65	struct ftgpio_gpio *g = gpiochip_get_data(gc);66	u32 val;67 68	val = readl(g->base + GPIO_INT_EN);69	val &= ~BIT(irqd_to_hwirq(d));70	writel(val, g->base + GPIO_INT_EN);71	gpiochip_disable_irq(gc, irqd_to_hwirq(d));72}73 74static void ftgpio_gpio_unmask_irq(struct irq_data *d)75{76	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);77	struct ftgpio_gpio *g = gpiochip_get_data(gc);78	u32 val;79 80	gpiochip_enable_irq(gc, irqd_to_hwirq(d));81	val = readl(g->base + GPIO_INT_EN);82	val |= BIT(irqd_to_hwirq(d));83	writel(val, g->base + GPIO_INT_EN);84}85 86static int ftgpio_gpio_set_irq_type(struct irq_data *d, unsigned int type)87{88	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);89	struct ftgpio_gpio *g = gpiochip_get_data(gc);90	u32 mask = BIT(irqd_to_hwirq(d));91	u32 reg_both, reg_level, reg_type;92 93	reg_type = readl(g->base + GPIO_INT_TYPE);94	reg_level = readl(g->base + GPIO_INT_LEVEL);95	reg_both = readl(g->base + GPIO_INT_BOTH_EDGE);96 97	switch (type) {98	case IRQ_TYPE_EDGE_BOTH:99		irq_set_handler_locked(d, handle_edge_irq);100		reg_type &= ~mask;101		reg_both |= mask;102		break;103	case IRQ_TYPE_EDGE_RISING:104		irq_set_handler_locked(d, handle_edge_irq);105		reg_type &= ~mask;106		reg_both &= ~mask;107		reg_level &= ~mask;108		break;109	case IRQ_TYPE_EDGE_FALLING:110		irq_set_handler_locked(d, handle_edge_irq);111		reg_type &= ~mask;112		reg_both &= ~mask;113		reg_level |= mask;114		break;115	case IRQ_TYPE_LEVEL_HIGH:116		irq_set_handler_locked(d, handle_level_irq);117		reg_type |= mask;118		reg_level &= ~mask;119		break;120	case IRQ_TYPE_LEVEL_LOW:121		irq_set_handler_locked(d, handle_level_irq);122		reg_type |= mask;123		reg_level |= mask;124		break;125	default:126		irq_set_handler_locked(d, handle_bad_irq);127		return -EINVAL;128	}129 130	writel(reg_type, g->base + GPIO_INT_TYPE);131	writel(reg_level, g->base + GPIO_INT_LEVEL);132	writel(reg_both, g->base + GPIO_INT_BOTH_EDGE);133 134	ftgpio_gpio_ack_irq(d);135 136	return 0;137}138 139static void ftgpio_gpio_irq_handler(struct irq_desc *desc)140{141	struct gpio_chip *gc = irq_desc_get_handler_data(desc);142	struct ftgpio_gpio *g = gpiochip_get_data(gc);143	struct irq_chip *irqchip = irq_desc_get_chip(desc);144	int offset;145	unsigned long stat;146 147	chained_irq_enter(irqchip, desc);148 149	stat = readl(g->base + GPIO_INT_STAT_RAW);150	if (stat)151		for_each_set_bit(offset, &stat, gc->ngpio)152			generic_handle_domain_irq(gc->irq.domain, offset);153 154	chained_irq_exit(irqchip, desc);155}156 157static int ftgpio_gpio_set_config(struct gpio_chip *gc, unsigned int offset,158				  unsigned long config)159{160	enum pin_config_param param = pinconf_to_config_param(config);161	u32 arg = pinconf_to_config_argument(config);162	struct ftgpio_gpio *g = gpiochip_get_data(gc);163	unsigned long pclk_freq;164	u32 deb_div;165	u32 val;166 167	if (param != PIN_CONFIG_INPUT_DEBOUNCE)168		return -ENOTSUPP;169 170	/*171	 * Debounce only works if interrupts are enabled. The manual172	 * states that if PCLK is 66 MHz, and this is set to 0x7D0, then173	 * PCLK is divided down to 33 kHz for the debounce timer. 0x7D0 is174	 * 2000 decimal, so what they mean is simply that the PCLK is175	 * divided by this value.176	 *177	 * As we get a debounce setting in microseconds, we calculate the178	 * desired period time and see if we can get a suitable debounce179	 * time.180	 */181	pclk_freq = clk_get_rate(g->clk);182	deb_div = DIV_ROUND_CLOSEST(pclk_freq, arg);183 184	/* This register is only 24 bits wide */185	if (deb_div > (1 << 24))186		return -ENOTSUPP;187 188	dev_dbg(g->dev, "prescale divisor: %08x, resulting frequency %lu Hz\n",189		deb_div, (pclk_freq/deb_div));190 191	val = readl(g->base + GPIO_DEBOUNCE_PRESCALE);192	if (val == deb_div) {193		/*194		 * The debounce timer happens to already be set to the195		 * desirable value, what a coincidence! We can just enable196		 * debounce on this GPIO line and return. This happens more197		 * often than you think, for example when all GPIO keys198		 * on a system are requesting the same debounce interval.199		 */200		val = readl(g->base + GPIO_DEBOUNCE_EN);201		val |= BIT(offset);202		writel(val, g->base + GPIO_DEBOUNCE_EN);203		return 0;204	}205 206	val = readl(g->base + GPIO_DEBOUNCE_EN);207	if (val) {208		/*209		 * Oh no! Someone is already using the debounce with210		 * another setting than what we need. Bummer.211		 */212		return -ENOTSUPP;213	}214 215	/* First come, first serve */216	writel(deb_div, g->base + GPIO_DEBOUNCE_PRESCALE);217	/* Enable debounce */218	val |= BIT(offset);219	writel(val, g->base + GPIO_DEBOUNCE_EN);220 221	return 0;222}223 224static const struct irq_chip ftgpio_irq_chip = {225	.name = "FTGPIO010",226	.irq_ack = ftgpio_gpio_ack_irq,227	.irq_mask = ftgpio_gpio_mask_irq,228	.irq_unmask = ftgpio_gpio_unmask_irq,229	.irq_set_type = ftgpio_gpio_set_irq_type,230	.flags = IRQCHIP_IMMUTABLE,231	 GPIOCHIP_IRQ_RESOURCE_HELPERS,232};233 234static int ftgpio_gpio_probe(struct platform_device *pdev)235{236	struct device *dev = &pdev->dev;237	struct ftgpio_gpio *g;238	struct gpio_irq_chip *girq;239	int irq;240	int ret;241 242	g = devm_kzalloc(dev, sizeof(*g), GFP_KERNEL);243	if (!g)244		return -ENOMEM;245 246	g->dev = dev;247 248	g->base = devm_platform_ioremap_resource(pdev, 0);249	if (IS_ERR(g->base))250		return PTR_ERR(g->base);251 252	irq = platform_get_irq(pdev, 0);253	if (irq < 0)254		return irq;255 256	g->clk = devm_clk_get(dev, NULL);257	if (!IS_ERR(g->clk)) {258		ret = clk_prepare_enable(g->clk);259		if (ret)260			return ret;261	} else if (PTR_ERR(g->clk) == -EPROBE_DEFER) {262		/*263		 * Percolate deferrals, for anything else,264		 * just live without the clocking.265		 */266		return PTR_ERR(g->clk);267	}268 269	ret = bgpio_init(&g->gc, dev, 4,270			 g->base + GPIO_DATA_IN,271			 g->base + GPIO_DATA_SET,272			 g->base + GPIO_DATA_CLR,273			 g->base + GPIO_DIR,274			 NULL,275			 0);276	if (ret) {277		dev_err(dev, "unable to init generic GPIO\n");278		goto dis_clk;279	}280	g->gc.label = dev_name(dev);281	g->gc.base = -1;282	g->gc.parent = dev;283	g->gc.owner = THIS_MODULE;284	/* ngpio is set by bgpio_init() */285 286	/* We need a silicon clock to do debounce */287	if (!IS_ERR(g->clk))288		g->gc.set_config = ftgpio_gpio_set_config;289 290	girq = &g->gc.irq;291	gpio_irq_chip_set_chip(girq, &ftgpio_irq_chip);292	girq->parent_handler = ftgpio_gpio_irq_handler;293	girq->num_parents = 1;294	girq->parents = devm_kcalloc(dev, 1, sizeof(*girq->parents),295				     GFP_KERNEL);296	if (!girq->parents) {297		ret = -ENOMEM;298		goto dis_clk;299	}300	girq->default_type = IRQ_TYPE_NONE;301	girq->handler = handle_bad_irq;302	girq->parents[0] = irq;303 304	/* Disable, unmask and clear all interrupts */305	writel(0x0, g->base + GPIO_INT_EN);306	writel(0x0, g->base + GPIO_INT_MASK);307	writel(~0x0, g->base + GPIO_INT_CLR);308 309	/* Clear any use of debounce */310	writel(0x0, g->base + GPIO_DEBOUNCE_EN);311 312	ret = devm_gpiochip_add_data(dev, &g->gc, g);313	if (ret)314		goto dis_clk;315 316	platform_set_drvdata(pdev, g);317	dev_info(dev, "FTGPIO010 @%p registered\n", g->base);318 319	return 0;320 321dis_clk:322	clk_disable_unprepare(g->clk);323 324	return ret;325}326 327static void ftgpio_gpio_remove(struct platform_device *pdev)328{329	struct ftgpio_gpio *g = platform_get_drvdata(pdev);330 331	clk_disable_unprepare(g->clk);332}333 334static const struct of_device_id ftgpio_gpio_of_match[] = {335	{336		.compatible = "cortina,gemini-gpio",337	},338	{339		.compatible = "moxa,moxart-gpio",340	},341	{342		.compatible = "faraday,ftgpio010",343	},344	{},345};346 347static struct platform_driver ftgpio_gpio_driver = {348	.driver = {349		.name		= "ftgpio010-gpio",350		.of_match_table = ftgpio_gpio_of_match,351	},352	.probe = ftgpio_gpio_probe,353	.remove_new = ftgpio_gpio_remove,354};355builtin_platform_driver(ftgpio_gpio_driver);356