brintos

brintos / linux-shallow public Read only

0
0
Text · 13.0 KiB · 4b29aba Raw
517 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Intel Tangier GPIO driver4 *5 * Copyright (c) 2016, 2021, 2023 Intel Corporation.6 *7 * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com>8 *          Pandith N <pandith.n@intel.com>9 *          Raag Jadav <raag.jadav@intel.com>10 */11 12#include <linux/bitops.h>13#include <linux/cleanup.h>14#include <linux/device.h>15#include <linux/errno.h>16#include <linux/export.h>17#include <linux/interrupt.h>18#include <linux/io.h>19#include <linux/irq.h>20#include <linux/math.h>21#include <linux/module.h>22#include <linux/pinctrl/pinconf-generic.h>23#include <linux/pm.h>24#include <linux/spinlock.h>25#include <linux/string_helpers.h>26#include <linux/types.h>27 28#include <linux/gpio/driver.h>29 30#include "gpio-tangier.h"31 32#define GCCR		0x000	/* Controller configuration */33#define GPLR		0x004	/* Pin level r/o */34#define GPDR		0x01c	/* Pin direction */35#define GPSR		0x034	/* Pin set w/o */36#define GPCR		0x04c	/* Pin clear w/o */37#define GRER		0x064	/* Rising edge detect */38#define GFER		0x07c	/* Falling edge detect */39#define GFBR		0x094	/* Glitch filter bypass */40#define GIMR		0x0ac	/* Interrupt mask */41#define GISR		0x0c4	/* Interrupt source */42#define GITR		0x300	/* Input type */43#define GLPR		0x318	/* Level input polarity */44 45/**46 * struct tng_gpio_context - Context to be saved during suspend-resume47 * @level: Pin level48 * @gpdr: Pin direction49 * @grer: Rising edge detect enable50 * @gfer: Falling edge detect enable51 * @gimr: Interrupt mask52 * @gwmr: Wake mask53 */54struct tng_gpio_context {55	u32 level;56	u32 gpdr;57	u32 grer;58	u32 gfer;59	u32 gimr;60	u32 gwmr;61};62 63static void __iomem *gpio_reg(struct gpio_chip *chip, unsigned int offset,64			      unsigned int reg)65{66	struct tng_gpio *priv = gpiochip_get_data(chip);67	u8 reg_offset = offset / 32;68 69	return priv->reg_base + reg + reg_offset * 4;70}71 72static void __iomem *gpio_reg_and_bit(struct gpio_chip *chip, unsigned int offset,73				      unsigned int reg, u8 *bit)74{75	struct tng_gpio *priv = gpiochip_get_data(chip);76	u8 reg_offset = offset / 32;77	u8 shift = offset % 32;78 79	*bit = shift;80	return priv->reg_base + reg + reg_offset * 4;81}82 83static int tng_gpio_get(struct gpio_chip *chip, unsigned int offset)84{85	void __iomem *gplr;86	u8 shift;87 88	gplr = gpio_reg_and_bit(chip, offset, GPLR, &shift);89 90	return !!(readl(gplr) & BIT(shift));91}92 93static void tng_gpio_set(struct gpio_chip *chip, unsigned int offset, int value)94{95	struct tng_gpio *priv = gpiochip_get_data(chip);96	void __iomem *reg;97	u8 shift;98 99	reg = gpio_reg_and_bit(chip, offset, value ? GPSR : GPCR, &shift);100 101	guard(raw_spinlock_irqsave)(&priv->lock);102 103	writel(BIT(shift), reg);104}105 106static int tng_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)107{108	struct tng_gpio *priv = gpiochip_get_data(chip);109	void __iomem *gpdr;110	u32 value;111	u8 shift;112 113	gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift);114 115	guard(raw_spinlock_irqsave)(&priv->lock);116 117	value = readl(gpdr);118	value &= ~BIT(shift);119	writel(value, gpdr);120 121	return 0;122}123 124static int tng_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,125				     int value)126{127	struct tng_gpio *priv = gpiochip_get_data(chip);128	void __iomem *gpdr;129	u8 shift;130 131	gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift);132	tng_gpio_set(chip, offset, value);133 134	guard(raw_spinlock_irqsave)(&priv->lock);135 136	value = readl(gpdr);137	value |= BIT(shift);138	writel(value, gpdr);139 140	return 0;141}142 143static int tng_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)144{145	void __iomem *gpdr;146	u8 shift;147 148	gpdr = gpio_reg_and_bit(chip, offset, GPDR, &shift);149 150	if (readl(gpdr) & BIT(shift))151		return GPIO_LINE_DIRECTION_OUT;152 153	return GPIO_LINE_DIRECTION_IN;154}155 156static int tng_gpio_set_debounce(struct gpio_chip *chip, unsigned int offset,157				 unsigned int debounce)158{159	struct tng_gpio *priv = gpiochip_get_data(chip);160	void __iomem *gfbr;161	u32 value;162	u8 shift;163 164	gfbr = gpio_reg_and_bit(chip, offset, GFBR, &shift);165 166	guard(raw_spinlock_irqsave)(&priv->lock);167 168	value = readl(gfbr);169	if (debounce)170		value &= ~BIT(shift);171	else172		value |= BIT(shift);173	writel(value, gfbr);174 175	return 0;176}177 178static int tng_gpio_set_config(struct gpio_chip *chip, unsigned int offset,179			       unsigned long config)180{181	u32 debounce;182 183	switch (pinconf_to_config_param(config)) {184	case PIN_CONFIG_BIAS_DISABLE:185	case PIN_CONFIG_BIAS_PULL_UP:186	case PIN_CONFIG_BIAS_PULL_DOWN:187		return gpiochip_generic_config(chip, offset, config);188	case PIN_CONFIG_INPUT_DEBOUNCE:189		debounce = pinconf_to_config_argument(config);190		return tng_gpio_set_debounce(chip, offset, debounce);191	default:192		return -ENOTSUPP;193	}194}195 196static void tng_irq_ack(struct irq_data *d)197{198	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);199	struct tng_gpio *priv = gpiochip_get_data(gc);200	irq_hw_number_t gpio = irqd_to_hwirq(d);201	void __iomem *gisr;202	u8 shift;203 204	gisr = gpio_reg_and_bit(&priv->chip, gpio, GISR, &shift);205 206	guard(raw_spinlock_irqsave)(&priv->lock);207 208	writel(BIT(shift), gisr);209}210 211static void tng_irq_unmask_mask(struct tng_gpio *priv, u32 gpio, bool unmask)212{213	void __iomem *gimr;214	u32 value;215	u8 shift;216 217	gimr = gpio_reg_and_bit(&priv->chip, gpio, GIMR, &shift);218 219	guard(raw_spinlock_irqsave)(&priv->lock);220 221	value = readl(gimr);222	if (unmask)223		value |= BIT(shift);224	else225		value &= ~BIT(shift);226	writel(value, gimr);227}228 229static void tng_irq_mask(struct irq_data *d)230{231	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);232	struct tng_gpio *priv = gpiochip_get_data(gc);233	irq_hw_number_t gpio = irqd_to_hwirq(d);234 235	tng_irq_unmask_mask(priv, gpio, false);236	gpiochip_disable_irq(&priv->chip, gpio);237}238 239static void tng_irq_unmask(struct irq_data *d)240{241	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);242	struct tng_gpio *priv = gpiochip_get_data(gc);243	irq_hw_number_t gpio = irqd_to_hwirq(d);244 245	gpiochip_enable_irq(&priv->chip, gpio);246	tng_irq_unmask_mask(priv, gpio, true);247}248 249static int tng_irq_set_type(struct irq_data *d, unsigned int type)250{251	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);252	struct tng_gpio *priv = gpiochip_get_data(gc);253	irq_hw_number_t gpio = irqd_to_hwirq(d);254	void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER);255	void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER);256	void __iomem *gitr = gpio_reg(&priv->chip, gpio, GITR);257	void __iomem *glpr = gpio_reg(&priv->chip, gpio, GLPR);258	u8 shift = gpio % 32;259	u32 value;260 261	guard(raw_spinlock_irqsave)(&priv->lock);262 263	value = readl(grer);264	if (type & IRQ_TYPE_EDGE_RISING)265		value |= BIT(shift);266	else267		value &= ~BIT(shift);268	writel(value, grer);269 270	value = readl(gfer);271	if (type & IRQ_TYPE_EDGE_FALLING)272		value |= BIT(shift);273	else274		value &= ~BIT(shift);275	writel(value, gfer);276 277	/*278	 * To prevent glitches from triggering an unintended level interrupt,279	 * configure GLPR register first and then configure GITR.280	 */281	value = readl(glpr);282	if (type & IRQ_TYPE_LEVEL_LOW)283		value |= BIT(shift);284	else285		value &= ~BIT(shift);286	writel(value, glpr);287 288	if (type & IRQ_TYPE_LEVEL_MASK) {289		value = readl(gitr);290		value |= BIT(shift);291		writel(value, gitr);292 293		irq_set_handler_locked(d, handle_level_irq);294	} else if (type & IRQ_TYPE_EDGE_BOTH) {295		value = readl(gitr);296		value &= ~BIT(shift);297		writel(value, gitr);298 299		irq_set_handler_locked(d, handle_edge_irq);300	}301 302	return 0;303}304 305static int tng_irq_set_wake(struct irq_data *d, unsigned int on)306{307	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);308	struct tng_gpio *priv = gpiochip_get_data(gc);309	irq_hw_number_t gpio = irqd_to_hwirq(d);310	void __iomem *gwmr = gpio_reg(&priv->chip, gpio, priv->wake_regs.gwmr);311	void __iomem *gwsr = gpio_reg(&priv->chip, gpio, priv->wake_regs.gwsr);312	u8 shift = gpio % 32;313	u32 value;314 315	dev_dbg(priv->dev, "%s wake for gpio %lu\n", str_enable_disable(on), gpio);316 317	guard(raw_spinlock_irqsave)(&priv->lock);318 319	/* Clear the existing wake status */320	writel(BIT(shift), gwsr);321 322	value = readl(gwmr);323	if (on)324		value |= BIT(shift);325	else326		value &= ~BIT(shift);327	writel(value, gwmr);328 329	return 0;330}331 332static const struct irq_chip tng_irqchip = {333	.name		= "gpio-tangier",334	.irq_ack	= tng_irq_ack,335	.irq_mask	= tng_irq_mask,336	.irq_unmask	= tng_irq_unmask,337	.irq_set_type	= tng_irq_set_type,338	.irq_set_wake	= tng_irq_set_wake,339	.flags          = IRQCHIP_IMMUTABLE,340	GPIOCHIP_IRQ_RESOURCE_HELPERS,341};342 343static void tng_irq_handler(struct irq_desc *desc)344{345	struct gpio_chip *gc = irq_desc_get_handler_data(desc);346	struct tng_gpio *priv = gpiochip_get_data(gc);347	struct irq_chip *irqchip = irq_desc_get_chip(desc);348	unsigned long base, gpio;349 350	chained_irq_enter(irqchip, desc);351 352	/* Check GPIO controller to check which pin triggered the interrupt */353	for (base = 0; base < priv->chip.ngpio; base += 32) {354		void __iomem *gisr = gpio_reg(&priv->chip, base, GISR);355		void __iomem *gimr = gpio_reg(&priv->chip, base, GIMR);356		unsigned long pending, enabled;357 358		pending = readl(gisr);359		enabled = readl(gimr);360 361		/* Only interrupts that are enabled */362		pending &= enabled;363 364		for_each_set_bit(gpio, &pending, 32)365			generic_handle_domain_irq(gc->irq.domain, base + gpio);366	}367 368	chained_irq_exit(irqchip, desc);369}370 371static int tng_irq_init_hw(struct gpio_chip *chip)372{373	struct tng_gpio *priv = gpiochip_get_data(chip);374	void __iomem *reg;375	unsigned int base;376 377	for (base = 0; base < priv->chip.ngpio; base += 32) {378		/* Clear the rising-edge detect register */379		reg = gpio_reg(&priv->chip, base, GRER);380		writel(0, reg);381 382		/* Clear the falling-edge detect register */383		reg = gpio_reg(&priv->chip, base, GFER);384		writel(0, reg);385	}386 387	return 0;388}389 390static int tng_gpio_add_pin_ranges(struct gpio_chip *chip)391{392	struct tng_gpio *priv = gpiochip_get_data(chip);393	const struct tng_gpio_pinrange *range;394	unsigned int i;395	int ret;396 397	for (i = 0; i < priv->pin_info.nranges; i++) {398		range = &priv->pin_info.pin_ranges[i];399		ret = gpiochip_add_pin_range(&priv->chip,400					     priv->pin_info.name,401					     range->gpio_base,402					     range->pin_base,403					     range->npins);404		if (ret) {405			dev_err(priv->dev, "failed to add GPIO pin range\n");406			return ret;407		}408	}409 410	return 0;411}412 413int devm_tng_gpio_probe(struct device *dev, struct tng_gpio *gpio)414{415	const struct tng_gpio_info *info = &gpio->info;416	size_t nctx = DIV_ROUND_UP(info->ngpio, 32);417	struct gpio_irq_chip *girq;418	int ret;419 420	gpio->ctx = devm_kcalloc(dev, nctx, sizeof(*gpio->ctx), GFP_KERNEL);421	if (!gpio->ctx)422		return -ENOMEM;423 424	gpio->chip.label = dev_name(dev);425	gpio->chip.parent = dev;426	gpio->chip.request = gpiochip_generic_request;427	gpio->chip.free = gpiochip_generic_free;428	gpio->chip.direction_input = tng_gpio_direction_input;429	gpio->chip.direction_output = tng_gpio_direction_output;430	gpio->chip.get = tng_gpio_get;431	gpio->chip.set = tng_gpio_set;432	gpio->chip.get_direction = tng_gpio_get_direction;433	gpio->chip.set_config = tng_gpio_set_config;434	gpio->chip.base = info->base;435	gpio->chip.ngpio = info->ngpio;436	gpio->chip.can_sleep = false;437	gpio->chip.add_pin_ranges = tng_gpio_add_pin_ranges;438 439	raw_spin_lock_init(&gpio->lock);440 441	girq = &gpio->chip.irq;442	gpio_irq_chip_set_chip(girq, &tng_irqchip);443	girq->init_hw = tng_irq_init_hw;444	girq->parent_handler = tng_irq_handler;445	girq->num_parents = 1;446	girq->parents = devm_kcalloc(dev, girq->num_parents,447				     sizeof(*girq->parents), GFP_KERNEL);448	if (!girq->parents)449		return -ENOMEM;450 451	girq->parents[0] = gpio->irq;452	girq->first = info->first;453	girq->default_type = IRQ_TYPE_NONE;454	girq->handler = handle_bad_irq;455 456	ret = devm_gpiochip_add_data(dev, &gpio->chip, gpio);457	if (ret)458		return dev_err_probe(dev, ret, "gpiochip_add error\n");459 460	return 0;461}462EXPORT_SYMBOL_NS_GPL(devm_tng_gpio_probe, GPIO_TANGIER);463 464static int tng_gpio_suspend(struct device *dev)465{466	struct tng_gpio *priv = dev_get_drvdata(dev);467	struct tng_gpio_context *ctx = priv->ctx;468	unsigned int base;469 470	guard(raw_spinlock_irqsave)(&priv->lock);471 472	for (base = 0; base < priv->chip.ngpio; base += 32, ctx++) {473		/* GPLR is RO, values read will be restored using GPSR */474		ctx->level = readl(gpio_reg(&priv->chip, base, GPLR));475 476		ctx->gpdr = readl(gpio_reg(&priv->chip, base, GPDR));477		ctx->grer = readl(gpio_reg(&priv->chip, base, GRER));478		ctx->gfer = readl(gpio_reg(&priv->chip, base, GFER));479		ctx->gimr = readl(gpio_reg(&priv->chip, base, GIMR));480 481		ctx->gwmr = readl(gpio_reg(&priv->chip, base, priv->wake_regs.gwmr));482	}483 484	return 0;485}486 487static int tng_gpio_resume(struct device *dev)488{489	struct tng_gpio *priv = dev_get_drvdata(dev);490	struct tng_gpio_context *ctx = priv->ctx;491	unsigned int base;492 493	guard(raw_spinlock_irqsave)(&priv->lock);494 495	for (base = 0; base < priv->chip.ngpio; base += 32, ctx++) {496		/* GPLR is RO, values read will be restored using GPSR */497		writel(ctx->level, gpio_reg(&priv->chip, base, GPSR));498 499		writel(ctx->gpdr, gpio_reg(&priv->chip, base, GPDR));500		writel(ctx->grer, gpio_reg(&priv->chip, base, GRER));501		writel(ctx->gfer, gpio_reg(&priv->chip, base, GFER));502		writel(ctx->gimr, gpio_reg(&priv->chip, base, GIMR));503 504		writel(ctx->gwmr, gpio_reg(&priv->chip, base, priv->wake_regs.gwmr));505	}506 507	return 0;508}509 510EXPORT_NS_GPL_SIMPLE_DEV_PM_OPS(tng_gpio_pm_ops, tng_gpio_suspend, tng_gpio_resume, GPIO_TANGIER);511 512MODULE_AUTHOR("Andy Shevchenko <andriy.shevchenko@linux.intel.com>");513MODULE_AUTHOR("Pandith N <pandith.n@intel.com>");514MODULE_AUTHOR("Raag Jadav <raag.jadav@intel.com>");515MODULE_DESCRIPTION("Intel Tangier GPIO driver");516MODULE_LICENSE("GPL");517