root/drivers/fpga/ts73xx-fpga.c

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

DEFINITIONS

This source file includes following definitions.
  1. ts73xx_fpga_state
  2. ts73xx_fpga_write_init
  3. ts73xx_fpga_write
  4. ts73xx_fpga_write_complete
  5. ts73xx_fpga_probe
  6. ts73xx_fpga_remove

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * Technologic Systems TS-73xx SBC FPGA loader
   4  *
   5  * Copyright (C) 2016 Florian Fainelli <f.fainelli@gmail.com>
   6  *
   7  * FPGA Manager Driver for the on-board Altera Cyclone II FPGA found on
   8  * TS-7300, heavily based on load_fpga.c in their vendor tree.
   9  */
  10 
  11 #include <linux/delay.h>
  12 #include <linux/io.h>
  13 #include <linux/module.h>
  14 #include <linux/platform_device.h>
  15 #include <linux/string.h>
  16 #include <linux/iopoll.h>
  17 #include <linux/fpga/fpga-mgr.h>
  18 
  19 #define TS73XX_FPGA_DATA_REG            0
  20 #define TS73XX_FPGA_CONFIG_REG          1
  21 
  22 #define TS73XX_FPGA_WRITE_DONE          0x1
  23 #define TS73XX_FPGA_WRITE_DONE_TIMEOUT  1000    /* us */
  24 #define TS73XX_FPGA_RESET               0x2
  25 #define TS73XX_FPGA_RESET_LOW_DELAY     30      /* us */
  26 #define TS73XX_FPGA_RESET_HIGH_DELAY    80      /* us */
  27 #define TS73XX_FPGA_LOAD_OK             0x4
  28 #define TS73XX_FPGA_CONFIG_LOAD         0x8
  29 
  30 struct ts73xx_fpga_priv {
  31         void __iomem    *io_base;
  32         struct device   *dev;
  33 };
  34 
  35 static enum fpga_mgr_states ts73xx_fpga_state(struct fpga_manager *mgr)
  36 {
  37         return FPGA_MGR_STATE_UNKNOWN;
  38 }
  39 
  40 static int ts73xx_fpga_write_init(struct fpga_manager *mgr,
  41                                   struct fpga_image_info *info,
  42                                   const char *buf, size_t count)
  43 {
  44         struct ts73xx_fpga_priv *priv = mgr->priv;
  45 
  46         /* Reset the FPGA */
  47         writeb(0, priv->io_base + TS73XX_FPGA_CONFIG_REG);
  48         udelay(TS73XX_FPGA_RESET_LOW_DELAY);
  49         writeb(TS73XX_FPGA_RESET, priv->io_base + TS73XX_FPGA_CONFIG_REG);
  50         udelay(TS73XX_FPGA_RESET_HIGH_DELAY);
  51 
  52         return 0;
  53 }
  54 
  55 static int ts73xx_fpga_write(struct fpga_manager *mgr, const char *buf,
  56                              size_t count)
  57 {
  58         struct ts73xx_fpga_priv *priv = mgr->priv;
  59         size_t i = 0;
  60         int ret;
  61         u8 reg;
  62 
  63         while (count--) {
  64                 ret = readb_poll_timeout(priv->io_base + TS73XX_FPGA_CONFIG_REG,
  65                                          reg, !(reg & TS73XX_FPGA_WRITE_DONE),
  66                                          1, TS73XX_FPGA_WRITE_DONE_TIMEOUT);
  67                 if (ret < 0)
  68                         return ret;
  69 
  70                 writeb(buf[i], priv->io_base + TS73XX_FPGA_DATA_REG);
  71                 i++;
  72         }
  73 
  74         return 0;
  75 }
  76 
  77 static int ts73xx_fpga_write_complete(struct fpga_manager *mgr,
  78                                       struct fpga_image_info *info)
  79 {
  80         struct ts73xx_fpga_priv *priv = mgr->priv;
  81         u8 reg;
  82 
  83         usleep_range(1000, 2000);
  84         reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG);
  85         reg |= TS73XX_FPGA_CONFIG_LOAD;
  86         writeb(reg, priv->io_base + TS73XX_FPGA_CONFIG_REG);
  87 
  88         usleep_range(1000, 2000);
  89         reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG);
  90         reg &= ~TS73XX_FPGA_CONFIG_LOAD;
  91         writeb(reg, priv->io_base + TS73XX_FPGA_CONFIG_REG);
  92 
  93         reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG);
  94         if ((reg & TS73XX_FPGA_LOAD_OK) != TS73XX_FPGA_LOAD_OK)
  95                 return -ETIMEDOUT;
  96 
  97         return 0;
  98 }
  99 
 100 static const struct fpga_manager_ops ts73xx_fpga_ops = {
 101         .state          = ts73xx_fpga_state,
 102         .write_init     = ts73xx_fpga_write_init,
 103         .write          = ts73xx_fpga_write,
 104         .write_complete = ts73xx_fpga_write_complete,
 105 };
 106 
 107 static int ts73xx_fpga_probe(struct platform_device *pdev)
 108 {
 109         struct device *kdev = &pdev->dev;
 110         struct ts73xx_fpga_priv *priv;
 111         struct fpga_manager *mgr;
 112         struct resource *res;
 113 
 114         priv = devm_kzalloc(kdev, sizeof(*priv), GFP_KERNEL);
 115         if (!priv)
 116                 return -ENOMEM;
 117 
 118         priv->dev = kdev;
 119 
 120         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 121         priv->io_base = devm_ioremap_resource(kdev, res);
 122         if (IS_ERR(priv->io_base)) {
 123                 dev_err(kdev, "unable to remap registers\n");
 124                 return PTR_ERR(priv->io_base);
 125         }
 126 
 127         mgr = devm_fpga_mgr_create(kdev, "TS-73xx FPGA Manager",
 128                                    &ts73xx_fpga_ops, priv);
 129         if (!mgr)
 130                 return -ENOMEM;
 131 
 132         platform_set_drvdata(pdev, mgr);
 133 
 134         return fpga_mgr_register(mgr);
 135 }
 136 
 137 static int ts73xx_fpga_remove(struct platform_device *pdev)
 138 {
 139         struct fpga_manager *mgr = platform_get_drvdata(pdev);
 140 
 141         fpga_mgr_unregister(mgr);
 142 
 143         return 0;
 144 }
 145 
 146 static struct platform_driver ts73xx_fpga_driver = {
 147         .driver = {
 148                 .name   = "ts73xx-fpga-mgr",
 149         },
 150         .probe  = ts73xx_fpga_probe,
 151         .remove = ts73xx_fpga_remove,
 152 };
 153 module_platform_driver(ts73xx_fpga_driver);
 154 
 155 MODULE_AUTHOR("Florian Fainelli <f.fainelli@gmail.com>");
 156 MODULE_DESCRIPTION("TS-73xx FPGA Manager driver");
 157 MODULE_LICENSE("GPL v2");

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