1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * TLMM driver for Qualcomm APQ8016, APQ8096 4 * 5 * (C) Copyright 2018 Ramon Fried <ramon.fried@gmail.com> 6 * 7 */ 8 9#include <common.h> 10#include <dm.h> 11#include <errno.h> 12#include <asm/io.h> 13#include <dm/device_compat.h> 14#include <dm/device-internal.h> 15#include <dm/lists.h> 16#include <asm/gpio.h> 17#include <dm/pinctrl.h> 18#include <linux/bitops.h> 19#include <linux/bug.h> 20#include <mach/gpio.h> 21 22#include "pinctrl-qcom.h" 23 24struct msm_pinctrl_priv { 25 phys_addr_t base; 26 struct msm_pinctrl_data *data; 27}; 28 29#define GPIO_CONFIG_REG(priv, x) \ 30 (qcom_pin_offset((priv)->data->pin_data.pin_offsets, x)) 31 32#define GPIO_IN_OUT_REG(priv, x) \ 33 (GPIO_CONFIG_REG(priv, x) + 0x4) 34 35#define TLMM_GPIO_PULL_MASK GENMASK(1, 0) 36#define TLMM_FUNC_SEL_MASK GENMASK(5, 2) 37#define TLMM_DRV_STRENGTH_MASK GENMASK(8, 6) 38#define TLMM_GPIO_OUTPUT_MASK BIT(1) 39#define TLMM_GPIO_OE_MASK BIT(9) 40 41/* GPIO register shifts. */ 42#define GPIO_OUT_SHIFT 1 43 44static const struct pinconf_param msm_conf_params[] = { 45 { "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 2 }, 46 { "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 }, 47 { "bias-pull-up", PIN_CONFIG_BIAS_PULL_UP, 3 }, 48 { "output-high", PIN_CONFIG_OUTPUT, 1, }, 49 { "output-low", PIN_CONFIG_OUTPUT, 0, }, 50}; 51 52static int msm_get_functions_count(struct udevice *dev) 53{ 54 struct msm_pinctrl_priv *priv = dev_get_priv(dev); 55 56 return priv->data->functions_count; 57} 58 59static int msm_get_pins_count(struct udevice *dev) 60{ 61 struct msm_pinctrl_priv *priv = dev_get_priv(dev); 62 63 return priv->data->pin_data.pin_count; 64} 65 66static const char *msm_get_function_name(struct udevice *dev, 67 unsigned int selector) 68{ 69 struct msm_pinctrl_priv *priv = dev_get_priv(dev); 70 71 return priv->data->get_function_name(dev, selector); 72} 73 74static int msm_pinctrl_probe(struct udevice *dev) 75{ 76 struct msm_pinctrl_priv *priv = dev_get_priv(dev); 77 78 priv->base = dev_read_addr(dev); 79 priv->data = (struct msm_pinctrl_data *)dev_get_driver_data(dev); 80 81 return priv->base == FDT_ADDR_T_NONE ? -EINVAL : 0; 82} 83 84static const char *msm_get_pin_name(struct udevice *dev, unsigned int selector) 85{ 86 struct msm_pinctrl_priv *priv = dev_get_priv(dev); 87 88 return priv->data->get_pin_name(dev, selector); 89} 90 91static int msm_pinmux_set(struct udevice *dev, unsigned int pin_selector, 92 unsigned int func_selector) 93{ 94 struct msm_pinctrl_priv *priv = dev_get_priv(dev); 95 u32 func = priv->data->get_function_mux(pin_selector, func_selector); 96 97 /* Always NOP for special pins, assume they're in the correct state */ 98 if (qcom_is_special_pin(&priv->data->pin_data, pin_selector)) 99 return 0; 100 101 clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector), 102 TLMM_FUNC_SEL_MASK | TLMM_GPIO_OE_MASK, func << 2); 103 return 0; 104} 105 106static int msm_pinconf_set(struct udevice *dev, unsigned int pin_selector, 107 unsigned int param, unsigned int argument) 108{ 109 struct msm_pinctrl_priv *priv = dev_get_priv(dev); 110 111 /* Always NOP for special pins */ 112 if (qcom_is_special_pin(&priv->data->pin_data, pin_selector)) 113 return 0; 114 115 switch (param) { 116 case PIN_CONFIG_DRIVE_STRENGTH: 117 argument = (argument / 2) - 1; 118 clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector), 119 TLMM_DRV_STRENGTH_MASK, argument << 6); 120 break; 121 case PIN_CONFIG_BIAS_DISABLE: 122 clrbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector), 123 TLMM_GPIO_PULL_MASK); 124 break; 125 case PIN_CONFIG_BIAS_PULL_UP: 126 clrsetbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector), 127 TLMM_GPIO_PULL_MASK, argument); 128 break; 129 case PIN_CONFIG_OUTPUT: 130 writel(argument << GPIO_OUT_SHIFT, 131 priv->base + GPIO_IN_OUT_REG(priv, pin_selector)); 132 setbits_le32(priv->base + GPIO_CONFIG_REG(priv, pin_selector), 133 TLMM_GPIO_OE_MASK); 134 break; 135 default: 136 return 0; 137 } 138 139 return 0; 140} 141 142struct pinctrl_ops msm_pinctrl_ops = { 143 .get_pins_count = msm_get_pins_count, 144 .get_pin_name = msm_get_pin_name, 145 .set_state = pinctrl_generic_set_state, 146 .pinmux_set = msm_pinmux_set, 147 .pinconf_num_params = ARRAY_SIZE(msm_conf_params), 148 .pinconf_params = msm_conf_params, 149 .pinconf_set = msm_pinconf_set, 150 .get_functions_count = msm_get_functions_count, 151 .get_function_name = msm_get_function_name, 152}; 153 154int msm_pinctrl_bind(struct udevice *dev) 155{ 156 ofnode node = dev_ofnode(dev); 157 struct msm_pinctrl_data *data = (struct msm_pinctrl_data *)dev_get_driver_data(dev); 158 struct driver *drv; 159 struct udevice *pinctrl_dev; 160 const char *name; 161 int ret; 162 163 if (!data->pin_data.special_pins_start) 164 dev_warn(dev, "Special pins start index not defined!\n"); 165 166 drv = lists_driver_lookup_name("pinctrl_qcom"); 167 if (!drv) 168 return -ENOENT; 169 170 ret = device_bind_with_driver_data(dev_get_parent(dev), drv, ofnode_get_name(node), (ulong)data, 171 dev_ofnode(dev), &pinctrl_dev); 172 if (ret) 173 return ret; 174 175 ofnode_get_property(node, "gpio-controller", &ret); 176 if (ret < 0) 177 return 0; 178 179 /* Get the name of gpio node */ 180 name = ofnode_get_name(node); 181 if (!name) 182 return -EINVAL; 183 184 drv = lists_driver_lookup_name("gpio_msm"); 185 if (!drv) { 186 printf("Can't find gpio_msm driver\n"); 187 return -ENODEV; 188 } 189 190 /* Bind gpio device as a child of the pinctrl device */ 191 ret = device_bind_with_driver_data(pinctrl_dev, drv, 192 name, (ulong)&data->pin_data, node, NULL); 193 if (ret) { 194 device_unbind(pinctrl_dev); 195 return ret; 196 } 197 198 return 0; 199} 200 201U_BOOT_DRIVER(pinctrl_qcom) = { 202 .name = "pinctrl_qcom", 203 .id = UCLASS_PINCTRL, 204 .priv_auto = sizeof(struct msm_pinctrl_priv), 205 .ops = &msm_pinctrl_ops, 206 .probe = msm_pinctrl_probe, 207}; 208