162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * GPIO driver for Marvell SoCs 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 Marvell 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 862306a36Sopenharmony_ci * Andrew Lunn <andrew@lunn.ch> 962306a36Sopenharmony_ci * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com> 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * This driver is a fairly straightforward GPIO driver for the 1262306a36Sopenharmony_ci * complete family of Marvell EBU SoC platforms (Orion, Dove, 1362306a36Sopenharmony_ci * Kirkwood, Discovery, Armada 370/XP). The only complexity of this 1462306a36Sopenharmony_ci * driver is the different register layout that exists between the 1562306a36Sopenharmony_ci * non-SMP platforms (Orion, Dove, Kirkwood, Armada 370) and the SMP 1662306a36Sopenharmony_ci * platforms (MV78200 from the Discovery family and the Armada 1762306a36Sopenharmony_ci * XP). Therefore, this driver handles three variants of the GPIO 1862306a36Sopenharmony_ci * block: 1962306a36Sopenharmony_ci * - the basic variant, called "orion-gpio", with the simplest 2062306a36Sopenharmony_ci * register set. Used on Orion, Dove, Kirkwoord, Armada 370 and 2162306a36Sopenharmony_ci * non-SMP Discovery systems 2262306a36Sopenharmony_ci * - the mv78200 variant for MV78200 Discovery systems. This variant 2362306a36Sopenharmony_ci * turns the edge mask and level mask registers into CPU0 edge 2462306a36Sopenharmony_ci * mask/level mask registers, and adds CPU1 edge mask/level mask 2562306a36Sopenharmony_ci * registers. 2662306a36Sopenharmony_ci * - the armadaxp variant for Armada XP systems. This variant keeps 2762306a36Sopenharmony_ci * the normal cause/edge mask/level mask registers when the global 2862306a36Sopenharmony_ci * interrupts are used, but adds per-CPU cause/edge mask/level mask 2962306a36Sopenharmony_ci * registers n a separate memory area for the per-CPU GPIO 3062306a36Sopenharmony_ci * interrupts. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include <linux/bitops.h> 3462306a36Sopenharmony_ci#include <linux/clk.h> 3562306a36Sopenharmony_ci#include <linux/err.h> 3662306a36Sopenharmony_ci#include <linux/gpio/driver.h> 3762306a36Sopenharmony_ci#include <linux/gpio/consumer.h> 3862306a36Sopenharmony_ci#include <linux/gpio/machine.h> 3962306a36Sopenharmony_ci#include <linux/init.h> 4062306a36Sopenharmony_ci#include <linux/io.h> 4162306a36Sopenharmony_ci#include <linux/irq.h> 4262306a36Sopenharmony_ci#include <linux/irqchip/chained_irq.h> 4362306a36Sopenharmony_ci#include <linux/irqdomain.h> 4462306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 4562306a36Sopenharmony_ci#include <linux/of_device.h> 4662306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 4762306a36Sopenharmony_ci#include <linux/platform_device.h> 4862306a36Sopenharmony_ci#include <linux/pwm.h> 4962306a36Sopenharmony_ci#include <linux/regmap.h> 5062306a36Sopenharmony_ci#include <linux/slab.h> 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/* 5362306a36Sopenharmony_ci * GPIO unit register offsets. 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci#define GPIO_OUT_OFF 0x0000 5662306a36Sopenharmony_ci#define GPIO_IO_CONF_OFF 0x0004 5762306a36Sopenharmony_ci#define GPIO_BLINK_EN_OFF 0x0008 5862306a36Sopenharmony_ci#define GPIO_IN_POL_OFF 0x000c 5962306a36Sopenharmony_ci#define GPIO_DATA_IN_OFF 0x0010 6062306a36Sopenharmony_ci#define GPIO_EDGE_CAUSE_OFF 0x0014 6162306a36Sopenharmony_ci#define GPIO_EDGE_MASK_OFF 0x0018 6262306a36Sopenharmony_ci#define GPIO_LEVEL_MASK_OFF 0x001c 6362306a36Sopenharmony_ci#define GPIO_BLINK_CNT_SELECT_OFF 0x0020 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* 6662306a36Sopenharmony_ci * PWM register offsets. 6762306a36Sopenharmony_ci */ 6862306a36Sopenharmony_ci#define PWM_BLINK_ON_DURATION_OFF 0x0 6962306a36Sopenharmony_ci#define PWM_BLINK_OFF_DURATION_OFF 0x4 7062306a36Sopenharmony_ci#define PWM_BLINK_COUNTER_B_OFF 0x8 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci/* Armada 8k variant gpios register offsets */ 7362306a36Sopenharmony_ci#define AP80X_GPIO0_OFF_A8K 0x1040 7462306a36Sopenharmony_ci#define CP11X_GPIO0_OFF_A8K 0x100 7562306a36Sopenharmony_ci#define CP11X_GPIO1_OFF_A8K 0x140 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/* The MV78200 has per-CPU registers for edge mask and level mask */ 7862306a36Sopenharmony_ci#define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18) 7962306a36Sopenharmony_ci#define GPIO_LEVEL_MASK_MV78200_OFF(cpu) ((cpu) ? 0x34 : 0x1C) 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* 8262306a36Sopenharmony_ci * The Armada XP has per-CPU registers for interrupt cause, interrupt 8362306a36Sopenharmony_ci * mask and interrupt level mask. Those are in percpu_regs range. 8462306a36Sopenharmony_ci */ 8562306a36Sopenharmony_ci#define GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu) ((cpu) * 0x4) 8662306a36Sopenharmony_ci#define GPIO_EDGE_MASK_ARMADAXP_OFF(cpu) (0x10 + (cpu) * 0x4) 8762306a36Sopenharmony_ci#define GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu) (0x20 + (cpu) * 0x4) 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#define MVEBU_GPIO_SOC_VARIANT_ORION 0x1 9062306a36Sopenharmony_ci#define MVEBU_GPIO_SOC_VARIANT_MV78200 0x2 9162306a36Sopenharmony_ci#define MVEBU_GPIO_SOC_VARIANT_ARMADAXP 0x3 9262306a36Sopenharmony_ci#define MVEBU_GPIO_SOC_VARIANT_A8K 0x4 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci#define MVEBU_MAX_GPIO_PER_BANK 32 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cistruct mvebu_pwm { 9762306a36Sopenharmony_ci struct regmap *regs; 9862306a36Sopenharmony_ci u32 offset; 9962306a36Sopenharmony_ci unsigned long clk_rate; 10062306a36Sopenharmony_ci struct gpio_desc *gpiod; 10162306a36Sopenharmony_ci struct pwm_chip chip; 10262306a36Sopenharmony_ci spinlock_t lock; 10362306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci /* Used to preserve GPIO/PWM registers across suspend/resume */ 10662306a36Sopenharmony_ci u32 blink_select; 10762306a36Sopenharmony_ci u32 blink_on_duration; 10862306a36Sopenharmony_ci u32 blink_off_duration; 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistruct mvebu_gpio_chip { 11262306a36Sopenharmony_ci struct gpio_chip chip; 11362306a36Sopenharmony_ci struct regmap *regs; 11462306a36Sopenharmony_ci u32 offset; 11562306a36Sopenharmony_ci struct regmap *percpu_regs; 11662306a36Sopenharmony_ci int irqbase; 11762306a36Sopenharmony_ci struct irq_domain *domain; 11862306a36Sopenharmony_ci int soc_variant; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* Used for PWM support */ 12162306a36Sopenharmony_ci struct clk *clk; 12262306a36Sopenharmony_ci struct mvebu_pwm *mvpwm; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Used to preserve GPIO registers across suspend/resume */ 12562306a36Sopenharmony_ci u32 out_reg; 12662306a36Sopenharmony_ci u32 io_conf_reg; 12762306a36Sopenharmony_ci u32 blink_en_reg; 12862306a36Sopenharmony_ci u32 in_pol_reg; 12962306a36Sopenharmony_ci u32 edge_mask_regs[4]; 13062306a36Sopenharmony_ci u32 level_mask_regs[4]; 13162306a36Sopenharmony_ci}; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* 13462306a36Sopenharmony_ci * Functions returning addresses of individual registers for a given 13562306a36Sopenharmony_ci * GPIO controller. 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic void mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip, 13962306a36Sopenharmony_ci struct regmap **map, unsigned int *offset) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci int cpu; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci switch (mvchip->soc_variant) { 14462306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_ORION: 14562306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_MV78200: 14662306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_A8K: 14762306a36Sopenharmony_ci *map = mvchip->regs; 14862306a36Sopenharmony_ci *offset = GPIO_EDGE_CAUSE_OFF + mvchip->offset; 14962306a36Sopenharmony_ci break; 15062306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: 15162306a36Sopenharmony_ci cpu = smp_processor_id(); 15262306a36Sopenharmony_ci *map = mvchip->percpu_regs; 15362306a36Sopenharmony_ci *offset = GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu); 15462306a36Sopenharmony_ci break; 15562306a36Sopenharmony_ci default: 15662306a36Sopenharmony_ci BUG(); 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_cistatic u32 16162306a36Sopenharmony_cimvebu_gpio_read_edge_cause(struct mvebu_gpio_chip *mvchip) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct regmap *map; 16462306a36Sopenharmony_ci unsigned int offset; 16562306a36Sopenharmony_ci u32 val; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci mvebu_gpioreg_edge_cause(mvchip, &map, &offset); 16862306a36Sopenharmony_ci regmap_read(map, offset, &val); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci return val; 17162306a36Sopenharmony_ci} 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic void 17462306a36Sopenharmony_cimvebu_gpio_write_edge_cause(struct mvebu_gpio_chip *mvchip, u32 val) 17562306a36Sopenharmony_ci{ 17662306a36Sopenharmony_ci struct regmap *map; 17762306a36Sopenharmony_ci unsigned int offset; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci mvebu_gpioreg_edge_cause(mvchip, &map, &offset); 18062306a36Sopenharmony_ci regmap_write(map, offset, val); 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic inline void 18462306a36Sopenharmony_cimvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip, 18562306a36Sopenharmony_ci struct regmap **map, unsigned int *offset) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci int cpu; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci switch (mvchip->soc_variant) { 19062306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_ORION: 19162306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_A8K: 19262306a36Sopenharmony_ci *map = mvchip->regs; 19362306a36Sopenharmony_ci *offset = GPIO_EDGE_MASK_OFF + mvchip->offset; 19462306a36Sopenharmony_ci break; 19562306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_MV78200: 19662306a36Sopenharmony_ci cpu = smp_processor_id(); 19762306a36Sopenharmony_ci *map = mvchip->regs; 19862306a36Sopenharmony_ci *offset = GPIO_EDGE_MASK_MV78200_OFF(cpu); 19962306a36Sopenharmony_ci break; 20062306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: 20162306a36Sopenharmony_ci cpu = smp_processor_id(); 20262306a36Sopenharmony_ci *map = mvchip->percpu_regs; 20362306a36Sopenharmony_ci *offset = GPIO_EDGE_MASK_ARMADAXP_OFF(cpu); 20462306a36Sopenharmony_ci break; 20562306a36Sopenharmony_ci default: 20662306a36Sopenharmony_ci BUG(); 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci} 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistatic u32 21162306a36Sopenharmony_cimvebu_gpio_read_edge_mask(struct mvebu_gpio_chip *mvchip) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct regmap *map; 21462306a36Sopenharmony_ci unsigned int offset; 21562306a36Sopenharmony_ci u32 val; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci mvebu_gpioreg_edge_mask(mvchip, &map, &offset); 21862306a36Sopenharmony_ci regmap_read(map, offset, &val); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return val; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic void 22462306a36Sopenharmony_cimvebu_gpio_write_edge_mask(struct mvebu_gpio_chip *mvchip, u32 val) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct regmap *map; 22762306a36Sopenharmony_ci unsigned int offset; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci mvebu_gpioreg_edge_mask(mvchip, &map, &offset); 23062306a36Sopenharmony_ci regmap_write(map, offset, val); 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic void 23462306a36Sopenharmony_cimvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip, 23562306a36Sopenharmony_ci struct regmap **map, unsigned int *offset) 23662306a36Sopenharmony_ci{ 23762306a36Sopenharmony_ci int cpu; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci switch (mvchip->soc_variant) { 24062306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_ORION: 24162306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_A8K: 24262306a36Sopenharmony_ci *map = mvchip->regs; 24362306a36Sopenharmony_ci *offset = GPIO_LEVEL_MASK_OFF + mvchip->offset; 24462306a36Sopenharmony_ci break; 24562306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_MV78200: 24662306a36Sopenharmony_ci cpu = smp_processor_id(); 24762306a36Sopenharmony_ci *map = mvchip->regs; 24862306a36Sopenharmony_ci *offset = GPIO_LEVEL_MASK_MV78200_OFF(cpu); 24962306a36Sopenharmony_ci break; 25062306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: 25162306a36Sopenharmony_ci cpu = smp_processor_id(); 25262306a36Sopenharmony_ci *map = mvchip->percpu_regs; 25362306a36Sopenharmony_ci *offset = GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu); 25462306a36Sopenharmony_ci break; 25562306a36Sopenharmony_ci default: 25662306a36Sopenharmony_ci BUG(); 25762306a36Sopenharmony_ci } 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic u32 26162306a36Sopenharmony_cimvebu_gpio_read_level_mask(struct mvebu_gpio_chip *mvchip) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci struct regmap *map; 26462306a36Sopenharmony_ci unsigned int offset; 26562306a36Sopenharmony_ci u32 val; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci mvebu_gpioreg_level_mask(mvchip, &map, &offset); 26862306a36Sopenharmony_ci regmap_read(map, offset, &val); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci return val; 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic void 27462306a36Sopenharmony_cimvebu_gpio_write_level_mask(struct mvebu_gpio_chip *mvchip, u32 val) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct regmap *map; 27762306a36Sopenharmony_ci unsigned int offset; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci mvebu_gpioreg_level_mask(mvchip, &map, &offset); 28062306a36Sopenharmony_ci regmap_write(map, offset, val); 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci/* 28462306a36Sopenharmony_ci * Functions returning offsets of individual registers for a given 28562306a36Sopenharmony_ci * PWM controller. 28662306a36Sopenharmony_ci */ 28762306a36Sopenharmony_cistatic unsigned int mvebu_pwmreg_blink_on_duration(struct mvebu_pwm *mvpwm) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci return mvpwm->offset + PWM_BLINK_ON_DURATION_OFF; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_cistatic unsigned int mvebu_pwmreg_blink_off_duration(struct mvebu_pwm *mvpwm) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci return mvpwm->offset + PWM_BLINK_OFF_DURATION_OFF; 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci/* 29862306a36Sopenharmony_ci * Functions implementing the gpio_chip methods 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_cistatic void mvebu_gpio_set(struct gpio_chip *chip, unsigned int pin, int value) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci regmap_update_bits(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, 30562306a36Sopenharmony_ci BIT(pin), value ? BIT(pin) : 0); 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic int mvebu_gpio_get(struct gpio_chip *chip, unsigned int pin) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); 31162306a36Sopenharmony_ci u32 u; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &u); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (u & BIT(pin)) { 31662306a36Sopenharmony_ci u32 data_in, in_pol; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_DATA_IN_OFF + mvchip->offset, 31962306a36Sopenharmony_ci &data_in); 32062306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset, 32162306a36Sopenharmony_ci &in_pol); 32262306a36Sopenharmony_ci u = data_in ^ in_pol; 32362306a36Sopenharmony_ci } else { 32462306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, &u); 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci return (u >> pin) & 1; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_cistatic void mvebu_gpio_blink(struct gpio_chip *chip, unsigned int pin, 33162306a36Sopenharmony_ci int value) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci regmap_update_bits(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, 33662306a36Sopenharmony_ci BIT(pin), value ? BIT(pin) : 0); 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic int mvebu_gpio_direction_input(struct gpio_chip *chip, unsigned int pin) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); 34262306a36Sopenharmony_ci int ret; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* 34562306a36Sopenharmony_ci * Check with the pinctrl driver whether this pin is usable as 34662306a36Sopenharmony_ci * an input GPIO 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci ret = pinctrl_gpio_direction_input(chip->base + pin); 34962306a36Sopenharmony_ci if (ret) 35062306a36Sopenharmony_ci return ret; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci regmap_update_bits(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, 35362306a36Sopenharmony_ci BIT(pin), BIT(pin)); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci return 0; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic int mvebu_gpio_direction_output(struct gpio_chip *chip, unsigned int pin, 35962306a36Sopenharmony_ci int value) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); 36262306a36Sopenharmony_ci int ret; 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci /* 36562306a36Sopenharmony_ci * Check with the pinctrl driver whether this pin is usable as 36662306a36Sopenharmony_ci * an output GPIO 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_ci ret = pinctrl_gpio_direction_output(chip->base + pin); 36962306a36Sopenharmony_ci if (ret) 37062306a36Sopenharmony_ci return ret; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci mvebu_gpio_blink(chip, pin, 0); 37362306a36Sopenharmony_ci mvebu_gpio_set(chip, pin, value); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci regmap_update_bits(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, 37662306a36Sopenharmony_ci BIT(pin), 0); 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci return 0; 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic int mvebu_gpio_get_direction(struct gpio_chip *chip, unsigned int pin) 38262306a36Sopenharmony_ci{ 38362306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); 38462306a36Sopenharmony_ci u32 u; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &u); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci if (u & BIT(pin)) 38962306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic int mvebu_gpio_to_irq(struct gpio_chip *chip, unsigned int pin) 39562306a36Sopenharmony_ci{ 39662306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci return irq_create_mapping(mvchip->domain, pin); 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci/* 40262306a36Sopenharmony_ci * Functions implementing the irq_chip methods 40362306a36Sopenharmony_ci */ 40462306a36Sopenharmony_cistatic void mvebu_gpio_irq_ack(struct irq_data *d) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 40762306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = gc->private; 40862306a36Sopenharmony_ci u32 mask = d->mask; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci irq_gc_lock(gc); 41162306a36Sopenharmony_ci mvebu_gpio_write_edge_cause(mvchip, ~mask); 41262306a36Sopenharmony_ci irq_gc_unlock(gc); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic void mvebu_gpio_edge_irq_mask(struct irq_data *d) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 41862306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = gc->private; 41962306a36Sopenharmony_ci struct irq_chip_type *ct = irq_data_get_chip_type(d); 42062306a36Sopenharmony_ci u32 mask = d->mask; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci irq_gc_lock(gc); 42362306a36Sopenharmony_ci ct->mask_cache_priv &= ~mask; 42462306a36Sopenharmony_ci mvebu_gpio_write_edge_mask(mvchip, ct->mask_cache_priv); 42562306a36Sopenharmony_ci irq_gc_unlock(gc); 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic void mvebu_gpio_edge_irq_unmask(struct irq_data *d) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 43162306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = gc->private; 43262306a36Sopenharmony_ci struct irq_chip_type *ct = irq_data_get_chip_type(d); 43362306a36Sopenharmony_ci u32 mask = d->mask; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci irq_gc_lock(gc); 43662306a36Sopenharmony_ci mvebu_gpio_write_edge_cause(mvchip, ~mask); 43762306a36Sopenharmony_ci ct->mask_cache_priv |= mask; 43862306a36Sopenharmony_ci mvebu_gpio_write_edge_mask(mvchip, ct->mask_cache_priv); 43962306a36Sopenharmony_ci irq_gc_unlock(gc); 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic void mvebu_gpio_level_irq_mask(struct irq_data *d) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 44562306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = gc->private; 44662306a36Sopenharmony_ci struct irq_chip_type *ct = irq_data_get_chip_type(d); 44762306a36Sopenharmony_ci u32 mask = d->mask; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci irq_gc_lock(gc); 45062306a36Sopenharmony_ci ct->mask_cache_priv &= ~mask; 45162306a36Sopenharmony_ci mvebu_gpio_write_level_mask(mvchip, ct->mask_cache_priv); 45262306a36Sopenharmony_ci irq_gc_unlock(gc); 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic void mvebu_gpio_level_irq_unmask(struct irq_data *d) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 45862306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = gc->private; 45962306a36Sopenharmony_ci struct irq_chip_type *ct = irq_data_get_chip_type(d); 46062306a36Sopenharmony_ci u32 mask = d->mask; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci irq_gc_lock(gc); 46362306a36Sopenharmony_ci ct->mask_cache_priv |= mask; 46462306a36Sopenharmony_ci mvebu_gpio_write_level_mask(mvchip, ct->mask_cache_priv); 46562306a36Sopenharmony_ci irq_gc_unlock(gc); 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci/***************************************************************************** 46962306a36Sopenharmony_ci * MVEBU GPIO IRQ 47062306a36Sopenharmony_ci * 47162306a36Sopenharmony_ci * GPIO_IN_POL register controls whether GPIO_DATA_IN will hold the same 47262306a36Sopenharmony_ci * value of the line or the opposite value. 47362306a36Sopenharmony_ci * 47462306a36Sopenharmony_ci * Level IRQ handlers: DATA_IN is used directly as cause register. 47562306a36Sopenharmony_ci * Interrupt are masked by LEVEL_MASK registers. 47662306a36Sopenharmony_ci * Edge IRQ handlers: Change in DATA_IN are latched in EDGE_CAUSE. 47762306a36Sopenharmony_ci * Interrupt are masked by EDGE_MASK registers. 47862306a36Sopenharmony_ci * Both-edge handlers: Similar to regular Edge handlers, but also swaps 47962306a36Sopenharmony_ci * the polarity to catch the next line transaction. 48062306a36Sopenharmony_ci * This is a race condition that might not perfectly 48162306a36Sopenharmony_ci * work on some use cases. 48262306a36Sopenharmony_ci * 48362306a36Sopenharmony_ci * Every eight GPIO lines are grouped (OR'ed) before going up to main 48462306a36Sopenharmony_ci * cause register. 48562306a36Sopenharmony_ci * 48662306a36Sopenharmony_ci * EDGE cause mask 48762306a36Sopenharmony_ci * data-in /--------| |-----| |----\ 48862306a36Sopenharmony_ci * -----| |----- ---- to main cause reg 48962306a36Sopenharmony_ci * X \----------------| |----/ 49062306a36Sopenharmony_ci * polarity LEVEL mask 49162306a36Sopenharmony_ci * 49262306a36Sopenharmony_ci ****************************************************************************/ 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_cistatic int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 49762306a36Sopenharmony_ci struct irq_chip_type *ct = irq_data_get_chip_type(d); 49862306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = gc->private; 49962306a36Sopenharmony_ci int pin; 50062306a36Sopenharmony_ci u32 u; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci pin = d->hwirq; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &u); 50562306a36Sopenharmony_ci if ((u & BIT(pin)) == 0) 50662306a36Sopenharmony_ci return -EINVAL; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci type &= IRQ_TYPE_SENSE_MASK; 50962306a36Sopenharmony_ci if (type == IRQ_TYPE_NONE) 51062306a36Sopenharmony_ci return -EINVAL; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci /* Check if we need to change chip and handler */ 51362306a36Sopenharmony_ci if (!(ct->type & type)) 51462306a36Sopenharmony_ci if (irq_setup_alt_chip(d, type)) 51562306a36Sopenharmony_ci return -EINVAL; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci /* 51862306a36Sopenharmony_ci * Configure interrupt polarity. 51962306a36Sopenharmony_ci */ 52062306a36Sopenharmony_ci switch (type) { 52162306a36Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 52262306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 52362306a36Sopenharmony_ci regmap_update_bits(mvchip->regs, 52462306a36Sopenharmony_ci GPIO_IN_POL_OFF + mvchip->offset, 52562306a36Sopenharmony_ci BIT(pin), 0); 52662306a36Sopenharmony_ci break; 52762306a36Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 52862306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 52962306a36Sopenharmony_ci regmap_update_bits(mvchip->regs, 53062306a36Sopenharmony_ci GPIO_IN_POL_OFF + mvchip->offset, 53162306a36Sopenharmony_ci BIT(pin), BIT(pin)); 53262306a36Sopenharmony_ci break; 53362306a36Sopenharmony_ci case IRQ_TYPE_EDGE_BOTH: { 53462306a36Sopenharmony_ci u32 data_in, in_pol, val; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci regmap_read(mvchip->regs, 53762306a36Sopenharmony_ci GPIO_IN_POL_OFF + mvchip->offset, &in_pol); 53862306a36Sopenharmony_ci regmap_read(mvchip->regs, 53962306a36Sopenharmony_ci GPIO_DATA_IN_OFF + mvchip->offset, &data_in); 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci /* 54262306a36Sopenharmony_ci * set initial polarity based on current input level 54362306a36Sopenharmony_ci */ 54462306a36Sopenharmony_ci if ((data_in ^ in_pol) & BIT(pin)) 54562306a36Sopenharmony_ci val = BIT(pin); /* falling */ 54662306a36Sopenharmony_ci else 54762306a36Sopenharmony_ci val = 0; /* raising */ 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci regmap_update_bits(mvchip->regs, 55062306a36Sopenharmony_ci GPIO_IN_POL_OFF + mvchip->offset, 55162306a36Sopenharmony_ci BIT(pin), val); 55262306a36Sopenharmony_ci break; 55362306a36Sopenharmony_ci } 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci return 0; 55662306a36Sopenharmony_ci} 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_cistatic void mvebu_gpio_irq_handler(struct irq_desc *desc) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = irq_desc_get_handler_data(desc); 56162306a36Sopenharmony_ci struct irq_chip *chip = irq_desc_get_chip(desc); 56262306a36Sopenharmony_ci u32 cause, type, data_in, level_mask, edge_cause, edge_mask; 56362306a36Sopenharmony_ci int i; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci if (mvchip == NULL) 56662306a36Sopenharmony_ci return; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci chained_irq_enter(chip, desc); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_DATA_IN_OFF + mvchip->offset, &data_in); 57162306a36Sopenharmony_ci level_mask = mvebu_gpio_read_level_mask(mvchip); 57262306a36Sopenharmony_ci edge_cause = mvebu_gpio_read_edge_cause(mvchip); 57362306a36Sopenharmony_ci edge_mask = mvebu_gpio_read_edge_mask(mvchip); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci cause = (data_in & level_mask) | (edge_cause & edge_mask); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci for (i = 0; i < mvchip->chip.ngpio; i++) { 57862306a36Sopenharmony_ci int irq; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci irq = irq_find_mapping(mvchip->domain, i); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (!(cause & BIT(i))) 58362306a36Sopenharmony_ci continue; 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci type = irq_get_trigger_type(irq); 58662306a36Sopenharmony_ci if ((type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH) { 58762306a36Sopenharmony_ci /* Swap polarity (race with GPIO line) */ 58862306a36Sopenharmony_ci u32 polarity; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci regmap_read(mvchip->regs, 59162306a36Sopenharmony_ci GPIO_IN_POL_OFF + mvchip->offset, 59262306a36Sopenharmony_ci &polarity); 59362306a36Sopenharmony_ci polarity ^= BIT(i); 59462306a36Sopenharmony_ci regmap_write(mvchip->regs, 59562306a36Sopenharmony_ci GPIO_IN_POL_OFF + mvchip->offset, 59662306a36Sopenharmony_ci polarity); 59762306a36Sopenharmony_ci } 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci generic_handle_irq(irq); 60062306a36Sopenharmony_ci } 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci chained_irq_exit(chip, desc); 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic const struct regmap_config mvebu_gpio_regmap_config = { 60662306a36Sopenharmony_ci .reg_bits = 32, 60762306a36Sopenharmony_ci .reg_stride = 4, 60862306a36Sopenharmony_ci .val_bits = 32, 60962306a36Sopenharmony_ci .fast_io = true, 61062306a36Sopenharmony_ci}; 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci/* 61362306a36Sopenharmony_ci * Functions implementing the pwm_chip methods 61462306a36Sopenharmony_ci */ 61562306a36Sopenharmony_cistatic struct mvebu_pwm *to_mvebu_pwm(struct pwm_chip *chip) 61662306a36Sopenharmony_ci{ 61762306a36Sopenharmony_ci return container_of(chip, struct mvebu_pwm, chip); 61862306a36Sopenharmony_ci} 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_cistatic int mvebu_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm) 62162306a36Sopenharmony_ci{ 62262306a36Sopenharmony_ci struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); 62362306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = mvpwm->mvchip; 62462306a36Sopenharmony_ci struct gpio_desc *desc; 62562306a36Sopenharmony_ci unsigned long flags; 62662306a36Sopenharmony_ci int ret = 0; 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci spin_lock_irqsave(&mvpwm->lock, flags); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (mvpwm->gpiod) { 63162306a36Sopenharmony_ci ret = -EBUSY; 63262306a36Sopenharmony_ci } else { 63362306a36Sopenharmony_ci desc = gpiochip_request_own_desc(&mvchip->chip, 63462306a36Sopenharmony_ci pwm->hwpwm, "mvebu-pwm", 63562306a36Sopenharmony_ci GPIO_ACTIVE_HIGH, 63662306a36Sopenharmony_ci GPIOD_OUT_LOW); 63762306a36Sopenharmony_ci if (IS_ERR(desc)) { 63862306a36Sopenharmony_ci ret = PTR_ERR(desc); 63962306a36Sopenharmony_ci goto out; 64062306a36Sopenharmony_ci } 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci mvpwm->gpiod = desc; 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ciout: 64562306a36Sopenharmony_ci spin_unlock_irqrestore(&mvpwm->lock, flags); 64662306a36Sopenharmony_ci return ret; 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_cistatic void mvebu_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm) 65062306a36Sopenharmony_ci{ 65162306a36Sopenharmony_ci struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); 65262306a36Sopenharmony_ci unsigned long flags; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci spin_lock_irqsave(&mvpwm->lock, flags); 65562306a36Sopenharmony_ci gpiochip_free_own_desc(mvpwm->gpiod); 65662306a36Sopenharmony_ci mvpwm->gpiod = NULL; 65762306a36Sopenharmony_ci spin_unlock_irqrestore(&mvpwm->lock, flags); 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic int mvebu_pwm_get_state(struct pwm_chip *chip, 66162306a36Sopenharmony_ci struct pwm_device *pwm, 66262306a36Sopenharmony_ci struct pwm_state *state) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); 66662306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = mvpwm->mvchip; 66762306a36Sopenharmony_ci unsigned long long val; 66862306a36Sopenharmony_ci unsigned long flags; 66962306a36Sopenharmony_ci u32 u; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci spin_lock_irqsave(&mvpwm->lock, flags); 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), &u); 67462306a36Sopenharmony_ci /* Hardware treats zero as 2^32. See mvebu_pwm_apply(). */ 67562306a36Sopenharmony_ci if (u > 0) 67662306a36Sopenharmony_ci val = u; 67762306a36Sopenharmony_ci else 67862306a36Sopenharmony_ci val = UINT_MAX + 1ULL; 67962306a36Sopenharmony_ci state->duty_cycle = DIV_ROUND_UP_ULL(val * NSEC_PER_SEC, 68062306a36Sopenharmony_ci mvpwm->clk_rate); 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), &u); 68362306a36Sopenharmony_ci /* period = on + off duration */ 68462306a36Sopenharmony_ci if (u > 0) 68562306a36Sopenharmony_ci val += u; 68662306a36Sopenharmony_ci else 68762306a36Sopenharmony_ci val += UINT_MAX + 1ULL; 68862306a36Sopenharmony_ci state->period = DIV_ROUND_UP_ULL(val * NSEC_PER_SEC, mvpwm->clk_rate); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &u); 69162306a36Sopenharmony_ci if (u) 69262306a36Sopenharmony_ci state->enabled = true; 69362306a36Sopenharmony_ci else 69462306a36Sopenharmony_ci state->enabled = false; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci spin_unlock_irqrestore(&mvpwm->lock, flags); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci return 0; 69962306a36Sopenharmony_ci} 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_cistatic int mvebu_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm, 70262306a36Sopenharmony_ci const struct pwm_state *state) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci struct mvebu_pwm *mvpwm = to_mvebu_pwm(chip); 70562306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = mvpwm->mvchip; 70662306a36Sopenharmony_ci unsigned long long val; 70762306a36Sopenharmony_ci unsigned long flags; 70862306a36Sopenharmony_ci unsigned int on, off; 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if (state->polarity != PWM_POLARITY_NORMAL) 71162306a36Sopenharmony_ci return -EINVAL; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci val = (unsigned long long) mvpwm->clk_rate * state->duty_cycle; 71462306a36Sopenharmony_ci do_div(val, NSEC_PER_SEC); 71562306a36Sopenharmony_ci if (val > UINT_MAX + 1ULL) 71662306a36Sopenharmony_ci return -EINVAL; 71762306a36Sopenharmony_ci /* 71862306a36Sopenharmony_ci * Zero on/off values don't work as expected. Experimentation shows 71962306a36Sopenharmony_ci * that zero value is treated as 2^32. This behavior is not documented. 72062306a36Sopenharmony_ci */ 72162306a36Sopenharmony_ci if (val == UINT_MAX + 1ULL) 72262306a36Sopenharmony_ci on = 0; 72362306a36Sopenharmony_ci else if (val) 72462306a36Sopenharmony_ci on = val; 72562306a36Sopenharmony_ci else 72662306a36Sopenharmony_ci on = 1; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci val = (unsigned long long) mvpwm->clk_rate * state->period; 72962306a36Sopenharmony_ci do_div(val, NSEC_PER_SEC); 73062306a36Sopenharmony_ci val -= on; 73162306a36Sopenharmony_ci if (val > UINT_MAX + 1ULL) 73262306a36Sopenharmony_ci return -EINVAL; 73362306a36Sopenharmony_ci if (val == UINT_MAX + 1ULL) 73462306a36Sopenharmony_ci off = 0; 73562306a36Sopenharmony_ci else if (val) 73662306a36Sopenharmony_ci off = val; 73762306a36Sopenharmony_ci else 73862306a36Sopenharmony_ci off = 1; 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci spin_lock_irqsave(&mvpwm->lock, flags); 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci regmap_write(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), on); 74362306a36Sopenharmony_ci regmap_write(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), off); 74462306a36Sopenharmony_ci if (state->enabled) 74562306a36Sopenharmony_ci mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 1); 74662306a36Sopenharmony_ci else 74762306a36Sopenharmony_ci mvebu_gpio_blink(&mvchip->chip, pwm->hwpwm, 0); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci spin_unlock_irqrestore(&mvpwm->lock, flags); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci return 0; 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic const struct pwm_ops mvebu_pwm_ops = { 75562306a36Sopenharmony_ci .request = mvebu_pwm_request, 75662306a36Sopenharmony_ci .free = mvebu_pwm_free, 75762306a36Sopenharmony_ci .get_state = mvebu_pwm_get_state, 75862306a36Sopenharmony_ci .apply = mvebu_pwm_apply, 75962306a36Sopenharmony_ci .owner = THIS_MODULE, 76062306a36Sopenharmony_ci}; 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cistatic void __maybe_unused mvebu_pwm_suspend(struct mvebu_gpio_chip *mvchip) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci struct mvebu_pwm *mvpwm = mvchip->mvpwm; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, 76762306a36Sopenharmony_ci &mvpwm->blink_select); 76862306a36Sopenharmony_ci regmap_read(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), 76962306a36Sopenharmony_ci &mvpwm->blink_on_duration); 77062306a36Sopenharmony_ci regmap_read(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), 77162306a36Sopenharmony_ci &mvpwm->blink_off_duration); 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic void __maybe_unused mvebu_pwm_resume(struct mvebu_gpio_chip *mvchip) 77562306a36Sopenharmony_ci{ 77662306a36Sopenharmony_ci struct mvebu_pwm *mvpwm = mvchip->mvpwm; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci regmap_write(mvchip->regs, GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, 77962306a36Sopenharmony_ci mvpwm->blink_select); 78062306a36Sopenharmony_ci regmap_write(mvpwm->regs, mvebu_pwmreg_blink_on_duration(mvpwm), 78162306a36Sopenharmony_ci mvpwm->blink_on_duration); 78262306a36Sopenharmony_ci regmap_write(mvpwm->regs, mvebu_pwmreg_blink_off_duration(mvpwm), 78362306a36Sopenharmony_ci mvpwm->blink_off_duration); 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cistatic int mvebu_pwm_probe(struct platform_device *pdev, 78762306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip, 78862306a36Sopenharmony_ci int id) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 79162306a36Sopenharmony_ci struct mvebu_pwm *mvpwm; 79262306a36Sopenharmony_ci void __iomem *base; 79362306a36Sopenharmony_ci u32 offset; 79462306a36Sopenharmony_ci u32 set; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) { 79762306a36Sopenharmony_ci int ret = of_property_read_u32(dev->of_node, 79862306a36Sopenharmony_ci "marvell,pwm-offset", &offset); 79962306a36Sopenharmony_ci if (ret < 0) 80062306a36Sopenharmony_ci return 0; 80162306a36Sopenharmony_ci } else { 80262306a36Sopenharmony_ci /* 80362306a36Sopenharmony_ci * There are only two sets of PWM configuration registers for 80462306a36Sopenharmony_ci * all the GPIO lines on those SoCs which this driver reserves 80562306a36Sopenharmony_ci * for the first two GPIO chips. So if the resource is missing 80662306a36Sopenharmony_ci * we can't treat it as an error. 80762306a36Sopenharmony_ci */ 80862306a36Sopenharmony_ci if (!platform_get_resource_byname(pdev, IORESOURCE_MEM, "pwm")) 80962306a36Sopenharmony_ci return 0; 81062306a36Sopenharmony_ci offset = 0; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci if (IS_ERR(mvchip->clk)) 81462306a36Sopenharmony_ci return PTR_ERR(mvchip->clk); 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci mvpwm = devm_kzalloc(dev, sizeof(struct mvebu_pwm), GFP_KERNEL); 81762306a36Sopenharmony_ci if (!mvpwm) 81862306a36Sopenharmony_ci return -ENOMEM; 81962306a36Sopenharmony_ci mvchip->mvpwm = mvpwm; 82062306a36Sopenharmony_ci mvpwm->mvchip = mvchip; 82162306a36Sopenharmony_ci mvpwm->offset = offset; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) { 82462306a36Sopenharmony_ci mvpwm->regs = mvchip->regs; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci switch (mvchip->offset) { 82762306a36Sopenharmony_ci case AP80X_GPIO0_OFF_A8K: 82862306a36Sopenharmony_ci case CP11X_GPIO0_OFF_A8K: 82962306a36Sopenharmony_ci /* Blink counter A */ 83062306a36Sopenharmony_ci set = 0; 83162306a36Sopenharmony_ci break; 83262306a36Sopenharmony_ci case CP11X_GPIO1_OFF_A8K: 83362306a36Sopenharmony_ci /* Blink counter B */ 83462306a36Sopenharmony_ci set = U32_MAX; 83562306a36Sopenharmony_ci mvpwm->offset += PWM_BLINK_COUNTER_B_OFF; 83662306a36Sopenharmony_ci break; 83762306a36Sopenharmony_ci default: 83862306a36Sopenharmony_ci return -EINVAL; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci } else { 84162306a36Sopenharmony_ci base = devm_platform_ioremap_resource_byname(pdev, "pwm"); 84262306a36Sopenharmony_ci if (IS_ERR(base)) 84362306a36Sopenharmony_ci return PTR_ERR(base); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci mvpwm->regs = devm_regmap_init_mmio(&pdev->dev, base, 84662306a36Sopenharmony_ci &mvebu_gpio_regmap_config); 84762306a36Sopenharmony_ci if (IS_ERR(mvpwm->regs)) 84862306a36Sopenharmony_ci return PTR_ERR(mvpwm->regs); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci /* 85162306a36Sopenharmony_ci * Use set A for lines of GPIO chip with id 0, B for GPIO chip 85262306a36Sopenharmony_ci * with id 1. Don't allow further GPIO chips to be used for PWM. 85362306a36Sopenharmony_ci */ 85462306a36Sopenharmony_ci if (id == 0) 85562306a36Sopenharmony_ci set = 0; 85662306a36Sopenharmony_ci else if (id == 1) 85762306a36Sopenharmony_ci set = U32_MAX; 85862306a36Sopenharmony_ci else 85962306a36Sopenharmony_ci return -EINVAL; 86062306a36Sopenharmony_ci } 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci regmap_write(mvchip->regs, 86362306a36Sopenharmony_ci GPIO_BLINK_CNT_SELECT_OFF + mvchip->offset, set); 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci mvpwm->clk_rate = clk_get_rate(mvchip->clk); 86662306a36Sopenharmony_ci if (!mvpwm->clk_rate) { 86762306a36Sopenharmony_ci dev_err(dev, "failed to get clock rate\n"); 86862306a36Sopenharmony_ci return -EINVAL; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci mvpwm->chip.dev = dev; 87262306a36Sopenharmony_ci mvpwm->chip.ops = &mvebu_pwm_ops; 87362306a36Sopenharmony_ci mvpwm->chip.npwm = mvchip->chip.ngpio; 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci spin_lock_init(&mvpwm->lock); 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci return devm_pwmchip_add(dev, &mvpwm->chip); 87862306a36Sopenharmony_ci} 87962306a36Sopenharmony_ci 88062306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 88162306a36Sopenharmony_ci#include <linux/seq_file.h> 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_cistatic void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) 88462306a36Sopenharmony_ci{ 88562306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = gpiochip_get_data(chip); 88662306a36Sopenharmony_ci u32 out, io_conf, blink, in_pol, data_in, cause, edg_msk, lvl_msk; 88762306a36Sopenharmony_ci const char *label; 88862306a36Sopenharmony_ci int i; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, &out); 89162306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, &io_conf); 89262306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, &blink); 89362306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset, &in_pol); 89462306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_DATA_IN_OFF + mvchip->offset, &data_in); 89562306a36Sopenharmony_ci cause = mvebu_gpio_read_edge_cause(mvchip); 89662306a36Sopenharmony_ci edg_msk = mvebu_gpio_read_edge_mask(mvchip); 89762306a36Sopenharmony_ci lvl_msk = mvebu_gpio_read_level_mask(mvchip); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci for_each_requested_gpio(chip, i, label) { 90062306a36Sopenharmony_ci u32 msk; 90162306a36Sopenharmony_ci bool is_out; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci msk = BIT(i); 90462306a36Sopenharmony_ci is_out = !(io_conf & msk); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci seq_printf(s, " gpio-%-3d (%-20.20s)", chip->base + i, label); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci if (is_out) { 90962306a36Sopenharmony_ci seq_printf(s, " out %s %s\n", 91062306a36Sopenharmony_ci out & msk ? "hi" : "lo", 91162306a36Sopenharmony_ci blink & msk ? "(blink )" : ""); 91262306a36Sopenharmony_ci continue; 91362306a36Sopenharmony_ci } 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci seq_printf(s, " in %s (act %s) - IRQ", 91662306a36Sopenharmony_ci (data_in ^ in_pol) & msk ? "hi" : "lo", 91762306a36Sopenharmony_ci in_pol & msk ? "lo" : "hi"); 91862306a36Sopenharmony_ci if (!((edg_msk | lvl_msk) & msk)) { 91962306a36Sopenharmony_ci seq_puts(s, " disabled\n"); 92062306a36Sopenharmony_ci continue; 92162306a36Sopenharmony_ci } 92262306a36Sopenharmony_ci if (edg_msk & msk) 92362306a36Sopenharmony_ci seq_puts(s, " edge "); 92462306a36Sopenharmony_ci if (lvl_msk & msk) 92562306a36Sopenharmony_ci seq_puts(s, " level"); 92662306a36Sopenharmony_ci seq_printf(s, " (%s)\n", cause & msk ? "pending" : "clear "); 92762306a36Sopenharmony_ci } 92862306a36Sopenharmony_ci} 92962306a36Sopenharmony_ci#else 93062306a36Sopenharmony_ci#define mvebu_gpio_dbg_show NULL 93162306a36Sopenharmony_ci#endif 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_cistatic const struct of_device_id mvebu_gpio_of_match[] = { 93462306a36Sopenharmony_ci { 93562306a36Sopenharmony_ci .compatible = "marvell,orion-gpio", 93662306a36Sopenharmony_ci .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, 93762306a36Sopenharmony_ci }, 93862306a36Sopenharmony_ci { 93962306a36Sopenharmony_ci .compatible = "marvell,mv78200-gpio", 94062306a36Sopenharmony_ci .data = (void *) MVEBU_GPIO_SOC_VARIANT_MV78200, 94162306a36Sopenharmony_ci }, 94262306a36Sopenharmony_ci { 94362306a36Sopenharmony_ci .compatible = "marvell,armadaxp-gpio", 94462306a36Sopenharmony_ci .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP, 94562306a36Sopenharmony_ci }, 94662306a36Sopenharmony_ci { 94762306a36Sopenharmony_ci .compatible = "marvell,armada-370-gpio", 94862306a36Sopenharmony_ci .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION, 94962306a36Sopenharmony_ci }, 95062306a36Sopenharmony_ci { 95162306a36Sopenharmony_ci .compatible = "marvell,armada-8k-gpio", 95262306a36Sopenharmony_ci .data = (void *) MVEBU_GPIO_SOC_VARIANT_A8K, 95362306a36Sopenharmony_ci }, 95462306a36Sopenharmony_ci { 95562306a36Sopenharmony_ci /* sentinel */ 95662306a36Sopenharmony_ci }, 95762306a36Sopenharmony_ci}; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_cistatic int mvebu_gpio_suspend(struct platform_device *pdev, pm_message_t state) 96062306a36Sopenharmony_ci{ 96162306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev); 96262306a36Sopenharmony_ci int i; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, 96562306a36Sopenharmony_ci &mvchip->out_reg); 96662306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, 96762306a36Sopenharmony_ci &mvchip->io_conf_reg); 96862306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, 96962306a36Sopenharmony_ci &mvchip->blink_en_reg); 97062306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset, 97162306a36Sopenharmony_ci &mvchip->in_pol_reg); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci switch (mvchip->soc_variant) { 97462306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_ORION: 97562306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_A8K: 97662306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_EDGE_MASK_OFF + mvchip->offset, 97762306a36Sopenharmony_ci &mvchip->edge_mask_regs[0]); 97862306a36Sopenharmony_ci regmap_read(mvchip->regs, GPIO_LEVEL_MASK_OFF + mvchip->offset, 97962306a36Sopenharmony_ci &mvchip->level_mask_regs[0]); 98062306a36Sopenharmony_ci break; 98162306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_MV78200: 98262306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 98362306a36Sopenharmony_ci regmap_read(mvchip->regs, 98462306a36Sopenharmony_ci GPIO_EDGE_MASK_MV78200_OFF(i), 98562306a36Sopenharmony_ci &mvchip->edge_mask_regs[i]); 98662306a36Sopenharmony_ci regmap_read(mvchip->regs, 98762306a36Sopenharmony_ci GPIO_LEVEL_MASK_MV78200_OFF(i), 98862306a36Sopenharmony_ci &mvchip->level_mask_regs[i]); 98962306a36Sopenharmony_ci } 99062306a36Sopenharmony_ci break; 99162306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: 99262306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 99362306a36Sopenharmony_ci regmap_read(mvchip->regs, 99462306a36Sopenharmony_ci GPIO_EDGE_MASK_ARMADAXP_OFF(i), 99562306a36Sopenharmony_ci &mvchip->edge_mask_regs[i]); 99662306a36Sopenharmony_ci regmap_read(mvchip->regs, 99762306a36Sopenharmony_ci GPIO_LEVEL_MASK_ARMADAXP_OFF(i), 99862306a36Sopenharmony_ci &mvchip->level_mask_regs[i]); 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci break; 100162306a36Sopenharmony_ci default: 100262306a36Sopenharmony_ci BUG(); 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci if (IS_REACHABLE(CONFIG_PWM)) 100662306a36Sopenharmony_ci mvebu_pwm_suspend(mvchip); 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci return 0; 100962306a36Sopenharmony_ci} 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_cistatic int mvebu_gpio_resume(struct platform_device *pdev) 101262306a36Sopenharmony_ci{ 101362306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip = platform_get_drvdata(pdev); 101462306a36Sopenharmony_ci int i; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci regmap_write(mvchip->regs, GPIO_OUT_OFF + mvchip->offset, 101762306a36Sopenharmony_ci mvchip->out_reg); 101862306a36Sopenharmony_ci regmap_write(mvchip->regs, GPIO_IO_CONF_OFF + mvchip->offset, 101962306a36Sopenharmony_ci mvchip->io_conf_reg); 102062306a36Sopenharmony_ci regmap_write(mvchip->regs, GPIO_BLINK_EN_OFF + mvchip->offset, 102162306a36Sopenharmony_ci mvchip->blink_en_reg); 102262306a36Sopenharmony_ci regmap_write(mvchip->regs, GPIO_IN_POL_OFF + mvchip->offset, 102362306a36Sopenharmony_ci mvchip->in_pol_reg); 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci switch (mvchip->soc_variant) { 102662306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_ORION: 102762306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_A8K: 102862306a36Sopenharmony_ci regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF + mvchip->offset, 102962306a36Sopenharmony_ci mvchip->edge_mask_regs[0]); 103062306a36Sopenharmony_ci regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF + mvchip->offset, 103162306a36Sopenharmony_ci mvchip->level_mask_regs[0]); 103262306a36Sopenharmony_ci break; 103362306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_MV78200: 103462306a36Sopenharmony_ci for (i = 0; i < 2; i++) { 103562306a36Sopenharmony_ci regmap_write(mvchip->regs, 103662306a36Sopenharmony_ci GPIO_EDGE_MASK_MV78200_OFF(i), 103762306a36Sopenharmony_ci mvchip->edge_mask_regs[i]); 103862306a36Sopenharmony_ci regmap_write(mvchip->regs, 103962306a36Sopenharmony_ci GPIO_LEVEL_MASK_MV78200_OFF(i), 104062306a36Sopenharmony_ci mvchip->level_mask_regs[i]); 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci break; 104362306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: 104462306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 104562306a36Sopenharmony_ci regmap_write(mvchip->regs, 104662306a36Sopenharmony_ci GPIO_EDGE_MASK_ARMADAXP_OFF(i), 104762306a36Sopenharmony_ci mvchip->edge_mask_regs[i]); 104862306a36Sopenharmony_ci regmap_write(mvchip->regs, 104962306a36Sopenharmony_ci GPIO_LEVEL_MASK_ARMADAXP_OFF(i), 105062306a36Sopenharmony_ci mvchip->level_mask_regs[i]); 105162306a36Sopenharmony_ci } 105262306a36Sopenharmony_ci break; 105362306a36Sopenharmony_ci default: 105462306a36Sopenharmony_ci BUG(); 105562306a36Sopenharmony_ci } 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci if (IS_REACHABLE(CONFIG_PWM)) 105862306a36Sopenharmony_ci mvebu_pwm_resume(mvchip); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci return 0; 106162306a36Sopenharmony_ci} 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_cistatic int mvebu_gpio_probe_raw(struct platform_device *pdev, 106462306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip) 106562306a36Sopenharmony_ci{ 106662306a36Sopenharmony_ci void __iomem *base; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci base = devm_platform_ioremap_resource(pdev, 0); 106962306a36Sopenharmony_ci if (IS_ERR(base)) 107062306a36Sopenharmony_ci return PTR_ERR(base); 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci mvchip->regs = devm_regmap_init_mmio(&pdev->dev, base, 107362306a36Sopenharmony_ci &mvebu_gpio_regmap_config); 107462306a36Sopenharmony_ci if (IS_ERR(mvchip->regs)) 107562306a36Sopenharmony_ci return PTR_ERR(mvchip->regs); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci /* 107862306a36Sopenharmony_ci * For the legacy SoCs, the regmap directly maps to the GPIO 107962306a36Sopenharmony_ci * registers, so no offset is needed. 108062306a36Sopenharmony_ci */ 108162306a36Sopenharmony_ci mvchip->offset = 0; 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci /* 108462306a36Sopenharmony_ci * The Armada XP has a second range of registers for the 108562306a36Sopenharmony_ci * per-CPU registers 108662306a36Sopenharmony_ci */ 108762306a36Sopenharmony_ci if (mvchip->soc_variant == MVEBU_GPIO_SOC_VARIANT_ARMADAXP) { 108862306a36Sopenharmony_ci base = devm_platform_ioremap_resource(pdev, 1); 108962306a36Sopenharmony_ci if (IS_ERR(base)) 109062306a36Sopenharmony_ci return PTR_ERR(base); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci mvchip->percpu_regs = 109362306a36Sopenharmony_ci devm_regmap_init_mmio(&pdev->dev, base, 109462306a36Sopenharmony_ci &mvebu_gpio_regmap_config); 109562306a36Sopenharmony_ci if (IS_ERR(mvchip->percpu_regs)) 109662306a36Sopenharmony_ci return PTR_ERR(mvchip->percpu_regs); 109762306a36Sopenharmony_ci } 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_ci return 0; 110062306a36Sopenharmony_ci} 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_cistatic int mvebu_gpio_probe_syscon(struct platform_device *pdev, 110362306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip) 110462306a36Sopenharmony_ci{ 110562306a36Sopenharmony_ci mvchip->regs = syscon_node_to_regmap(pdev->dev.parent->of_node); 110662306a36Sopenharmony_ci if (IS_ERR(mvchip->regs)) 110762306a36Sopenharmony_ci return PTR_ERR(mvchip->regs); 110862306a36Sopenharmony_ci 110962306a36Sopenharmony_ci if (of_property_read_u32(pdev->dev.of_node, "offset", &mvchip->offset)) 111062306a36Sopenharmony_ci return -EINVAL; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci return 0; 111362306a36Sopenharmony_ci} 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_cistatic void mvebu_gpio_remove_irq_domain(void *data) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci struct irq_domain *domain = data; 111862306a36Sopenharmony_ci 111962306a36Sopenharmony_ci irq_domain_remove(domain); 112062306a36Sopenharmony_ci} 112162306a36Sopenharmony_ci 112262306a36Sopenharmony_cistatic int mvebu_gpio_probe(struct platform_device *pdev) 112362306a36Sopenharmony_ci{ 112462306a36Sopenharmony_ci struct mvebu_gpio_chip *mvchip; 112562306a36Sopenharmony_ci const struct of_device_id *match; 112662306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 112762306a36Sopenharmony_ci struct irq_chip_generic *gc; 112862306a36Sopenharmony_ci struct irq_chip_type *ct; 112962306a36Sopenharmony_ci unsigned int ngpios; 113062306a36Sopenharmony_ci bool have_irqs; 113162306a36Sopenharmony_ci int soc_variant; 113262306a36Sopenharmony_ci int i, cpu, id; 113362306a36Sopenharmony_ci int err; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci match = of_match_device(mvebu_gpio_of_match, &pdev->dev); 113662306a36Sopenharmony_ci if (match) 113762306a36Sopenharmony_ci soc_variant = (unsigned long) match->data; 113862306a36Sopenharmony_ci else 113962306a36Sopenharmony_ci soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION; 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci /* Some gpio controllers do not provide irq support */ 114262306a36Sopenharmony_ci err = platform_irq_count(pdev); 114362306a36Sopenharmony_ci if (err < 0) 114462306a36Sopenharmony_ci return err; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci have_irqs = err != 0; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), 114962306a36Sopenharmony_ci GFP_KERNEL); 115062306a36Sopenharmony_ci if (!mvchip) 115162306a36Sopenharmony_ci return -ENOMEM; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci platform_set_drvdata(pdev, mvchip); 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci if (of_property_read_u32(pdev->dev.of_node, "ngpios", &ngpios)) { 115662306a36Sopenharmony_ci dev_err(&pdev->dev, "Missing ngpios OF property\n"); 115762306a36Sopenharmony_ci return -ENODEV; 115862306a36Sopenharmony_ci } 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_ci id = of_alias_get_id(pdev->dev.of_node, "gpio"); 116162306a36Sopenharmony_ci if (id < 0) { 116262306a36Sopenharmony_ci dev_err(&pdev->dev, "Couldn't get OF id\n"); 116362306a36Sopenharmony_ci return id; 116462306a36Sopenharmony_ci } 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci mvchip->clk = devm_clk_get(&pdev->dev, NULL); 116762306a36Sopenharmony_ci /* Not all SoCs require a clock.*/ 116862306a36Sopenharmony_ci if (!IS_ERR(mvchip->clk)) 116962306a36Sopenharmony_ci clk_prepare_enable(mvchip->clk); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci mvchip->soc_variant = soc_variant; 117262306a36Sopenharmony_ci mvchip->chip.label = dev_name(&pdev->dev); 117362306a36Sopenharmony_ci mvchip->chip.parent = &pdev->dev; 117462306a36Sopenharmony_ci mvchip->chip.request = gpiochip_generic_request; 117562306a36Sopenharmony_ci mvchip->chip.free = gpiochip_generic_free; 117662306a36Sopenharmony_ci mvchip->chip.get_direction = mvebu_gpio_get_direction; 117762306a36Sopenharmony_ci mvchip->chip.direction_input = mvebu_gpio_direction_input; 117862306a36Sopenharmony_ci mvchip->chip.get = mvebu_gpio_get; 117962306a36Sopenharmony_ci mvchip->chip.direction_output = mvebu_gpio_direction_output; 118062306a36Sopenharmony_ci mvchip->chip.set = mvebu_gpio_set; 118162306a36Sopenharmony_ci if (have_irqs) 118262306a36Sopenharmony_ci mvchip->chip.to_irq = mvebu_gpio_to_irq; 118362306a36Sopenharmony_ci mvchip->chip.base = id * MVEBU_MAX_GPIO_PER_BANK; 118462306a36Sopenharmony_ci mvchip->chip.ngpio = ngpios; 118562306a36Sopenharmony_ci mvchip->chip.can_sleep = false; 118662306a36Sopenharmony_ci mvchip->chip.dbg_show = mvebu_gpio_dbg_show; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci if (soc_variant == MVEBU_GPIO_SOC_VARIANT_A8K) 118962306a36Sopenharmony_ci err = mvebu_gpio_probe_syscon(pdev, mvchip); 119062306a36Sopenharmony_ci else 119162306a36Sopenharmony_ci err = mvebu_gpio_probe_raw(pdev, mvchip); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci if (err) 119462306a36Sopenharmony_ci return err; 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci /* 119762306a36Sopenharmony_ci * Mask and clear GPIO interrupts. 119862306a36Sopenharmony_ci */ 119962306a36Sopenharmony_ci switch (soc_variant) { 120062306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_ORION: 120162306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_A8K: 120262306a36Sopenharmony_ci regmap_write(mvchip->regs, 120362306a36Sopenharmony_ci GPIO_EDGE_CAUSE_OFF + mvchip->offset, 0); 120462306a36Sopenharmony_ci regmap_write(mvchip->regs, 120562306a36Sopenharmony_ci GPIO_EDGE_MASK_OFF + mvchip->offset, 0); 120662306a36Sopenharmony_ci regmap_write(mvchip->regs, 120762306a36Sopenharmony_ci GPIO_LEVEL_MASK_OFF + mvchip->offset, 0); 120862306a36Sopenharmony_ci break; 120962306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_MV78200: 121062306a36Sopenharmony_ci regmap_write(mvchip->regs, GPIO_EDGE_CAUSE_OFF, 0); 121162306a36Sopenharmony_ci for (cpu = 0; cpu < 2; cpu++) { 121262306a36Sopenharmony_ci regmap_write(mvchip->regs, 121362306a36Sopenharmony_ci GPIO_EDGE_MASK_MV78200_OFF(cpu), 0); 121462306a36Sopenharmony_ci regmap_write(mvchip->regs, 121562306a36Sopenharmony_ci GPIO_LEVEL_MASK_MV78200_OFF(cpu), 0); 121662306a36Sopenharmony_ci } 121762306a36Sopenharmony_ci break; 121862306a36Sopenharmony_ci case MVEBU_GPIO_SOC_VARIANT_ARMADAXP: 121962306a36Sopenharmony_ci regmap_write(mvchip->regs, GPIO_EDGE_CAUSE_OFF, 0); 122062306a36Sopenharmony_ci regmap_write(mvchip->regs, GPIO_EDGE_MASK_OFF, 0); 122162306a36Sopenharmony_ci regmap_write(mvchip->regs, GPIO_LEVEL_MASK_OFF, 0); 122262306a36Sopenharmony_ci for (cpu = 0; cpu < 4; cpu++) { 122362306a36Sopenharmony_ci regmap_write(mvchip->percpu_regs, 122462306a36Sopenharmony_ci GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu), 0); 122562306a36Sopenharmony_ci regmap_write(mvchip->percpu_regs, 122662306a36Sopenharmony_ci GPIO_EDGE_MASK_ARMADAXP_OFF(cpu), 0); 122762306a36Sopenharmony_ci regmap_write(mvchip->percpu_regs, 122862306a36Sopenharmony_ci GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu), 0); 122962306a36Sopenharmony_ci } 123062306a36Sopenharmony_ci break; 123162306a36Sopenharmony_ci default: 123262306a36Sopenharmony_ci BUG(); 123362306a36Sopenharmony_ci } 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci devm_gpiochip_add_data(&pdev->dev, &mvchip->chip, mvchip); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci /* Some MVEBU SoCs have simple PWM support for GPIO lines */ 123862306a36Sopenharmony_ci if (IS_REACHABLE(CONFIG_PWM)) { 123962306a36Sopenharmony_ci err = mvebu_pwm_probe(pdev, mvchip, id); 124062306a36Sopenharmony_ci if (err) 124162306a36Sopenharmony_ci return err; 124262306a36Sopenharmony_ci } 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_ci /* Some gpio controllers do not provide irq support */ 124562306a36Sopenharmony_ci if (!have_irqs) 124662306a36Sopenharmony_ci return 0; 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci mvchip->domain = 124962306a36Sopenharmony_ci irq_domain_add_linear(np, ngpios, &irq_generic_chip_ops, NULL); 125062306a36Sopenharmony_ci if (!mvchip->domain) { 125162306a36Sopenharmony_ci dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n", 125262306a36Sopenharmony_ci mvchip->chip.label); 125362306a36Sopenharmony_ci return -ENODEV; 125462306a36Sopenharmony_ci } 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci err = devm_add_action_or_reset(&pdev->dev, mvebu_gpio_remove_irq_domain, 125762306a36Sopenharmony_ci mvchip->domain); 125862306a36Sopenharmony_ci if (err) 125962306a36Sopenharmony_ci return err; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci err = irq_alloc_domain_generic_chips( 126262306a36Sopenharmony_ci mvchip->domain, ngpios, 2, np->name, handle_level_irq, 126362306a36Sopenharmony_ci IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_LEVEL, 0, 0); 126462306a36Sopenharmony_ci if (err) { 126562306a36Sopenharmony_ci dev_err(&pdev->dev, "couldn't allocate irq chips %s (DT).\n", 126662306a36Sopenharmony_ci mvchip->chip.label); 126762306a36Sopenharmony_ci return err; 126862306a36Sopenharmony_ci } 126962306a36Sopenharmony_ci 127062306a36Sopenharmony_ci /* 127162306a36Sopenharmony_ci * NOTE: The common accessors cannot be used because of the percpu 127262306a36Sopenharmony_ci * access to the mask registers 127362306a36Sopenharmony_ci */ 127462306a36Sopenharmony_ci gc = irq_get_domain_generic_chip(mvchip->domain, 0); 127562306a36Sopenharmony_ci gc->private = mvchip; 127662306a36Sopenharmony_ci ct = &gc->chip_types[0]; 127762306a36Sopenharmony_ci ct->type = IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW; 127862306a36Sopenharmony_ci ct->chip.irq_mask = mvebu_gpio_level_irq_mask; 127962306a36Sopenharmony_ci ct->chip.irq_unmask = mvebu_gpio_level_irq_unmask; 128062306a36Sopenharmony_ci ct->chip.irq_set_type = mvebu_gpio_irq_set_type; 128162306a36Sopenharmony_ci ct->chip.name = mvchip->chip.label; 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_ci ct = &gc->chip_types[1]; 128462306a36Sopenharmony_ci ct->type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING; 128562306a36Sopenharmony_ci ct->chip.irq_ack = mvebu_gpio_irq_ack; 128662306a36Sopenharmony_ci ct->chip.irq_mask = mvebu_gpio_edge_irq_mask; 128762306a36Sopenharmony_ci ct->chip.irq_unmask = mvebu_gpio_edge_irq_unmask; 128862306a36Sopenharmony_ci ct->chip.irq_set_type = mvebu_gpio_irq_set_type; 128962306a36Sopenharmony_ci ct->handler = handle_edge_irq; 129062306a36Sopenharmony_ci ct->chip.name = mvchip->chip.label; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci /* 129362306a36Sopenharmony_ci * Setup the interrupt handlers. Each chip can have up to 4 129462306a36Sopenharmony_ci * interrupt handlers, with each handler dealing with 8 GPIO 129562306a36Sopenharmony_ci * pins. 129662306a36Sopenharmony_ci */ 129762306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 129862306a36Sopenharmony_ci int irq = platform_get_irq_optional(pdev, i); 129962306a36Sopenharmony_ci 130062306a36Sopenharmony_ci if (irq < 0) 130162306a36Sopenharmony_ci continue; 130262306a36Sopenharmony_ci irq_set_chained_handler_and_data(irq, mvebu_gpio_irq_handler, 130362306a36Sopenharmony_ci mvchip); 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci return 0; 130762306a36Sopenharmony_ci} 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_cistatic struct platform_driver mvebu_gpio_driver = { 131062306a36Sopenharmony_ci .driver = { 131162306a36Sopenharmony_ci .name = "mvebu-gpio", 131262306a36Sopenharmony_ci .of_match_table = mvebu_gpio_of_match, 131362306a36Sopenharmony_ci }, 131462306a36Sopenharmony_ci .probe = mvebu_gpio_probe, 131562306a36Sopenharmony_ci .suspend = mvebu_gpio_suspend, 131662306a36Sopenharmony_ci .resume = mvebu_gpio_resume, 131762306a36Sopenharmony_ci}; 131862306a36Sopenharmony_cibuiltin_platform_driver(mvebu_gpio_driver); 1319