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