Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 //
0003 // Synopsys CREG (Control REGisters) GPIO driver
0004 //
0005 // Copyright (C) 2018 Synopsys
0006 // Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
0007 
0008 #include <linux/gpio/driver.h>
0009 #include <linux/io.h>
0010 #include <linux/of.h>
0011 #include <linux/of_platform.h>
0012 
0013 #define MAX_GPIO    32
0014 
0015 struct creg_layout {
0016     u8 ngpio;
0017     u8 shift[MAX_GPIO];
0018     u8 on[MAX_GPIO];
0019     u8 off[MAX_GPIO];
0020     u8 bit_per_gpio[MAX_GPIO];
0021 };
0022 
0023 struct creg_gpio {
0024     struct gpio_chip gc;
0025     void __iomem *regs;
0026     spinlock_t lock;
0027     const struct creg_layout *layout;
0028 };
0029 
0030 static void creg_gpio_set(struct gpio_chip *gc, unsigned int offset, int val)
0031 {
0032     struct creg_gpio *hcg = gpiochip_get_data(gc);
0033     const struct creg_layout *layout = hcg->layout;
0034     u32 reg, reg_shift, value;
0035     unsigned long flags;
0036     int i;
0037 
0038     value = val ? hcg->layout->on[offset] : hcg->layout->off[offset];
0039 
0040     reg_shift = layout->shift[offset];
0041     for (i = 0; i < offset; i++)
0042         reg_shift += layout->bit_per_gpio[i] + layout->shift[i];
0043 
0044     spin_lock_irqsave(&hcg->lock, flags);
0045     reg = readl(hcg->regs);
0046     reg &= ~(GENMASK(layout->bit_per_gpio[i] - 1, 0) << reg_shift);
0047     reg |=  (value << reg_shift);
0048     writel(reg, hcg->regs);
0049     spin_unlock_irqrestore(&hcg->lock, flags);
0050 }
0051 
0052 static int creg_gpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
0053 {
0054     creg_gpio_set(gc, offset, val);
0055 
0056     return 0;
0057 }
0058 
0059 static int creg_gpio_validate_pg(struct device *dev, struct creg_gpio *hcg,
0060                  int i)
0061 {
0062     const struct creg_layout *layout = hcg->layout;
0063 
0064     if (layout->bit_per_gpio[i] < 1 || layout->bit_per_gpio[i] > 8)
0065         return -EINVAL;
0066 
0067     /* Check that on value fits its placeholder */
0068     if (GENMASK(31, layout->bit_per_gpio[i]) & layout->on[i])
0069         return -EINVAL;
0070 
0071     /* Check that off value fits its placeholder */
0072     if (GENMASK(31, layout->bit_per_gpio[i]) & layout->off[i])
0073         return -EINVAL;
0074 
0075     if (layout->on[i] == layout->off[i])
0076         return -EINVAL;
0077 
0078     return 0;
0079 }
0080 
0081 static int creg_gpio_validate(struct device *dev, struct creg_gpio *hcg,
0082                   u32 ngpios)
0083 {
0084     u32 reg_len = 0;
0085     int i;
0086 
0087     if (hcg->layout->ngpio < 1 || hcg->layout->ngpio > MAX_GPIO)
0088         return -EINVAL;
0089 
0090     if (ngpios < 1 || ngpios > hcg->layout->ngpio) {
0091         dev_err(dev, "ngpios must be in [1:%u]\n", hcg->layout->ngpio);
0092         return -EINVAL;
0093     }
0094 
0095     for (i = 0; i < hcg->layout->ngpio; i++) {
0096         if (creg_gpio_validate_pg(dev, hcg, i))
0097             return -EINVAL;
0098 
0099         reg_len += hcg->layout->shift[i] + hcg->layout->bit_per_gpio[i];
0100     }
0101 
0102     /* Check that we fit in 32 bit register */
0103     if (reg_len > 32)
0104         return -EINVAL;
0105 
0106     return 0;
0107 }
0108 
0109 static const struct creg_layout hsdk_cs_ctl = {
0110     .ngpio      = 10,
0111     .shift      = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
0112     .off        = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 },
0113     .on     = { 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 },
0114     .bit_per_gpio   = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 }
0115 };
0116 
0117 static const struct creg_layout axs10x_flsh_cs_ctl = {
0118     .ngpio      = 1,
0119     .shift      = { 0 },
0120     .off        = { 1 },
0121     .on     = { 3 },
0122     .bit_per_gpio   = { 2 }
0123 };
0124 
0125 static const struct of_device_id creg_gpio_ids[] = {
0126     {
0127         .compatible = "snps,creg-gpio-axs10x",
0128         .data = &axs10x_flsh_cs_ctl
0129     }, {
0130         .compatible = "snps,creg-gpio-hsdk",
0131         .data = &hsdk_cs_ctl
0132     }, { /* sentinel */ }
0133 };
0134 
0135 static int creg_gpio_probe(struct platform_device *pdev)
0136 {
0137     const struct of_device_id *match;
0138     struct device *dev = &pdev->dev;
0139     struct creg_gpio *hcg;
0140     u32 ngpios;
0141     int ret;
0142 
0143     hcg = devm_kzalloc(dev, sizeof(struct creg_gpio), GFP_KERNEL);
0144     if (!hcg)
0145         return -ENOMEM;
0146 
0147     hcg->regs = devm_platform_ioremap_resource(pdev, 0);
0148     if (IS_ERR(hcg->regs))
0149         return PTR_ERR(hcg->regs);
0150 
0151     match = of_match_node(creg_gpio_ids, pdev->dev.of_node);
0152     hcg->layout = match->data;
0153     if (!hcg->layout)
0154         return -EINVAL;
0155 
0156     ret = of_property_read_u32(dev->of_node, "ngpios", &ngpios);
0157     if (ret)
0158         return ret;
0159 
0160     ret = creg_gpio_validate(dev, hcg, ngpios);
0161     if (ret)
0162         return ret;
0163 
0164     spin_lock_init(&hcg->lock);
0165 
0166     hcg->gc.parent = dev;
0167     hcg->gc.label = dev_name(dev);
0168     hcg->gc.base = -1;
0169     hcg->gc.ngpio = ngpios;
0170     hcg->gc.set = creg_gpio_set;
0171     hcg->gc.direction_output = creg_gpio_dir_out;
0172 
0173     ret = devm_gpiochip_add_data(dev, &hcg->gc, hcg);
0174     if (ret)
0175         return ret;
0176 
0177     dev_info(dev, "GPIO controller with %d gpios probed\n", ngpios);
0178 
0179     return 0;
0180 }
0181 
0182 static struct platform_driver creg_gpio_snps_driver = {
0183     .driver = {
0184         .name = "snps-creg-gpio",
0185         .of_match_table = creg_gpio_ids,
0186     },
0187     .probe  = creg_gpio_probe,
0188 };
0189 builtin_platform_driver(creg_gpio_snps_driver);