brintos

brintos / linux-shallow public Read only

0
0
Text · 16.7 KiB · 6159fda Raw
673 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Renesas R-Car GPIO Support4 *5 *  Copyright (C) 2014 Renesas Electronics Corporation6 *  Copyright (C) 2013 Magnus Damm7 */8 9#include <linux/err.h>10#include <linux/gpio/driver.h>11#include <linux/init.h>12#include <linux/interrupt.h>13#include <linux/io.h>14#include <linux/ioport.h>15#include <linux/irq.h>16#include <linux/module.h>17#include <linux/of.h>18#include <linux/pinctrl/consumer.h>19#include <linux/platform_device.h>20#include <linux/pm_runtime.h>21#include <linux/spinlock.h>22#include <linux/slab.h>23 24struct gpio_rcar_bank_info {25	u32 iointsel;26	u32 inoutsel;27	u32 outdt;28	u32 posneg;29	u32 edglevel;30	u32 bothedge;31	u32 intmsk;32};33 34struct gpio_rcar_info {35	bool has_outdtsel;36	bool has_both_edge_trigger;37	bool has_always_in;38	bool has_inen;39};40 41struct gpio_rcar_priv {42	void __iomem *base;43	spinlock_t lock;44	struct device *dev;45	struct gpio_chip gpio_chip;46	unsigned int irq_parent;47	atomic_t wakeup_path;48	struct gpio_rcar_info info;49	struct gpio_rcar_bank_info bank_info;50};51 52#define IOINTSEL	0x00	/* General IO/Interrupt Switching Register */53#define INOUTSEL	0x04	/* General Input/Output Switching Register */54#define OUTDT		0x08	/* General Output Register */55#define INDT		0x0c	/* General Input Register */56#define INTDT		0x10	/* Interrupt Display Register */57#define INTCLR		0x14	/* Interrupt Clear Register */58#define INTMSK		0x18	/* Interrupt Mask Register */59#define MSKCLR		0x1c	/* Interrupt Mask Clear Register */60#define POSNEG		0x20	/* Positive/Negative Logic Select Register */61#define EDGLEVEL	0x24	/* Edge/level Select Register */62#define FILONOFF	0x28	/* Chattering Prevention On/Off Register */63#define OUTDTSEL	0x40	/* Output Data Select Register */64#define BOTHEDGE	0x4c	/* One Edge/Both Edge Select Register */65#define INEN		0x50	/* General Input Enable Register */66 67#define RCAR_MAX_GPIO_PER_BANK		3268 69static inline u32 gpio_rcar_read(struct gpio_rcar_priv *p, int offs)70{71	return ioread32(p->base + offs);72}73 74static inline void gpio_rcar_write(struct gpio_rcar_priv *p, int offs,75				   u32 value)76{77	iowrite32(value, p->base + offs);78}79 80static void gpio_rcar_modify_bit(struct gpio_rcar_priv *p, int offs,81				 int bit, bool value)82{83	u32 tmp = gpio_rcar_read(p, offs);84 85	if (value)86		tmp |= BIT(bit);87	else88		tmp &= ~BIT(bit);89 90	gpio_rcar_write(p, offs, tmp);91}92 93static void gpio_rcar_irq_disable(struct irq_data *d)94{95	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);96	struct gpio_rcar_priv *p = gpiochip_get_data(gc);97	irq_hw_number_t hwirq = irqd_to_hwirq(d);98 99	gpio_rcar_write(p, INTMSK, ~BIT(hwirq));100	gpiochip_disable_irq(gc, hwirq);101}102 103static void gpio_rcar_irq_enable(struct irq_data *d)104{105	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);106	struct gpio_rcar_priv *p = gpiochip_get_data(gc);107	irq_hw_number_t hwirq = irqd_to_hwirq(d);108 109	gpiochip_enable_irq(gc, hwirq);110	gpio_rcar_write(p, MSKCLR, BIT(hwirq));111}112 113static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,114						  unsigned int hwirq,115						  bool active_high_rising_edge,116						  bool level_trigger,117						  bool both)118{119	unsigned long flags;120 121	/* follow steps in the GPIO documentation for122	 * "Setting Edge-Sensitive Interrupt Input Mode" and123	 * "Setting Level-Sensitive Interrupt Input Mode"124	 */125 126	spin_lock_irqsave(&p->lock, flags);127 128	/* Configure positive or negative logic in POSNEG */129	gpio_rcar_modify_bit(p, POSNEG, hwirq, !active_high_rising_edge);130 131	/* Configure edge or level trigger in EDGLEVEL */132	gpio_rcar_modify_bit(p, EDGLEVEL, hwirq, !level_trigger);133 134	/* Select one edge or both edges in BOTHEDGE */135	if (p->info.has_both_edge_trigger)136		gpio_rcar_modify_bit(p, BOTHEDGE, hwirq, both);137 138	/* Select "Interrupt Input Mode" in IOINTSEL */139	gpio_rcar_modify_bit(p, IOINTSEL, hwirq, true);140 141	/* Write INTCLR in case of edge trigger */142	if (!level_trigger)143		gpio_rcar_write(p, INTCLR, BIT(hwirq));144 145	spin_unlock_irqrestore(&p->lock, flags);146}147 148static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)149{150	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);151	struct gpio_rcar_priv *p = gpiochip_get_data(gc);152	unsigned int hwirq = irqd_to_hwirq(d);153 154	dev_dbg(p->dev, "sense irq = %d, type = %d\n", hwirq, type);155 156	switch (type & IRQ_TYPE_SENSE_MASK) {157	case IRQ_TYPE_LEVEL_HIGH:158		gpio_rcar_config_interrupt_input_mode(p, hwirq, true, true,159						      false);160		break;161	case IRQ_TYPE_LEVEL_LOW:162		gpio_rcar_config_interrupt_input_mode(p, hwirq, false, true,163						      false);164		break;165	case IRQ_TYPE_EDGE_RISING:166		gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false,167						      false);168		break;169	case IRQ_TYPE_EDGE_FALLING:170		gpio_rcar_config_interrupt_input_mode(p, hwirq, false, false,171						      false);172		break;173	case IRQ_TYPE_EDGE_BOTH:174		if (!p->info.has_both_edge_trigger)175			return -EINVAL;176		gpio_rcar_config_interrupt_input_mode(p, hwirq, true, false,177						      true);178		break;179	default:180		return -EINVAL;181	}182	return 0;183}184 185static int gpio_rcar_irq_set_wake(struct irq_data *d, unsigned int on)186{187	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);188	struct gpio_rcar_priv *p = gpiochip_get_data(gc);189	int error;190 191	if (p->irq_parent) {192		error = irq_set_irq_wake(p->irq_parent, on);193		if (error) {194			dev_dbg(p->dev, "irq %u doesn't support irq_set_wake\n",195				p->irq_parent);196			p->irq_parent = 0;197		}198	}199 200	if (on)201		atomic_inc(&p->wakeup_path);202	else203		atomic_dec(&p->wakeup_path);204 205	return 0;206}207 208static const struct irq_chip gpio_rcar_irq_chip = {209	.name		= "gpio-rcar",210	.irq_mask	= gpio_rcar_irq_disable,211	.irq_unmask	= gpio_rcar_irq_enable,212	.irq_set_type	= gpio_rcar_irq_set_type,213	.irq_set_wake	= gpio_rcar_irq_set_wake,214	.flags		= IRQCHIP_IMMUTABLE | IRQCHIP_SET_TYPE_MASKED |215			  IRQCHIP_MASK_ON_SUSPEND,216	GPIOCHIP_IRQ_RESOURCE_HELPERS,217};218 219static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)220{221	struct gpio_rcar_priv *p = dev_id;222	u32 pending;223	unsigned int offset, irqs_handled = 0;224 225	while ((pending = gpio_rcar_read(p, INTDT) &226			  gpio_rcar_read(p, INTMSK))) {227		offset = __ffs(pending);228		gpio_rcar_write(p, INTCLR, BIT(offset));229		generic_handle_domain_irq(p->gpio_chip.irq.domain,230					  offset);231		irqs_handled++;232	}233 234	return irqs_handled ? IRQ_HANDLED : IRQ_NONE;235}236 237static void gpio_rcar_config_general_input_output_mode(struct gpio_chip *chip,238						       unsigned int gpio,239						       bool output)240{241	struct gpio_rcar_priv *p = gpiochip_get_data(chip);242	unsigned long flags;243 244	/* follow steps in the GPIO documentation for245	 * "Setting General Output Mode" and246	 * "Setting General Input Mode"247	 */248 249	spin_lock_irqsave(&p->lock, flags);250 251	/* Configure positive logic in POSNEG */252	gpio_rcar_modify_bit(p, POSNEG, gpio, false);253 254	/* Select "General Input/Output Mode" in IOINTSEL */255	gpio_rcar_modify_bit(p, IOINTSEL, gpio, false);256 257	/* Select Input Mode or Output Mode in INOUTSEL */258	gpio_rcar_modify_bit(p, INOUTSEL, gpio, output);259 260	/* Select General Output Register to output data in OUTDTSEL */261	if (p->info.has_outdtsel && output)262		gpio_rcar_modify_bit(p, OUTDTSEL, gpio, false);263 264	spin_unlock_irqrestore(&p->lock, flags);265}266 267static int gpio_rcar_request(struct gpio_chip *chip, unsigned offset)268{269	struct gpio_rcar_priv *p = gpiochip_get_data(chip);270	int error;271 272	error = pm_runtime_get_sync(p->dev);273	if (error < 0) {274		pm_runtime_put(p->dev);275		return error;276	}277 278	error = pinctrl_gpio_request(chip, offset);279	if (error)280		pm_runtime_put(p->dev);281 282	return error;283}284 285static void gpio_rcar_free(struct gpio_chip *chip, unsigned offset)286{287	struct gpio_rcar_priv *p = gpiochip_get_data(chip);288 289	pinctrl_gpio_free(chip, offset);290 291	/*292	 * Set the GPIO as an input to ensure that the next GPIO request won't293	 * drive the GPIO pin as an output.294	 */295	gpio_rcar_config_general_input_output_mode(chip, offset, false);296 297	pm_runtime_put(p->dev);298}299 300static int gpio_rcar_get_direction(struct gpio_chip *chip, unsigned int offset)301{302	struct gpio_rcar_priv *p = gpiochip_get_data(chip);303 304	if (gpio_rcar_read(p, INOUTSEL) & BIT(offset))305		return GPIO_LINE_DIRECTION_OUT;306 307	return GPIO_LINE_DIRECTION_IN;308}309 310static int gpio_rcar_direction_input(struct gpio_chip *chip, unsigned offset)311{312	gpio_rcar_config_general_input_output_mode(chip, offset, false);313	return 0;314}315 316static int gpio_rcar_get(struct gpio_chip *chip, unsigned offset)317{318	struct gpio_rcar_priv *p = gpiochip_get_data(chip);319	u32 bit = BIT(offset);320 321	/*322	 * Before R-Car Gen3, INDT does not show correct pin state when323	 * configured as output, so use OUTDT in case of output pins324	 */325	if (!p->info.has_always_in && (gpio_rcar_read(p, INOUTSEL) & bit))326		return !!(gpio_rcar_read(p, OUTDT) & bit);327	else328		return !!(gpio_rcar_read(p, INDT) & bit);329}330 331static int gpio_rcar_get_multiple(struct gpio_chip *chip, unsigned long *mask,332				  unsigned long *bits)333{334	struct gpio_rcar_priv *p = gpiochip_get_data(chip);335	u32 bankmask, outputs, m, val = 0;336	unsigned long flags;337 338	bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0);339	if (chip->valid_mask)340		bankmask &= chip->valid_mask[0];341 342	if (!bankmask)343		return 0;344 345	if (p->info.has_always_in) {346		bits[0] = gpio_rcar_read(p, INDT) & bankmask;347		return 0;348	}349 350	spin_lock_irqsave(&p->lock, flags);351	outputs = gpio_rcar_read(p, INOUTSEL);352	m = outputs & bankmask;353	if (m)354		val |= gpio_rcar_read(p, OUTDT) & m;355 356	m = ~outputs & bankmask;357	if (m)358		val |= gpio_rcar_read(p, INDT) & m;359	spin_unlock_irqrestore(&p->lock, flags);360 361	bits[0] = val;362	return 0;363}364 365static void gpio_rcar_set(struct gpio_chip *chip, unsigned offset, int value)366{367	struct gpio_rcar_priv *p = gpiochip_get_data(chip);368	unsigned long flags;369 370	spin_lock_irqsave(&p->lock, flags);371	gpio_rcar_modify_bit(p, OUTDT, offset, value);372	spin_unlock_irqrestore(&p->lock, flags);373}374 375static void gpio_rcar_set_multiple(struct gpio_chip *chip, unsigned long *mask,376				   unsigned long *bits)377{378	struct gpio_rcar_priv *p = gpiochip_get_data(chip);379	unsigned long flags;380	u32 val, bankmask;381 382	bankmask = mask[0] & GENMASK(chip->ngpio - 1, 0);383	if (chip->valid_mask)384		bankmask &= chip->valid_mask[0];385 386	if (!bankmask)387		return;388 389	spin_lock_irqsave(&p->lock, flags);390	val = gpio_rcar_read(p, OUTDT);391	val &= ~bankmask;392	val |= (bankmask & bits[0]);393	gpio_rcar_write(p, OUTDT, val);394	spin_unlock_irqrestore(&p->lock, flags);395}396 397static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,398				      int value)399{400	/* write GPIO value to output before selecting output mode of pin */401	gpio_rcar_set(chip, offset, value);402	gpio_rcar_config_general_input_output_mode(chip, offset, true);403	return 0;404}405 406static const struct gpio_rcar_info gpio_rcar_info_gen1 = {407	.has_outdtsel = false,408	.has_both_edge_trigger = false,409	.has_always_in = false,410	.has_inen = false,411};412 413static const struct gpio_rcar_info gpio_rcar_info_gen2 = {414	.has_outdtsel = true,415	.has_both_edge_trigger = true,416	.has_always_in = false,417	.has_inen = false,418};419 420static const struct gpio_rcar_info gpio_rcar_info_gen3 = {421	.has_outdtsel = true,422	.has_both_edge_trigger = true,423	.has_always_in = true,424	.has_inen = false,425};426 427static const struct gpio_rcar_info gpio_rcar_info_gen4 = {428	.has_outdtsel = true,429	.has_both_edge_trigger = true,430	.has_always_in = true,431	.has_inen = true,432};433 434static const struct of_device_id gpio_rcar_of_table[] = {435	{436		.compatible = "renesas,gpio-r8a779a0",437		.data = &gpio_rcar_info_gen4,438	}, {439		.compatible = "renesas,rcar-gen1-gpio",440		.data = &gpio_rcar_info_gen1,441	}, {442		.compatible = "renesas,rcar-gen2-gpio",443		.data = &gpio_rcar_info_gen2,444	}, {445		.compatible = "renesas,rcar-gen3-gpio",446		.data = &gpio_rcar_info_gen3,447	}, {448		.compatible = "renesas,rcar-gen4-gpio",449		.data = &gpio_rcar_info_gen4,450	}, {451		.compatible = "renesas,gpio-rcar",452		.data = &gpio_rcar_info_gen1,453	}, {454		/* Terminator */455	},456};457 458MODULE_DEVICE_TABLE(of, gpio_rcar_of_table);459 460static int gpio_rcar_parse_dt(struct gpio_rcar_priv *p, unsigned int *npins)461{462	struct device_node *np = p->dev->of_node;463	const struct gpio_rcar_info *info;464	struct of_phandle_args args;465	int ret;466 467	info = of_device_get_match_data(p->dev);468	p->info = *info;469 470	ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3, 0, &args);471	*npins = ret == 0 ? args.args[2] : RCAR_MAX_GPIO_PER_BANK;472 473	if (*npins == 0 || *npins > RCAR_MAX_GPIO_PER_BANK) {474		dev_warn(p->dev, "Invalid number of gpio lines %u, using %u\n",475			 *npins, RCAR_MAX_GPIO_PER_BANK);476		*npins = RCAR_MAX_GPIO_PER_BANK;477	}478 479	return 0;480}481 482static void gpio_rcar_enable_inputs(struct gpio_rcar_priv *p)483{484	u32 mask = GENMASK(p->gpio_chip.ngpio - 1, 0);485 486	/* Select "Input Enable" in INEN */487	if (p->gpio_chip.valid_mask)488		mask &= p->gpio_chip.valid_mask[0];489	if (mask)490		gpio_rcar_write(p, INEN, gpio_rcar_read(p, INEN) | mask);491}492 493static int gpio_rcar_probe(struct platform_device *pdev)494{495	struct gpio_rcar_priv *p;496	struct gpio_chip *gpio_chip;497	struct gpio_irq_chip *girq;498	struct device *dev = &pdev->dev;499	const char *name = dev_name(dev);500	unsigned int npins;501	int ret;502 503	p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);504	if (!p)505		return -ENOMEM;506 507	p->dev = dev;508	spin_lock_init(&p->lock);509 510	/* Get device configuration from DT node */511	ret = gpio_rcar_parse_dt(p, &npins);512	if (ret < 0)513		return ret;514 515	platform_set_drvdata(pdev, p);516 517	pm_runtime_enable(dev);518 519	ret = platform_get_irq(pdev, 0);520	if (ret < 0)521		goto err0;522	p->irq_parent = ret;523 524	p->base = devm_platform_ioremap_resource(pdev, 0);525	if (IS_ERR(p->base)) {526		ret = PTR_ERR(p->base);527		goto err0;528	}529 530	gpio_chip = &p->gpio_chip;531	gpio_chip->request = gpio_rcar_request;532	gpio_chip->free = gpio_rcar_free;533	gpio_chip->get_direction = gpio_rcar_get_direction;534	gpio_chip->direction_input = gpio_rcar_direction_input;535	gpio_chip->get = gpio_rcar_get;536	gpio_chip->get_multiple = gpio_rcar_get_multiple;537	gpio_chip->direction_output = gpio_rcar_direction_output;538	gpio_chip->set = gpio_rcar_set;539	gpio_chip->set_multiple = gpio_rcar_set_multiple;540	gpio_chip->label = name;541	gpio_chip->parent = dev;542	gpio_chip->owner = THIS_MODULE;543	gpio_chip->base = -1;544	gpio_chip->ngpio = npins;545 546	girq = &gpio_chip->irq;547	gpio_irq_chip_set_chip(girq, &gpio_rcar_irq_chip);548	/* This will let us handle the parent IRQ in the driver */549	girq->parent_handler = NULL;550	girq->num_parents = 0;551	girq->parents = NULL;552	girq->default_type = IRQ_TYPE_NONE;553	girq->handler = handle_level_irq;554 555	ret = gpiochip_add_data(gpio_chip, p);556	if (ret) {557		dev_err(dev, "failed to add GPIO controller\n");558		goto err0;559	}560 561	irq_domain_set_pm_device(gpio_chip->irq.domain, dev);562	ret = devm_request_irq(dev, p->irq_parent, gpio_rcar_irq_handler,563			       IRQF_SHARED, name, p);564	if (ret) {565		dev_err(dev, "failed to request IRQ\n");566		goto err1;567	}568 569	if (p->info.has_inen) {570		pm_runtime_get_sync(dev);571		gpio_rcar_enable_inputs(p);572		pm_runtime_put(dev);573	}574 575	dev_info(dev, "driving %d GPIOs\n", npins);576 577	return 0;578 579err1:580	gpiochip_remove(gpio_chip);581err0:582	pm_runtime_disable(dev);583	return ret;584}585 586static void gpio_rcar_remove(struct platform_device *pdev)587{588	struct gpio_rcar_priv *p = platform_get_drvdata(pdev);589 590	gpiochip_remove(&p->gpio_chip);591 592	pm_runtime_disable(&pdev->dev);593}594 595#ifdef CONFIG_PM_SLEEP596static int gpio_rcar_suspend(struct device *dev)597{598	struct gpio_rcar_priv *p = dev_get_drvdata(dev);599 600	p->bank_info.iointsel = gpio_rcar_read(p, IOINTSEL);601	p->bank_info.inoutsel = gpio_rcar_read(p, INOUTSEL);602	p->bank_info.outdt = gpio_rcar_read(p, OUTDT);603	p->bank_info.intmsk = gpio_rcar_read(p, INTMSK);604	p->bank_info.posneg = gpio_rcar_read(p, POSNEG);605	p->bank_info.edglevel = gpio_rcar_read(p, EDGLEVEL);606	if (p->info.has_both_edge_trigger)607		p->bank_info.bothedge = gpio_rcar_read(p, BOTHEDGE);608 609	if (atomic_read(&p->wakeup_path))610		device_set_wakeup_path(dev);611 612	return 0;613}614 615static int gpio_rcar_resume(struct device *dev)616{617	struct gpio_rcar_priv *p = dev_get_drvdata(dev);618	unsigned int offset;619	u32 mask;620 621	for (offset = 0; offset < p->gpio_chip.ngpio; offset++) {622		if (!gpiochip_line_is_valid(&p->gpio_chip, offset))623			continue;624 625		mask = BIT(offset);626		/* I/O pin */627		if (!(p->bank_info.iointsel & mask)) {628			if (p->bank_info.inoutsel & mask)629				gpio_rcar_direction_output(630					&p->gpio_chip, offset,631					!!(p->bank_info.outdt & mask));632			else633				gpio_rcar_direction_input(&p->gpio_chip,634							  offset);635		} else {636			/* Interrupt pin */637			gpio_rcar_config_interrupt_input_mode(638				p,639				offset,640				!(p->bank_info.posneg & mask),641				!(p->bank_info.edglevel & mask),642				!!(p->bank_info.bothedge & mask));643 644			if (p->bank_info.intmsk & mask)645				gpio_rcar_write(p, MSKCLR, mask);646		}647	}648 649	if (p->info.has_inen)650		gpio_rcar_enable_inputs(p);651 652	return 0;653}654#endif /* CONFIG_PM_SLEEP*/655 656static SIMPLE_DEV_PM_OPS(gpio_rcar_pm_ops, gpio_rcar_suspend, gpio_rcar_resume);657 658static struct platform_driver gpio_rcar_device_driver = {659	.probe		= gpio_rcar_probe,660	.remove_new	= gpio_rcar_remove,661	.driver		= {662		.name	= "gpio_rcar",663		.pm     = &gpio_rcar_pm_ops,664		.of_match_table = gpio_rcar_of_table,665	}666};667 668module_platform_driver(gpio_rcar_device_driver);669 670MODULE_AUTHOR("Magnus Damm");671MODULE_DESCRIPTION("Renesas R-Car GPIO Driver");672MODULE_LICENSE("GPL v2");673