root/drivers/siox/siox-bus-gpio.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. siox_gpio_pushpull
  2. siox_gpio_probe
  3. siox_gpio_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Copyright (C) 2015-2017 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
   4  */
   5 
   6 #include <linux/gpio/consumer.h>
   7 #include <linux/module.h>
   8 #include <linux/mod_devicetable.h>
   9 #include <linux/platform_device.h>
  10 
  11 #include <linux/delay.h>
  12 
  13 #include "siox.h"
  14 
  15 #define DRIVER_NAME "siox-gpio"
  16 
  17 struct siox_gpio_ddata {
  18         struct gpio_desc *din;
  19         struct gpio_desc *dout;
  20         struct gpio_desc *dclk;
  21         struct gpio_desc *dld;
  22 };
  23 
  24 static unsigned int siox_clkhigh_ns = 1000;
  25 static unsigned int siox_loadhigh_ns;
  26 static unsigned int siox_bytegap_ns;
  27 
  28 static int siox_gpio_pushpull(struct siox_master *smaster,
  29                               size_t setbuf_len, const u8 setbuf[],
  30                               size_t getbuf_len, u8 getbuf[])
  31 {
  32         struct siox_gpio_ddata *ddata = siox_master_get_devdata(smaster);
  33         size_t i;
  34         size_t cycles = max(setbuf_len, getbuf_len);
  35 
  36         /* reset data and clock */
  37         gpiod_set_value_cansleep(ddata->dout, 0);
  38         gpiod_set_value_cansleep(ddata->dclk, 0);
  39 
  40         gpiod_set_value_cansleep(ddata->dld, 1);
  41         ndelay(siox_loadhigh_ns);
  42         gpiod_set_value_cansleep(ddata->dld, 0);
  43 
  44         for (i = 0; i < cycles; ++i) {
  45                 u8 set = 0, get = 0;
  46                 size_t j;
  47 
  48                 if (i >= cycles - setbuf_len)
  49                         set = setbuf[i - (cycles - setbuf_len)];
  50 
  51                 for (j = 0; j < 8; ++j) {
  52                         get <<= 1;
  53                         if (gpiod_get_value_cansleep(ddata->din))
  54                                 get |= 1;
  55 
  56                         /* DOUT is logically inverted */
  57                         gpiod_set_value_cansleep(ddata->dout, !(set & 0x80));
  58                         set <<= 1;
  59 
  60                         gpiod_set_value_cansleep(ddata->dclk, 1);
  61                         ndelay(siox_clkhigh_ns);
  62                         gpiod_set_value_cansleep(ddata->dclk, 0);
  63                 }
  64 
  65                 if (i < getbuf_len)
  66                         getbuf[i] = get;
  67 
  68                 ndelay(siox_bytegap_ns);
  69         }
  70 
  71         gpiod_set_value_cansleep(ddata->dld, 1);
  72         ndelay(siox_loadhigh_ns);
  73         gpiod_set_value_cansleep(ddata->dld, 0);
  74 
  75         /*
  76          * Resetting dout isn't necessary protocol wise, but it makes the
  77          * signals more pretty because the dout level is deterministic between
  78          * cycles. Note that this only affects dout between the master and the
  79          * first siox device. dout for the later devices depend on the output of
  80          * the previous siox device.
  81          */
  82         gpiod_set_value_cansleep(ddata->dout, 0);
  83 
  84         return 0;
  85 }
  86 
  87 static int siox_gpio_probe(struct platform_device *pdev)
  88 {
  89         struct device *dev = &pdev->dev;
  90         struct siox_gpio_ddata *ddata;
  91         int ret;
  92         struct siox_master *smaster;
  93 
  94         smaster = siox_master_alloc(&pdev->dev, sizeof(*ddata));
  95         if (!smaster) {
  96                 dev_err(dev, "failed to allocate siox master\n");
  97                 return -ENOMEM;
  98         }
  99 
 100         platform_set_drvdata(pdev, smaster);
 101         ddata = siox_master_get_devdata(smaster);
 102 
 103         ddata->din = devm_gpiod_get(dev, "din", GPIOD_IN);
 104         if (IS_ERR(ddata->din)) {
 105                 ret = PTR_ERR(ddata->din);
 106                 dev_err(dev, "Failed to get %s GPIO: %d\n", "din", ret);
 107                 goto err;
 108         }
 109 
 110         ddata->dout = devm_gpiod_get(dev, "dout", GPIOD_OUT_LOW);
 111         if (IS_ERR(ddata->dout)) {
 112                 ret = PTR_ERR(ddata->dout);
 113                 dev_err(dev, "Failed to get %s GPIO: %d\n", "dout", ret);
 114                 goto err;
 115         }
 116 
 117         ddata->dclk = devm_gpiod_get(dev, "dclk", GPIOD_OUT_LOW);
 118         if (IS_ERR(ddata->dclk)) {
 119                 ret = PTR_ERR(ddata->dclk);
 120                 dev_err(dev, "Failed to get %s GPIO: %d\n", "dclk", ret);
 121                 goto err;
 122         }
 123 
 124         ddata->dld = devm_gpiod_get(dev, "dld", GPIOD_OUT_LOW);
 125         if (IS_ERR(ddata->dld)) {
 126                 ret = PTR_ERR(ddata->dld);
 127                 dev_err(dev, "Failed to get %s GPIO: %d\n", "dld", ret);
 128                 goto err;
 129         }
 130 
 131         smaster->pushpull = siox_gpio_pushpull;
 132         /* XXX: determine automatically like spi does */
 133         smaster->busno = 0;
 134 
 135         ret = siox_master_register(smaster);
 136         if (ret) {
 137                 dev_err(dev, "Failed to register siox master: %d\n", ret);
 138 err:
 139                 siox_master_put(smaster);
 140         }
 141 
 142         return ret;
 143 }
 144 
 145 static int siox_gpio_remove(struct platform_device *pdev)
 146 {
 147         struct siox_master *master = platform_get_drvdata(pdev);
 148 
 149         siox_master_unregister(master);
 150 
 151         return 0;
 152 }
 153 
 154 static const struct of_device_id siox_gpio_dt_ids[] = {
 155         { .compatible = "eckelmann,siox-gpio", },
 156         { /* sentinel */ }
 157 };
 158 MODULE_DEVICE_TABLE(of, siox_gpio_dt_ids);
 159 
 160 static struct platform_driver siox_gpio_driver = {
 161         .probe = siox_gpio_probe,
 162         .remove = siox_gpio_remove,
 163 
 164         .driver = {
 165                 .name = DRIVER_NAME,
 166                 .of_match_table = siox_gpio_dt_ids,
 167         },
 168 };
 169 module_platform_driver(siox_gpio_driver);
 170 
 171 MODULE_AUTHOR("Uwe Kleine-Koenig <u.kleine-koenig@pengutronix.de>");
 172 MODULE_LICENSE("GPL v2");
 173 MODULE_ALIAS("platform:" DRIVER_NAME);

/* [<][>][^][v][top][bottom][index][help] */