1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2018 Alexander Graf <agraf@suse.de> 4 * 5 * Based on drivers/pinctrl/mvebu/pinctrl-mvebu.c and 6 * drivers/gpio/bcm2835_gpio.c 7 * 8 * This driver gets instantiated by the GPIO driver, because both devices 9 * share the same device node. 10 * https://spdx.org/licenses 11 */ 12 13#include <common.h> 14#include <config.h> 15#include <errno.h> 16#include <dm.h> 17#include <log.h> 18#include <dm/pinctrl.h> 19#include <dm/root.h> 20#include <dm/device-internal.h> 21#include <dm/lists.h> 22#include <asm/system.h> 23#include <asm/io.h> 24#include <asm/gpio.h> 25 26struct bcm283x_pinctrl_priv { 27 u32 *base_reg; 28}; 29 30#define MAX_PINS_PER_BANK 16 31 32static void bcm2835_gpio_set_func_id(struct udevice *dev, unsigned int gpio, 33 int func) 34{ 35 struct bcm283x_pinctrl_priv *priv = dev_get_priv(dev); 36 int reg_offset; 37 int field_offset; 38 39 reg_offset = BCM2835_GPIO_FSEL_BANK(gpio); 40 field_offset = BCM2835_GPIO_FSEL_SHIFT(gpio); 41 42 clrsetbits_le32(&priv->base_reg[reg_offset], 43 BCM2835_GPIO_FSEL_MASK << field_offset, 44 (func & BCM2835_GPIO_FSEL_MASK) << field_offset); 45} 46 47static int bcm2835_gpio_get_func_id(struct udevice *dev, unsigned int gpio) 48{ 49 struct bcm283x_pinctrl_priv *priv = dev_get_priv(dev); 50 u32 val; 51 52 val = readl(&priv->base_reg[BCM2835_GPIO_FSEL_BANK(gpio)]); 53 54 return (val >> BCM2835_GPIO_FSEL_SHIFT(gpio) & BCM2835_GPIO_FSEL_MASK); 55} 56 57/* 58 * bcm283x_pinctrl_set_state: configure pin functions. 59 * @dev: the pinctrl device to be configured. 60 * @config: the state to be configured. 61 * @return: 0 in success 62 */ 63int bcm283x_pinctrl_set_state(struct udevice *dev, struct udevice *config) 64{ 65 u32 pin_arr[MAX_PINS_PER_BANK]; 66 int function; 67 int i, len, pin_count = 0; 68 69 if (!dev_read_prop(config, "brcm,pins", &len) || !len || 70 len & 0x3 || dev_read_u32_array(config, "brcm,pins", pin_arr, 71 len / sizeof(u32))) { 72 debug("Failed reading pins array for pinconfig %s (%d)\n", 73 config->name, len); 74 return -EINVAL; 75 } 76 77 pin_count = len / sizeof(u32); 78 79 function = dev_read_u32_default(config, "brcm,function", -1); 80 if (function < 0) { 81 debug("Failed reading function for pinconfig %s (%d)\n", 82 config->name, function); 83 return -EINVAL; 84 } 85 86 for (i = 0; i < pin_count; i++) 87 bcm2835_gpio_set_func_id(dev, pin_arr[i], function); 88 89 return 0; 90} 91 92static int bcm283x_pinctrl_get_gpio_mux(struct udevice *dev, int banknum, 93 int index) 94{ 95 if (banknum != 0) 96 return -EINVAL; 97 98 return bcm2835_gpio_get_func_id(dev, index); 99} 100 101static const struct udevice_id bcm2835_pinctrl_id[] = { 102 {.compatible = "brcm,bcm2835-gpio"}, 103 {.compatible = "brcm,bcm2711-gpio"}, 104 {} 105}; 106 107int bcm283x_pinctl_of_to_plat(struct udevice *dev) 108{ 109 struct bcm283x_pinctrl_priv *priv; 110 111 priv = dev_get_priv(dev); 112 113 priv->base_reg = dev_read_addr_ptr(dev); 114 if (!priv->base_reg) { 115 debug("%s: Failed to get base address\n", __func__); 116 return -EINVAL; 117 } 118 119 return 0; 120} 121 122int bcm283x_pinctl_probe(struct udevice *dev) 123{ 124 int ret; 125 struct udevice *pdev; 126 127 /* Create GPIO device as well */ 128 ret = device_bind(dev, lists_driver_lookup_name("gpio_bcm2835"), 129 "gpio_bcm2835", NULL, dev_ofnode(dev), &pdev); 130 if (ret) { 131 /* 132 * While we really want the pinctrl driver to work to make 133 * devices go where they should go, the GPIO controller is 134 * not quite as crucial as it's only rarely used, so don't 135 * fail here. 136 */ 137 printf("Failed to bind GPIO driver\n"); 138 } 139 140 return 0; 141} 142 143static struct pinctrl_ops bcm283x_pinctrl_ops = { 144 .set_state = bcm283x_pinctrl_set_state, 145 .get_gpio_mux = bcm283x_pinctrl_get_gpio_mux, 146}; 147 148U_BOOT_DRIVER(pinctrl_bcm283x) = { 149 .name = "bcm283x_pinctrl", 150 .id = UCLASS_PINCTRL, 151 .of_match = of_match_ptr(bcm2835_pinctrl_id), 152 .of_to_plat = bcm283x_pinctl_of_to_plat, 153 .priv_auto = sizeof(struct bcm283x_pinctrl_priv), 154 .ops = &bcm283x_pinctrl_ops, 155 .probe = bcm283x_pinctl_probe, 156#if IS_ENABLED(CONFIG_OF_BOARD) 157 .flags = DM_FLAG_PRE_RELOC, 158#endif 159}; 160