1 /* 2 * Copyright (C) 2018 Alexander Graf <agraf@suse.de> 3 * 4 * Based on drivers/pinctrl/mvebu/pinctrl-mvebu.c and 5 * drivers/gpio/bcm2835_gpio.c 6 * 7 * This driver gets instantiated by the GPIO driver, because both devices 8 * share the same device node. 9 * 10 * SPDX-License-Identifier: GPL-2.0 11 * https://spdx.org/licenses 12 */ 13 14 #include <common.h> 15 #include <config.h> 16 #include <errno.h> 17 #include <dm.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 26 struct bcm283x_pinctrl_priv { 27 u32 *base_reg; 28 }; 29 30 #define MAX_PINS_PER_BANK 16 31 32 static 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 47 static 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 */ 63 int bcm283x_pinctrl_set_state(struct udevice *dev, struct udevice *config) 64 { 65 u32 pin_arr[MAX_PINS_PER_BANK]; 66 u32 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 92 static 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 101 static const struct udevice_id bcm2835_pinctrl_id[] = { 102 {.compatible = "brcm,bcm2835-gpio"}, 103 {} 104 }; 105 106 int bcm283x_pinctl_probe(struct udevice *dev) 107 { 108 struct bcm283x_pinctrl_priv *priv; 109 int ret; 110 struct udevice *pdev; 111 112 priv = dev_get_priv(dev); 113 if (!priv) { 114 debug("%s: Failed to get private\n", __func__); 115 return -EINVAL; 116 } 117 118 priv->base_reg = dev_read_addr_ptr(dev); 119 if (priv->base_reg == (void *)FDT_ADDR_T_NONE) { 120 debug("%s: Failed to get base address\n", __func__); 121 return -EINVAL; 122 } 123 124 /* Create GPIO device as well */ 125 ret = device_bind(dev, lists_driver_lookup_name("gpio_bcm2835"), 126 "gpio_bcm2835", NULL, dev_of_offset(dev), &pdev); 127 if (ret) { 128 /* 129 * While we really want the pinctrl driver to work to make 130 * devices go where they should go, the GPIO controller is 131 * not quite as crucial as it's only rarely used, so don't 132 * fail here. 133 */ 134 printf("Failed to bind GPIO driver\n"); 135 } 136 137 return 0; 138 } 139 140 static struct pinctrl_ops bcm283x_pinctrl_ops = { 141 .set_state = bcm283x_pinctrl_set_state, 142 .get_gpio_mux = bcm283x_pinctrl_get_gpio_mux, 143 }; 144 145 U_BOOT_DRIVER(pinctrl_bcm283x) = { 146 .name = "bcm283x_pinctrl", 147 .id = UCLASS_PINCTRL, 148 .of_match = of_match_ptr(bcm2835_pinctrl_id), 149 .priv_auto_alloc_size = sizeof(struct bcm283x_pinctrl_priv), 150 .ops = &bcm283x_pinctrl_ops, 151 .probe = bcm283x_pinctl_probe, 152 .flags = DM_FLAG_PRE_RELOC, 153 }; 154