| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * OpenCores tiny SPI master driver |
|---|
| 3 | 4 | * |
|---|
| 4 | | - * http://opencores.org/project,tiny_spi |
|---|
| 5 | + * https://opencores.org/project,tiny_spi |
|---|
| 5 | 6 | * |
|---|
| 6 | 7 | * Copyright (C) 2011 Thomas Chou <thomas@wytron.com.tw> |
|---|
| 7 | 8 | * |
|---|
| .. | .. |
|---|
| 9 | 10 | * Copyright (c) 2006 Ben Dooks |
|---|
| 10 | 11 | * Copyright (c) 2006 Simtec Electronics |
|---|
| 11 | 12 | * Ben Dooks <ben@simtec.co.uk> |
|---|
| 12 | | - * |
|---|
| 13 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 14 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 15 | | - * published by the Free Software Foundation. |
|---|
| 16 | 13 | */ |
|---|
| 17 | 14 | |
|---|
| 18 | 15 | #include <linux/interrupt.h> |
|---|
| .. | .. |
|---|
| 23 | 20 | #include <linux/spi/spi_bitbang.h> |
|---|
| 24 | 21 | #include <linux/spi/spi_oc_tiny.h> |
|---|
| 25 | 22 | #include <linux/io.h> |
|---|
| 26 | | -#include <linux/gpio.h> |
|---|
| 27 | 23 | #include <linux/of.h> |
|---|
| 28 | 24 | |
|---|
| 29 | 25 | #define DRV_NAME "spi_oc_tiny" |
|---|
| .. | .. |
|---|
| 53 | 49 | unsigned int txc, rxc; |
|---|
| 54 | 50 | const u8 *txp; |
|---|
| 55 | 51 | u8 *rxp; |
|---|
| 56 | | - int gpio_cs_count; |
|---|
| 57 | | - int *gpio_cs; |
|---|
| 58 | 52 | }; |
|---|
| 59 | 53 | |
|---|
| 60 | 54 | static inline struct tiny_spi *tiny_spi_to_hw(struct spi_device *sdev) |
|---|
| .. | .. |
|---|
| 67 | 61 | struct tiny_spi *hw = tiny_spi_to_hw(spi); |
|---|
| 68 | 62 | |
|---|
| 69 | 63 | return min(DIV_ROUND_UP(hw->freq, hz * 2), (1U << hw->baudwidth)) - 1; |
|---|
| 70 | | -} |
|---|
| 71 | | - |
|---|
| 72 | | -static void tiny_spi_chipselect(struct spi_device *spi, int is_active) |
|---|
| 73 | | -{ |
|---|
| 74 | | - struct tiny_spi *hw = tiny_spi_to_hw(spi); |
|---|
| 75 | | - |
|---|
| 76 | | - if (hw->gpio_cs_count > 0) { |
|---|
| 77 | | - gpio_set_value(hw->gpio_cs[spi->chip_select], |
|---|
| 78 | | - (spi->mode & SPI_CS_HIGH) ? is_active : !is_active); |
|---|
| 79 | | - } |
|---|
| 80 | 64 | } |
|---|
| 81 | 65 | |
|---|
| 82 | 66 | static int tiny_spi_setup_transfer(struct spi_device *spi, |
|---|
| .. | .. |
|---|
| 206 | 190 | { |
|---|
| 207 | 191 | struct tiny_spi *hw = platform_get_drvdata(pdev); |
|---|
| 208 | 192 | struct device_node *np = pdev->dev.of_node; |
|---|
| 209 | | - unsigned int i; |
|---|
| 210 | 193 | u32 val; |
|---|
| 211 | 194 | |
|---|
| 212 | 195 | if (!np) |
|---|
| 213 | 196 | return 0; |
|---|
| 214 | | - hw->gpio_cs_count = of_gpio_count(np); |
|---|
| 215 | | - if (hw->gpio_cs_count > 0) { |
|---|
| 216 | | - hw->gpio_cs = devm_kcalloc(&pdev->dev, |
|---|
| 217 | | - hw->gpio_cs_count, sizeof(unsigned int), |
|---|
| 218 | | - GFP_KERNEL); |
|---|
| 219 | | - if (!hw->gpio_cs) |
|---|
| 220 | | - return -ENOMEM; |
|---|
| 221 | | - } |
|---|
| 222 | | - for (i = 0; i < hw->gpio_cs_count; i++) { |
|---|
| 223 | | - hw->gpio_cs[i] = of_get_gpio_flags(np, i, NULL); |
|---|
| 224 | | - if (hw->gpio_cs[i] < 0) |
|---|
| 225 | | - return -ENODEV; |
|---|
| 226 | | - } |
|---|
| 227 | 197 | hw->bitbang.master->dev.of_node = pdev->dev.of_node; |
|---|
| 228 | 198 | if (!of_property_read_u32(np, "clock-frequency", &val)) |
|---|
| 229 | 199 | hw->freq = val; |
|---|
| .. | .. |
|---|
| 243 | 213 | struct tiny_spi_platform_data *platp = dev_get_platdata(&pdev->dev); |
|---|
| 244 | 214 | struct tiny_spi *hw; |
|---|
| 245 | 215 | struct spi_master *master; |
|---|
| 246 | | - struct resource *res; |
|---|
| 247 | | - unsigned int i; |
|---|
| 248 | 216 | int err = -ENODEV; |
|---|
| 249 | 217 | |
|---|
| 250 | 218 | master = spi_alloc_master(&pdev->dev, sizeof(struct tiny_spi)); |
|---|
| .. | .. |
|---|
| 253 | 221 | |
|---|
| 254 | 222 | /* setup the master state. */ |
|---|
| 255 | 223 | master->bus_num = pdev->id; |
|---|
| 256 | | - master->num_chipselect = 255; |
|---|
| 257 | 224 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; |
|---|
| 258 | 225 | master->setup = tiny_spi_setup; |
|---|
| 226 | + master->use_gpio_descriptors = true; |
|---|
| 259 | 227 | |
|---|
| 260 | 228 | hw = spi_master_get_devdata(master); |
|---|
| 261 | 229 | platform_set_drvdata(pdev, hw); |
|---|
| .. | .. |
|---|
| 263 | 231 | /* setup the state for the bitbang driver */ |
|---|
| 264 | 232 | hw->bitbang.master = master; |
|---|
| 265 | 233 | hw->bitbang.setup_transfer = tiny_spi_setup_transfer; |
|---|
| 266 | | - hw->bitbang.chipselect = tiny_spi_chipselect; |
|---|
| 267 | 234 | hw->bitbang.txrx_bufs = tiny_spi_txrx_bufs; |
|---|
| 268 | 235 | |
|---|
| 269 | 236 | /* find and map our resources */ |
|---|
| 270 | | - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
|---|
| 271 | | - hw->base = devm_ioremap_resource(&pdev->dev, res); |
|---|
| 237 | + hw->base = devm_platform_ioremap_resource(pdev, 0); |
|---|
| 272 | 238 | if (IS_ERR(hw->base)) { |
|---|
| 273 | 239 | err = PTR_ERR(hw->base); |
|---|
| 274 | 240 | goto exit; |
|---|
| .. | .. |
|---|
| 284 | 250 | } |
|---|
| 285 | 251 | /* find platform data */ |
|---|
| 286 | 252 | if (platp) { |
|---|
| 287 | | - hw->gpio_cs_count = platp->gpio_cs_count; |
|---|
| 288 | | - hw->gpio_cs = platp->gpio_cs; |
|---|
| 289 | | - if (platp->gpio_cs_count && !platp->gpio_cs) { |
|---|
| 290 | | - err = -EBUSY; |
|---|
| 291 | | - goto exit; |
|---|
| 292 | | - } |
|---|
| 293 | 253 | hw->freq = platp->freq; |
|---|
| 294 | 254 | hw->baudwidth = platp->baudwidth; |
|---|
| 295 | 255 | } else { |
|---|
| .. | .. |
|---|
| 297 | 257 | if (err) |
|---|
| 298 | 258 | goto exit; |
|---|
| 299 | 259 | } |
|---|
| 300 | | - for (i = 0; i < hw->gpio_cs_count; i++) { |
|---|
| 301 | | - err = gpio_request(hw->gpio_cs[i], dev_name(&pdev->dev)); |
|---|
| 302 | | - if (err) |
|---|
| 303 | | - goto exit_gpio; |
|---|
| 304 | | - gpio_direction_output(hw->gpio_cs[i], 1); |
|---|
| 305 | | - } |
|---|
| 306 | | - hw->bitbang.master->num_chipselect = max(1, hw->gpio_cs_count); |
|---|
| 307 | 260 | |
|---|
| 308 | 261 | /* register our spi controller */ |
|---|
| 309 | 262 | err = spi_bitbang_start(&hw->bitbang); |
|---|
| .. | .. |
|---|
| 313 | 266 | |
|---|
| 314 | 267 | return 0; |
|---|
| 315 | 268 | |
|---|
| 316 | | -exit_gpio: |
|---|
| 317 | | - while (i-- > 0) |
|---|
| 318 | | - gpio_free(hw->gpio_cs[i]); |
|---|
| 319 | 269 | exit: |
|---|
| 320 | 270 | spi_master_put(master); |
|---|
| 321 | 271 | return err; |
|---|
| .. | .. |
|---|
| 325 | 275 | { |
|---|
| 326 | 276 | struct tiny_spi *hw = platform_get_drvdata(pdev); |
|---|
| 327 | 277 | struct spi_master *master = hw->bitbang.master; |
|---|
| 328 | | - unsigned int i; |
|---|
| 329 | 278 | |
|---|
| 330 | 279 | spi_bitbang_stop(&hw->bitbang); |
|---|
| 331 | | - for (i = 0; i < hw->gpio_cs_count; i++) |
|---|
| 332 | | - gpio_free(hw->gpio_cs[i]); |
|---|
| 333 | 280 | spi_master_put(master); |
|---|
| 334 | 281 | return 0; |
|---|
| 335 | 282 | } |
|---|