root/drivers/bus/ts-nbus.c

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

DEFINITIONS

This source file includes following definitions.
  1. ts_nbus_init_pdata
  2. ts_nbus_set_direction
  3. ts_nbus_reset_bus
  4. ts_nbus_start_transaction
  5. ts_nbus_read_byte
  6. ts_nbus_write_byte
  7. ts_nbus_read_bus
  8. ts_nbus_write_bus
  9. ts_nbus_read
  10. ts_nbus_write
  11. ts_nbus_probe
  12. ts_nbus_remove

   1 /*
   2  * NBUS driver for TS-4600 based boards
   3  *
   4  * Copyright (c) 2016 - Savoir-faire Linux
   5  * Author: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
   6  *
   7  * This file is licensed under the terms of the GNU General Public
   8  * License version 2. This program is licensed "as is" without any
   9  * warranty of any kind, whether express or implied.
  10  *
  11  * This driver implements a GPIOs bit-banged bus, called the NBUS by Technologic
  12  * Systems. It is used to communicate with the peripherals in the FPGA on the
  13  * TS-4600 SoM.
  14  */
  15 
  16 #include <linux/bitops.h>
  17 #include <linux/gpio/consumer.h>
  18 #include <linux/kernel.h>
  19 #include <linux/module.h>
  20 #include <linux/mutex.h>
  21 #include <linux/of_platform.h>
  22 #include <linux/platform_device.h>
  23 #include <linux/pwm.h>
  24 #include <linux/ts-nbus.h>
  25 
  26 #define TS_NBUS_DIRECTION_IN  0
  27 #define TS_NBUS_DIRECTION_OUT 1
  28 #define TS_NBUS_WRITE_ADR 0
  29 #define TS_NBUS_WRITE_VAL 1
  30 
  31 struct ts_nbus {
  32         struct pwm_device *pwm;
  33         struct gpio_descs *data;
  34         struct gpio_desc *csn;
  35         struct gpio_desc *txrx;
  36         struct gpio_desc *strobe;
  37         struct gpio_desc *ale;
  38         struct gpio_desc *rdy;
  39         struct mutex lock;
  40 };
  41 
  42 /*
  43  * request all gpios required by the bus.
  44  */
  45 static int ts_nbus_init_pdata(struct platform_device *pdev, struct ts_nbus
  46                 *ts_nbus)
  47 {
  48         ts_nbus->data = devm_gpiod_get_array(&pdev->dev, "ts,data",
  49                         GPIOD_OUT_HIGH);
  50         if (IS_ERR(ts_nbus->data)) {
  51                 dev_err(&pdev->dev, "failed to retrieve ts,data-gpio from dts\n");
  52                 return PTR_ERR(ts_nbus->data);
  53         }
  54 
  55         ts_nbus->csn = devm_gpiod_get(&pdev->dev, "ts,csn", GPIOD_OUT_HIGH);
  56         if (IS_ERR(ts_nbus->csn)) {
  57                 dev_err(&pdev->dev, "failed to retrieve ts,csn-gpio from dts\n");
  58                 return PTR_ERR(ts_nbus->csn);
  59         }
  60 
  61         ts_nbus->txrx = devm_gpiod_get(&pdev->dev, "ts,txrx", GPIOD_OUT_HIGH);
  62         if (IS_ERR(ts_nbus->txrx)) {
  63                 dev_err(&pdev->dev, "failed to retrieve ts,txrx-gpio from dts\n");
  64                 return PTR_ERR(ts_nbus->txrx);
  65         }
  66 
  67         ts_nbus->strobe = devm_gpiod_get(&pdev->dev, "ts,strobe", GPIOD_OUT_HIGH);
  68         if (IS_ERR(ts_nbus->strobe)) {
  69                 dev_err(&pdev->dev, "failed to retrieve ts,strobe-gpio from dts\n");
  70                 return PTR_ERR(ts_nbus->strobe);
  71         }
  72 
  73         ts_nbus->ale = devm_gpiod_get(&pdev->dev, "ts,ale", GPIOD_OUT_HIGH);
  74         if (IS_ERR(ts_nbus->ale)) {
  75                 dev_err(&pdev->dev, "failed to retrieve ts,ale-gpio from dts\n");
  76                 return PTR_ERR(ts_nbus->ale);
  77         }
  78 
  79         ts_nbus->rdy = devm_gpiod_get(&pdev->dev, "ts,rdy", GPIOD_IN);
  80         if (IS_ERR(ts_nbus->rdy)) {
  81                 dev_err(&pdev->dev, "failed to retrieve ts,rdy-gpio from dts\n");
  82                 return PTR_ERR(ts_nbus->rdy);
  83         }
  84 
  85         return 0;
  86 }
  87 
  88 /*
  89  * the data gpios are used for reading and writing values, their directions
  90  * should be adjusted accordingly.
  91  */
  92 static void ts_nbus_set_direction(struct ts_nbus *ts_nbus, int direction)
  93 {
  94         int i;
  95 
  96         for (i = 0; i < 8; i++) {
  97                 if (direction == TS_NBUS_DIRECTION_IN)
  98                         gpiod_direction_input(ts_nbus->data->desc[i]);
  99                 else
 100                         /* when used as output the default state of the data
 101                          * lines are set to high */
 102                         gpiod_direction_output(ts_nbus->data->desc[i], 1);
 103         }
 104 }
 105 
 106 /*
 107  * reset the bus in its initial state.
 108  * The data, csn, strobe and ale lines must be zero'ed to let the FPGA knows a
 109  * new transaction can be process.
 110  */
 111 static void ts_nbus_reset_bus(struct ts_nbus *ts_nbus)
 112 {
 113         DECLARE_BITMAP(values, 8);
 114 
 115         values[0] = 0;
 116 
 117         gpiod_set_array_value_cansleep(8, ts_nbus->data->desc,
 118                                        ts_nbus->data->info, values);
 119         gpiod_set_value_cansleep(ts_nbus->csn, 0);
 120         gpiod_set_value_cansleep(ts_nbus->strobe, 0);
 121         gpiod_set_value_cansleep(ts_nbus->ale, 0);
 122 }
 123 
 124 /*
 125  * let the FPGA knows it can process.
 126  */
 127 static void ts_nbus_start_transaction(struct ts_nbus *ts_nbus)
 128 {
 129         gpiod_set_value_cansleep(ts_nbus->strobe, 1);
 130 }
 131 
 132 /*
 133  * read a byte value from the data gpios.
 134  * return 0 on success or negative errno on failure.
 135  */
 136 static int ts_nbus_read_byte(struct ts_nbus *ts_nbus, u8 *val)
 137 {
 138         struct gpio_descs *gpios = ts_nbus->data;
 139         int ret, i;
 140 
 141         *val = 0;
 142         for (i = 0; i < 8; i++) {
 143                 ret = gpiod_get_value_cansleep(gpios->desc[i]);
 144                 if (ret < 0)
 145                         return ret;
 146                 if (ret)
 147                         *val |= BIT(i);
 148         }
 149 
 150         return 0;
 151 }
 152 
 153 /*
 154  * set the data gpios accordingly to the byte value.
 155  */
 156 static void ts_nbus_write_byte(struct ts_nbus *ts_nbus, u8 byte)
 157 {
 158         struct gpio_descs *gpios = ts_nbus->data;
 159         DECLARE_BITMAP(values, 8);
 160 
 161         values[0] = byte;
 162 
 163         gpiod_set_array_value_cansleep(8, gpios->desc, gpios->info, values);
 164 }
 165 
 166 /*
 167  * reading the bus consists of resetting the bus, then notifying the FPGA to
 168  * send the data in the data gpios and return the read value.
 169  * return 0 on success or negative errno on failure.
 170  */
 171 static int ts_nbus_read_bus(struct ts_nbus *ts_nbus, u8 *val)
 172 {
 173         ts_nbus_reset_bus(ts_nbus);
 174         ts_nbus_start_transaction(ts_nbus);
 175 
 176         return ts_nbus_read_byte(ts_nbus, val);
 177 }
 178 
 179 /*
 180  * writing to the bus consists of resetting the bus, then define the type of
 181  * command (address/value), write the data and notify the FPGA to retrieve the
 182  * value in the data gpios.
 183  */
 184 static void ts_nbus_write_bus(struct ts_nbus *ts_nbus, int cmd, u8 val)
 185 {
 186         ts_nbus_reset_bus(ts_nbus);
 187 
 188         if (cmd == TS_NBUS_WRITE_ADR)
 189                 gpiod_set_value_cansleep(ts_nbus->ale, 1);
 190 
 191         ts_nbus_write_byte(ts_nbus, val);
 192         ts_nbus_start_transaction(ts_nbus);
 193 }
 194 
 195 /*
 196  * read the value in the FPGA register at the given address.
 197  * return 0 on success or negative errno on failure.
 198  */
 199 int ts_nbus_read(struct ts_nbus *ts_nbus, u8 adr, u16 *val)
 200 {
 201         int ret, i;
 202         u8 byte;
 203 
 204         /* bus access must be atomic */
 205         mutex_lock(&ts_nbus->lock);
 206 
 207         /* set the bus in read mode */
 208         gpiod_set_value_cansleep(ts_nbus->txrx, 0);
 209 
 210         /* write address */
 211         ts_nbus_write_bus(ts_nbus, TS_NBUS_WRITE_ADR, adr);
 212 
 213         /* set the data gpios direction as input before reading */
 214         ts_nbus_set_direction(ts_nbus, TS_NBUS_DIRECTION_IN);
 215 
 216         /* reading value MSB first */
 217         do {
 218                 *val = 0;
 219                 byte = 0;
 220                 for (i = 1; i >= 0; i--) {
 221                         /* read a byte from the bus, leave on error */
 222                         ret = ts_nbus_read_bus(ts_nbus, &byte);
 223                         if (ret < 0)
 224                                 goto err;
 225 
 226                         /* append the byte read to the final value */
 227                         *val |= byte << (i * 8);
 228                 }
 229                 gpiod_set_value_cansleep(ts_nbus->csn, 1);
 230                 ret = gpiod_get_value_cansleep(ts_nbus->rdy);
 231         } while (ret);
 232 
 233 err:
 234         /* restore the data gpios direction as output after reading */
 235         ts_nbus_set_direction(ts_nbus, TS_NBUS_DIRECTION_OUT);
 236 
 237         mutex_unlock(&ts_nbus->lock);
 238 
 239         return ret;
 240 }
 241 EXPORT_SYMBOL_GPL(ts_nbus_read);
 242 
 243 /*
 244  * write the desired value in the FPGA register at the given address.
 245  */
 246 int ts_nbus_write(struct ts_nbus *ts_nbus, u8 adr, u16 val)
 247 {
 248         int i;
 249 
 250         /* bus access must be atomic */
 251         mutex_lock(&ts_nbus->lock);
 252 
 253         /* set the bus in write mode */
 254         gpiod_set_value_cansleep(ts_nbus->txrx, 1);
 255 
 256         /* write address */
 257         ts_nbus_write_bus(ts_nbus, TS_NBUS_WRITE_ADR, adr);
 258 
 259         /* writing value MSB first */
 260         for (i = 1; i >= 0; i--)
 261                 ts_nbus_write_bus(ts_nbus, TS_NBUS_WRITE_VAL, (u8)(val >> (i * 8)));
 262 
 263         /* wait for completion */
 264         gpiod_set_value_cansleep(ts_nbus->csn, 1);
 265         while (gpiod_get_value_cansleep(ts_nbus->rdy) != 0) {
 266                 gpiod_set_value_cansleep(ts_nbus->csn, 0);
 267                 gpiod_set_value_cansleep(ts_nbus->csn, 1);
 268         }
 269 
 270         mutex_unlock(&ts_nbus->lock);
 271 
 272         return 0;
 273 }
 274 EXPORT_SYMBOL_GPL(ts_nbus_write);
 275 
 276 static int ts_nbus_probe(struct platform_device *pdev)
 277 {
 278         struct pwm_device *pwm;
 279         struct pwm_args pargs;
 280         struct device *dev = &pdev->dev;
 281         struct ts_nbus *ts_nbus;
 282         int ret;
 283 
 284         ts_nbus = devm_kzalloc(dev, sizeof(*ts_nbus), GFP_KERNEL);
 285         if (!ts_nbus)
 286                 return -ENOMEM;
 287 
 288         mutex_init(&ts_nbus->lock);
 289 
 290         ret = ts_nbus_init_pdata(pdev, ts_nbus);
 291         if (ret < 0)
 292                 return ret;
 293 
 294         pwm = devm_pwm_get(dev, NULL);
 295         if (IS_ERR(pwm)) {
 296                 ret = PTR_ERR(pwm);
 297                 if (ret != -EPROBE_DEFER)
 298                         dev_err(dev, "unable to request PWM\n");
 299                 return ret;
 300         }
 301 
 302         pwm_get_args(pwm, &pargs);
 303         if (!pargs.period) {
 304                 dev_err(&pdev->dev, "invalid PWM period\n");
 305                 return -EINVAL;
 306         }
 307 
 308         /*
 309          * FIXME: pwm_apply_args() should be removed when switching to
 310          * the atomic PWM API.
 311          */
 312         pwm_apply_args(pwm);
 313         ret = pwm_config(pwm, pargs.period, pargs.period);
 314         if (ret < 0)
 315                 return ret;
 316 
 317         /*
 318          * we can now start the FPGA and populate the peripherals.
 319          */
 320         pwm_enable(pwm);
 321         ts_nbus->pwm = pwm;
 322 
 323         /*
 324          * let the child nodes retrieve this instance of the ts-nbus.
 325          */
 326         dev_set_drvdata(dev, ts_nbus);
 327 
 328         ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
 329         if (ret < 0)
 330                 return ret;
 331 
 332         dev_info(dev, "initialized\n");
 333 
 334         return 0;
 335 }
 336 
 337 static int ts_nbus_remove(struct platform_device *pdev)
 338 {
 339         struct ts_nbus *ts_nbus = dev_get_drvdata(&pdev->dev);
 340 
 341         /* shutdown the FPGA */
 342         mutex_lock(&ts_nbus->lock);
 343         pwm_disable(ts_nbus->pwm);
 344         mutex_unlock(&ts_nbus->lock);
 345 
 346         return 0;
 347 }
 348 
 349 static const struct of_device_id ts_nbus_of_match[] = {
 350         { .compatible = "technologic,ts-nbus", },
 351         { },
 352 };
 353 MODULE_DEVICE_TABLE(of, ts_nbus_of_match);
 354 
 355 static struct platform_driver ts_nbus_driver = {
 356         .probe          = ts_nbus_probe,
 357         .remove         = ts_nbus_remove,
 358         .driver         = {
 359                 .name   = "ts_nbus",
 360                 .of_match_table = ts_nbus_of_match,
 361         },
 362 };
 363 
 364 module_platform_driver(ts_nbus_driver);
 365 
 366 MODULE_ALIAS("platform:ts_nbus");
 367 MODULE_AUTHOR("Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>");
 368 MODULE_DESCRIPTION("Technologic Systems NBUS");
 369 MODULE_LICENSE("GPL v2");

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