brintos

brintos / linux-shallow public Read only

0
0
Text · 11.1 KiB · f2e7e87 Raw
405 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * TQ-Systems TQMx86 PLD GPIO driver4 *5 * Based on vendor driver by:6 *   Vadim V.Vlasov <vvlasov@dev.rtsoft.ru>7 */8 9#include <linux/bitmap.h>10#include <linux/bitops.h>11#include <linux/errno.h>12#include <linux/gpio/driver.h>13#include <linux/init.h>14#include <linux/interrupt.h>15#include <linux/kernel.h>16#include <linux/module.h>17#include <linux/platform_device.h>18#include <linux/pm_runtime.h>19#include <linux/seq_file.h>20#include <linux/slab.h>21 22#define TQMX86_NGPIO	823#define TQMX86_NGPO	4	/* 0-3 - output */24#define TQMX86_NGPI	4	/* 4-7 - input */25#define TQMX86_DIR_INPUT_MASK	0xf0	/* 0-3 - output, 4-7 - input */26 27#define TQMX86_GPIODD	0	/* GPIO Data Direction Register */28#define TQMX86_GPIOD	1	/* GPIO Data Register */29#define TQMX86_GPIIC	3	/* GPI Interrupt Configuration Register */30#define TQMX86_GPIIS	4	/* GPI Interrupt Status Register */31 32#define TQMX86_GPII_NONE	033#define TQMX86_GPII_FALLING	BIT(0)34#define TQMX86_GPII_RISING	BIT(1)35/* Stored in irq_type as a trigger type, but not actually valid as a register36 * value, so the name doesn't use "GPII"37 */38#define TQMX86_INT_BOTH		(BIT(0) | BIT(1))39#define TQMX86_GPII_MASK	(BIT(0) | BIT(1))40#define TQMX86_GPII_BITS	241/* Stored in irq_type with GPII bits */42#define TQMX86_INT_UNMASKED	BIT(2)43 44struct tqmx86_gpio_data {45	struct gpio_chip	chip;46	void __iomem		*io_base;47	int			irq;48	/* Lock must be held for accessing output and irq_type fields */49	raw_spinlock_t		spinlock;50	DECLARE_BITMAP(output, TQMX86_NGPIO);51	u8			irq_type[TQMX86_NGPI];52};53 54static u8 tqmx86_gpio_read(struct tqmx86_gpio_data *gd, unsigned int reg)55{56	return ioread8(gd->io_base + reg);57}58 59static void tqmx86_gpio_write(struct tqmx86_gpio_data *gd, u8 val,60			      unsigned int reg)61{62	iowrite8(val, gd->io_base + reg);63}64 65static int tqmx86_gpio_get(struct gpio_chip *chip, unsigned int offset)66{67	struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip);68 69	return !!(tqmx86_gpio_read(gpio, TQMX86_GPIOD) & BIT(offset));70}71 72static void tqmx86_gpio_set(struct gpio_chip *chip, unsigned int offset,73			    int value)74{75	struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip);76	unsigned long flags;77 78	raw_spin_lock_irqsave(&gpio->spinlock, flags);79	__assign_bit(offset, gpio->output, value);80	tqmx86_gpio_write(gpio, bitmap_get_value8(gpio->output, 0), TQMX86_GPIOD);81	raw_spin_unlock_irqrestore(&gpio->spinlock, flags);82}83 84static int tqmx86_gpio_direction_input(struct gpio_chip *chip,85				       unsigned int offset)86{87	/* Direction cannot be changed. Validate is an input. */88	if (BIT(offset) & TQMX86_DIR_INPUT_MASK)89		return 0;90	else91		return -EINVAL;92}93 94static int tqmx86_gpio_direction_output(struct gpio_chip *chip,95					unsigned int offset,96					int value)97{98	/* Direction cannot be changed, validate is an output */99	if (BIT(offset) & TQMX86_DIR_INPUT_MASK)100		return -EINVAL;101 102	tqmx86_gpio_set(chip, offset, value);103	return 0;104}105 106static int tqmx86_gpio_get_direction(struct gpio_chip *chip,107				     unsigned int offset)108{109	if (TQMX86_DIR_INPUT_MASK & BIT(offset))110		return GPIO_LINE_DIRECTION_IN;111 112	return GPIO_LINE_DIRECTION_OUT;113}114 115static void tqmx86_gpio_irq_config(struct tqmx86_gpio_data *gpio, int offset)116	__must_hold(&gpio->spinlock)117{118	u8 type = TQMX86_GPII_NONE, gpiic;119 120	if (gpio->irq_type[offset] & TQMX86_INT_UNMASKED) {121		type = gpio->irq_type[offset] & TQMX86_GPII_MASK;122 123		if (type == TQMX86_INT_BOTH)124			type = tqmx86_gpio_get(&gpio->chip, offset + TQMX86_NGPO)125				? TQMX86_GPII_FALLING126				: TQMX86_GPII_RISING;127	}128 129	gpiic = tqmx86_gpio_read(gpio, TQMX86_GPIIC);130	gpiic &= ~(TQMX86_GPII_MASK << (offset * TQMX86_GPII_BITS));131	gpiic |= type << (offset * TQMX86_GPII_BITS);132	tqmx86_gpio_write(gpio, gpiic, TQMX86_GPIIC);133}134 135static void tqmx86_gpio_irq_mask(struct irq_data *data)136{137	unsigned int offset = (data->hwirq - TQMX86_NGPO);138	struct tqmx86_gpio_data *gpio = gpiochip_get_data(139		irq_data_get_irq_chip_data(data));140	unsigned long flags;141 142	raw_spin_lock_irqsave(&gpio->spinlock, flags);143	gpio->irq_type[offset] &= ~TQMX86_INT_UNMASKED;144	tqmx86_gpio_irq_config(gpio, offset);145	raw_spin_unlock_irqrestore(&gpio->spinlock, flags);146 147	gpiochip_disable_irq(&gpio->chip, irqd_to_hwirq(data));148}149 150static void tqmx86_gpio_irq_unmask(struct irq_data *data)151{152	unsigned int offset = (data->hwirq - TQMX86_NGPO);153	struct tqmx86_gpio_data *gpio = gpiochip_get_data(154		irq_data_get_irq_chip_data(data));155	unsigned long flags;156 157	gpiochip_enable_irq(&gpio->chip, irqd_to_hwirq(data));158 159	raw_spin_lock_irqsave(&gpio->spinlock, flags);160	gpio->irq_type[offset] |= TQMX86_INT_UNMASKED;161	tqmx86_gpio_irq_config(gpio, offset);162	raw_spin_unlock_irqrestore(&gpio->spinlock, flags);163}164 165static int tqmx86_gpio_irq_set_type(struct irq_data *data, unsigned int type)166{167	struct tqmx86_gpio_data *gpio = gpiochip_get_data(168		irq_data_get_irq_chip_data(data));169	unsigned int offset = (data->hwirq - TQMX86_NGPO);170	unsigned int edge_type = type & IRQF_TRIGGER_MASK;171	unsigned long flags;172	u8 new_type;173 174	switch (edge_type) {175	case IRQ_TYPE_EDGE_RISING:176		new_type = TQMX86_GPII_RISING;177		break;178	case IRQ_TYPE_EDGE_FALLING:179		new_type = TQMX86_GPII_FALLING;180		break;181	case IRQ_TYPE_EDGE_BOTH:182		new_type = TQMX86_INT_BOTH;183		break;184	default:185		return -EINVAL; /* not supported */186	}187 188	raw_spin_lock_irqsave(&gpio->spinlock, flags);189	gpio->irq_type[offset] &= ~TQMX86_GPII_MASK;190	gpio->irq_type[offset] |= new_type;191	tqmx86_gpio_irq_config(gpio, offset);192	raw_spin_unlock_irqrestore(&gpio->spinlock, flags);193 194	return 0;195}196 197static void tqmx86_gpio_irq_handler(struct irq_desc *desc)198{199	struct gpio_chip *chip = irq_desc_get_handler_data(desc);200	struct tqmx86_gpio_data *gpio = gpiochip_get_data(chip);201	struct irq_chip *irq_chip = irq_desc_get_chip(desc);202	unsigned long irq_bits, flags;203	int i;204	u8 irq_status;205 206	chained_irq_enter(irq_chip, desc);207 208	irq_status = tqmx86_gpio_read(gpio, TQMX86_GPIIS);209	tqmx86_gpio_write(gpio, irq_status, TQMX86_GPIIS);210 211	irq_bits = irq_status;212 213	raw_spin_lock_irqsave(&gpio->spinlock, flags);214	for_each_set_bit(i, &irq_bits, TQMX86_NGPI) {215		/*216		 * Edge-both triggers are implemented by flipping the edge217		 * trigger after each interrupt, as the controller only supports218		 * either rising or falling edge triggers, but not both.219		 *220		 * Internally, the TQMx86 GPIO controller has separate status221		 * registers for rising and falling edge interrupts. GPIIC222		 * configures which bits from which register are visible in the223		 * interrupt status register GPIIS and defines what triggers the224		 * parent IRQ line. Writing to GPIIS always clears both rising225		 * and falling interrupt flags internally, regardless of the226		 * currently configured trigger.227		 *228		 * In consequence, we can cleanly implement the edge-both229		 * trigger in software by first clearing the interrupt and then230		 * setting the new trigger based on the current GPIO input in231		 * tqmx86_gpio_irq_config() - even if an edge arrives between232		 * reading the input and setting the trigger, we will have a new233		 * interrupt pending.234		 */235		if ((gpio->irq_type[i] & TQMX86_GPII_MASK) == TQMX86_INT_BOTH)236			tqmx86_gpio_irq_config(gpio, i);237	}238	raw_spin_unlock_irqrestore(&gpio->spinlock, flags);239 240	for_each_set_bit(i, &irq_bits, TQMX86_NGPI)241		generic_handle_domain_irq(gpio->chip.irq.domain,242					  i + TQMX86_NGPO);243 244	chained_irq_exit(irq_chip, desc);245}246 247/* Minimal runtime PM is needed by the IRQ subsystem */248static int __maybe_unused tqmx86_gpio_runtime_suspend(struct device *dev)249{250	return 0;251}252 253static int __maybe_unused tqmx86_gpio_runtime_resume(struct device *dev)254{255	return 0;256}257 258static const struct dev_pm_ops tqmx86_gpio_dev_pm_ops = {259	SET_RUNTIME_PM_OPS(tqmx86_gpio_runtime_suspend,260			   tqmx86_gpio_runtime_resume, NULL)261};262 263static void tqmx86_init_irq_valid_mask(struct gpio_chip *chip,264				       unsigned long *valid_mask,265				       unsigned int ngpios)266{267	/* Only GPIOs 4-7 are valid for interrupts. Clear the others */268	clear_bit(0, valid_mask);269	clear_bit(1, valid_mask);270	clear_bit(2, valid_mask);271	clear_bit(3, valid_mask);272}273 274static void tqmx86_gpio_irq_print_chip(struct irq_data *d, struct seq_file *p)275{276	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);277 278	seq_printf(p, gc->label);279}280 281static const struct irq_chip tqmx86_gpio_irq_chip = {282	.irq_mask = tqmx86_gpio_irq_mask,283	.irq_unmask = tqmx86_gpio_irq_unmask,284	.irq_set_type = tqmx86_gpio_irq_set_type,285	.irq_print_chip = tqmx86_gpio_irq_print_chip,286	.flags = IRQCHIP_IMMUTABLE,287	GPIOCHIP_IRQ_RESOURCE_HELPERS,288};289 290static int tqmx86_gpio_probe(struct platform_device *pdev)291{292	struct device *dev = &pdev->dev;293	struct tqmx86_gpio_data *gpio;294	struct gpio_chip *chip;295	struct gpio_irq_chip *girq;296	void __iomem *io_base;297	struct resource *res;298	int ret, irq;299 300	irq = platform_get_irq_optional(pdev, 0);301	if (irq < 0 && irq != -ENXIO)302		return irq;303 304	res = platform_get_resource(pdev, IORESOURCE_IO, 0);305	if (!res) {306		dev_err(&pdev->dev, "Cannot get I/O\n");307		return -ENODEV;308	}309 310	io_base = devm_ioport_map(&pdev->dev, res->start, resource_size(res));311	if (!io_base)312		return -ENOMEM;313 314	gpio = devm_kzalloc(dev, sizeof(*gpio), GFP_KERNEL);315	if (!gpio)316		return -ENOMEM;317 318	raw_spin_lock_init(&gpio->spinlock);319	gpio->io_base = io_base;320 321	tqmx86_gpio_write(gpio, (u8)~TQMX86_DIR_INPUT_MASK, TQMX86_GPIODD);322 323	/*324	 * Reading the previous output state is not possible with TQMx86 hardware.325	 * Initialize all outputs to 0 to have a defined state that matches the326	 * shadow register.327	 */328	tqmx86_gpio_write(gpio, 0, TQMX86_GPIOD);329 330	chip = &gpio->chip;331	chip->label = "gpio-tqmx86";332	chip->owner = THIS_MODULE;333	chip->can_sleep = false;334	chip->base = -1;335	chip->direction_input = tqmx86_gpio_direction_input;336	chip->direction_output = tqmx86_gpio_direction_output;337	chip->get_direction = tqmx86_gpio_get_direction;338	chip->get = tqmx86_gpio_get;339	chip->set = tqmx86_gpio_set;340	chip->ngpio = TQMX86_NGPIO;341	chip->parent = pdev->dev.parent;342 343	pm_runtime_enable(&pdev->dev);344 345	if (irq > 0) {346		u8 irq_status;347 348		/* Mask all interrupts */349		tqmx86_gpio_write(gpio, 0, TQMX86_GPIIC);350 351		/* Clear all pending interrupts */352		irq_status = tqmx86_gpio_read(gpio, TQMX86_GPIIS);353		tqmx86_gpio_write(gpio, irq_status, TQMX86_GPIIS);354 355		girq = &chip->irq;356		gpio_irq_chip_set_chip(girq, &tqmx86_gpio_irq_chip);357		girq->parent_handler = tqmx86_gpio_irq_handler;358		girq->num_parents = 1;359		girq->parents = devm_kcalloc(&pdev->dev, 1,360					     sizeof(*girq->parents),361					     GFP_KERNEL);362		if (!girq->parents) {363			ret = -ENOMEM;364			goto out_pm_dis;365		}366		girq->parents[0] = irq;367		girq->default_type = IRQ_TYPE_NONE;368		girq->handler = handle_simple_irq;369		girq->init_valid_mask = tqmx86_init_irq_valid_mask;370 371		irq_domain_set_pm_device(girq->domain, dev);372	}373 374	ret = devm_gpiochip_add_data(dev, chip, gpio);375	if (ret) {376		dev_err(dev, "Could not register GPIO chip\n");377		goto out_pm_dis;378	}379 380	dev_info(dev, "GPIO functionality initialized with %d pins\n",381		 chip->ngpio);382 383	return 0;384 385out_pm_dis:386	pm_runtime_disable(&pdev->dev);387 388	return ret;389}390 391static struct platform_driver tqmx86_gpio_driver = {392	.driver = {393		.name = "tqmx86-gpio",394		.pm = &tqmx86_gpio_dev_pm_ops,395	},396	.probe		= tqmx86_gpio_probe,397};398 399module_platform_driver(tqmx86_gpio_driver);400 401MODULE_DESCRIPTION("TQMx86 PLD GPIO Driver");402MODULE_AUTHOR("Andrew Lunn <andrew@lunn.ch>");403MODULE_LICENSE("GPL");404MODULE_ALIAS("platform:tqmx86-gpio");405