13194c3cdSEugeniy Paltsev /* 23194c3cdSEugeniy Paltsev * Synopsys HSDK SDP Generic PLL clock driver 33194c3cdSEugeniy Paltsev * 43194c3cdSEugeniy Paltsev * Copyright (C) 2017 Synopsys 53194c3cdSEugeniy Paltsev * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com> 63194c3cdSEugeniy Paltsev * 73194c3cdSEugeniy Paltsev * This file is licensed under the terms of the GNU General Public 83194c3cdSEugeniy Paltsev * License version 2. This program is licensed "as is" without any 93194c3cdSEugeniy Paltsev * warranty of any kind, whether express or implied. 103194c3cdSEugeniy Paltsev */ 113194c3cdSEugeniy Paltsev 123194c3cdSEugeniy Paltsev #include <asm-generic/gpio.h> 133194c3cdSEugeniy Paltsev #include <asm/io.h> 143194c3cdSEugeniy Paltsev #include <common.h> 153194c3cdSEugeniy Paltsev #include <dm.h> 163194c3cdSEugeniy Paltsev #include <errno.h> 173194c3cdSEugeniy Paltsev #include <linux/printk.h> 183194c3cdSEugeniy Paltsev 19*fe3eb7a8SEugeniy Paltsev #define DRV_NAME "gpio_creg" 203194c3cdSEugeniy Paltsev 213194c3cdSEugeniy Paltsev struct hsdk_creg_gpio { 22*fe3eb7a8SEugeniy Paltsev u32 *regs; 23*fe3eb7a8SEugeniy Paltsev u8 shift; 24*fe3eb7a8SEugeniy Paltsev u8 activate; 25*fe3eb7a8SEugeniy Paltsev u8 deactivate; 26*fe3eb7a8SEugeniy Paltsev u8 bit_per_gpio; 273194c3cdSEugeniy Paltsev }; 283194c3cdSEugeniy Paltsev 293194c3cdSEugeniy Paltsev static int hsdk_creg_gpio_set_value(struct udevice *dev, unsigned oft, int val) 303194c3cdSEugeniy Paltsev { 313194c3cdSEugeniy Paltsev struct hsdk_creg_gpio *hcg = dev_get_priv(dev); 32*fe3eb7a8SEugeniy Paltsev u8 reg_shift = oft * hcg->bit_per_gpio + hcg->shift; 33*fe3eb7a8SEugeniy Paltsev u32 reg = readl(hcg->regs); 343194c3cdSEugeniy Paltsev 35*fe3eb7a8SEugeniy Paltsev reg &= ~(GENMASK(hcg->bit_per_gpio - 1, 0) << reg_shift); 36*fe3eb7a8SEugeniy Paltsev reg |= ((val ? hcg->deactivate : hcg->activate) << reg_shift); 373194c3cdSEugeniy Paltsev 383194c3cdSEugeniy Paltsev writel(reg, hcg->regs); 393194c3cdSEugeniy Paltsev 403194c3cdSEugeniy Paltsev return 0; 413194c3cdSEugeniy Paltsev } 423194c3cdSEugeniy Paltsev 433194c3cdSEugeniy Paltsev static int hsdk_creg_gpio_direction_output(struct udevice *dev, unsigned oft, 443194c3cdSEugeniy Paltsev int val) 453194c3cdSEugeniy Paltsev { 463194c3cdSEugeniy Paltsev hsdk_creg_gpio_set_value(dev, oft, val); 473194c3cdSEugeniy Paltsev 483194c3cdSEugeniy Paltsev return 0; 493194c3cdSEugeniy Paltsev } 503194c3cdSEugeniy Paltsev 513194c3cdSEugeniy Paltsev static int hsdk_creg_gpio_direction_input(struct udevice *dev, unsigned oft) 523194c3cdSEugeniy Paltsev { 53*fe3eb7a8SEugeniy Paltsev struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 54*fe3eb7a8SEugeniy Paltsev 55*fe3eb7a8SEugeniy Paltsev pr_err("%s can't be used as input!\n", uc_priv->bank_name); 563194c3cdSEugeniy Paltsev 573194c3cdSEugeniy Paltsev return -ENOTSUPP; 583194c3cdSEugeniy Paltsev } 593194c3cdSEugeniy Paltsev 603194c3cdSEugeniy Paltsev static int hsdk_creg_gpio_get_value(struct udevice *dev, unsigned int oft) 613194c3cdSEugeniy Paltsev { 623194c3cdSEugeniy Paltsev struct hsdk_creg_gpio *hcg = dev_get_priv(dev); 63*fe3eb7a8SEugeniy Paltsev u32 val = readl(hcg->regs); 643194c3cdSEugeniy Paltsev 65*fe3eb7a8SEugeniy Paltsev val >>= oft * hcg->bit_per_gpio + hcg->shift; 66*fe3eb7a8SEugeniy Paltsev val &= GENMASK(hcg->bit_per_gpio - 1, 0); 67*fe3eb7a8SEugeniy Paltsev return (val == hcg->deactivate) ? 1 : 0; 683194c3cdSEugeniy Paltsev } 693194c3cdSEugeniy Paltsev 703194c3cdSEugeniy Paltsev static const struct dm_gpio_ops hsdk_creg_gpio_ops = { 713194c3cdSEugeniy Paltsev .direction_output = hsdk_creg_gpio_direction_output, 723194c3cdSEugeniy Paltsev .direction_input = hsdk_creg_gpio_direction_input, 733194c3cdSEugeniy Paltsev .set_value = hsdk_creg_gpio_set_value, 743194c3cdSEugeniy Paltsev .get_value = hsdk_creg_gpio_get_value, 753194c3cdSEugeniy Paltsev }; 763194c3cdSEugeniy Paltsev 773194c3cdSEugeniy Paltsev static int hsdk_creg_gpio_probe(struct udevice *dev) 783194c3cdSEugeniy Paltsev { 793194c3cdSEugeniy Paltsev struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 803194c3cdSEugeniy Paltsev struct hsdk_creg_gpio *hcg = dev_get_priv(dev); 81*fe3eb7a8SEugeniy Paltsev u32 shift, bit_per_gpio, activate, deactivate, gpio_count; 82*fe3eb7a8SEugeniy Paltsev const u8 *defaults; 833194c3cdSEugeniy Paltsev 84*fe3eb7a8SEugeniy Paltsev hcg->regs = (u32 *)devfdt_get_addr_ptr(dev); 85*fe3eb7a8SEugeniy Paltsev gpio_count = dev_read_u32_default(dev, "gpio-count", 1); 86*fe3eb7a8SEugeniy Paltsev shift = dev_read_u32_default(dev, "gpio-first-shift", 0); 87*fe3eb7a8SEugeniy Paltsev bit_per_gpio = dev_read_u32_default(dev, "gpio-bit-per-line", 1); 88*fe3eb7a8SEugeniy Paltsev activate = dev_read_u32_default(dev, "gpio-activate-val", 1); 89*fe3eb7a8SEugeniy Paltsev deactivate = dev_read_u32_default(dev, "gpio-deactivate-val", 0); 90*fe3eb7a8SEugeniy Paltsev defaults = dev_read_u8_array_ptr(dev, "gpio-default-val", gpio_count); 913194c3cdSEugeniy Paltsev 923194c3cdSEugeniy Paltsev uc_priv->bank_name = dev_read_string(dev, "gpio-bank-name"); 933194c3cdSEugeniy Paltsev if (!uc_priv->bank_name) 943194c3cdSEugeniy Paltsev uc_priv->bank_name = dev_read_name(dev); 953194c3cdSEugeniy Paltsev 96*fe3eb7a8SEugeniy Paltsev if (!bit_per_gpio) { 97*fe3eb7a8SEugeniy Paltsev pr_err("%s: 'gpio-bit-per-line' can't be 0\n", 98*fe3eb7a8SEugeniy Paltsev uc_priv->bank_name); 99*fe3eb7a8SEugeniy Paltsev 100*fe3eb7a8SEugeniy Paltsev return -EINVAL; 101*fe3eb7a8SEugeniy Paltsev } 102*fe3eb7a8SEugeniy Paltsev 103*fe3eb7a8SEugeniy Paltsev if (!gpio_count) { 104*fe3eb7a8SEugeniy Paltsev pr_err("%s: 'gpio-count' can't be 0\n", 105*fe3eb7a8SEugeniy Paltsev uc_priv->bank_name); 106*fe3eb7a8SEugeniy Paltsev 107*fe3eb7a8SEugeniy Paltsev return -EINVAL; 108*fe3eb7a8SEugeniy Paltsev } 109*fe3eb7a8SEugeniy Paltsev 110*fe3eb7a8SEugeniy Paltsev if ((gpio_count * bit_per_gpio + shift) > 32) { 111*fe3eb7a8SEugeniy Paltsev pr_err("%s: u32 io register overflow: try to use %u bits\n", 112*fe3eb7a8SEugeniy Paltsev uc_priv->bank_name, gpio_count * bit_per_gpio + shift); 113*fe3eb7a8SEugeniy Paltsev 114*fe3eb7a8SEugeniy Paltsev return -EINVAL; 115*fe3eb7a8SEugeniy Paltsev } 116*fe3eb7a8SEugeniy Paltsev 117*fe3eb7a8SEugeniy Paltsev if (GENMASK(31, bit_per_gpio) & activate) { 118*fe3eb7a8SEugeniy Paltsev pr_err("%s: 'gpio-activate-val' can't be more than %lu\n", 119*fe3eb7a8SEugeniy Paltsev uc_priv->bank_name, GENMASK(bit_per_gpio - 1, 0)); 120*fe3eb7a8SEugeniy Paltsev 121*fe3eb7a8SEugeniy Paltsev return -EINVAL; 122*fe3eb7a8SEugeniy Paltsev } 123*fe3eb7a8SEugeniy Paltsev 124*fe3eb7a8SEugeniy Paltsev if (GENMASK(31, bit_per_gpio) & deactivate) { 125*fe3eb7a8SEugeniy Paltsev pr_err("%s: 'gpio-deactivate-val' can't be more than %lu\n", 126*fe3eb7a8SEugeniy Paltsev uc_priv->bank_name, GENMASK(bit_per_gpio - 1, 0)); 127*fe3eb7a8SEugeniy Paltsev 128*fe3eb7a8SEugeniy Paltsev return -EINVAL; 129*fe3eb7a8SEugeniy Paltsev } 130*fe3eb7a8SEugeniy Paltsev 131*fe3eb7a8SEugeniy Paltsev if (activate == deactivate) { 132*fe3eb7a8SEugeniy Paltsev pr_err("%s: 'gpio-deactivate-val' and 'gpio-activate-val' can't be equal\n", 133*fe3eb7a8SEugeniy Paltsev uc_priv->bank_name); 134*fe3eb7a8SEugeniy Paltsev 135*fe3eb7a8SEugeniy Paltsev return -EINVAL; 136*fe3eb7a8SEugeniy Paltsev } 137*fe3eb7a8SEugeniy Paltsev 138*fe3eb7a8SEugeniy Paltsev hcg->shift = (u8)shift; 139*fe3eb7a8SEugeniy Paltsev hcg->bit_per_gpio = (u8)bit_per_gpio; 140*fe3eb7a8SEugeniy Paltsev hcg->activate = (u8)activate; 141*fe3eb7a8SEugeniy Paltsev hcg->deactivate = (u8)deactivate; 142*fe3eb7a8SEugeniy Paltsev uc_priv->gpio_count = gpio_count; 143*fe3eb7a8SEugeniy Paltsev 144*fe3eb7a8SEugeniy Paltsev /* Setup default GPIO value if we have "gpio-default-val" array */ 145*fe3eb7a8SEugeniy Paltsev if (defaults) 146*fe3eb7a8SEugeniy Paltsev for (u8 i = 0; i < gpio_count; i++) 147*fe3eb7a8SEugeniy Paltsev hsdk_creg_gpio_set_value(dev, i, defaults[i]); 148*fe3eb7a8SEugeniy Paltsev 1493194c3cdSEugeniy Paltsev pr_debug("%s GPIO [0x%p] controller with %d gpios probed\n", 1503194c3cdSEugeniy Paltsev uc_priv->bank_name, hcg->regs, uc_priv->gpio_count); 1513194c3cdSEugeniy Paltsev 1523194c3cdSEugeniy Paltsev return 0; 1533194c3cdSEugeniy Paltsev } 1543194c3cdSEugeniy Paltsev 1553194c3cdSEugeniy Paltsev static const struct udevice_id hsdk_creg_gpio_ids[] = { 156*fe3eb7a8SEugeniy Paltsev { .compatible = "snps,creg-gpio" }, 1573194c3cdSEugeniy Paltsev { } 1583194c3cdSEugeniy Paltsev }; 1593194c3cdSEugeniy Paltsev 1603194c3cdSEugeniy Paltsev U_BOOT_DRIVER(gpio_hsdk_creg) = { 161*fe3eb7a8SEugeniy Paltsev .name = DRV_NAME, 1623194c3cdSEugeniy Paltsev .id = UCLASS_GPIO, 1633194c3cdSEugeniy Paltsev .ops = &hsdk_creg_gpio_ops, 1643194c3cdSEugeniy Paltsev .probe = hsdk_creg_gpio_probe, 1653194c3cdSEugeniy Paltsev .of_match = hsdk_creg_gpio_ids, 1663194c3cdSEugeniy Paltsev .platdata_auto_alloc_size = sizeof(struct hsdk_creg_gpio), 1673194c3cdSEugeniy Paltsev }; 168