mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
pinctrl: renesas: Updates for v7.4
- Add SD power source support on RZ/G3L, - Add I3C power source support on RZ/G3S, - Miscellaneous fixes and improvements. -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQQ9qaHoIs/1I4cXmEiKwlD9ZEnxcAUCaqz8wQAKCRCKwlD9ZEnx cK8eAP9aLWRAr4YQarpbdC+z36BfXqGB+M4hlcisQUJQObpTmwEAiHcMvkdx7OUu GrcZ/sndJF2jysdfqiAqDwHsylKsYwk= =tTQy -----END PGP SIGNATURE----- Merge tag 'renesas-pinctrl-for-v7.4-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/geert/renesas-drivers into devel pinctrl: renesas: Updates for v7.4 - Add SD power source support on RZ/G3L, - Add I3C power source support on RZ/G3S, - Miscellaneous fixes and improvements. Signed-off-by: Linus Walleij <linusw@kernel.org>
This commit is contained in:
commit
3977a850dd
|
|
@ -129,13 +129,15 @@ additionalProperties:
|
|||
enum: [ 33, 50, 66, 100 ]
|
||||
power-source:
|
||||
description: I/O voltage in millivolt.
|
||||
enum: [ 1800, 2500, 3300 ]
|
||||
enum: [ 1200, 1800, 2500, 3300 ]
|
||||
slew-rate: true
|
||||
gpio-hog: true
|
||||
gpios: true
|
||||
input: true
|
||||
input-enable: true
|
||||
input-disable: true
|
||||
output-enable: true
|
||||
output-disable: true
|
||||
output-high: true
|
||||
output-low: true
|
||||
line-name: true
|
||||
|
|
|
|||
|
|
@ -69,6 +69,8 @@
|
|||
#define PIN_CFG_PVDD1833_OTH_AWO_POC BIT(19) /* known on RZ/G3L only */
|
||||
#define PIN_CFG_PVDD1833_OTH_ISO_POC BIT(20) /* known on RZ/G3L only */
|
||||
#define PIN_CFG_WDTOVF_N_POC BIT(21) /* known on RZ/G3L only */
|
||||
#define PIN_CFG_IO_VMC_SD2 BIT(22) /* known on RZ/G3L only */
|
||||
#define PIN_CFG_IO_VMC_I3C BIT(23)
|
||||
|
||||
#define RZG2L_SINGLE_PIN BIT_ULL(63) /* Dedicated pin */
|
||||
#define RZG2L_VARIABLE_CFG BIT_ULL(62) /* Variable cfg for port pins */
|
||||
|
|
@ -180,12 +182,8 @@
|
|||
#define SMT(off) (0x3400 + (off) * 8)
|
||||
#define SD_CH(off, ch) ((off) + (ch) * 4)
|
||||
#define ETH_POC(off, ch) ((off) + (ch) * 4)
|
||||
#define QSPI (0x3008) /* known on RZ/{G2L,G2LC,G2UL,Five} only */
|
||||
#define OTHER_POC (0x3028) /* known on RZ/G3L only */
|
||||
|
||||
#define PVDD_2500 2 /* I/O domain voltage 2.5V */
|
||||
#define PVDD_1800 1 /* I/O domain voltage <= 1.8V */
|
||||
#define PVDD_3300 0 /* I/O domain voltage >= 3.3V */
|
||||
#define PVDD_MASK 0x3
|
||||
|
||||
#define PWPR_B0WI BIT(7) /* Bit Write Disable */
|
||||
#define PWPR_PFCWE BIT(6) /* PFC Register Write Enable */
|
||||
|
|
@ -254,28 +252,57 @@ static const struct pin_config_item renesas_rzv2h_conf_items[] = {
|
|||
* struct rzg2l_register_offsets - specific register offsets
|
||||
* @pwpr: PWPR register offset
|
||||
* @sd_ch: SD_CH register offset
|
||||
* @sd_ch2: SD_CH2_POC register offset
|
||||
* @eth_poc: ETH_POC register offset
|
||||
* @oen: OEN register offset
|
||||
* @qspi: QSPI register offset
|
||||
* @other_poc: OTHER_POC register offset
|
||||
* @i3c_set: I3C_SET register offset
|
||||
*/
|
||||
struct rzg2l_register_offsets {
|
||||
u16 pwpr;
|
||||
u16 sd_ch;
|
||||
u16 sd_ch2;
|
||||
u16 eth_poc;
|
||||
u16 oen;
|
||||
u16 qspi;
|
||||
u16 other_poc;
|
||||
u16 i3c_set;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct rzg2l_register_masks - Masks for different RZ/G2L pinctrl functionalities
|
||||
* @other_poc_pvdd1833_oth_awo_poc: PVDD1833_OTH_AWO_POC mask
|
||||
* @other_poc_pvdd1833_oth_iso_poc: PVDD1833_OTH_ISO_POC mask
|
||||
* @other_poc_wdtovf_n_poc: WDTOVF_N_POC mask
|
||||
* @i3c_set_poc: I3C_SET_POC mask
|
||||
*/
|
||||
struct rzg2l_register_masks {
|
||||
union {
|
||||
/* RZ/G3L masks */
|
||||
struct {
|
||||
u8 other_poc_pvdd1833_oth_awo_poc;
|
||||
u8 other_poc_pvdd1833_oth_iso_poc;
|
||||
u8 other_poc_wdtovf_n_poc;
|
||||
};
|
||||
|
||||
/* RZ/G3S masks */
|
||||
struct {
|
||||
u8 i3c_set_poc;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* enum rzg2l_iolh_index - starting indices in IOLH specific arrays
|
||||
* @RZG2L_IOLH_IDX_NA: index N/A (to be used for error checking)
|
||||
* @RZG2L_IOLH_IDX_1V8: starting index for 1V8 power source
|
||||
* @RZG2L_IOLH_IDX_2V5: starting index for 2V5 power source
|
||||
* @RZG2L_IOLH_IDX_3V3: starting index for 3V3 power source
|
||||
* @RZG2L_IOLH_IDX_MAX: maximum index
|
||||
*/
|
||||
enum rzg2l_iolh_index {
|
||||
RZG2L_IOLH_IDX_NA = -1,
|
||||
RZG2L_IOLH_IDX_1V8 = 0,
|
||||
RZG2L_IOLH_IDX_2V5 = 4,
|
||||
RZG2L_IOLH_IDX_3V3 = 8,
|
||||
|
|
@ -288,6 +315,8 @@ enum rzg2l_iolh_index {
|
|||
/**
|
||||
* struct rzg2l_hwcfg - hardware configuration data structure
|
||||
* @regs: hardware specific register offsets
|
||||
* @masks: hardware specific masks for various functionalities available in
|
||||
* the registers described by regs
|
||||
* @iolh_groupa_ua: IOLH group A uA specific values
|
||||
* @iolh_groupb_ua: IOLH group B uA specific values
|
||||
* @iolh_groupc_ua: IOLH group C uA specific values
|
||||
|
|
@ -301,6 +330,7 @@ enum rzg2l_iolh_index {
|
|||
*/
|
||||
struct rzg2l_hwcfg {
|
||||
const struct rzg2l_register_offsets regs;
|
||||
const struct rzg2l_register_masks masks;
|
||||
u16 iolh_groupa_ua[RZG2L_IOLH_IDX_MAX];
|
||||
u16 iolh_groupb_ua[RZG2L_IOLH_IDX_MAX];
|
||||
u16 iolh_groupc_ua[RZG2L_IOLH_IDX_MAX];
|
||||
|
|
@ -368,10 +398,12 @@ struct rzg2l_pinctrl_pin_settings {
|
|||
* @nod: NOD registers cache
|
||||
* @clone: Clone register cache
|
||||
* @sd_ch: SD_CH registers cache
|
||||
* @sd_ch2: SD_CH2_POC registers cache
|
||||
* @eth_poc: ET_POC registers cache
|
||||
* @oen: Output Enable register cache
|
||||
* @other_poc: OTHER_POC register cache
|
||||
* @qspi: QSPI registers cache
|
||||
* @i3c_set: I3C_SET register cache
|
||||
*/
|
||||
struct rzg2l_pinctrl_reg_cache {
|
||||
u8 *p;
|
||||
|
|
@ -386,10 +418,12 @@ struct rzg2l_pinctrl_reg_cache {
|
|||
u32 *nod[2];
|
||||
u32 clone;
|
||||
u8 sd_ch[2];
|
||||
u8 sd_ch2;
|
||||
u8 eth_poc[2];
|
||||
u8 oen;
|
||||
u8 other_poc;
|
||||
u8 qspi;
|
||||
u8 i3c_set;
|
||||
};
|
||||
|
||||
struct rzg2l_pinctrl {
|
||||
|
|
@ -421,7 +455,89 @@ struct rzg2l_pinctrl {
|
|||
u32 clone_offset;
|
||||
};
|
||||
|
||||
static const u16 available_ps[] = { 1800, 2500, 3300 };
|
||||
/**
|
||||
* struct rzg2l_pinctrl_ps_desc - RZ/G2L power source descriptor
|
||||
* @caps: Capabilities that applies to the power source
|
||||
* @iolh_index: IOLH index
|
||||
* @ps: Power source value
|
||||
* @pwr_reg_val: Power source register value
|
||||
*/
|
||||
struct rzg2l_pinctrl_ps_desc {
|
||||
u32 caps;
|
||||
enum rzg2l_iolh_index iolh_index;
|
||||
u16 ps;
|
||||
u16 pwr_reg_val;
|
||||
};
|
||||
|
||||
#define RZG2L_PINCTRL_PS_DESC(_ps, _pwr_reg_val, _caps, _iolh_index) \
|
||||
{ \
|
||||
.ps = _ps, \
|
||||
.pwr_reg_val = _pwr_reg_val, \
|
||||
.caps = _caps, \
|
||||
.iolh_index = _iolh_index, \
|
||||
}
|
||||
|
||||
static const struct rzg2l_pinctrl_ps_desc available_ps[] = {
|
||||
/* Ethernet I/O voltage domains */
|
||||
RZG2L_PINCTRL_PS_DESC(1800, 1, PIN_CFG_IO_VMC_ETH0 | PIN_CFG_IO_VMC_ETH1,
|
||||
RZG2L_IOLH_IDX_1V8),
|
||||
RZG2L_PINCTRL_PS_DESC(2500, 2, PIN_CFG_IO_VMC_ETH0 | PIN_CFG_IO_VMC_ETH1,
|
||||
RZG2L_IOLH_IDX_2V5),
|
||||
RZG2L_PINCTRL_PS_DESC(3300, 0, PIN_CFG_IO_VMC_ETH0 | PIN_CFG_IO_VMC_ETH1,
|
||||
RZG2L_IOLH_IDX_3V3),
|
||||
|
||||
/* SD I/O voltage domains */
|
||||
RZG2L_PINCTRL_PS_DESC(1800, 1, PIN_CFG_IO_VMC_SD0 | PIN_CFG_IO_VMC_SD1 |
|
||||
PIN_CFG_IO_VMC_SD2, RZG2L_IOLH_IDX_1V8),
|
||||
RZG2L_PINCTRL_PS_DESC(3300, 0, PIN_CFG_IO_VMC_SD0 | PIN_CFG_IO_VMC_SD1 |
|
||||
PIN_CFG_IO_VMC_SD2, RZG2L_IOLH_IDX_3V3),
|
||||
|
||||
/* QSPI I/O voltage domains */
|
||||
RZG2L_PINCTRL_PS_DESC(1800, 1, PIN_CFG_IO_VMC_QSPI, RZG2L_IOLH_IDX_1V8),
|
||||
RZG2L_PINCTRL_PS_DESC(3300, 0, PIN_CFG_IO_VMC_QSPI, RZG2L_IOLH_IDX_3V3),
|
||||
|
||||
/* AWO I/O voltage domains */
|
||||
RZG2L_PINCTRL_PS_DESC(1800, 1, PIN_CFG_PVDD1833_OTH_AWO_POC,
|
||||
RZG2L_IOLH_IDX_1V8),
|
||||
RZG2L_PINCTRL_PS_DESC(3300, 0, PIN_CFG_PVDD1833_OTH_AWO_POC,
|
||||
RZG2L_IOLH_IDX_3V3),
|
||||
|
||||
/* ISO I/O voltage domains */
|
||||
RZG2L_PINCTRL_PS_DESC(1800, 1, PIN_CFG_PVDD1833_OTH_ISO_POC,
|
||||
RZG2L_IOLH_IDX_1V8),
|
||||
RZG2L_PINCTRL_PS_DESC(3300, 0, PIN_CFG_PVDD1833_OTH_ISO_POC,
|
||||
RZG2L_IOLH_IDX_3V3),
|
||||
|
||||
/* WDTOVF I/O voltage domains */
|
||||
RZG2L_PINCTRL_PS_DESC(1800, 1, PIN_CFG_WDTOVF_N_POC, RZG2L_IOLH_IDX_1V8),
|
||||
RZG2L_PINCTRL_PS_DESC(3300, 0, PIN_CFG_WDTOVF_N_POC, RZG2L_IOLH_IDX_3V3),
|
||||
|
||||
/* I3C I/O voltage domains */
|
||||
RZG2L_PINCTRL_PS_DESC(1200, 1, PIN_CFG_IO_VMC_I3C, RZG2L_IOLH_IDX_NA),
|
||||
RZG2L_PINCTRL_PS_DESC(1800, 0, PIN_CFG_IO_VMC_I3C, RZG2L_IOLH_IDX_NA),
|
||||
|
||||
/* Software voltage domains */
|
||||
RZG2L_PINCTRL_PS_DESC(1800, 0, PIN_CFG_SOFT_PS, RZG2L_IOLH_IDX_1V8),
|
||||
RZG2L_PINCTRL_PS_DESC(2500, 0, PIN_CFG_SOFT_PS, RZG2L_IOLH_IDX_2V5),
|
||||
RZG2L_PINCTRL_PS_DESC(3300, 0, PIN_CFG_SOFT_PS, RZG2L_IOLH_IDX_3V3),
|
||||
};
|
||||
|
||||
#define RZG2L_PINCTRL_PS_DESC_MEMBER_TO_DESC_FUNC(_name, _desc_member, _caps) \
|
||||
static const struct rzg2l_pinctrl_ps_desc *_name(u16 _desc_member, u32 _caps) \
|
||||
{ \
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(available_ps); i++) { \
|
||||
if (available_ps[i]._desc_member != _desc_member) \
|
||||
continue; \
|
||||
\
|
||||
if (available_ps[i].caps & _caps) \
|
||||
return &available_ps[i]; \
|
||||
} \
|
||||
\
|
||||
return NULL; \
|
||||
}
|
||||
|
||||
RZG2L_PINCTRL_PS_DESC_MEMBER_TO_DESC_FUNC(rzg2l_ps_to_desc, ps, caps)
|
||||
RZG2L_PINCTRL_PS_DESC_MEMBER_TO_DESC_FUNC(rzg2l_pwr_reg_val_to_desc, pwr_reg_val, caps)
|
||||
|
||||
static u64 rzg2l_pinctrl_get_variable_pin_cfg(struct rzg2l_pinctrl *pctrl,
|
||||
u64 pincfg,
|
||||
|
|
@ -474,20 +590,32 @@ static const u64 r9a08g046_variable_pin_cfg[] = {
|
|||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PE, 5, RZG3L_MPXED_ETH_PIN_FUNCS(ETH1)),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PE, 6, RZG3L_MPXED_ETH_PIN_FUNCS(ETH1)),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PE, 7, RZG3L_MPXED_ETH_PIN_FUNCS(ETH1)),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PG, 0, RZG3L_MPXED_PIN_FUNCS(B)),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PG, 1, RZG3L_MPXED_PIN_FUNCS(B) | PIN_CFG_IEN),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PG, 2, RZG3L_MPXED_PIN_FUNCS(B) | PIN_CFG_IEN),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PG, 3, RZG3L_MPXED_PIN_FUNCS(B) | PIN_CFG_IEN),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PG, 4, RZG3L_MPXED_PIN_FUNCS(B) | PIN_CFG_IEN),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PG, 5, RZG3L_MPXED_PIN_FUNCS(B) | PIN_CFG_IEN),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PG, 0, RZG2L_MPXED_COMMON_PIN_FUNCS(B) |
|
||||
PIN_CFG_IO_VMC_SD1),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PG, 1, RZG2L_MPXED_COMMON_PIN_FUNCS(B) |
|
||||
PIN_CFG_IEN | PIN_CFG_IO_VMC_SD1),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PG, 2, RZG2L_MPXED_COMMON_PIN_FUNCS(B) |
|
||||
PIN_CFG_IEN | PIN_CFG_IO_VMC_SD1),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PG, 3, RZG2L_MPXED_COMMON_PIN_FUNCS(B) | PIN_CFG_IEN |
|
||||
PIN_CFG_IO_VMC_SD1),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PG, 4, RZG2L_MPXED_COMMON_PIN_FUNCS(B) |
|
||||
PIN_CFG_IEN | PIN_CFG_IO_VMC_SD1),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PG, 5, RZG2L_MPXED_COMMON_PIN_FUNCS(B) |
|
||||
PIN_CFG_IEN | PIN_CFG_IO_VMC_SD1),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PG, 6, RZG3L_MPXED_PIN_FUNCS_POC(B, ISO)),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PG, 7, RZG3L_MPXED_PIN_FUNCS_POC(B, ISO)),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PH, 0, RZG3L_MPXED_PIN_FUNCS(B)),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PH, 1, RZG3L_MPXED_PIN_FUNCS(B) | PIN_CFG_IEN),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PH, 2, RZG3L_MPXED_PIN_FUNCS(B) | PIN_CFG_IEN),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PH, 3, RZG3L_MPXED_PIN_FUNCS(B) | PIN_CFG_IEN),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PH, 4, RZG3L_MPXED_PIN_FUNCS(B) | PIN_CFG_IEN),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PH, 5, RZG3L_MPXED_PIN_FUNCS(B) | PIN_CFG_IEN),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PH, 0, RZG2L_MPXED_COMMON_PIN_FUNCS(B) |
|
||||
PIN_CFG_IO_VMC_SD2),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PH, 1, RZG2L_MPXED_COMMON_PIN_FUNCS(B) |
|
||||
PIN_CFG_IEN | PIN_CFG_IO_VMC_SD2),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PH, 2, RZG2L_MPXED_COMMON_PIN_FUNCS(B) |
|
||||
PIN_CFG_IEN | PIN_CFG_IO_VMC_SD2),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PH, 3, RZG2L_MPXED_COMMON_PIN_FUNCS(B) |
|
||||
PIN_CFG_IEN | PIN_CFG_IO_VMC_SD2),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PH, 4, RZG2L_MPXED_COMMON_PIN_FUNCS(B) |
|
||||
PIN_CFG_IEN | PIN_CFG_IO_VMC_SD2),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PH, 5, RZG2L_MPXED_COMMON_PIN_FUNCS(B) |
|
||||
PIN_CFG_IEN | PIN_CFG_IO_VMC_SD2),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PJ, 0, RZG3L_MPXED_PIN_FUNCS(A) | PIN_CFG_IEN),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PJ, 1, RZG3L_MPXED_PIN_FUNCS(A)),
|
||||
RZG2L_VARIABLE_PIN_CFG_PACK(RZG3L_PJ, 2, RZG3L_MPXED_PIN_FUNCS(A)),
|
||||
|
|
@ -1047,106 +1175,125 @@ static void rzg2l_rmw_pin_config(struct rzg2l_pinctrl *pctrl, u32 offset,
|
|||
}
|
||||
|
||||
static int rzg2l_caps_to_pwr_reg(const struct rzg2l_register_offsets *regs,
|
||||
u32 caps, u8 *mask)
|
||||
const struct rzg2l_register_masks *masks,
|
||||
u32 caps, u16 *offset, u8 *mask)
|
||||
{
|
||||
if (caps & PIN_CFG_IO_VMC_SD0)
|
||||
return SD_CH(regs->sd_ch, 0);
|
||||
if (caps & PIN_CFG_IO_VMC_SD1)
|
||||
return SD_CH(regs->sd_ch, 1);
|
||||
if (caps & PIN_CFG_IO_VMC_ETH0)
|
||||
return ETH_POC(regs->eth_poc, 0);
|
||||
if (caps & PIN_CFG_IO_VMC_ETH1)
|
||||
return ETH_POC(regs->eth_poc, 1);
|
||||
if (caps & PIN_CFG_IO_VMC_QSPI)
|
||||
return QSPI;
|
||||
if (caps & PIN_CFG_OTHER_POC_MASK) {
|
||||
if (caps & PIN_CFG_PVDD1833_OTH_AWO_POC)
|
||||
*mask = BIT(0);
|
||||
else if (caps & PIN_CFG_PVDD1833_OTH_ISO_POC)
|
||||
*mask = BIT(1);
|
||||
else
|
||||
*mask = BIT(2);
|
||||
*mask = PVDD_MASK;
|
||||
|
||||
return OTHER_POC;
|
||||
if (caps & PIN_CFG_IO_VMC_SD0) {
|
||||
*offset = SD_CH(regs->sd_ch, 0);
|
||||
return 0;
|
||||
}
|
||||
if (caps & PIN_CFG_IO_VMC_SD1) {
|
||||
*offset = SD_CH(regs->sd_ch, 1);
|
||||
return 0;
|
||||
}
|
||||
if (caps & PIN_CFG_IO_VMC_SD2) {
|
||||
*offset = regs->sd_ch2;
|
||||
return 0;
|
||||
}
|
||||
if (caps & PIN_CFG_IO_VMC_ETH0) {
|
||||
*offset = ETH_POC(regs->eth_poc, 0);
|
||||
return 0;
|
||||
}
|
||||
if (caps & PIN_CFG_IO_VMC_ETH1) {
|
||||
*offset = ETH_POC(regs->eth_poc, 1);
|
||||
return 0;
|
||||
}
|
||||
if (caps & PIN_CFG_IO_VMC_QSPI) {
|
||||
*offset = regs->qspi;
|
||||
return 0;
|
||||
}
|
||||
if (caps & PIN_CFG_OTHER_POC_MASK) {
|
||||
*offset = regs->other_poc;
|
||||
if (caps & PIN_CFG_PVDD1833_OTH_AWO_POC)
|
||||
*mask = masks->other_poc_pvdd1833_oth_awo_poc;
|
||||
else if (caps & PIN_CFG_PVDD1833_OTH_ISO_POC)
|
||||
*mask = masks->other_poc_pvdd1833_oth_iso_poc;
|
||||
else
|
||||
*mask = masks->other_poc_wdtovf_n_poc;
|
||||
return 0;
|
||||
}
|
||||
if (caps & PIN_CFG_IO_VMC_I3C) {
|
||||
*offset = regs->i3c_set;
|
||||
*mask = masks->i3c_set_poc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int rzg2l_pwr_reg_val_to_ps(u16 pwr_reg_val, u32 caps)
|
||||
{
|
||||
const struct rzg2l_pinctrl_ps_desc *desc;
|
||||
|
||||
desc = rzg2l_pwr_reg_val_to_desc(pwr_reg_val, caps);
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
return desc->ps;
|
||||
}
|
||||
|
||||
static int rzg2l_ps_to_pwr_reg_val(u16 ps, u32 caps)
|
||||
{
|
||||
const struct rzg2l_pinctrl_ps_desc *desc;
|
||||
|
||||
desc = rzg2l_ps_to_desc(ps, caps);
|
||||
if (!desc)
|
||||
return -EINVAL;
|
||||
|
||||
return desc->pwr_reg_val;
|
||||
}
|
||||
|
||||
static int rzg2l_get_power_source(struct rzg2l_pinctrl *pctrl, u32 pin, u32 caps)
|
||||
{
|
||||
const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
|
||||
const struct rzg2l_register_offsets *regs = &hwcfg->regs;
|
||||
u8 val, mask;
|
||||
int pwr_reg;
|
||||
const struct rzg2l_register_masks *masks = &hwcfg->masks;
|
||||
u8 mask, val;
|
||||
u16 offset;
|
||||
int ret;
|
||||
|
||||
if (caps & PIN_CFG_SOFT_PS)
|
||||
return pctrl->settings[pin].power_source;
|
||||
|
||||
pwr_reg = rzg2l_caps_to_pwr_reg(regs, caps, &mask);
|
||||
if (pwr_reg < 0)
|
||||
return pwr_reg;
|
||||
ret = rzg2l_caps_to_pwr_reg(regs, masks, caps, &offset, &mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
val = readb(pctrl->base + pwr_reg);
|
||||
if (pwr_reg == OTHER_POC)
|
||||
val = field_get(mask, val);
|
||||
val = readb(pctrl->base + offset);
|
||||
|
||||
switch (val) {
|
||||
case PVDD_1800:
|
||||
return 1800;
|
||||
case PVDD_2500:
|
||||
return 2500;
|
||||
case PVDD_3300:
|
||||
return 3300;
|
||||
default:
|
||||
/* Should not happen. */
|
||||
return -EINVAL;
|
||||
}
|
||||
return rzg2l_pwr_reg_val_to_ps(field_get(mask, val), caps);
|
||||
}
|
||||
|
||||
static int rzg2l_set_power_source(struct rzg2l_pinctrl *pctrl, u32 pin, u32 caps, u32 ps)
|
||||
{
|
||||
const struct rzg2l_hwcfg *hwcfg = pctrl->data->hwcfg;
|
||||
const struct rzg2l_register_offsets *regs = &hwcfg->regs;
|
||||
u8 poc_val, val, mask;
|
||||
int pwr_reg;
|
||||
const struct rzg2l_register_masks *masks = &hwcfg->masks;
|
||||
u16 offset;
|
||||
u8 mask;
|
||||
int ret;
|
||||
|
||||
if (caps & PIN_CFG_SOFT_PS) {
|
||||
pctrl->settings[pin].power_source = ps;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (ps) {
|
||||
case 1800:
|
||||
poc_val = PVDD_1800;
|
||||
break;
|
||||
case 2500:
|
||||
if (!(caps & (PIN_CFG_IO_VMC_ETH0 | PIN_CFG_IO_VMC_ETH1)))
|
||||
return -EINVAL;
|
||||
poc_val = PVDD_2500;
|
||||
break;
|
||||
case 3300:
|
||||
poc_val = PVDD_3300;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
ret = rzg2l_caps_to_pwr_reg(regs, masks, caps, &offset, &mask);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
pwr_reg = rzg2l_caps_to_pwr_reg(regs, caps, &mask);
|
||||
if (pwr_reg < 0)
|
||||
return pwr_reg;
|
||||
ret = rzg2l_ps_to_pwr_reg_val(ps, caps);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (pwr_reg == OTHER_POC) {
|
||||
scoped_guard(raw_spinlock_irqsave, &pctrl->lock) {
|
||||
val = readb(pctrl->base + pwr_reg);
|
||||
if (poc_val)
|
||||
val |= mask;
|
||||
else
|
||||
val &= ~mask;
|
||||
writeb(val, pctrl->base + pwr_reg);
|
||||
}
|
||||
} else {
|
||||
writeb(poc_val, pctrl->base + pwr_reg);
|
||||
scoped_guard(raw_spinlock_irqsave, &pctrl->lock) {
|
||||
u8 tmp = readb(pctrl->base + offset);
|
||||
|
||||
tmp &= ~mask;
|
||||
tmp |= field_prep(mask, ret);
|
||||
writeb(tmp, pctrl->base + offset);
|
||||
}
|
||||
|
||||
pctrl->settings[pin].power_source = ps;
|
||||
|
|
@ -1154,32 +1301,11 @@ static int rzg2l_set_power_source(struct rzg2l_pinctrl *pctrl, u32 pin, u32 caps
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool rzg2l_ps_is_supported(u16 ps)
|
||||
static enum rzg2l_iolh_index rzg2l_ps_to_iolh_idx(u16 ps, u32 caps)
|
||||
{
|
||||
unsigned int i;
|
||||
const struct rzg2l_pinctrl_ps_desc *desc = rzg2l_ps_to_desc(ps, caps);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(available_ps); i++) {
|
||||
if (available_ps[i] == ps)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static enum rzg2l_iolh_index rzg2l_ps_to_iolh_idx(u16 ps)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(available_ps); i++) {
|
||||
if (available_ps[i] == ps)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* We multiply with RZG2L_IOLH_MAX_DS_ENTRIES as we have
|
||||
* RZG2L_IOLH_MAX_DS_ENTRIES DS values per power source
|
||||
*/
|
||||
return i * RZG2L_IOLH_MAX_DS_ENTRIES;
|
||||
return desc ? desc->iolh_index : RZG2L_IOLH_IDX_NA;
|
||||
}
|
||||
|
||||
static u16 rzg2l_iolh_val_to_ua(const struct rzg2l_hwcfg *hwcfg, u32 caps, u8 val)
|
||||
|
|
@ -1564,7 +1690,11 @@ static int rzg2l_pinctrl_pinconf_get(struct pinctrl_dev *pctldev,
|
|||
ret = rzg2l_get_power_source(pctrl, _pin, cfg);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
iolh_idx = rzg2l_ps_to_iolh_idx(ret);
|
||||
|
||||
iolh_idx = rzg2l_ps_to_iolh_idx(ret, cfg);
|
||||
if (iolh_idx == RZG2L_IOLH_IDX_NA)
|
||||
return -EINVAL;
|
||||
|
||||
val = rzg2l_read_pin_config(pctrl, IOLH(off), bit, IOLH_MASK);
|
||||
arg = rzg2l_iolh_val_to_ua(hwcfg, cfg, iolh_idx + val);
|
||||
break;
|
||||
|
|
@ -1760,8 +1890,7 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
|
|||
|
||||
/* Apply power source. */
|
||||
if (settings.power_source != pctrl->settings[_pin].power_source) {
|
||||
ret = rzg2l_ps_is_supported(settings.power_source);
|
||||
if (!ret)
|
||||
if (!rzg2l_ps_to_desc(settings.power_source, cfg))
|
||||
return -EINVAL;
|
||||
|
||||
/* Apply power source. */
|
||||
|
|
@ -1775,7 +1904,10 @@ static int rzg2l_pinctrl_pinconf_set(struct pinctrl_dev *pctldev,
|
|||
enum rzg2l_iolh_index iolh_idx;
|
||||
int val;
|
||||
|
||||
iolh_idx = rzg2l_ps_to_iolh_idx(settings.power_source);
|
||||
iolh_idx = rzg2l_ps_to_iolh_idx(settings.power_source, cfg);
|
||||
if (iolh_idx == RZG2L_IOLH_IDX_NA)
|
||||
return -EINVAL;
|
||||
|
||||
ret = rzg2l_ds_is_supported(pctrl, cfg, iolh_idx,
|
||||
settings.drive_strength_ua);
|
||||
if (!ret)
|
||||
|
|
@ -2458,6 +2590,8 @@ static const struct rzg2l_dedicated_configs rzg3s_dedicated_pins[] = {
|
|||
{ "AUDIO_CLK1", RZG2L_SINGLE_PIN_PACK(0x2, 0, PIN_CFG_IEN) },
|
||||
{ "AUDIO_CLK2", RZG2L_SINGLE_PIN_PACK(0x2, 1, PIN_CFG_IEN) },
|
||||
{ "WDTOVF_PERROUT#", RZG2L_SINGLE_PIN_PACK(0x6, 0, PIN_CFG_IOLH_A | PIN_CFG_SOFT_PS) },
|
||||
{ "I3C_SDA", RZG2L_SINGLE_PIN_PACK(0x9, 0, (PIN_CFG_IEN | PIN_CFG_IO_VMC_I3C)) },
|
||||
{ "I3C_SCL", RZG2L_SINGLE_PIN_PACK(0x9, 1, (PIN_CFG_IEN | PIN_CFG_IO_VMC_I3C)) },
|
||||
{ "SD0_CLK", RZG2L_SINGLE_PIN_PACK(0x10, 0, (PIN_CFG_IOLH_B | PIN_CFG_IO_VMC_SD0)) },
|
||||
{ "SD0_CMD", RZG2L_SINGLE_PIN_PACK(0x10, 1, (PIN_CFG_IOLH_B | PIN_CFG_IEN |
|
||||
PIN_CFG_IO_VMC_SD0)) },
|
||||
|
|
@ -2677,28 +2811,28 @@ static const struct rzg2l_dedicated_configs rzg3l_dedicated_pins[] = {
|
|||
(PIN_CFG_IOLH_A | PIN_CFG_PUPD | PIN_CFG_PVDD1833_OTH_AWO_POC)) },
|
||||
{ "SCIF0_TXD", RZG2L_SINGLE_PIN_PACK(0x6, 1,
|
||||
(PIN_CFG_IOLH_A | PIN_CFG_PUPD | PIN_CFG_PVDD1833_OTH_AWO_POC)) },
|
||||
{ "SD0_CLK", RZG2L_SINGLE_PIN_PACK(0x9, 0, PIN_CFG_IOLH_B) },
|
||||
{ "SD0_CLK", RZG2L_SINGLE_PIN_PACK(0x9, 0, PIN_CFG_IOLH_B | PIN_CFG_IO_VMC_SD0) },
|
||||
{ "SD0_CMD", RZG2L_SINGLE_PIN_PACK(0x9, 1,
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD)) },
|
||||
{ "SD0_RST#", RZG2L_SINGLE_PIN_PACK(0x9, 2, PIN_CFG_IOLH_B) },
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD | PIN_CFG_IO_VMC_SD0)) },
|
||||
{ "SD0_RST#", RZG2L_SINGLE_PIN_PACK(0x9, 2, PIN_CFG_IOLH_B | PIN_CFG_IO_VMC_SD0) },
|
||||
{ "SD0_DS", RZG2L_SINGLE_PIN_PACK(0x9, 5,
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD)) },
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD | PIN_CFG_IO_VMC_SD0)) },
|
||||
{ "SD0_DAT0", RZG2L_SINGLE_PIN_PACK(0x0a, 0,
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD)) },
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD | PIN_CFG_IO_VMC_SD0)) },
|
||||
{ "SD0_DAT1", RZG2L_SINGLE_PIN_PACK(0x0a, 1,
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD)) },
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD | PIN_CFG_IO_VMC_SD0)) },
|
||||
{ "SD0_DAT2", RZG2L_SINGLE_PIN_PACK(0x0a, 2,
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD)) },
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD | PIN_CFG_IO_VMC_SD0)) },
|
||||
{ "SD0_DAT3", RZG2L_SINGLE_PIN_PACK(0x0a, 3,
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD)) },
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD | PIN_CFG_IO_VMC_SD0)) },
|
||||
{ "SD0_DAT4", RZG2L_SINGLE_PIN_PACK(0x0a, 4,
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD)) },
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD | PIN_CFG_IO_VMC_SD0)) },
|
||||
{ "SD0_DAT5", RZG2L_SINGLE_PIN_PACK(0x0a, 5,
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD)) },
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD | PIN_CFG_IO_VMC_SD0)) },
|
||||
{ "SD0_DAT6", RZG2L_SINGLE_PIN_PACK(0x0a, 6,
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD)) },
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD | PIN_CFG_IO_VMC_SD0)) },
|
||||
{ "SD0_DAT7", RZG2L_SINGLE_PIN_PACK(0x0a, 7,
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD)) },
|
||||
(PIN_CFG_IOLH_B | PIN_CFG_IEN | PIN_CFG_PUPD | PIN_CFG_IO_VMC_SD0)) },
|
||||
};
|
||||
|
||||
static const u32 r9a08g046_clone_channel_data[] = {
|
||||
|
|
@ -3672,11 +3806,16 @@ static int rzg2l_pinctrl_suspend_noirq(struct device *dev)
|
|||
cache->eth_poc[i] = readb(pctrl->base + ETH_POC(regs->eth_poc, i));
|
||||
}
|
||||
|
||||
if (regs->sd_ch2)
|
||||
cache->sd_ch2 = readb(pctrl->base + regs->sd_ch2);
|
||||
|
||||
if (regs->qspi)
|
||||
cache->qspi = readb(pctrl->base + regs->qspi);
|
||||
cache->oen = readb(pctrl->base + pctrl->data->hwcfg->regs.oen);
|
||||
if (regs->other_poc)
|
||||
cache->other_poc = readb(pctrl->base + regs->other_poc);
|
||||
if (regs->i3c_set)
|
||||
cache->i3c_set = readb(pctrl->base + regs->i3c_set);
|
||||
|
||||
if (pctrl->syscon) {
|
||||
int ret;
|
||||
|
|
@ -3719,11 +3858,16 @@ static int rzg2l_pinctrl_resume_noirq(struct device *dev)
|
|||
writeb(cache->qspi, pctrl->base + regs->qspi);
|
||||
if (regs->other_poc)
|
||||
writeb(cache->other_poc, pctrl->base + regs->other_poc);
|
||||
if (regs->i3c_set)
|
||||
writeb(cache->i3c_set, pctrl->base + regs->i3c_set);
|
||||
|
||||
raw_spin_lock_irqsave(&pctrl->lock, flags);
|
||||
rzg2l_oen_write_with_pwpr(pctrl, cache->oen);
|
||||
raw_spin_unlock_irqrestore(&pctrl->lock, flags);
|
||||
|
||||
if (regs->sd_ch2)
|
||||
writeb(cache->sd_ch2, pctrl->base + regs->sd_ch2);
|
||||
|
||||
for (u8 i = 0; i < 2; i++) {
|
||||
if (regs->sd_ch)
|
||||
writeb(cache->sd_ch[i], pctrl->base + SD_CH(regs->sd_ch, i));
|
||||
|
|
@ -3774,9 +3918,9 @@ static const struct rzg2l_hwcfg rzg2l_hwcfg = {
|
|||
.regs = {
|
||||
.pwpr = 0x3014,
|
||||
.sd_ch = 0x3000,
|
||||
.qspi = 0x3008,
|
||||
.eth_poc = 0x300c,
|
||||
.oen = 0x3018,
|
||||
.qspi = QSPI,
|
||||
},
|
||||
.iolh_groupa_ua = {
|
||||
/* 3v3 power source */
|
||||
|
|
@ -3791,9 +3935,15 @@ static const struct rzg2l_hwcfg rzg3l_hwcfg = {
|
|||
.regs = {
|
||||
.pwpr = 0x3000,
|
||||
.sd_ch = 0x3004,
|
||||
.sd_ch2 = 0x3024,
|
||||
.eth_poc = 0x3010,
|
||||
.oen = 0x3018,
|
||||
.other_poc = OTHER_POC,
|
||||
.other_poc = 0x3028,
|
||||
},
|
||||
.masks = {
|
||||
.other_poc_pvdd1833_oth_awo_poc = BIT(0),
|
||||
.other_poc_pvdd1833_oth_iso_poc = BIT(1),
|
||||
.other_poc_wdtovf_n_poc = BIT(2),
|
||||
},
|
||||
.iolh_groupa_ua = {
|
||||
/* 1v8 power source */
|
||||
|
|
@ -3826,8 +3976,12 @@ static const struct rzg2l_hwcfg rzg3s_hwcfg = {
|
|||
.pwpr = 0x3000,
|
||||
.sd_ch = 0x3004,
|
||||
.eth_poc = 0x3010,
|
||||
.i3c_set = 0x301c,
|
||||
.oen = 0x3018,
|
||||
},
|
||||
.masks = {
|
||||
.i3c_set_poc = BIT(2),
|
||||
},
|
||||
.iolh_groupa_ua = {
|
||||
/* 1v8 power source */
|
||||
[RZG2L_IOLH_IDX_1V8] = 2200, 4400, 9000, 10000,
|
||||
|
|
|
|||
|
|
@ -94,8 +94,8 @@ struct rzt2h_pinctrl {
|
|||
void __iomem *base0, *base1;
|
||||
struct device *dev;
|
||||
struct gpio_chip gpio_chip;
|
||||
struct pinctrl_gpio_range gpio_range;
|
||||
DECLARE_BITMAP(used_irqs, RZT2H_INTERRUPTS_NUM);
|
||||
u8 saved_pm[RZT2H_INTERRUPTS_NUM];
|
||||
raw_spinlock_t lock; /* lock read/write registers */
|
||||
struct mutex mutex; /* serialize adding groups and functions */
|
||||
bool safety_port_enabled;
|
||||
|
|
@ -170,6 +170,43 @@ static int rzt2h_validate_pin(struct rzt2h_pinctrl *pctrl, unsigned int offset)
|
|||
return (pincfg & BIT(pin)) ? 0 : -EINVAL;
|
||||
}
|
||||
|
||||
static bool rzt2h_pin_mode_is_peripheral(struct rzt2h_pinctrl *pctrl, u8 port, u8 bit)
|
||||
{
|
||||
return rzt2h_pinctrl_readb(pctrl, port, PMC(port)) & BIT(bit);
|
||||
}
|
||||
|
||||
static u8 rzt2h_pin_read_pfc(struct rzt2h_pinctrl *pctrl, u8 port, u8 pin)
|
||||
{
|
||||
u64 reg64 = rzt2h_pinctrl_readq(pctrl, port, PFC(port));
|
||||
|
||||
return field_get(PFC_PIN_MASK(pin), reg64);
|
||||
}
|
||||
|
||||
static bool rzt2h_pin_read_input(struct rzt2h_pinctrl *pctrl, u8 port, u8 bit)
|
||||
{
|
||||
return rzt2h_pinctrl_readb(pctrl, port, PIN(port)) & BIT(bit);
|
||||
}
|
||||
|
||||
static u8 rzt2h_pin_read_pm(struct rzt2h_pinctrl *pctrl, u8 port, u8 pin)
|
||||
{
|
||||
u16 reg = rzt2h_pinctrl_readw(pctrl, port, PM(port));
|
||||
|
||||
return field_get(PM_PIN_MASK(pin), reg);
|
||||
}
|
||||
|
||||
static void rzt2h_pin_write_pm(struct rzt2h_pinctrl *pctrl, u8 port, u8 pin,
|
||||
unsigned int pm)
|
||||
{
|
||||
u16 reg;
|
||||
|
||||
guard(raw_spinlock_irqsave)(&pctrl->lock);
|
||||
|
||||
reg = rzt2h_pinctrl_readw(pctrl, port, PM(port));
|
||||
reg &= ~PM_PIN_MASK(pin);
|
||||
reg |= pm << (pin * 2);
|
||||
rzt2h_pinctrl_writew(pctrl, port, reg, PM(port));
|
||||
}
|
||||
|
||||
static void rzt2h_pinctrl_set_gpio_en(struct rzt2h_pinctrl *pctrl,
|
||||
u8 port, u8 pin, bool en)
|
||||
{
|
||||
|
|
@ -193,7 +230,7 @@ static void rzt2h_pinctrl_set_pfc_mode(struct rzt2h_pinctrl *pctrl,
|
|||
|
||||
reg64 = rzt2h_pinctrl_readq(pctrl, port, PFC(port));
|
||||
/* Check if pin is already configured to the desired function */
|
||||
if ((rzt2h_pinctrl_readb(pctrl, port, PMC(port)) & BIT(pin)) &&
|
||||
if (rzt2h_pin_mode_is_peripheral(pctrl, port, pin) &&
|
||||
field_get(PFC_PIN_MASK(pin), reg64) == func)
|
||||
return;
|
||||
|
||||
|
|
@ -747,15 +784,7 @@ static int rzt2h_gpio_request(struct gpio_chip *chip, unsigned int offset)
|
|||
static void rzt2h_gpio_set_direction(struct rzt2h_pinctrl *pctrl, u32 port,
|
||||
u8 bit, bool output)
|
||||
{
|
||||
u16 reg;
|
||||
|
||||
guard(raw_spinlock_irqsave)(&pctrl->lock);
|
||||
|
||||
reg = rzt2h_pinctrl_readw(pctrl, port, PM(port));
|
||||
reg &= ~PM_PIN_MASK(bit);
|
||||
|
||||
reg |= (output ? PM_OUTPUT : PM_INPUT) << (bit * 2);
|
||||
rzt2h_pinctrl_writew(pctrl, port, reg, PM(port));
|
||||
rzt2h_pin_write_pm(pctrl, port, bit, output ? PM_OUTPUT : PM_INPUT);
|
||||
}
|
||||
|
||||
static int rzt2h_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
|
||||
|
|
@ -763,9 +792,8 @@ static int rzt2h_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
|
|||
struct rzt2h_pinctrl *pctrl = gpiochip_get_data(chip);
|
||||
u8 port = RZT2H_PIN_ID_TO_PORT(offset);
|
||||
u8 bit = RZT2H_PIN_ID_TO_PIN(offset);
|
||||
u64 reg64;
|
||||
u16 reg;
|
||||
int ret;
|
||||
u8 pm;
|
||||
|
||||
ret = rzt2h_validate_pin(pctrl, offset);
|
||||
if (ret)
|
||||
|
|
@ -773,7 +801,7 @@ static int rzt2h_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
|
|||
|
||||
guard(raw_spinlock_irqsave)(&pctrl->lock);
|
||||
|
||||
if (rzt2h_pinctrl_readb(pctrl, port, PMC(port)) & BIT(bit)) {
|
||||
if (rzt2h_pin_mode_is_peripheral(pctrl, port, bit)) {
|
||||
/*
|
||||
* When a GPIO is being requested as an IRQ, the pinctrl
|
||||
* framework expects to be able to read the GPIO's direction.
|
||||
|
|
@ -783,19 +811,16 @@ static int rzt2h_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
|
|||
* called to enable the IRQ function.
|
||||
* Default to input direction for IRQ function.
|
||||
*/
|
||||
reg64 = rzt2h_pinctrl_readq(pctrl, port, PFC(port));
|
||||
reg64 = (reg64 >> (bit * 8)) & PFC_MASK;
|
||||
if (reg64 == PFC_FUNC_INTERRUPT)
|
||||
if (rzt2h_pin_read_pfc(pctrl, port, bit) == PFC_FUNC_INTERRUPT)
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
reg = rzt2h_pinctrl_readw(pctrl, port, PM(port));
|
||||
reg = (reg >> (bit * 2)) & PM_MASK;
|
||||
if (reg & PM_OUTPUT)
|
||||
pm = rzt2h_pin_read_pm(pctrl, port, bit);
|
||||
if (pm & PM_OUTPUT)
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
if (reg & PM_INPUT)
|
||||
if (pm & PM_INPUT)
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return -EINVAL;
|
||||
|
|
@ -825,13 +850,15 @@ static int rzt2h_gpio_get(struct gpio_chip *chip, unsigned int offset)
|
|||
struct rzt2h_pinctrl *pctrl = gpiochip_get_data(chip);
|
||||
u8 port = RZT2H_PIN_ID_TO_PORT(offset);
|
||||
u8 bit = RZT2H_PIN_ID_TO_PIN(offset);
|
||||
u16 reg;
|
||||
u8 pm;
|
||||
|
||||
reg = rzt2h_pinctrl_readw(pctrl, port, PM(port));
|
||||
reg = (reg >> (bit * 2)) & PM_MASK;
|
||||
if (reg & PM_INPUT)
|
||||
return !!(rzt2h_pinctrl_readb(pctrl, port, PIN(port)) & BIT(bit));
|
||||
if (reg & PM_OUTPUT)
|
||||
if (rzt2h_pin_mode_is_peripheral(pctrl, port, bit))
|
||||
return rzt2h_pin_read_input(pctrl, port, bit);
|
||||
|
||||
pm = rzt2h_pin_read_pm(pctrl, port, bit);
|
||||
if (pm & PM_INPUT)
|
||||
return rzt2h_pin_read_input(pctrl, port, bit);
|
||||
if (pm & PM_OUTPUT)
|
||||
return !!(rzt2h_pinctrl_readb(pctrl, port, P(port)) & BIT(bit));
|
||||
|
||||
return -EINVAL;
|
||||
|
|
@ -1000,6 +1027,66 @@ static int rzt2h_gpio_irq_set_wake(struct irq_data *d, unsigned int on)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int rzt2h_gpio_irq_request_resources(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct rzt2h_pinctrl *pctrl = gpiochip_get_data(gc);
|
||||
irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||
u8 port = RZT2H_PIN_ID_TO_PORT(hwirq);
|
||||
u8 pin = RZT2H_PIN_ID_TO_PIN(hwirq);
|
||||
u8 parent_irq, irq_idx;
|
||||
int ret;
|
||||
|
||||
parent_irq = rzt2h_gpio_irq_map[hwirq];
|
||||
if (parent_irq < RZT2H_INTERRUPTS_START)
|
||||
return -EINVAL;
|
||||
|
||||
irq_idx = parent_irq - RZT2H_INTERRUPTS_START;
|
||||
if (test_and_set_bit(irq_idx, pctrl->used_irqs))
|
||||
return -EBUSY;
|
||||
|
||||
/*
|
||||
* rzt2h_pinctrl_set_pfc_mode() sets PM to Hi-Z before switching to the
|
||||
* interrupt function, losing the previous PM value.
|
||||
* Save it so it can be restored when the IRQ is freed.
|
||||
*/
|
||||
pctrl->saved_pm[irq_idx] = rzt2h_pin_read_pm(pctrl, port, pin);
|
||||
|
||||
rzt2h_pinctrl_set_pfc_mode(pctrl, port, pin, PFC_FUNC_INTERRUPT);
|
||||
|
||||
ret = gpiochip_lock_as_irq(gc, hwirq);
|
||||
if (ret) {
|
||||
clear_bit(irq_idx, pctrl->used_irqs);
|
||||
rzt2h_pin_write_pm(pctrl, port, pin, pctrl->saved_pm[irq_idx]);
|
||||
rzt2h_pinctrl_set_gpio_en(pctrl, port, pin, true);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rzt2h_gpio_irq_release_resources(struct irq_data *d)
|
||||
{
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct rzt2h_pinctrl *pctrl = gpiochip_get_data(gc);
|
||||
irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||
u8 port = RZT2H_PIN_ID_TO_PORT(hwirq);
|
||||
u8 pin = RZT2H_PIN_ID_TO_PIN(hwirq);
|
||||
u8 parent_irq, irq_idx;
|
||||
|
||||
parent_irq = rzt2h_gpio_irq_map[hwirq];
|
||||
if (parent_irq < RZT2H_INTERRUPTS_START)
|
||||
return;
|
||||
|
||||
irq_idx = parent_irq - RZT2H_INTERRUPTS_START;
|
||||
if (test_and_clear_bit(irq_idx, pctrl->used_irqs)) {
|
||||
rzt2h_pin_write_pm(pctrl, port, pin, pctrl->saved_pm[irq_idx]);
|
||||
rzt2h_pinctrl_set_gpio_en(pctrl, port, pin, true);
|
||||
}
|
||||
|
||||
gpiochip_unlock_as_irq(gc, hwirq);
|
||||
}
|
||||
|
||||
static const struct irq_chip rzt2h_gpio_irqchip = {
|
||||
.name = "rzt2h-gpio",
|
||||
.irq_disable = rzt2h_gpio_irq_disable,
|
||||
|
|
@ -1009,9 +1096,10 @@ static const struct irq_chip rzt2h_gpio_irqchip = {
|
|||
.irq_set_type = irq_chip_set_type_parent,
|
||||
.irq_set_wake = rzt2h_gpio_irq_set_wake,
|
||||
.irq_eoi = irq_chip_eoi_parent,
|
||||
.irq_request_resources = rzt2h_gpio_irq_request_resources,
|
||||
.irq_release_resources = rzt2h_gpio_irq_release_resources,
|
||||
.irq_set_affinity = irq_chip_set_affinity_parent,
|
||||
.flags = IRQCHIP_IMMUTABLE,
|
||||
GPIOCHIP_IRQ_RESOURCE_HELPERS,
|
||||
};
|
||||
|
||||
static int rzt2h_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
|
||||
|
|
@ -1020,43 +1108,17 @@ static int rzt2h_gpio_child_to_parent_hwirq(struct gpio_chip *gc,
|
|||
unsigned int *parent,
|
||||
unsigned int *parent_type)
|
||||
{
|
||||
struct rzt2h_pinctrl *pctrl = gpiochip_get_data(gc);
|
||||
u8 port = RZT2H_PIN_ID_TO_PORT(child);
|
||||
u8 pin = RZT2H_PIN_ID_TO_PIN(child);
|
||||
u8 parent_irq;
|
||||
u8 parent_irq = rzt2h_gpio_irq_map[child];
|
||||
|
||||
parent_irq = rzt2h_gpio_irq_map[child];
|
||||
if (parent_irq < RZT2H_INTERRUPTS_START)
|
||||
return -EINVAL;
|
||||
|
||||
if (test_and_set_bit(parent_irq - RZT2H_INTERRUPTS_START,
|
||||
pctrl->used_irqs))
|
||||
return -EBUSY;
|
||||
|
||||
rzt2h_pinctrl_set_pfc_mode(pctrl, port, pin, PFC_FUNC_INTERRUPT);
|
||||
|
||||
*parent = parent_irq;
|
||||
*parent_type = child_type;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rzt2h_gpio_irq_domain_free(struct irq_domain *domain, unsigned int virq,
|
||||
unsigned int nr_irqs)
|
||||
{
|
||||
struct irq_data *d = irq_domain_get_irq_data(domain, virq);
|
||||
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
|
||||
struct rzt2h_pinctrl *pctrl = container_of(gc, struct rzt2h_pinctrl, gpio_chip);
|
||||
irq_hw_number_t hwirq = irqd_to_hwirq(d);
|
||||
u8 port = RZT2H_PIN_ID_TO_PORT(hwirq);
|
||||
u8 pin = RZT2H_PIN_ID_TO_PIN(hwirq);
|
||||
|
||||
if (test_and_clear_bit(hwirq - RZT2H_INTERRUPTS_START, pctrl->used_irqs))
|
||||
rzt2h_pinctrl_set_gpio_en(pctrl, port, pin, false);
|
||||
|
||||
irq_domain_free_irqs_common(domain, virq, nr_irqs);
|
||||
}
|
||||
|
||||
static void rzt2h_gpio_init_irq_valid_mask(struct gpio_chip *gc,
|
||||
unsigned long *valid_mask,
|
||||
unsigned int ngpios)
|
||||
|
|
@ -1072,7 +1134,6 @@ static void rzt2h_gpio_init_irq_valid_mask(struct gpio_chip *gc,
|
|||
|
||||
static int rzt2h_gpio_register(struct rzt2h_pinctrl *pctrl)
|
||||
{
|
||||
struct pinctrl_gpio_range *range = &pctrl->gpio_range;
|
||||
struct gpio_chip *chip = &pctrl->gpio_chip;
|
||||
struct device_node *np = pctrl->dev->of_node;
|
||||
struct irq_domain *parent_domain;
|
||||
|
|
@ -1113,6 +1174,7 @@ static int rzt2h_gpio_register(struct rzt2h_pinctrl *pctrl)
|
|||
chip->direction_output = rzt2h_gpio_direction_output;
|
||||
chip->get = rzt2h_gpio_get;
|
||||
chip->set = rzt2h_gpio_set;
|
||||
chip->set_config = gpiochip_generic_config;
|
||||
chip->label = dev_name(dev);
|
||||
|
||||
if (of_property_present(np, "interrupt-controller")) {
|
||||
|
|
@ -1122,17 +1184,9 @@ static int rzt2h_gpio_register(struct rzt2h_pinctrl *pctrl)
|
|||
girq->parent_domain = parent_domain;
|
||||
girq->child_to_parent_hwirq = rzt2h_gpio_child_to_parent_hwirq;
|
||||
girq->populate_parent_alloc_arg = gpiochip_populate_parent_fwspec_twocell;
|
||||
girq->child_irq_domain_ops.free = rzt2h_gpio_irq_domain_free;
|
||||
girq->init_valid_mask = rzt2h_gpio_init_irq_valid_mask;
|
||||
}
|
||||
|
||||
range->id = 0;
|
||||
range->pin_base = 0;
|
||||
range->base = 0;
|
||||
range->npins = chip->ngpio;
|
||||
range->name = chip->label;
|
||||
range->gc = chip;
|
||||
|
||||
ret = devm_gpiochip_add_data(dev, chip, pctrl);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "gpiochip registration failed\n");
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user