2013-01-19 01:30:34 +04:00
|
|
|
/*
|
|
|
|
* Allwinner A1X SoCs pinctrl driver.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012 Maxime Ripard
|
|
|
|
*
|
|
|
|
* Maxime Ripard <maxime.ripard@free-electrons.com>
|
|
|
|
*
|
|
|
|
* This file is licensed under the terms of the GNU General Public
|
|
|
|
* License version 2. This program is licensed "as is" without any
|
|
|
|
* warranty of any kind, whether express or implied.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __PINCTRL_SUNXI_H
|
|
|
|
#define __PINCTRL_SUNXI_H
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
2013-08-04 14:38:48 +04:00
|
|
|
#include <linux/spinlock.h>
|
2013-01-19 01:30:34 +04:00
|
|
|
|
|
|
|
#define PA_BASE 0
|
|
|
|
#define PB_BASE 32
|
|
|
|
#define PC_BASE 64
|
|
|
|
#define PD_BASE 96
|
|
|
|
#define PE_BASE 128
|
|
|
|
#define PF_BASE 160
|
|
|
|
#define PG_BASE 192
|
2013-01-26 18:36:53 +04:00
|
|
|
#define PH_BASE 224
|
|
|
|
#define PI_BASE 256
|
2014-04-10 17:52:42 +04:00
|
|
|
#define PL_BASE 352
|
|
|
|
#define PM_BASE 384
|
2014-10-29 00:41:26 +03:00
|
|
|
#define PN_BASE 416
|
2013-01-19 01:30:34 +04:00
|
|
|
|
2014-04-24 18:06:52 +04:00
|
|
|
#define SUNXI_PINCTRL_PIN(bank, pin) \
|
|
|
|
PINCTRL_PIN(P ## bank ## _BASE + (pin), "P" #bank #pin)
|
2014-04-10 17:52:42 +04:00
|
|
|
|
2013-01-29 00:33:12 +04:00
|
|
|
#define SUNXI_PIN_NAME_MAX_LEN 5
|
|
|
|
|
2013-01-19 01:30:34 +04:00
|
|
|
#define BANK_MEM_SIZE 0x24
|
|
|
|
#define MUX_REGS_OFFSET 0x0
|
2022-07-13 05:52:31 +03:00
|
|
|
#define MUX_FIELD_WIDTH 4
|
2013-01-29 00:33:12 +04:00
|
|
|
#define DATA_REGS_OFFSET 0x10
|
2022-07-13 05:52:31 +03:00
|
|
|
#define DATA_FIELD_WIDTH 1
|
2013-01-19 01:30:34 +04:00
|
|
|
#define DLEVEL_REGS_OFFSET 0x14
|
2022-07-13 05:52:31 +03:00
|
|
|
#define DLEVEL_FIELD_WIDTH 2
|
2013-01-19 01:30:34 +04:00
|
|
|
#define PULL_REGS_OFFSET 0x1c
|
2022-07-13 05:52:31 +03:00
|
|
|
#define PULL_FIELD_WIDTH 2
|
2013-01-19 01:30:34 +04:00
|
|
|
|
2022-07-13 05:52:33 +03:00
|
|
|
#define D1_BANK_MEM_SIZE 0x30
|
|
|
|
#define D1_DLEVEL_FIELD_WIDTH 4
|
|
|
|
#define D1_PULL_REGS_OFFSET 0x24
|
|
|
|
|
2013-01-19 01:30:34 +04:00
|
|
|
#define PINS_PER_BANK 32
|
|
|
|
|
2014-06-05 17:26:04 +04:00
|
|
|
#define IRQ_PER_BANK 32
|
2013-06-08 14:05:44 +04:00
|
|
|
|
|
|
|
#define IRQ_CFG_REG 0x200
|
|
|
|
#define IRQ_CFG_IRQ_PER_REG 8
|
|
|
|
#define IRQ_CFG_IRQ_BITS 4
|
|
|
|
#define IRQ_CFG_IRQ_MASK ((1 << IRQ_CFG_IRQ_BITS) - 1)
|
|
|
|
#define IRQ_CTRL_REG 0x210
|
|
|
|
#define IRQ_CTRL_IRQ_PER_REG 32
|
|
|
|
#define IRQ_CTRL_IRQ_BITS 1
|
|
|
|
#define IRQ_CTRL_IRQ_MASK ((1 << IRQ_CTRL_IRQ_BITS) - 1)
|
|
|
|
#define IRQ_STATUS_REG 0x214
|
|
|
|
#define IRQ_STATUS_IRQ_PER_REG 32
|
|
|
|
#define IRQ_STATUS_IRQ_BITS 1
|
|
|
|
#define IRQ_STATUS_IRQ_MASK ((1 << IRQ_STATUS_IRQ_BITS) - 1)
|
|
|
|
|
2016-11-14 23:53:03 +03:00
|
|
|
#define IRQ_DEBOUNCE_REG 0x218
|
|
|
|
|
2014-06-05 17:26:04 +04:00
|
|
|
#define IRQ_MEM_SIZE 0x20
|
|
|
|
|
2013-06-08 14:05:44 +04:00
|
|
|
#define IRQ_EDGE_RISING 0x00
|
|
|
|
#define IRQ_EDGE_FALLING 0x01
|
|
|
|
#define IRQ_LEVEL_HIGH 0x02
|
|
|
|
#define IRQ_LEVEL_LOW 0x03
|
|
|
|
#define IRQ_EDGE_BOTH 0x04
|
|
|
|
|
2019-02-06 06:32:31 +03:00
|
|
|
#define GRP_CFG_REG 0x300
|
|
|
|
|
|
|
|
#define IO_BIAS_MASK GENMASK(3, 0)
|
|
|
|
|
2015-03-09 00:13:57 +03:00
|
|
|
#define SUN4I_FUNC_INPUT 0
|
|
|
|
#define SUN4I_FUNC_IRQ 6
|
|
|
|
|
2017-01-09 00:31:16 +03:00
|
|
|
#define PINCTRL_SUN5I_A10S BIT(1)
|
|
|
|
#define PINCTRL_SUN5I_A13 BIT(2)
|
|
|
|
#define PINCTRL_SUN5I_GR8 BIT(3)
|
2017-02-01 19:25:46 +03:00
|
|
|
#define PINCTRL_SUN6I_A31 BIT(4)
|
|
|
|
#define PINCTRL_SUN6I_A31S BIT(5)
|
2017-05-27 13:23:00 +03:00
|
|
|
#define PINCTRL_SUN4I_A10 BIT(6)
|
|
|
|
#define PINCTRL_SUN7I_A20 BIT(7)
|
|
|
|
#define PINCTRL_SUN8I_R40 BIT(8)
|
2019-07-28 06:12:22 +03:00
|
|
|
#define PINCTRL_SUN8I_V3 BIT(9)
|
|
|
|
#define PINCTRL_SUN8I_V3S BIT(10)
|
2022-07-13 05:52:33 +03:00
|
|
|
/* Variants below here have an updated register layout. */
|
|
|
|
#define PINCTRL_SUN20I_D1 BIT(11)
|
2017-01-09 00:31:16 +03:00
|
|
|
|
2019-04-13 19:54:13 +03:00
|
|
|
#define PIO_POW_MOD_SEL_REG 0x340
|
2022-07-13 05:52:30 +03:00
|
|
|
#define PIO_POW_MOD_CTL_REG 0x344
|
2019-04-13 19:54:13 +03:00
|
|
|
|
2019-04-13 19:54:12 +03:00
|
|
|
enum sunxi_desc_bias_voltage {
|
|
|
|
BIAS_VOLTAGE_NONE,
|
|
|
|
/*
|
|
|
|
* Bias voltage configuration is done through
|
|
|
|
* Pn_GRP_CONFIG registers, as seen on A80 SoC.
|
|
|
|
*/
|
|
|
|
BIAS_VOLTAGE_GRP_CONFIG,
|
2019-04-13 19:54:13 +03:00
|
|
|
/*
|
|
|
|
* Bias voltage is set through PIO_POW_MOD_SEL_REG
|
|
|
|
* register, as seen on H6 SoC, for example.
|
|
|
|
*/
|
|
|
|
BIAS_VOLTAGE_PIO_POW_MODE_SEL,
|
2022-07-13 05:52:30 +03:00
|
|
|
/*
|
|
|
|
* Bias voltage is set through PIO_POW_MOD_SEL_REG
|
|
|
|
* and PIO_POW_MOD_CTL_REG register, as seen on
|
|
|
|
* A100 and D1 SoC, for example.
|
|
|
|
*/
|
|
|
|
BIAS_VOLTAGE_PIO_POW_MODE_CTL,
|
2019-04-13 19:54:12 +03:00
|
|
|
};
|
|
|
|
|
2013-01-19 01:30:34 +04:00
|
|
|
struct sunxi_desc_function {
|
2017-01-09 00:31:15 +03:00
|
|
|
unsigned long variant;
|
2013-01-19 01:30:34 +04:00
|
|
|
const char *name;
|
|
|
|
u8 muxval;
|
2014-06-05 17:26:01 +04:00
|
|
|
u8 irqbank;
|
2013-06-08 14:05:44 +04:00
|
|
|
u8 irqnum;
|
2013-01-19 01:30:34 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct sunxi_desc_pin {
|
|
|
|
struct pinctrl_pin_desc pin;
|
2017-01-09 00:31:15 +03:00
|
|
|
unsigned long variant;
|
2013-01-19 01:30:34 +04:00
|
|
|
struct sunxi_desc_function *functions;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sunxi_pinctrl_desc {
|
|
|
|
const struct sunxi_desc_pin *pins;
|
|
|
|
int npins;
|
2014-04-10 17:52:43 +04:00
|
|
|
unsigned pin_base;
|
2014-06-05 17:26:02 +04:00
|
|
|
unsigned irq_banks;
|
2018-03-16 17:02:09 +03:00
|
|
|
const unsigned int *irq_bank_map;
|
2015-03-09 00:13:57 +03:00
|
|
|
bool irq_read_needs_mux;
|
2017-10-09 23:53:37 +03:00
|
|
|
bool disable_strict_mode;
|
2019-04-13 19:54:12 +03:00
|
|
|
enum sunxi_desc_bias_voltage io_bias_cfg_variant;
|
2013-01-19 01:30:34 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct sunxi_pinctrl_function {
|
|
|
|
const char *name;
|
|
|
|
const char **groups;
|
|
|
|
unsigned ngroups;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sunxi_pinctrl_group {
|
|
|
|
const char *name;
|
|
|
|
unsigned pin;
|
|
|
|
};
|
|
|
|
|
pinctrl: sunxi: Deal with per-bank regulators
The Allwinner SoCs have on most of their GPIO banks a regulator input.
This issue was mainly ignored so far because either the regulator was a
static regulator that would be providing power anyway, or the bank was used
for a feature unsupported so far (CSI). For the odd cases, enabling it in
the bootloader was the preferred option.
However, now that we are starting to support those features, and that we
can't really rely on the bootloader for this, we need to model those
regulators as such in the DT.
This is slightly more complicated than what it looks like, since some
regulators will be tied to the PMIC, and in order to have access to the
PMIC bus, you need to mux its pins, which will need the pinctrl driver,
that needs the regulator driver to be registered. And this is how you get a
circular dependency.
In practice however, the hardware cannot fall into this case since it would
result in a completely unusable bus. In order to avoid that circular
dependency, we can thus get and enable the regulators at pin_request time.
We'll then need to account for the references of all the pins of a
particular branch to know when to put the reference, but it works pretty
nicely once implemented.
Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2018-12-06 17:02:03 +03:00
|
|
|
struct sunxi_pinctrl_regulator {
|
|
|
|
struct regulator *regulator;
|
|
|
|
refcount_t refcount;
|
|
|
|
};
|
|
|
|
|
2013-01-19 01:30:34 +04:00
|
|
|
struct sunxi_pinctrl {
|
|
|
|
void __iomem *membase;
|
2013-01-29 00:33:12 +04:00
|
|
|
struct gpio_chip *chip;
|
2014-04-18 21:34:07 +04:00
|
|
|
const struct sunxi_pinctrl_desc *desc;
|
2013-01-19 01:30:34 +04:00
|
|
|
struct device *dev;
|
pinctrl: sunxi: Consider pin_base when calculating regulator array index
On most newer Allwinner SoCs, there are two pinctrl devices, the PIO and
R_PIO. PIO covers pin-banks PA to PI (PJ and PK have not been seen),
while R_PIO covers PL to PN. The regulator array only has space for 12
entries, which was designed to cover PA to PL. On the A80, the pin banks
go up to PN, which would be the 14th entry in the regulator array.
However since the driver only needs to track regulators for its own pin
banks, the array only needs to have 9 entries, and also take in to
account the value of pin_base, such that the regulator for the first
pin-bank of the pinctrl device, be it "PA" or "PL" uses the first entry
of the array.
Base the regulator array index on pin_base, such that "PA" for PIO and
"PL" for R_PIO both take the first element within their respective
device's regulator array.
Also decrease the size of the regulator array to 9, just enough to cover
"PA" to "PI".
Fixes: 9a2a566adb00 ("pinctrl: sunxi: Deal with per-bank regulators")
Signed-off-by: Chen-Yu Tsai <wens@csie.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
2019-01-13 12:57:23 +03:00
|
|
|
struct sunxi_pinctrl_regulator regulators[9];
|
2013-06-08 14:05:44 +04:00
|
|
|
struct irq_domain *domain;
|
2013-01-19 01:30:34 +04:00
|
|
|
struct sunxi_pinctrl_function *functions;
|
|
|
|
unsigned nfunctions;
|
|
|
|
struct sunxi_pinctrl_group *groups;
|
|
|
|
unsigned ngroups;
|
2014-06-05 17:26:04 +04:00
|
|
|
int *irq;
|
|
|
|
unsigned *irq_array;
|
2017-03-09 19:22:06 +03:00
|
|
|
raw_spinlock_t lock;
|
2013-01-19 01:30:34 +04:00
|
|
|
struct pinctrl_dev *pctl_dev;
|
2017-01-09 00:31:15 +03:00
|
|
|
unsigned long variant;
|
2022-07-13 05:52:32 +03:00
|
|
|
u32 bank_mem_size;
|
|
|
|
u32 pull_regs_offset;
|
|
|
|
u32 dlevel_field_width;
|
2013-01-19 01:30:34 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
#define SUNXI_PIN(_pin, ...) \
|
|
|
|
{ \
|
|
|
|
.pin = _pin, \
|
|
|
|
.functions = (struct sunxi_desc_function[]){ \
|
|
|
|
__VA_ARGS__, { } }, \
|
|
|
|
}
|
|
|
|
|
2017-01-09 00:31:15 +03:00
|
|
|
#define SUNXI_PIN_VARIANT(_pin, _variant, ...) \
|
|
|
|
{ \
|
|
|
|
.pin = _pin, \
|
|
|
|
.variant = _variant, \
|
|
|
|
.functions = (struct sunxi_desc_function[]){ \
|
|
|
|
__VA_ARGS__, { } }, \
|
|
|
|
}
|
|
|
|
|
2013-01-19 01:30:34 +04:00
|
|
|
#define SUNXI_FUNCTION(_val, _name) \
|
|
|
|
{ \
|
|
|
|
.name = _name, \
|
|
|
|
.muxval = _val, \
|
|
|
|
}
|
|
|
|
|
2017-01-09 00:31:15 +03:00
|
|
|
#define SUNXI_FUNCTION_VARIANT(_val, _name, _variant) \
|
|
|
|
{ \
|
|
|
|
.name = _name, \
|
|
|
|
.muxval = _val, \
|
|
|
|
.variant = _variant, \
|
|
|
|
}
|
|
|
|
|
2013-06-08 14:05:44 +04:00
|
|
|
#define SUNXI_FUNCTION_IRQ(_val, _irq) \
|
|
|
|
{ \
|
|
|
|
.name = "irq", \
|
|
|
|
.muxval = _val, \
|
|
|
|
.irqnum = _irq, \
|
|
|
|
}
|
|
|
|
|
2014-06-05 17:26:01 +04:00
|
|
|
#define SUNXI_FUNCTION_IRQ_BANK(_val, _bank, _irq) \
|
|
|
|
{ \
|
|
|
|
.name = "irq", \
|
|
|
|
.muxval = _val, \
|
|
|
|
.irqbank = _bank, \
|
|
|
|
.irqnum = _irq, \
|
|
|
|
}
|
|
|
|
|
2018-03-16 17:02:08 +03:00
|
|
|
static inline u32 sunxi_irq_hw_bank_num(const struct sunxi_pinctrl_desc *desc, u8 bank)
|
|
|
|
{
|
2018-03-16 17:02:09 +03:00
|
|
|
if (!desc->irq_bank_map)
|
|
|
|
return bank;
|
|
|
|
else
|
|
|
|
return desc->irq_bank_map[bank];
|
2018-03-16 17:02:08 +03:00
|
|
|
}
|
|
|
|
|
2018-03-16 17:02:07 +03:00
|
|
|
static inline u32 sunxi_irq_cfg_reg(const struct sunxi_pinctrl_desc *desc,
|
|
|
|
u16 irq)
|
2013-06-08 14:05:44 +04:00
|
|
|
{
|
2014-06-05 17:26:04 +04:00
|
|
|
u8 bank = irq / IRQ_PER_BANK;
|
|
|
|
u8 reg = (irq % IRQ_PER_BANK) / IRQ_CFG_IRQ_PER_REG * 0x04;
|
|
|
|
|
2018-03-16 17:02:08 +03:00
|
|
|
return IRQ_CFG_REG +
|
|
|
|
sunxi_irq_hw_bank_num(desc, bank) * IRQ_MEM_SIZE + reg;
|
2013-06-08 14:05:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 sunxi_irq_cfg_offset(u16 irq)
|
|
|
|
{
|
|
|
|
u32 irq_num = irq % IRQ_CFG_IRQ_PER_REG;
|
|
|
|
return irq_num * IRQ_CFG_IRQ_BITS;
|
|
|
|
}
|
|
|
|
|
2018-03-16 17:02:07 +03:00
|
|
|
static inline u32 sunxi_irq_ctrl_reg_from_bank(const struct sunxi_pinctrl_desc *desc, u8 bank)
|
2014-06-05 17:26:04 +04:00
|
|
|
{
|
2018-03-16 17:02:08 +03:00
|
|
|
return IRQ_CTRL_REG + sunxi_irq_hw_bank_num(desc, bank) * IRQ_MEM_SIZE;
|
2014-06-05 17:26:04 +04:00
|
|
|
}
|
|
|
|
|
2018-03-16 17:02:07 +03:00
|
|
|
static inline u32 sunxi_irq_ctrl_reg(const struct sunxi_pinctrl_desc *desc,
|
|
|
|
u16 irq)
|
2013-06-08 14:05:44 +04:00
|
|
|
{
|
2014-06-05 17:26:04 +04:00
|
|
|
u8 bank = irq / IRQ_PER_BANK;
|
|
|
|
|
2018-03-16 17:02:07 +03:00
|
|
|
return sunxi_irq_ctrl_reg_from_bank(desc, bank);
|
2013-06-08 14:05:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 sunxi_irq_ctrl_offset(u16 irq)
|
|
|
|
{
|
|
|
|
u32 irq_num = irq % IRQ_CTRL_IRQ_PER_REG;
|
|
|
|
return irq_num * IRQ_CTRL_IRQ_BITS;
|
|
|
|
}
|
|
|
|
|
2018-03-16 17:02:07 +03:00
|
|
|
static inline u32 sunxi_irq_debounce_reg_from_bank(const struct sunxi_pinctrl_desc *desc, u8 bank)
|
2016-11-14 23:53:03 +03:00
|
|
|
{
|
2018-03-16 17:02:08 +03:00
|
|
|
return IRQ_DEBOUNCE_REG +
|
|
|
|
sunxi_irq_hw_bank_num(desc, bank) * IRQ_MEM_SIZE;
|
2016-11-14 23:53:03 +03:00
|
|
|
}
|
|
|
|
|
2018-03-16 17:02:07 +03:00
|
|
|
static inline u32 sunxi_irq_status_reg_from_bank(const struct sunxi_pinctrl_desc *desc, u8 bank)
|
2014-06-05 17:26:04 +04:00
|
|
|
{
|
2018-03-16 17:02:08 +03:00
|
|
|
return IRQ_STATUS_REG +
|
|
|
|
sunxi_irq_hw_bank_num(desc, bank) * IRQ_MEM_SIZE;
|
2014-06-05 17:26:04 +04:00
|
|
|
}
|
|
|
|
|
2018-03-16 17:02:07 +03:00
|
|
|
static inline u32 sunxi_irq_status_reg(const struct sunxi_pinctrl_desc *desc,
|
|
|
|
u16 irq)
|
2013-06-08 14:05:44 +04:00
|
|
|
{
|
2014-06-05 17:26:04 +04:00
|
|
|
u8 bank = irq / IRQ_PER_BANK;
|
|
|
|
|
2018-03-16 17:02:07 +03:00
|
|
|
return sunxi_irq_status_reg_from_bank(desc, bank);
|
2013-06-08 14:05:44 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u32 sunxi_irq_status_offset(u16 irq)
|
|
|
|
{
|
|
|
|
u32 irq_num = irq % IRQ_STATUS_IRQ_PER_REG;
|
|
|
|
return irq_num * IRQ_STATUS_IRQ_BITS;
|
|
|
|
}
|
|
|
|
|
2019-02-06 06:32:31 +03:00
|
|
|
static inline u32 sunxi_grp_config_reg(u16 pin)
|
|
|
|
{
|
|
|
|
u8 bank = pin / PINS_PER_BANK;
|
|
|
|
|
|
|
|
return GRP_CFG_REG + bank * 0x4;
|
|
|
|
}
|
|
|
|
|
2017-01-09 00:31:15 +03:00
|
|
|
int sunxi_pinctrl_init_with_variant(struct platform_device *pdev,
|
|
|
|
const struct sunxi_pinctrl_desc *desc,
|
|
|
|
unsigned long variant);
|
|
|
|
|
|
|
|
#define sunxi_pinctrl_init(_dev, _desc) \
|
|
|
|
sunxi_pinctrl_init_with_variant(_dev, _desc, 0)
|
2014-04-18 22:10:41 +04:00
|
|
|
|
2013-01-19 01:30:34 +04:00
|
|
|
#endif /* __PINCTRL_SUNXI_H */
|