162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2014-2018 Renesas Electronics Europe Limited 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Phil Edworthy <phil.edworthy@renesas.com> 662306a36Sopenharmony_ci * Based on a driver originally written by Michel Pollet at Renesas. 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <dt-bindings/pinctrl/rzn1-pinctrl.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/clk.h> 1262306a36Sopenharmony_ci#include <linux/device.h> 1362306a36Sopenharmony_ci#include <linux/io.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/of.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h> 2062306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h> 2162306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h> 2262306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "../core.h" 2562306a36Sopenharmony_ci#include "../pinconf.h" 2662306a36Sopenharmony_ci#include "../pinctrl-utils.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/* Field positions and masks in the pinmux registers */ 2962306a36Sopenharmony_ci#define RZN1_L1_PIN_DRIVE_STRENGTH 10 3062306a36Sopenharmony_ci#define RZN1_L1_PIN_DRIVE_STRENGTH_4MA 0 3162306a36Sopenharmony_ci#define RZN1_L1_PIN_DRIVE_STRENGTH_6MA 1 3262306a36Sopenharmony_ci#define RZN1_L1_PIN_DRIVE_STRENGTH_8MA 2 3362306a36Sopenharmony_ci#define RZN1_L1_PIN_DRIVE_STRENGTH_12MA 3 3462306a36Sopenharmony_ci#define RZN1_L1_PIN_PULL 8 3562306a36Sopenharmony_ci#define RZN1_L1_PIN_PULL_NONE 0 3662306a36Sopenharmony_ci#define RZN1_L1_PIN_PULL_UP 1 3762306a36Sopenharmony_ci#define RZN1_L1_PIN_PULL_DOWN 3 3862306a36Sopenharmony_ci#define RZN1_L1_FUNCTION 0 3962306a36Sopenharmony_ci#define RZN1_L1_FUNC_MASK 0xf 4062306a36Sopenharmony_ci#define RZN1_L1_FUNCTION_L2 0xf 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* 4362306a36Sopenharmony_ci * The hardware manual describes two levels of multiplexing, but it's more 4462306a36Sopenharmony_ci * logical to think of the hardware as three levels, with level 3 consisting of 4562306a36Sopenharmony_ci * the multiplexing for Ethernet MDIO signals. 4662306a36Sopenharmony_ci * 4762306a36Sopenharmony_ci * Level 1 functions go from 0 to 9, with level 1 function '15' (0xf) specifying 4862306a36Sopenharmony_ci * that level 2 functions are used instead. Level 2 has a lot more options, 4962306a36Sopenharmony_ci * going from 0 to 61. Level 3 allows selection of MDIO functions which can be 5062306a36Sopenharmony_ci * floating, or one of seven internal peripherals. Unfortunately, there are two 5162306a36Sopenharmony_ci * level 2 functions that can select MDIO, and two MDIO channels so we have four 5262306a36Sopenharmony_ci * sets of level 3 functions. 5362306a36Sopenharmony_ci * 5462306a36Sopenharmony_ci * For this driver, we've compounded the numbers together, so: 5562306a36Sopenharmony_ci * 0 to 9 is level 1 5662306a36Sopenharmony_ci * 10 to 71 is 10 + level 2 number 5762306a36Sopenharmony_ci * 72 to 79 is 72 + MDIO0 source for level 2 MDIO function. 5862306a36Sopenharmony_ci * 80 to 87 is 80 + MDIO0 source for level 2 MDIO_E1 function. 5962306a36Sopenharmony_ci * 88 to 95 is 88 + MDIO1 source for level 2 MDIO function. 6062306a36Sopenharmony_ci * 96 to 103 is 96 + MDIO1 source for level 2 MDIO_E1 function. 6162306a36Sopenharmony_ci * Examples: 6262306a36Sopenharmony_ci * Function 28 corresponds UART0 6362306a36Sopenharmony_ci * Function 73 corresponds to MDIO0 to GMAC0 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * There are 170 configurable pins (called PL_GPIO in the datasheet). 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* 6962306a36Sopenharmony_ci * Structure detailing the HW registers on the RZ/N1 devices. 7062306a36Sopenharmony_ci * Both the Level 1 mux registers and Level 2 mux registers have the same 7162306a36Sopenharmony_ci * structure. The only difference is that Level 2 has additional MDIO registers 7262306a36Sopenharmony_ci * at the end. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_cistruct rzn1_pinctrl_regs { 7562306a36Sopenharmony_ci u32 conf[170]; 7662306a36Sopenharmony_ci u32 pad0[86]; 7762306a36Sopenharmony_ci u32 status_protect; /* 0x400 */ 7862306a36Sopenharmony_ci /* MDIO mux registers, level2 only */ 7962306a36Sopenharmony_ci u32 l2_mdio[2]; 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/** 8362306a36Sopenharmony_ci * struct rzn1_pmx_func - describes rzn1 pinmux functions 8462306a36Sopenharmony_ci * @name: the name of this specific function 8562306a36Sopenharmony_ci * @groups: corresponding pin groups 8662306a36Sopenharmony_ci * @num_groups: the number of groups 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_cistruct rzn1_pmx_func { 8962306a36Sopenharmony_ci const char *name; 9062306a36Sopenharmony_ci const char **groups; 9162306a36Sopenharmony_ci unsigned int num_groups; 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/** 9562306a36Sopenharmony_ci * struct rzn1_pin_group - describes an rzn1 pin group 9662306a36Sopenharmony_ci * @name: the name of this specific pin group 9762306a36Sopenharmony_ci * @func: the name of the function selected by this group 9862306a36Sopenharmony_ci * @npins: the number of pins in this group array, i.e. the number of 9962306a36Sopenharmony_ci * elements in .pins so we can iterate over that array 10062306a36Sopenharmony_ci * @pins: array of pins. Needed due to pinctrl_ops.get_group_pins() 10162306a36Sopenharmony_ci * @pin_ids: array of pin_ids, i.e. the value used to select the mux 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_cistruct rzn1_pin_group { 10462306a36Sopenharmony_ci const char *name; 10562306a36Sopenharmony_ci const char *func; 10662306a36Sopenharmony_ci unsigned int npins; 10762306a36Sopenharmony_ci unsigned int *pins; 10862306a36Sopenharmony_ci u8 *pin_ids; 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistruct rzn1_pinctrl { 11262306a36Sopenharmony_ci struct device *dev; 11362306a36Sopenharmony_ci struct clk *clk; 11462306a36Sopenharmony_ci struct pinctrl_dev *pctl; 11562306a36Sopenharmony_ci struct rzn1_pinctrl_regs __iomem *lev1; 11662306a36Sopenharmony_ci struct rzn1_pinctrl_regs __iomem *lev2; 11762306a36Sopenharmony_ci u32 lev1_protect_phys; 11862306a36Sopenharmony_ci u32 lev2_protect_phys; 11962306a36Sopenharmony_ci int mdio_func[2]; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci struct rzn1_pin_group *groups; 12262306a36Sopenharmony_ci unsigned int ngroups; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci struct rzn1_pmx_func *functions; 12562306a36Sopenharmony_ci unsigned int nfunctions; 12662306a36Sopenharmony_ci}; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci#define RZN1_PINS_PROP "pinmux" 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci#define RZN1_PIN(pin) PINCTRL_PIN(pin, "pl_gpio"#pin) 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cistatic const struct pinctrl_pin_desc rzn1_pins[] = { 13362306a36Sopenharmony_ci RZN1_PIN(0), RZN1_PIN(1), RZN1_PIN(2), RZN1_PIN(3), RZN1_PIN(4), 13462306a36Sopenharmony_ci RZN1_PIN(5), RZN1_PIN(6), RZN1_PIN(7), RZN1_PIN(8), RZN1_PIN(9), 13562306a36Sopenharmony_ci RZN1_PIN(10), RZN1_PIN(11), RZN1_PIN(12), RZN1_PIN(13), RZN1_PIN(14), 13662306a36Sopenharmony_ci RZN1_PIN(15), RZN1_PIN(16), RZN1_PIN(17), RZN1_PIN(18), RZN1_PIN(19), 13762306a36Sopenharmony_ci RZN1_PIN(20), RZN1_PIN(21), RZN1_PIN(22), RZN1_PIN(23), RZN1_PIN(24), 13862306a36Sopenharmony_ci RZN1_PIN(25), RZN1_PIN(26), RZN1_PIN(27), RZN1_PIN(28), RZN1_PIN(29), 13962306a36Sopenharmony_ci RZN1_PIN(30), RZN1_PIN(31), RZN1_PIN(32), RZN1_PIN(33), RZN1_PIN(34), 14062306a36Sopenharmony_ci RZN1_PIN(35), RZN1_PIN(36), RZN1_PIN(37), RZN1_PIN(38), RZN1_PIN(39), 14162306a36Sopenharmony_ci RZN1_PIN(40), RZN1_PIN(41), RZN1_PIN(42), RZN1_PIN(43), RZN1_PIN(44), 14262306a36Sopenharmony_ci RZN1_PIN(45), RZN1_PIN(46), RZN1_PIN(47), RZN1_PIN(48), RZN1_PIN(49), 14362306a36Sopenharmony_ci RZN1_PIN(50), RZN1_PIN(51), RZN1_PIN(52), RZN1_PIN(53), RZN1_PIN(54), 14462306a36Sopenharmony_ci RZN1_PIN(55), RZN1_PIN(56), RZN1_PIN(57), RZN1_PIN(58), RZN1_PIN(59), 14562306a36Sopenharmony_ci RZN1_PIN(60), RZN1_PIN(61), RZN1_PIN(62), RZN1_PIN(63), RZN1_PIN(64), 14662306a36Sopenharmony_ci RZN1_PIN(65), RZN1_PIN(66), RZN1_PIN(67), RZN1_PIN(68), RZN1_PIN(69), 14762306a36Sopenharmony_ci RZN1_PIN(70), RZN1_PIN(71), RZN1_PIN(72), RZN1_PIN(73), RZN1_PIN(74), 14862306a36Sopenharmony_ci RZN1_PIN(75), RZN1_PIN(76), RZN1_PIN(77), RZN1_PIN(78), RZN1_PIN(79), 14962306a36Sopenharmony_ci RZN1_PIN(80), RZN1_PIN(81), RZN1_PIN(82), RZN1_PIN(83), RZN1_PIN(84), 15062306a36Sopenharmony_ci RZN1_PIN(85), RZN1_PIN(86), RZN1_PIN(87), RZN1_PIN(88), RZN1_PIN(89), 15162306a36Sopenharmony_ci RZN1_PIN(90), RZN1_PIN(91), RZN1_PIN(92), RZN1_PIN(93), RZN1_PIN(94), 15262306a36Sopenharmony_ci RZN1_PIN(95), RZN1_PIN(96), RZN1_PIN(97), RZN1_PIN(98), RZN1_PIN(99), 15362306a36Sopenharmony_ci RZN1_PIN(100), RZN1_PIN(101), RZN1_PIN(102), RZN1_PIN(103), 15462306a36Sopenharmony_ci RZN1_PIN(104), RZN1_PIN(105), RZN1_PIN(106), RZN1_PIN(107), 15562306a36Sopenharmony_ci RZN1_PIN(108), RZN1_PIN(109), RZN1_PIN(110), RZN1_PIN(111), 15662306a36Sopenharmony_ci RZN1_PIN(112), RZN1_PIN(113), RZN1_PIN(114), RZN1_PIN(115), 15762306a36Sopenharmony_ci RZN1_PIN(116), RZN1_PIN(117), RZN1_PIN(118), RZN1_PIN(119), 15862306a36Sopenharmony_ci RZN1_PIN(120), RZN1_PIN(121), RZN1_PIN(122), RZN1_PIN(123), 15962306a36Sopenharmony_ci RZN1_PIN(124), RZN1_PIN(125), RZN1_PIN(126), RZN1_PIN(127), 16062306a36Sopenharmony_ci RZN1_PIN(128), RZN1_PIN(129), RZN1_PIN(130), RZN1_PIN(131), 16162306a36Sopenharmony_ci RZN1_PIN(132), RZN1_PIN(133), RZN1_PIN(134), RZN1_PIN(135), 16262306a36Sopenharmony_ci RZN1_PIN(136), RZN1_PIN(137), RZN1_PIN(138), RZN1_PIN(139), 16362306a36Sopenharmony_ci RZN1_PIN(140), RZN1_PIN(141), RZN1_PIN(142), RZN1_PIN(143), 16462306a36Sopenharmony_ci RZN1_PIN(144), RZN1_PIN(145), RZN1_PIN(146), RZN1_PIN(147), 16562306a36Sopenharmony_ci RZN1_PIN(148), RZN1_PIN(149), RZN1_PIN(150), RZN1_PIN(151), 16662306a36Sopenharmony_ci RZN1_PIN(152), RZN1_PIN(153), RZN1_PIN(154), RZN1_PIN(155), 16762306a36Sopenharmony_ci RZN1_PIN(156), RZN1_PIN(157), RZN1_PIN(158), RZN1_PIN(159), 16862306a36Sopenharmony_ci RZN1_PIN(160), RZN1_PIN(161), RZN1_PIN(162), RZN1_PIN(163), 16962306a36Sopenharmony_ci RZN1_PIN(164), RZN1_PIN(165), RZN1_PIN(166), RZN1_PIN(167), 17062306a36Sopenharmony_ci RZN1_PIN(168), RZN1_PIN(169), 17162306a36Sopenharmony_ci}; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cienum { 17462306a36Sopenharmony_ci LOCK_LEVEL1 = 0x1, 17562306a36Sopenharmony_ci LOCK_LEVEL2 = 0x2, 17662306a36Sopenharmony_ci LOCK_ALL = LOCK_LEVEL1 | LOCK_LEVEL2, 17762306a36Sopenharmony_ci}; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_cistatic void rzn1_hw_set_lock(struct rzn1_pinctrl *ipctl, u8 lock, u8 value) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci /* 18262306a36Sopenharmony_ci * The pinmux configuration is locked by writing the physical address of 18362306a36Sopenharmony_ci * the status_protect register to itself. It is unlocked by writing the 18462306a36Sopenharmony_ci * address | 1. 18562306a36Sopenharmony_ci */ 18662306a36Sopenharmony_ci if (lock & LOCK_LEVEL1) { 18762306a36Sopenharmony_ci u32 val = ipctl->lev1_protect_phys | !(value & LOCK_LEVEL1); 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci writel(val, &ipctl->lev1->status_protect); 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci if (lock & LOCK_LEVEL2) { 19362306a36Sopenharmony_ci u32 val = ipctl->lev2_protect_phys | !(value & LOCK_LEVEL2); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci writel(val, &ipctl->lev2->status_protect); 19662306a36Sopenharmony_ci } 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic void rzn1_pinctrl_mdio_select(struct rzn1_pinctrl *ipctl, int mdio, 20062306a36Sopenharmony_ci u32 func) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci if (ipctl->mdio_func[mdio] >= 0 && ipctl->mdio_func[mdio] != func) 20362306a36Sopenharmony_ci dev_warn(ipctl->dev, "conflicting setting for mdio%d!\n", mdio); 20462306a36Sopenharmony_ci ipctl->mdio_func[mdio] = func; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci dev_dbg(ipctl->dev, "setting mdio%d to %u\n", mdio, func); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci writel(func, &ipctl->lev2->l2_mdio[mdio]); 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci/* 21262306a36Sopenharmony_ci * Using a composite pin description, set the hardware pinmux registers 21362306a36Sopenharmony_ci * with the corresponding values. 21462306a36Sopenharmony_ci * Make sure to unlock write protection and reset it afterward. 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * NOTE: There is no protection for potential concurrency, it is assumed these 21762306a36Sopenharmony_ci * calls are serialized already. 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_cistatic int rzn1_set_hw_pin_func(struct rzn1_pinctrl *ipctl, unsigned int pin, 22062306a36Sopenharmony_ci u32 pin_config, u8 use_locks) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci u32 l1_cache; 22362306a36Sopenharmony_ci u32 l2_cache; 22462306a36Sopenharmony_ci u32 l1; 22562306a36Sopenharmony_ci u32 l2; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci /* Level 3 MDIO multiplexing */ 22862306a36Sopenharmony_ci if (pin_config >= RZN1_FUNC_MDIO0_HIGHZ && 22962306a36Sopenharmony_ci pin_config <= RZN1_FUNC_MDIO1_E1_SWITCH) { 23062306a36Sopenharmony_ci int mdio_channel; 23162306a36Sopenharmony_ci u32 mdio_func; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci if (pin_config <= RZN1_FUNC_MDIO1_HIGHZ) 23462306a36Sopenharmony_ci mdio_channel = 0; 23562306a36Sopenharmony_ci else 23662306a36Sopenharmony_ci mdio_channel = 1; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci /* Get MDIO func, and convert the func to the level 2 number */ 23962306a36Sopenharmony_ci if (pin_config <= RZN1_FUNC_MDIO0_SWITCH) { 24062306a36Sopenharmony_ci mdio_func = pin_config - RZN1_FUNC_MDIO0_HIGHZ; 24162306a36Sopenharmony_ci pin_config = RZN1_FUNC_ETH_MDIO; 24262306a36Sopenharmony_ci } else if (pin_config <= RZN1_FUNC_MDIO0_E1_SWITCH) { 24362306a36Sopenharmony_ci mdio_func = pin_config - RZN1_FUNC_MDIO0_E1_HIGHZ; 24462306a36Sopenharmony_ci pin_config = RZN1_FUNC_ETH_MDIO_E1; 24562306a36Sopenharmony_ci } else if (pin_config <= RZN1_FUNC_MDIO1_SWITCH) { 24662306a36Sopenharmony_ci mdio_func = pin_config - RZN1_FUNC_MDIO1_HIGHZ; 24762306a36Sopenharmony_ci pin_config = RZN1_FUNC_ETH_MDIO; 24862306a36Sopenharmony_ci } else { 24962306a36Sopenharmony_ci mdio_func = pin_config - RZN1_FUNC_MDIO1_E1_HIGHZ; 25062306a36Sopenharmony_ci pin_config = RZN1_FUNC_ETH_MDIO_E1; 25162306a36Sopenharmony_ci } 25262306a36Sopenharmony_ci rzn1_pinctrl_mdio_select(ipctl, mdio_channel, mdio_func); 25362306a36Sopenharmony_ci } 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* Note here, we do not allow anything past the MDIO Mux values */ 25662306a36Sopenharmony_ci if (pin >= ARRAY_SIZE(ipctl->lev1->conf) || 25762306a36Sopenharmony_ci pin_config >= RZN1_FUNC_MDIO0_HIGHZ) 25862306a36Sopenharmony_ci return -EINVAL; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci l1 = readl(&ipctl->lev1->conf[pin]); 26162306a36Sopenharmony_ci l1_cache = l1; 26262306a36Sopenharmony_ci l2 = readl(&ipctl->lev2->conf[pin]); 26362306a36Sopenharmony_ci l2_cache = l2; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci dev_dbg(ipctl->dev, "setting func for pin %u to %u\n", pin, pin_config); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci l1 &= ~(RZN1_L1_FUNC_MASK << RZN1_L1_FUNCTION); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci if (pin_config < RZN1_FUNC_L2_OFFSET) { 27062306a36Sopenharmony_ci l1 |= (pin_config << RZN1_L1_FUNCTION); 27162306a36Sopenharmony_ci } else { 27262306a36Sopenharmony_ci l1 |= (RZN1_L1_FUNCTION_L2 << RZN1_L1_FUNCTION); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci l2 = pin_config - RZN1_FUNC_L2_OFFSET; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* If either configuration changes, we update both anyway */ 27862306a36Sopenharmony_ci if (l1 != l1_cache || l2 != l2_cache) { 27962306a36Sopenharmony_ci writel(l1, &ipctl->lev1->conf[pin]); 28062306a36Sopenharmony_ci writel(l2, &ipctl->lev2->conf[pin]); 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci return 0; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic const struct rzn1_pin_group *rzn1_pinctrl_find_group_by_name( 28762306a36Sopenharmony_ci const struct rzn1_pinctrl *ipctl, const char *name) 28862306a36Sopenharmony_ci{ 28962306a36Sopenharmony_ci unsigned int i; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci for (i = 0; i < ipctl->ngroups; i++) { 29262306a36Sopenharmony_ci if (!strcmp(ipctl->groups[i].name, name)) 29362306a36Sopenharmony_ci return &ipctl->groups[i]; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return NULL; 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic int rzn1_get_groups_count(struct pinctrl_dev *pctldev) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci return ipctl->ngroups; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic const char *rzn1_get_group_name(struct pinctrl_dev *pctldev, 30762306a36Sopenharmony_ci unsigned int selector) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci return ipctl->groups[selector].name; 31262306a36Sopenharmony_ci} 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_cistatic int rzn1_get_group_pins(struct pinctrl_dev *pctldev, 31562306a36Sopenharmony_ci unsigned int selector, const unsigned int **pins, 31662306a36Sopenharmony_ci unsigned int *npins) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci if (selector >= ipctl->ngroups) 32162306a36Sopenharmony_ci return -EINVAL; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci *pins = ipctl->groups[selector].pins; 32462306a36Sopenharmony_ci *npins = ipctl->groups[selector].npins; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci/* 33062306a36Sopenharmony_ci * This function is called for each pinctl 'Function' node. 33162306a36Sopenharmony_ci * Sub-nodes can be used to describe multiple 'Groups' for the 'Function' 33262306a36Sopenharmony_ci * If there aren't any sub-nodes, the 'Group' is essentially the 'Function'. 33362306a36Sopenharmony_ci * Each 'Group' uses pinmux = <...> to detail the pins and data used to select 33462306a36Sopenharmony_ci * the functionality. Each 'Group' has optional pin configurations that apply 33562306a36Sopenharmony_ci * to all pins in the 'Group'. 33662306a36Sopenharmony_ci */ 33762306a36Sopenharmony_cistatic int rzn1_dt_node_to_map_one(struct pinctrl_dev *pctldev, 33862306a36Sopenharmony_ci struct device_node *np, 33962306a36Sopenharmony_ci struct pinctrl_map **map, 34062306a36Sopenharmony_ci unsigned int *num_maps) 34162306a36Sopenharmony_ci{ 34262306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 34362306a36Sopenharmony_ci const struct rzn1_pin_group *grp; 34462306a36Sopenharmony_ci unsigned long *configs = NULL; 34562306a36Sopenharmony_ci unsigned int reserved_maps = *num_maps; 34662306a36Sopenharmony_ci unsigned int num_configs = 0; 34762306a36Sopenharmony_ci unsigned int reserve = 1; 34862306a36Sopenharmony_ci int ret; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci dev_dbg(ipctl->dev, "processing node %pOF\n", np); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci grp = rzn1_pinctrl_find_group_by_name(ipctl, np->name); 35362306a36Sopenharmony_ci if (!grp) { 35462306a36Sopenharmony_ci dev_err(ipctl->dev, "unable to find group for node %pOF\n", np); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci return -EINVAL; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* Get the group's pin configuration */ 36062306a36Sopenharmony_ci ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, 36162306a36Sopenharmony_ci &num_configs); 36262306a36Sopenharmony_ci if (ret < 0) { 36362306a36Sopenharmony_ci dev_err(ipctl->dev, "%pOF: could not parse property\n", np); 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci return ret; 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci if (num_configs) 36962306a36Sopenharmony_ci reserve++; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* Increase the number of maps to cover this group */ 37262306a36Sopenharmony_ci ret = pinctrl_utils_reserve_map(pctldev, map, &reserved_maps, num_maps, 37362306a36Sopenharmony_ci reserve); 37462306a36Sopenharmony_ci if (ret < 0) 37562306a36Sopenharmony_ci goto out; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci /* Associate the group with the function */ 37862306a36Sopenharmony_ci ret = pinctrl_utils_add_map_mux(pctldev, map, &reserved_maps, num_maps, 37962306a36Sopenharmony_ci grp->name, grp->func); 38062306a36Sopenharmony_ci if (ret < 0) 38162306a36Sopenharmony_ci goto out; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (num_configs) { 38462306a36Sopenharmony_ci /* Associate the group's pin configuration with the group */ 38562306a36Sopenharmony_ci ret = pinctrl_utils_add_map_configs(pctldev, map, 38662306a36Sopenharmony_ci &reserved_maps, num_maps, grp->name, 38762306a36Sopenharmony_ci configs, num_configs, 38862306a36Sopenharmony_ci PIN_MAP_TYPE_CONFIGS_GROUP); 38962306a36Sopenharmony_ci if (ret < 0) 39062306a36Sopenharmony_ci goto out; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci dev_dbg(pctldev->dev, "maps: function %s group %s (%d pins)\n", 39462306a36Sopenharmony_ci grp->func, grp->name, grp->npins); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ciout: 39762306a36Sopenharmony_ci kfree(configs); 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci return ret; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic int rzn1_dt_node_to_map(struct pinctrl_dev *pctldev, 40362306a36Sopenharmony_ci struct device_node *np, 40462306a36Sopenharmony_ci struct pinctrl_map **map, 40562306a36Sopenharmony_ci unsigned int *num_maps) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct device_node *child; 40862306a36Sopenharmony_ci int ret; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci *map = NULL; 41162306a36Sopenharmony_ci *num_maps = 0; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci ret = rzn1_dt_node_to_map_one(pctldev, np, map, num_maps); 41462306a36Sopenharmony_ci if (ret < 0) 41562306a36Sopenharmony_ci return ret; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci for_each_child_of_node(np, child) { 41862306a36Sopenharmony_ci ret = rzn1_dt_node_to_map_one(pctldev, child, map, num_maps); 41962306a36Sopenharmony_ci if (ret < 0) { 42062306a36Sopenharmony_ci of_node_put(child); 42162306a36Sopenharmony_ci return ret; 42262306a36Sopenharmony_ci } 42362306a36Sopenharmony_ci } 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci return 0; 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic const struct pinctrl_ops rzn1_pctrl_ops = { 42962306a36Sopenharmony_ci .get_groups_count = rzn1_get_groups_count, 43062306a36Sopenharmony_ci .get_group_name = rzn1_get_group_name, 43162306a36Sopenharmony_ci .get_group_pins = rzn1_get_group_pins, 43262306a36Sopenharmony_ci .dt_node_to_map = rzn1_dt_node_to_map, 43362306a36Sopenharmony_ci .dt_free_map = pinctrl_utils_free_map, 43462306a36Sopenharmony_ci}; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_cistatic int rzn1_pmx_get_funcs_count(struct pinctrl_dev *pctldev) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci return ipctl->nfunctions; 44162306a36Sopenharmony_ci} 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_cistatic const char *rzn1_pmx_get_func_name(struct pinctrl_dev *pctldev, 44462306a36Sopenharmony_ci unsigned int selector) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci return ipctl->functions[selector].name; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic int rzn1_pmx_get_groups(struct pinctrl_dev *pctldev, 45262306a36Sopenharmony_ci unsigned int selector, 45362306a36Sopenharmony_ci const char * const **groups, 45462306a36Sopenharmony_ci unsigned int * const num_groups) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci *groups = ipctl->functions[selector].groups; 45962306a36Sopenharmony_ci *num_groups = ipctl->functions[selector].num_groups; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return 0; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_cistatic int rzn1_set_mux(struct pinctrl_dev *pctldev, unsigned int selector, 46562306a36Sopenharmony_ci unsigned int group) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 46862306a36Sopenharmony_ci struct rzn1_pin_group *grp = &ipctl->groups[group]; 46962306a36Sopenharmony_ci unsigned int i, grp_pins = grp->npins; 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci dev_dbg(ipctl->dev, "set mux %s(%d) group %s(%d)\n", 47262306a36Sopenharmony_ci ipctl->functions[selector].name, selector, grp->name, group); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci rzn1_hw_set_lock(ipctl, LOCK_ALL, LOCK_ALL); 47562306a36Sopenharmony_ci for (i = 0; i < grp_pins; i++) 47662306a36Sopenharmony_ci rzn1_set_hw_pin_func(ipctl, grp->pins[i], grp->pin_ids[i], 0); 47762306a36Sopenharmony_ci rzn1_hw_set_lock(ipctl, LOCK_ALL, 0); 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci return 0; 48062306a36Sopenharmony_ci} 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_cistatic const struct pinmux_ops rzn1_pmx_ops = { 48362306a36Sopenharmony_ci .get_functions_count = rzn1_pmx_get_funcs_count, 48462306a36Sopenharmony_ci .get_function_name = rzn1_pmx_get_func_name, 48562306a36Sopenharmony_ci .get_function_groups = rzn1_pmx_get_groups, 48662306a36Sopenharmony_ci .set_mux = rzn1_set_mux, 48762306a36Sopenharmony_ci}; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_cistatic int rzn1_pinconf_get(struct pinctrl_dev *pctldev, unsigned int pin, 49062306a36Sopenharmony_ci unsigned long *config) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 49362306a36Sopenharmony_ci enum pin_config_param param = pinconf_to_config_param(*config); 49462306a36Sopenharmony_ci static const u32 reg_drive[4] = { 4, 6, 8, 12 }; 49562306a36Sopenharmony_ci u32 pull, drive, l1mux; 49662306a36Sopenharmony_ci u32 l1, l2, arg = 0; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci if (pin >= ARRAY_SIZE(ipctl->lev1->conf)) 49962306a36Sopenharmony_ci return -EINVAL; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci l1 = readl(&ipctl->lev1->conf[pin]); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci l1mux = l1 & RZN1_L1_FUNC_MASK; 50462306a36Sopenharmony_ci pull = (l1 >> RZN1_L1_PIN_PULL) & 0x3; 50562306a36Sopenharmony_ci drive = (l1 >> RZN1_L1_PIN_DRIVE_STRENGTH) & 0x3; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci switch (param) { 50862306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 50962306a36Sopenharmony_ci if (pull != RZN1_L1_PIN_PULL_UP) 51062306a36Sopenharmony_ci return -EINVAL; 51162306a36Sopenharmony_ci break; 51262306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 51362306a36Sopenharmony_ci if (pull != RZN1_L1_PIN_PULL_DOWN) 51462306a36Sopenharmony_ci return -EINVAL; 51562306a36Sopenharmony_ci break; 51662306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 51762306a36Sopenharmony_ci if (pull != RZN1_L1_PIN_PULL_NONE) 51862306a36Sopenharmony_ci return -EINVAL; 51962306a36Sopenharmony_ci break; 52062306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 52162306a36Sopenharmony_ci arg = reg_drive[drive]; 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: 52462306a36Sopenharmony_ci l2 = readl(&ipctl->lev2->conf[pin]); 52562306a36Sopenharmony_ci if (l1mux == RZN1_L1_FUNCTION_L2) { 52662306a36Sopenharmony_ci if (l2 != 0) 52762306a36Sopenharmony_ci return -EINVAL; 52862306a36Sopenharmony_ci } else if (l1mux != RZN1_FUNC_HIGHZ) { 52962306a36Sopenharmony_ci return -EINVAL; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci break; 53262306a36Sopenharmony_ci default: 53362306a36Sopenharmony_ci return -ENOTSUPP; 53462306a36Sopenharmony_ci } 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci *config = pinconf_to_config_packed(param, arg); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci return 0; 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic int rzn1_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin, 54262306a36Sopenharmony_ci unsigned long *configs, unsigned int num_configs) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 54562306a36Sopenharmony_ci enum pin_config_param param; 54662306a36Sopenharmony_ci unsigned int i; 54762306a36Sopenharmony_ci u32 l1, l1_cache; 54862306a36Sopenharmony_ci u32 drv; 54962306a36Sopenharmony_ci u32 arg; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci if (pin >= ARRAY_SIZE(ipctl->lev1->conf)) 55262306a36Sopenharmony_ci return -EINVAL; 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_ci l1 = readl(&ipctl->lev1->conf[pin]); 55562306a36Sopenharmony_ci l1_cache = l1; 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci for (i = 0; i < num_configs; i++) { 55862306a36Sopenharmony_ci param = pinconf_to_config_param(configs[i]); 55962306a36Sopenharmony_ci arg = pinconf_to_config_argument(configs[i]); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci switch (param) { 56262306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_UP: 56362306a36Sopenharmony_ci dev_dbg(ipctl->dev, "set pin %d pull up\n", pin); 56462306a36Sopenharmony_ci l1 &= ~(0x3 << RZN1_L1_PIN_PULL); 56562306a36Sopenharmony_ci l1 |= (RZN1_L1_PIN_PULL_UP << RZN1_L1_PIN_PULL); 56662306a36Sopenharmony_ci break; 56762306a36Sopenharmony_ci case PIN_CONFIG_BIAS_PULL_DOWN: 56862306a36Sopenharmony_ci dev_dbg(ipctl->dev, "set pin %d pull down\n", pin); 56962306a36Sopenharmony_ci l1 &= ~(0x3 << RZN1_L1_PIN_PULL); 57062306a36Sopenharmony_ci l1 |= (RZN1_L1_PIN_PULL_DOWN << RZN1_L1_PIN_PULL); 57162306a36Sopenharmony_ci break; 57262306a36Sopenharmony_ci case PIN_CONFIG_BIAS_DISABLE: 57362306a36Sopenharmony_ci dev_dbg(ipctl->dev, "set pin %d bias off\n", pin); 57462306a36Sopenharmony_ci l1 &= ~(0x3 << RZN1_L1_PIN_PULL); 57562306a36Sopenharmony_ci l1 |= (RZN1_L1_PIN_PULL_NONE << RZN1_L1_PIN_PULL); 57662306a36Sopenharmony_ci break; 57762306a36Sopenharmony_ci case PIN_CONFIG_DRIVE_STRENGTH: 57862306a36Sopenharmony_ci dev_dbg(ipctl->dev, "set pin %d drv %umA\n", pin, arg); 57962306a36Sopenharmony_ci switch (arg) { 58062306a36Sopenharmony_ci case 4: 58162306a36Sopenharmony_ci drv = RZN1_L1_PIN_DRIVE_STRENGTH_4MA; 58262306a36Sopenharmony_ci break; 58362306a36Sopenharmony_ci case 6: 58462306a36Sopenharmony_ci drv = RZN1_L1_PIN_DRIVE_STRENGTH_6MA; 58562306a36Sopenharmony_ci break; 58662306a36Sopenharmony_ci case 8: 58762306a36Sopenharmony_ci drv = RZN1_L1_PIN_DRIVE_STRENGTH_8MA; 58862306a36Sopenharmony_ci break; 58962306a36Sopenharmony_ci case 12: 59062306a36Sopenharmony_ci drv = RZN1_L1_PIN_DRIVE_STRENGTH_12MA; 59162306a36Sopenharmony_ci break; 59262306a36Sopenharmony_ci default: 59362306a36Sopenharmony_ci dev_err(ipctl->dev, 59462306a36Sopenharmony_ci "Drive strength %umA not supported\n", 59562306a36Sopenharmony_ci arg); 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci return -EINVAL; 59862306a36Sopenharmony_ci } 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci l1 &= ~(0x3 << RZN1_L1_PIN_DRIVE_STRENGTH); 60162306a36Sopenharmony_ci l1 |= (drv << RZN1_L1_PIN_DRIVE_STRENGTH); 60262306a36Sopenharmony_ci break; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: 60562306a36Sopenharmony_ci dev_dbg(ipctl->dev, "set pin %d High-Z\n", pin); 60662306a36Sopenharmony_ci l1 &= ~RZN1_L1_FUNC_MASK; 60762306a36Sopenharmony_ci l1 |= RZN1_FUNC_HIGHZ; 60862306a36Sopenharmony_ci break; 60962306a36Sopenharmony_ci default: 61062306a36Sopenharmony_ci return -ENOTSUPP; 61162306a36Sopenharmony_ci } 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if (l1 != l1_cache) { 61562306a36Sopenharmony_ci rzn1_hw_set_lock(ipctl, LOCK_LEVEL1, LOCK_LEVEL1); 61662306a36Sopenharmony_ci writel(l1, &ipctl->lev1->conf[pin]); 61762306a36Sopenharmony_ci rzn1_hw_set_lock(ipctl, LOCK_LEVEL1, 0); 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci return 0; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic int rzn1_pinconf_group_get(struct pinctrl_dev *pctldev, 62462306a36Sopenharmony_ci unsigned int selector, 62562306a36Sopenharmony_ci unsigned long *config) 62662306a36Sopenharmony_ci{ 62762306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 62862306a36Sopenharmony_ci struct rzn1_pin_group *grp = &ipctl->groups[selector]; 62962306a36Sopenharmony_ci unsigned long old = 0; 63062306a36Sopenharmony_ci unsigned int i; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci dev_dbg(ipctl->dev, "group get %s selector:%u\n", grp->name, selector); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci for (i = 0; i < grp->npins; i++) { 63562306a36Sopenharmony_ci if (rzn1_pinconf_get(pctldev, grp->pins[i], config)) 63662306a36Sopenharmony_ci return -ENOTSUPP; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* configs do not match between two pins */ 63962306a36Sopenharmony_ci if (i && (old != *config)) 64062306a36Sopenharmony_ci return -ENOTSUPP; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci old = *config; 64362306a36Sopenharmony_ci } 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci return 0; 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic int rzn1_pinconf_group_set(struct pinctrl_dev *pctldev, 64962306a36Sopenharmony_ci unsigned int selector, 65062306a36Sopenharmony_ci unsigned long *configs, 65162306a36Sopenharmony_ci unsigned int num_configs) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev); 65462306a36Sopenharmony_ci struct rzn1_pin_group *grp = &ipctl->groups[selector]; 65562306a36Sopenharmony_ci unsigned int i; 65662306a36Sopenharmony_ci int ret; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci dev_dbg(ipctl->dev, "group set %s selector:%u configs:%p/%d\n", 65962306a36Sopenharmony_ci grp->name, selector, configs, num_configs); 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci for (i = 0; i < grp->npins; i++) { 66262306a36Sopenharmony_ci unsigned int pin = grp->pins[i]; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci ret = rzn1_pinconf_set(pctldev, pin, configs, num_configs); 66562306a36Sopenharmony_ci if (ret) 66662306a36Sopenharmony_ci return ret; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci return 0; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistatic const struct pinconf_ops rzn1_pinconf_ops = { 67362306a36Sopenharmony_ci .is_generic = true, 67462306a36Sopenharmony_ci .pin_config_get = rzn1_pinconf_get, 67562306a36Sopenharmony_ci .pin_config_set = rzn1_pinconf_set, 67662306a36Sopenharmony_ci .pin_config_group_get = rzn1_pinconf_group_get, 67762306a36Sopenharmony_ci .pin_config_group_set = rzn1_pinconf_group_set, 67862306a36Sopenharmony_ci .pin_config_config_dbg_show = pinconf_generic_dump_config, 67962306a36Sopenharmony_ci}; 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic struct pinctrl_desc rzn1_pinctrl_desc = { 68262306a36Sopenharmony_ci .pctlops = &rzn1_pctrl_ops, 68362306a36Sopenharmony_ci .pmxops = &rzn1_pmx_ops, 68462306a36Sopenharmony_ci .confops = &rzn1_pinconf_ops, 68562306a36Sopenharmony_ci .owner = THIS_MODULE, 68662306a36Sopenharmony_ci}; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_cistatic int rzn1_pinctrl_parse_groups(struct device_node *np, 68962306a36Sopenharmony_ci struct rzn1_pin_group *grp, 69062306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl) 69162306a36Sopenharmony_ci{ 69262306a36Sopenharmony_ci const __be32 *list; 69362306a36Sopenharmony_ci unsigned int i; 69462306a36Sopenharmony_ci int size; 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci dev_dbg(ipctl->dev, "%s: %s\n", __func__, np->name); 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci /* Initialise group */ 69962306a36Sopenharmony_ci grp->name = np->name; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci /* 70262306a36Sopenharmony_ci * The binding format is 70362306a36Sopenharmony_ci * pinmux = <PIN_FUNC_ID CONFIG ...>, 70462306a36Sopenharmony_ci * do sanity check and calculate pins number 70562306a36Sopenharmony_ci */ 70662306a36Sopenharmony_ci list = of_get_property(np, RZN1_PINS_PROP, &size); 70762306a36Sopenharmony_ci if (!list) { 70862306a36Sopenharmony_ci dev_err(ipctl->dev, 70962306a36Sopenharmony_ci "no " RZN1_PINS_PROP " property in node %pOF\n", np); 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci return -EINVAL; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (!size) { 71562306a36Sopenharmony_ci dev_err(ipctl->dev, "Invalid " RZN1_PINS_PROP " in node %pOF\n", 71662306a36Sopenharmony_ci np); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci return -EINVAL; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci grp->npins = size / sizeof(list[0]); 72262306a36Sopenharmony_ci grp->pin_ids = devm_kmalloc_array(ipctl->dev, 72362306a36Sopenharmony_ci grp->npins, sizeof(grp->pin_ids[0]), 72462306a36Sopenharmony_ci GFP_KERNEL); 72562306a36Sopenharmony_ci grp->pins = devm_kmalloc_array(ipctl->dev, 72662306a36Sopenharmony_ci grp->npins, sizeof(grp->pins[0]), 72762306a36Sopenharmony_ci GFP_KERNEL); 72862306a36Sopenharmony_ci if (!grp->pin_ids || !grp->pins) 72962306a36Sopenharmony_ci return -ENOMEM; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci for (i = 0; i < grp->npins; i++) { 73262306a36Sopenharmony_ci u32 pin_id = be32_to_cpu(*list++); 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci grp->pins[i] = pin_id & 0xff; 73562306a36Sopenharmony_ci grp->pin_ids[i] = (pin_id >> 8) & 0x7f; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci return grp->npins; 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic int rzn1_pinctrl_count_function_groups(struct device_node *np) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci struct device_node *child; 74462306a36Sopenharmony_ci int count = 0; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci if (of_property_count_u32_elems(np, RZN1_PINS_PROP) > 0) 74762306a36Sopenharmony_ci count++; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci for_each_child_of_node(np, child) { 75062306a36Sopenharmony_ci if (of_property_count_u32_elems(child, RZN1_PINS_PROP) > 0) 75162306a36Sopenharmony_ci count++; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci return count; 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cistatic int rzn1_pinctrl_parse_functions(struct device_node *np, 75862306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl, 75962306a36Sopenharmony_ci unsigned int index) 76062306a36Sopenharmony_ci{ 76162306a36Sopenharmony_ci struct rzn1_pmx_func *func; 76262306a36Sopenharmony_ci struct rzn1_pin_group *grp; 76362306a36Sopenharmony_ci struct device_node *child; 76462306a36Sopenharmony_ci unsigned int i = 0; 76562306a36Sopenharmony_ci int ret; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci func = &ipctl->functions[index]; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci /* Initialise function */ 77062306a36Sopenharmony_ci func->name = np->name; 77162306a36Sopenharmony_ci func->num_groups = rzn1_pinctrl_count_function_groups(np); 77262306a36Sopenharmony_ci if (func->num_groups == 0) { 77362306a36Sopenharmony_ci dev_err(ipctl->dev, "no groups defined in %pOF\n", np); 77462306a36Sopenharmony_ci return -EINVAL; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci dev_dbg(ipctl->dev, "function %s has %d groups\n", 77762306a36Sopenharmony_ci np->name, func->num_groups); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci func->groups = devm_kmalloc_array(ipctl->dev, 78062306a36Sopenharmony_ci func->num_groups, sizeof(char *), 78162306a36Sopenharmony_ci GFP_KERNEL); 78262306a36Sopenharmony_ci if (!func->groups) 78362306a36Sopenharmony_ci return -ENOMEM; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (of_property_count_u32_elems(np, RZN1_PINS_PROP) > 0) { 78662306a36Sopenharmony_ci func->groups[i] = np->name; 78762306a36Sopenharmony_ci grp = &ipctl->groups[ipctl->ngroups]; 78862306a36Sopenharmony_ci grp->func = func->name; 78962306a36Sopenharmony_ci ret = rzn1_pinctrl_parse_groups(np, grp, ipctl); 79062306a36Sopenharmony_ci if (ret < 0) 79162306a36Sopenharmony_ci return ret; 79262306a36Sopenharmony_ci i++; 79362306a36Sopenharmony_ci ipctl->ngroups++; 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci for_each_child_of_node(np, child) { 79762306a36Sopenharmony_ci func->groups[i] = child->name; 79862306a36Sopenharmony_ci grp = &ipctl->groups[ipctl->ngroups]; 79962306a36Sopenharmony_ci grp->func = func->name; 80062306a36Sopenharmony_ci ret = rzn1_pinctrl_parse_groups(child, grp, ipctl); 80162306a36Sopenharmony_ci if (ret < 0) { 80262306a36Sopenharmony_ci of_node_put(child); 80362306a36Sopenharmony_ci return ret; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci i++; 80662306a36Sopenharmony_ci ipctl->ngroups++; 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci dev_dbg(ipctl->dev, "function %s parsed %u/%u groups\n", 81062306a36Sopenharmony_ci np->name, i, func->num_groups); 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return 0; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic int rzn1_pinctrl_probe_dt(struct platform_device *pdev, 81662306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl) 81762306a36Sopenharmony_ci{ 81862306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 81962306a36Sopenharmony_ci struct device_node *child; 82062306a36Sopenharmony_ci unsigned int maxgroups = 0; 82162306a36Sopenharmony_ci unsigned int i = 0; 82262306a36Sopenharmony_ci int nfuncs = 0; 82362306a36Sopenharmony_ci int ret; 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci nfuncs = of_get_child_count(np); 82662306a36Sopenharmony_ci if (nfuncs <= 0) 82762306a36Sopenharmony_ci return 0; 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci ipctl->nfunctions = nfuncs; 83062306a36Sopenharmony_ci ipctl->functions = devm_kmalloc_array(&pdev->dev, nfuncs, 83162306a36Sopenharmony_ci sizeof(*ipctl->functions), 83262306a36Sopenharmony_ci GFP_KERNEL); 83362306a36Sopenharmony_ci if (!ipctl->functions) 83462306a36Sopenharmony_ci return -ENOMEM; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci ipctl->ngroups = 0; 83762306a36Sopenharmony_ci for_each_child_of_node(np, child) 83862306a36Sopenharmony_ci maxgroups += rzn1_pinctrl_count_function_groups(child); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci ipctl->groups = devm_kmalloc_array(&pdev->dev, 84162306a36Sopenharmony_ci maxgroups, 84262306a36Sopenharmony_ci sizeof(*ipctl->groups), 84362306a36Sopenharmony_ci GFP_KERNEL); 84462306a36Sopenharmony_ci if (!ipctl->groups) 84562306a36Sopenharmony_ci return -ENOMEM; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci for_each_child_of_node(np, child) { 84862306a36Sopenharmony_ci ret = rzn1_pinctrl_parse_functions(child, ipctl, i++); 84962306a36Sopenharmony_ci if (ret < 0) { 85062306a36Sopenharmony_ci of_node_put(child); 85162306a36Sopenharmony_ci return ret; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci return 0; 85662306a36Sopenharmony_ci} 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_cistatic int rzn1_pinctrl_probe(struct platform_device *pdev) 85962306a36Sopenharmony_ci{ 86062306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl; 86162306a36Sopenharmony_ci struct resource *res; 86262306a36Sopenharmony_ci int ret; 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* Create state holders etc for this driver */ 86562306a36Sopenharmony_ci ipctl = devm_kzalloc(&pdev->dev, sizeof(*ipctl), GFP_KERNEL); 86662306a36Sopenharmony_ci if (!ipctl) 86762306a36Sopenharmony_ci return -ENOMEM; 86862306a36Sopenharmony_ci 86962306a36Sopenharmony_ci ipctl->mdio_func[0] = -1; 87062306a36Sopenharmony_ci ipctl->mdio_func[1] = -1; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci ipctl->lev1 = devm_platform_get_and_ioremap_resource(pdev, 0, &res); 87362306a36Sopenharmony_ci if (IS_ERR(ipctl->lev1)) 87462306a36Sopenharmony_ci return PTR_ERR(ipctl->lev1); 87562306a36Sopenharmony_ci ipctl->lev1_protect_phys = (u32)res->start + 0x400; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci ipctl->lev2 = devm_platform_get_and_ioremap_resource(pdev, 1, &res); 87862306a36Sopenharmony_ci if (IS_ERR(ipctl->lev2)) 87962306a36Sopenharmony_ci return PTR_ERR(ipctl->lev2); 88062306a36Sopenharmony_ci ipctl->lev2_protect_phys = (u32)res->start + 0x400; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci ipctl->clk = devm_clk_get(&pdev->dev, NULL); 88362306a36Sopenharmony_ci if (IS_ERR(ipctl->clk)) 88462306a36Sopenharmony_ci return PTR_ERR(ipctl->clk); 88562306a36Sopenharmony_ci ret = clk_prepare_enable(ipctl->clk); 88662306a36Sopenharmony_ci if (ret) 88762306a36Sopenharmony_ci return ret; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci ipctl->dev = &pdev->dev; 89062306a36Sopenharmony_ci rzn1_pinctrl_desc.name = dev_name(&pdev->dev); 89162306a36Sopenharmony_ci rzn1_pinctrl_desc.pins = rzn1_pins; 89262306a36Sopenharmony_ci rzn1_pinctrl_desc.npins = ARRAY_SIZE(rzn1_pins); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci ret = rzn1_pinctrl_probe_dt(pdev, ipctl); 89562306a36Sopenharmony_ci if (ret) { 89662306a36Sopenharmony_ci dev_err(&pdev->dev, "fail to probe dt properties\n"); 89762306a36Sopenharmony_ci goto err_clk; 89862306a36Sopenharmony_ci } 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci platform_set_drvdata(pdev, ipctl); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci ret = devm_pinctrl_register_and_init(&pdev->dev, &rzn1_pinctrl_desc, 90362306a36Sopenharmony_ci ipctl, &ipctl->pctl); 90462306a36Sopenharmony_ci if (ret) { 90562306a36Sopenharmony_ci dev_err(&pdev->dev, "could not register rzn1 pinctrl driver\n"); 90662306a36Sopenharmony_ci goto err_clk; 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci ret = pinctrl_enable(ipctl->pctl); 91062306a36Sopenharmony_ci if (ret) 91162306a36Sopenharmony_ci goto err_clk; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci dev_info(&pdev->dev, "probed\n"); 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci return 0; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_cierr_clk: 91862306a36Sopenharmony_ci clk_disable_unprepare(ipctl->clk); 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci return ret; 92162306a36Sopenharmony_ci} 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_cistatic int rzn1_pinctrl_remove(struct platform_device *pdev) 92462306a36Sopenharmony_ci{ 92562306a36Sopenharmony_ci struct rzn1_pinctrl *ipctl = platform_get_drvdata(pdev); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci clk_disable_unprepare(ipctl->clk); 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci return 0; 93062306a36Sopenharmony_ci} 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_cistatic const struct of_device_id rzn1_pinctrl_match[] = { 93362306a36Sopenharmony_ci { .compatible = "renesas,rzn1-pinctrl", }, 93462306a36Sopenharmony_ci { /* sentinel */ } 93562306a36Sopenharmony_ci}; 93662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, rzn1_pinctrl_match); 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_cistatic struct platform_driver rzn1_pinctrl_driver = { 93962306a36Sopenharmony_ci .probe = rzn1_pinctrl_probe, 94062306a36Sopenharmony_ci .remove = rzn1_pinctrl_remove, 94162306a36Sopenharmony_ci .driver = { 94262306a36Sopenharmony_ci .name = "rzn1-pinctrl", 94362306a36Sopenharmony_ci .of_match_table = rzn1_pinctrl_match, 94462306a36Sopenharmony_ci }, 94562306a36Sopenharmony_ci}; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_cistatic int __init _pinctrl_drv_register(void) 94862306a36Sopenharmony_ci{ 94962306a36Sopenharmony_ci return platform_driver_register(&rzn1_pinctrl_driver); 95062306a36Sopenharmony_ci} 95162306a36Sopenharmony_cisubsys_initcall(_pinctrl_drv_register); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ciMODULE_AUTHOR("Phil Edworthy <phil.edworthy@renesas.com>"); 95462306a36Sopenharmony_ciMODULE_DESCRIPTION("Renesas RZ/N1 pinctrl driver"); 955