0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <linux/delay.h>
0012 #include <linux/io.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_device.h>
0015 #include <linux/string.h>
0016 #include <linux/iopoll.h>
0017 #include <linux/fpga/fpga-mgr.h>
0018
0019 #define TS73XX_FPGA_DATA_REG 0
0020 #define TS73XX_FPGA_CONFIG_REG 1
0021
0022 #define TS73XX_FPGA_WRITE_DONE 0x1
0023 #define TS73XX_FPGA_WRITE_DONE_TIMEOUT 1000
0024 #define TS73XX_FPGA_RESET 0x2
0025 #define TS73XX_FPGA_RESET_LOW_DELAY 30
0026 #define TS73XX_FPGA_RESET_HIGH_DELAY 80
0027 #define TS73XX_FPGA_LOAD_OK 0x4
0028 #define TS73XX_FPGA_CONFIG_LOAD 0x8
0029
0030 struct ts73xx_fpga_priv {
0031 void __iomem *io_base;
0032 struct device *dev;
0033 };
0034
0035 static int ts73xx_fpga_write_init(struct fpga_manager *mgr,
0036 struct fpga_image_info *info,
0037 const char *buf, size_t count)
0038 {
0039 struct ts73xx_fpga_priv *priv = mgr->priv;
0040
0041
0042 writeb(0, priv->io_base + TS73XX_FPGA_CONFIG_REG);
0043 udelay(TS73XX_FPGA_RESET_LOW_DELAY);
0044 writeb(TS73XX_FPGA_RESET, priv->io_base + TS73XX_FPGA_CONFIG_REG);
0045 udelay(TS73XX_FPGA_RESET_HIGH_DELAY);
0046
0047 return 0;
0048 }
0049
0050 static int ts73xx_fpga_write(struct fpga_manager *mgr, const char *buf,
0051 size_t count)
0052 {
0053 struct ts73xx_fpga_priv *priv = mgr->priv;
0054 size_t i = 0;
0055 int ret;
0056 u8 reg;
0057
0058 while (count--) {
0059 ret = readb_poll_timeout(priv->io_base + TS73XX_FPGA_CONFIG_REG,
0060 reg, !(reg & TS73XX_FPGA_WRITE_DONE),
0061 1, TS73XX_FPGA_WRITE_DONE_TIMEOUT);
0062 if (ret < 0)
0063 return ret;
0064
0065 writeb(buf[i], priv->io_base + TS73XX_FPGA_DATA_REG);
0066 i++;
0067 }
0068
0069 return 0;
0070 }
0071
0072 static int ts73xx_fpga_write_complete(struct fpga_manager *mgr,
0073 struct fpga_image_info *info)
0074 {
0075 struct ts73xx_fpga_priv *priv = mgr->priv;
0076 u8 reg;
0077
0078 usleep_range(1000, 2000);
0079 reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG);
0080 reg |= TS73XX_FPGA_CONFIG_LOAD;
0081 writeb(reg, priv->io_base + TS73XX_FPGA_CONFIG_REG);
0082
0083 usleep_range(1000, 2000);
0084 reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG);
0085 reg &= ~TS73XX_FPGA_CONFIG_LOAD;
0086 writeb(reg, priv->io_base + TS73XX_FPGA_CONFIG_REG);
0087
0088 reg = readb(priv->io_base + TS73XX_FPGA_CONFIG_REG);
0089 if ((reg & TS73XX_FPGA_LOAD_OK) != TS73XX_FPGA_LOAD_OK)
0090 return -ETIMEDOUT;
0091
0092 return 0;
0093 }
0094
0095 static const struct fpga_manager_ops ts73xx_fpga_ops = {
0096 .write_init = ts73xx_fpga_write_init,
0097 .write = ts73xx_fpga_write,
0098 .write_complete = ts73xx_fpga_write_complete,
0099 };
0100
0101 static int ts73xx_fpga_probe(struct platform_device *pdev)
0102 {
0103 struct device *kdev = &pdev->dev;
0104 struct ts73xx_fpga_priv *priv;
0105 struct fpga_manager *mgr;
0106 struct resource *res;
0107
0108 priv = devm_kzalloc(kdev, sizeof(*priv), GFP_KERNEL);
0109 if (!priv)
0110 return -ENOMEM;
0111
0112 priv->dev = kdev;
0113
0114 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0115 priv->io_base = devm_ioremap_resource(kdev, res);
0116 if (IS_ERR(priv->io_base))
0117 return PTR_ERR(priv->io_base);
0118
0119 mgr = devm_fpga_mgr_register(kdev, "TS-73xx FPGA Manager",
0120 &ts73xx_fpga_ops, priv);
0121 return PTR_ERR_OR_ZERO(mgr);
0122 }
0123
0124 static struct platform_driver ts73xx_fpga_driver = {
0125 .driver = {
0126 .name = "ts73xx-fpga-mgr",
0127 },
0128 .probe = ts73xx_fpga_probe,
0129 };
0130 module_platform_driver(ts73xx_fpga_driver);
0131
0132 MODULE_AUTHOR("Florian Fainelli <f.fainelli@gmail.com>");
0133 MODULE_DESCRIPTION("TS-73xx FPGA Manager driver");
0134 MODULE_LICENSE("GPL v2");