1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * SPEAr platform SPI chipselect abstraction over gpiolib 4 * 5 * Copyright (C) 2012 ST Microelectronics 6 * Shiraz Hashim <shiraz.linux.kernel@gmail.com> 7 */ 8 9 #include <linux/err.h> 10 #include <linux/gpio/driver.h> 11 #include <linux/io.h> 12 #include <linux/init.h> 13 #include <linux/of.h> 14 #include <linux/platform_device.h> 15 #include <linux/types.h> 16 17 /* maximum chipselects */ 18 #define NUM_OF_GPIO 4 19 20 /* 21 * Provision is available on some SPEAr SoCs to control ARM PL022 spi cs 22 * through system registers. This register lies outside spi (pl022) 23 * address space into system registers. 24 * 25 * It provides control for spi chip select lines so that any chipselect 26 * (out of 4 possible chipselects in pl022) can be made low to select 27 * the particular slave. 28 */ 29 30 /** 31 * struct spear_spics - represents spi chip select control 32 * @base: base address 33 * @perip_cfg: configuration register 34 * @sw_enable_bit: bit to enable s/w control over chipselects 35 * @cs_value_bit: bit to program high or low chipselect 36 * @cs_enable_mask: mask to select bits required to select chipselect 37 * @cs_enable_shift: bit pos of cs_enable_mask 38 * @use_count: use count of a spi controller cs lines 39 * @last_off: stores last offset caller of set_value() 40 * @chip: gpio_chip abstraction 41 */ 42 struct spear_spics { 43 void __iomem *base; 44 u32 perip_cfg; 45 u32 sw_enable_bit; 46 u32 cs_value_bit; 47 u32 cs_enable_mask; 48 u32 cs_enable_shift; 49 unsigned long use_count; 50 int last_off; 51 struct gpio_chip chip; 52 }; 53 54 static int spics_set_value(struct gpio_chip *chip, unsigned int offset, 55 int value) 56 { 57 struct spear_spics *spics = gpiochip_get_data(chip); 58 u32 tmp; 59 60 /* select chip select from register */ 61 tmp = readl_relaxed(spics->base + spics->perip_cfg); 62 if (spics->last_off != offset) { 63 spics->last_off = offset; 64 tmp &= ~(spics->cs_enable_mask << spics->cs_enable_shift); 65 tmp |= offset << spics->cs_enable_shift; 66 } 67 68 /* toggle chip select line */ 69 tmp &= ~(0x1 << spics->cs_value_bit); 70 tmp |= value << spics->cs_value_bit; 71 writel_relaxed(tmp, spics->base + spics->perip_cfg); 72 73 return 0; 74 } 75 76 static int spics_direction_output(struct gpio_chip *chip, unsigned offset, 77 int value) 78 { 79 return spics_set_value(chip, offset, value); 80 } 81 82 static int spics_request(struct gpio_chip *chip, unsigned offset) 83 { 84 struct spear_spics *spics = gpiochip_get_data(chip); 85 u32 tmp; 86 87 if (!spics->use_count++) { 88 tmp = readl_relaxed(spics->base + spics->perip_cfg); 89 tmp |= 0x1 << spics->sw_enable_bit; 90 tmp |= 0x1 << spics->cs_value_bit; 91 writel_relaxed(tmp, spics->base + spics->perip_cfg); 92 } 93 94 return 0; 95 } 96 97 static void spics_free(struct gpio_chip *chip, unsigned offset) 98 { 99 struct spear_spics *spics = gpiochip_get_data(chip); 100 u32 tmp; 101 102 if (!--spics->use_count) { 103 tmp = readl_relaxed(spics->base + spics->perip_cfg); 104 tmp &= ~(0x1 << spics->sw_enable_bit); 105 writel_relaxed(tmp, spics->base + spics->perip_cfg); 106 } 107 } 108 109 static int spics_gpio_probe(struct platform_device *pdev) 110 { 111 struct device_node *np = pdev->dev.of_node; 112 struct spear_spics *spics; 113 114 spics = devm_kzalloc(&pdev->dev, sizeof(*spics), GFP_KERNEL); 115 if (!spics) 116 return -ENOMEM; 117 118 spics->base = devm_platform_ioremap_resource(pdev, 0); 119 if (IS_ERR(spics->base)) 120 return PTR_ERR(spics->base); 121 122 if (of_property_read_u32(np, "st-spics,peripcfg-reg", 123 &spics->perip_cfg)) 124 goto err_dt_data; 125 if (of_property_read_u32(np, "st-spics,sw-enable-bit", 126 &spics->sw_enable_bit)) 127 goto err_dt_data; 128 if (of_property_read_u32(np, "st-spics,cs-value-bit", 129 &spics->cs_value_bit)) 130 goto err_dt_data; 131 if (of_property_read_u32(np, "st-spics,cs-enable-mask", 132 &spics->cs_enable_mask)) 133 goto err_dt_data; 134 if (of_property_read_u32(np, "st-spics,cs-enable-shift", 135 &spics->cs_enable_shift)) 136 goto err_dt_data; 137 138 spics->chip.ngpio = NUM_OF_GPIO; 139 spics->chip.base = -1; 140 spics->chip.request = spics_request; 141 spics->chip.free = spics_free; 142 spics->chip.direction_output = spics_direction_output; 143 spics->chip.set = spics_set_value; 144 spics->chip.label = dev_name(&pdev->dev); 145 spics->chip.parent = &pdev->dev; 146 spics->chip.owner = THIS_MODULE; 147 spics->last_off = -1; 148 149 return devm_gpiochip_add_data(&pdev->dev, &spics->chip, spics); 150 151 err_dt_data: 152 dev_err(&pdev->dev, "DT probe failed\n"); 153 return -EINVAL; 154 } 155 156 static const struct of_device_id spics_gpio_of_match[] = { 157 { .compatible = "st,spear-spics-gpio" }, 158 {} 159 }; 160 161 static struct platform_driver spics_gpio_driver = { 162 .probe = spics_gpio_probe, 163 .driver = { 164 .name = "spear-spics-gpio", 165 .of_match_table = spics_gpio_of_match, 166 }, 167 }; 168 169 static int __init spics_gpio_init(void) 170 { 171 return platform_driver_register(&spics_gpio_driver); 172 } 173 subsys_initcall(spics_gpio_init); 174