Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * NBUS driver for TS-4600 based boards
0004  *
0005  * Copyright (c) 2016 - Savoir-faire Linux
0006  * Author: Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>
0007  *
0008  * This driver implements a GPIOs bit-banged bus, called the NBUS by Technologic
0009  * Systems. It is used to communicate with the peripherals in the FPGA on the
0010  * TS-4600 SoM.
0011  */
0012 
0013 #include <linux/bitops.h>
0014 #include <linux/gpio/consumer.h>
0015 #include <linux/kernel.h>
0016 #include <linux/module.h>
0017 #include <linux/mutex.h>
0018 #include <linux/of_platform.h>
0019 #include <linux/platform_device.h>
0020 #include <linux/pwm.h>
0021 #include <linux/ts-nbus.h>
0022 
0023 #define TS_NBUS_DIRECTION_IN  0
0024 #define TS_NBUS_DIRECTION_OUT 1
0025 #define TS_NBUS_WRITE_ADR 0
0026 #define TS_NBUS_WRITE_VAL 1
0027 
0028 struct ts_nbus {
0029     struct pwm_device *pwm;
0030     struct gpio_descs *data;
0031     struct gpio_desc *csn;
0032     struct gpio_desc *txrx;
0033     struct gpio_desc *strobe;
0034     struct gpio_desc *ale;
0035     struct gpio_desc *rdy;
0036     struct mutex lock;
0037 };
0038 
0039 /*
0040  * request all gpios required by the bus.
0041  */
0042 static int ts_nbus_init_pdata(struct platform_device *pdev, struct ts_nbus
0043         *ts_nbus)
0044 {
0045     ts_nbus->data = devm_gpiod_get_array(&pdev->dev, "ts,data",
0046             GPIOD_OUT_HIGH);
0047     if (IS_ERR(ts_nbus->data)) {
0048         dev_err(&pdev->dev, "failed to retrieve ts,data-gpio from dts\n");
0049         return PTR_ERR(ts_nbus->data);
0050     }
0051 
0052     ts_nbus->csn = devm_gpiod_get(&pdev->dev, "ts,csn", GPIOD_OUT_HIGH);
0053     if (IS_ERR(ts_nbus->csn)) {
0054         dev_err(&pdev->dev, "failed to retrieve ts,csn-gpio from dts\n");
0055         return PTR_ERR(ts_nbus->csn);
0056     }
0057 
0058     ts_nbus->txrx = devm_gpiod_get(&pdev->dev, "ts,txrx", GPIOD_OUT_HIGH);
0059     if (IS_ERR(ts_nbus->txrx)) {
0060         dev_err(&pdev->dev, "failed to retrieve ts,txrx-gpio from dts\n");
0061         return PTR_ERR(ts_nbus->txrx);
0062     }
0063 
0064     ts_nbus->strobe = devm_gpiod_get(&pdev->dev, "ts,strobe", GPIOD_OUT_HIGH);
0065     if (IS_ERR(ts_nbus->strobe)) {
0066         dev_err(&pdev->dev, "failed to retrieve ts,strobe-gpio from dts\n");
0067         return PTR_ERR(ts_nbus->strobe);
0068     }
0069 
0070     ts_nbus->ale = devm_gpiod_get(&pdev->dev, "ts,ale", GPIOD_OUT_HIGH);
0071     if (IS_ERR(ts_nbus->ale)) {
0072         dev_err(&pdev->dev, "failed to retrieve ts,ale-gpio from dts\n");
0073         return PTR_ERR(ts_nbus->ale);
0074     }
0075 
0076     ts_nbus->rdy = devm_gpiod_get(&pdev->dev, "ts,rdy", GPIOD_IN);
0077     if (IS_ERR(ts_nbus->rdy)) {
0078         dev_err(&pdev->dev, "failed to retrieve ts,rdy-gpio from dts\n");
0079         return PTR_ERR(ts_nbus->rdy);
0080     }
0081 
0082     return 0;
0083 }
0084 
0085 /*
0086  * the data gpios are used for reading and writing values, their directions
0087  * should be adjusted accordingly.
0088  */
0089 static void ts_nbus_set_direction(struct ts_nbus *ts_nbus, int direction)
0090 {
0091     int i;
0092 
0093     for (i = 0; i < 8; i++) {
0094         if (direction == TS_NBUS_DIRECTION_IN)
0095             gpiod_direction_input(ts_nbus->data->desc[i]);
0096         else
0097             /* when used as output the default state of the data
0098              * lines are set to high */
0099             gpiod_direction_output(ts_nbus->data->desc[i], 1);
0100     }
0101 }
0102 
0103 /*
0104  * reset the bus in its initial state.
0105  * The data, csn, strobe and ale lines must be zero'ed to let the FPGA knows a
0106  * new transaction can be process.
0107  */
0108 static void ts_nbus_reset_bus(struct ts_nbus *ts_nbus)
0109 {
0110     DECLARE_BITMAP(values, 8);
0111 
0112     values[0] = 0;
0113 
0114     gpiod_set_array_value_cansleep(8, ts_nbus->data->desc,
0115                        ts_nbus->data->info, values);
0116     gpiod_set_value_cansleep(ts_nbus->csn, 0);
0117     gpiod_set_value_cansleep(ts_nbus->strobe, 0);
0118     gpiod_set_value_cansleep(ts_nbus->ale, 0);
0119 }
0120 
0121 /*
0122  * let the FPGA knows it can process.
0123  */
0124 static void ts_nbus_start_transaction(struct ts_nbus *ts_nbus)
0125 {
0126     gpiod_set_value_cansleep(ts_nbus->strobe, 1);
0127 }
0128 
0129 /*
0130  * read a byte value from the data gpios.
0131  * return 0 on success or negative errno on failure.
0132  */
0133 static int ts_nbus_read_byte(struct ts_nbus *ts_nbus, u8 *val)
0134 {
0135     struct gpio_descs *gpios = ts_nbus->data;
0136     int ret, i;
0137 
0138     *val = 0;
0139     for (i = 0; i < 8; i++) {
0140         ret = gpiod_get_value_cansleep(gpios->desc[i]);
0141         if (ret < 0)
0142             return ret;
0143         if (ret)
0144             *val |= BIT(i);
0145     }
0146 
0147     return 0;
0148 }
0149 
0150 /*
0151  * set the data gpios accordingly to the byte value.
0152  */
0153 static void ts_nbus_write_byte(struct ts_nbus *ts_nbus, u8 byte)
0154 {
0155     struct gpio_descs *gpios = ts_nbus->data;
0156     DECLARE_BITMAP(values, 8);
0157 
0158     values[0] = byte;
0159 
0160     gpiod_set_array_value_cansleep(8, gpios->desc, gpios->info, values);
0161 }
0162 
0163 /*
0164  * reading the bus consists of resetting the bus, then notifying the FPGA to
0165  * send the data in the data gpios and return the read value.
0166  * return 0 on success or negative errno on failure.
0167  */
0168 static int ts_nbus_read_bus(struct ts_nbus *ts_nbus, u8 *val)
0169 {
0170     ts_nbus_reset_bus(ts_nbus);
0171     ts_nbus_start_transaction(ts_nbus);
0172 
0173     return ts_nbus_read_byte(ts_nbus, val);
0174 }
0175 
0176 /*
0177  * writing to the bus consists of resetting the bus, then define the type of
0178  * command (address/value), write the data and notify the FPGA to retrieve the
0179  * value in the data gpios.
0180  */
0181 static void ts_nbus_write_bus(struct ts_nbus *ts_nbus, int cmd, u8 val)
0182 {
0183     ts_nbus_reset_bus(ts_nbus);
0184 
0185     if (cmd == TS_NBUS_WRITE_ADR)
0186         gpiod_set_value_cansleep(ts_nbus->ale, 1);
0187 
0188     ts_nbus_write_byte(ts_nbus, val);
0189     ts_nbus_start_transaction(ts_nbus);
0190 }
0191 
0192 /*
0193  * read the value in the FPGA register at the given address.
0194  * return 0 on success or negative errno on failure.
0195  */
0196 int ts_nbus_read(struct ts_nbus *ts_nbus, u8 adr, u16 *val)
0197 {
0198     int ret, i;
0199     u8 byte;
0200 
0201     /* bus access must be atomic */
0202     mutex_lock(&ts_nbus->lock);
0203 
0204     /* set the bus in read mode */
0205     gpiod_set_value_cansleep(ts_nbus->txrx, 0);
0206 
0207     /* write address */
0208     ts_nbus_write_bus(ts_nbus, TS_NBUS_WRITE_ADR, adr);
0209 
0210     /* set the data gpios direction as input before reading */
0211     ts_nbus_set_direction(ts_nbus, TS_NBUS_DIRECTION_IN);
0212 
0213     /* reading value MSB first */
0214     do {
0215         *val = 0;
0216         byte = 0;
0217         for (i = 1; i >= 0; i--) {
0218             /* read a byte from the bus, leave on error */
0219             ret = ts_nbus_read_bus(ts_nbus, &byte);
0220             if (ret < 0)
0221                 goto err;
0222 
0223             /* append the byte read to the final value */
0224             *val |= byte << (i * 8);
0225         }
0226         gpiod_set_value_cansleep(ts_nbus->csn, 1);
0227         ret = gpiod_get_value_cansleep(ts_nbus->rdy);
0228     } while (ret);
0229 
0230 err:
0231     /* restore the data gpios direction as output after reading */
0232     ts_nbus_set_direction(ts_nbus, TS_NBUS_DIRECTION_OUT);
0233 
0234     mutex_unlock(&ts_nbus->lock);
0235 
0236     return ret;
0237 }
0238 EXPORT_SYMBOL_GPL(ts_nbus_read);
0239 
0240 /*
0241  * write the desired value in the FPGA register at the given address.
0242  */
0243 int ts_nbus_write(struct ts_nbus *ts_nbus, u8 adr, u16 val)
0244 {
0245     int i;
0246 
0247     /* bus access must be atomic */
0248     mutex_lock(&ts_nbus->lock);
0249 
0250     /* set the bus in write mode */
0251     gpiod_set_value_cansleep(ts_nbus->txrx, 1);
0252 
0253     /* write address */
0254     ts_nbus_write_bus(ts_nbus, TS_NBUS_WRITE_ADR, adr);
0255 
0256     /* writing value MSB first */
0257     for (i = 1; i >= 0; i--)
0258         ts_nbus_write_bus(ts_nbus, TS_NBUS_WRITE_VAL, (u8)(val >> (i * 8)));
0259 
0260     /* wait for completion */
0261     gpiod_set_value_cansleep(ts_nbus->csn, 1);
0262     while (gpiod_get_value_cansleep(ts_nbus->rdy) != 0) {
0263         gpiod_set_value_cansleep(ts_nbus->csn, 0);
0264         gpiod_set_value_cansleep(ts_nbus->csn, 1);
0265     }
0266 
0267     mutex_unlock(&ts_nbus->lock);
0268 
0269     return 0;
0270 }
0271 EXPORT_SYMBOL_GPL(ts_nbus_write);
0272 
0273 static int ts_nbus_probe(struct platform_device *pdev)
0274 {
0275     struct pwm_device *pwm;
0276     struct pwm_args pargs;
0277     struct device *dev = &pdev->dev;
0278     struct ts_nbus *ts_nbus;
0279     int ret;
0280 
0281     ts_nbus = devm_kzalloc(dev, sizeof(*ts_nbus), GFP_KERNEL);
0282     if (!ts_nbus)
0283         return -ENOMEM;
0284 
0285     mutex_init(&ts_nbus->lock);
0286 
0287     ret = ts_nbus_init_pdata(pdev, ts_nbus);
0288     if (ret < 0)
0289         return ret;
0290 
0291     pwm = devm_pwm_get(dev, NULL);
0292     if (IS_ERR(pwm)) {
0293         ret = PTR_ERR(pwm);
0294         if (ret != -EPROBE_DEFER)
0295             dev_err(dev, "unable to request PWM\n");
0296         return ret;
0297     }
0298 
0299     pwm_get_args(pwm, &pargs);
0300     if (!pargs.period) {
0301         dev_err(&pdev->dev, "invalid PWM period\n");
0302         return -EINVAL;
0303     }
0304 
0305     /*
0306      * FIXME: pwm_apply_args() should be removed when switching to
0307      * the atomic PWM API.
0308      */
0309     pwm_apply_args(pwm);
0310     ret = pwm_config(pwm, pargs.period, pargs.period);
0311     if (ret < 0)
0312         return ret;
0313 
0314     /*
0315      * we can now start the FPGA and populate the peripherals.
0316      */
0317     pwm_enable(pwm);
0318     ts_nbus->pwm = pwm;
0319 
0320     /*
0321      * let the child nodes retrieve this instance of the ts-nbus.
0322      */
0323     dev_set_drvdata(dev, ts_nbus);
0324 
0325     ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
0326     if (ret < 0)
0327         return ret;
0328 
0329     dev_info(dev, "initialized\n");
0330 
0331     return 0;
0332 }
0333 
0334 static int ts_nbus_remove(struct platform_device *pdev)
0335 {
0336     struct ts_nbus *ts_nbus = dev_get_drvdata(&pdev->dev);
0337 
0338     /* shutdown the FPGA */
0339     mutex_lock(&ts_nbus->lock);
0340     pwm_disable(ts_nbus->pwm);
0341     mutex_unlock(&ts_nbus->lock);
0342 
0343     return 0;
0344 }
0345 
0346 static const struct of_device_id ts_nbus_of_match[] = {
0347     { .compatible = "technologic,ts-nbus", },
0348     { },
0349 };
0350 MODULE_DEVICE_TABLE(of, ts_nbus_of_match);
0351 
0352 static struct platform_driver ts_nbus_driver = {
0353     .probe      = ts_nbus_probe,
0354     .remove     = ts_nbus_remove,
0355     .driver     = {
0356         .name   = "ts_nbus",
0357         .of_match_table = ts_nbus_of_match,
0358     },
0359 };
0360 
0361 module_platform_driver(ts_nbus_driver);
0362 
0363 MODULE_ALIAS("platform:ts_nbus");
0364 MODULE_AUTHOR("Sebastien Bourdelin <sebastien.bourdelin@savoirfairelinux.com>");
0365 MODULE_DESCRIPTION("Technologic Systems NBUS");
0366 MODULE_LICENSE("GPL v2");