FPGA on LX2160AQDS/LX2160ARDB connected on I2C bus, so add qixis
driver which is basically an i2c client driver to control FPGA.

Signed-off-by: Wang Dongsheng <dongsheng.w...@freescale.com>
Signed-off-by: Pankaj Bansal <pankaj.ban...@nxp.com>
---

Notes:
    V2:
    - Modify the driver to not create platform devices corresponding to 
subnodes.
      because the subnodes are not actual devices.
    - Use mdio_mux_regmap_init/mdio_mux_regmap_uninit
    - Remove header file from include folder, as no qixis api is called from 
outside
    - Add regmap_exit in driver's remove function
    Dendencies:
        - https://www.mail-archive.com/netdev@vger.kernel.org/msg281274.html

 drivers/soc/fsl/Kconfig      |   8 +++
 drivers/soc/fsl/Makefile     |   1 +
 drivers/soc/fsl/qixis_ctrl.c | 121 +++++++++++++++++++++++++++++++++
 3 files changed, 130 insertions(+)

diff --git a/drivers/soc/fsl/Kconfig b/drivers/soc/fsl/Kconfig
index 8a0ba6da6f8a..e787d3e637a4 100644
--- a/drivers/soc/fsl/Kconfig
+++ b/drivers/soc/fsl/Kconfig
@@ -36,6 +36,14 @@ config FSL_SLEEP_FSM
          The FSM is used to finish clean-ups at the last stage of system 
entering deep
          sleep, and also wakes up system when a wake up event happens.
 
+config FSL_QIXIS
+       tristate "QIXIS system controller driver"
+       depends on REGMAP_I2C
+       default n
+       help
+         Say y here to enable QIXIS system controller api. The qixis driver
+         provides FPGA functions to control system.
+
 if ARM || ARM64
 source "drivers/soc/fsl/Kconfig.arm"
 endif
diff --git a/drivers/soc/fsl/Makefile b/drivers/soc/fsl/Makefile
index ffdf93b34501..db7b09bfbd91 100644
--- a/drivers/soc/fsl/Makefile
+++ b/drivers/soc/fsl/Makefile
@@ -5,6 +5,7 @@
 obj-$(CONFIG_FSL_DPAA)                 += qbman/
 obj-$(CONFIG_QUICC_ENGINE)             += qe/
 obj-$(CONFIG_CPM)                      += qe/
+obj-$(CONFIG_FSL_QIXIS)                += qixis_ctrl.o
 obj-$(CONFIG_FSL_GUTS)                 += guts.o
 obj-$(CONFIG_FSL_MC_DPIO)              += dpio/
 obj-$(CONFIG_FSL_LS2_CONSOLE)          += ls2-console/
diff --git a/drivers/soc/fsl/qixis_ctrl.c b/drivers/soc/fsl/qixis_ctrl.c
new file mode 100644
index 000000000000..336f366e228e
--- /dev/null
+++ b/drivers/soc/fsl/qixis_ctrl.c
@@ -0,0 +1,121 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/* Freescale QIXIS system controller driver.
+ *
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ * Copyright 2018 NXP
+ */
+
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mdio-mux.h>
+
+/* QIXIS MAP */
+struct fsl_qixis_regs {
+       u8              id;             /* Identification Registers */
+       u8              version;        /* Version Register */
+       u8              qixis_ver;      /* QIXIS Version Register */
+       u8              reserved1[0x1f];
+};
+
+struct mdio_mux_data {
+       void                    *data;
+       struct list_head        link;
+};
+
+struct qixis_priv {
+       struct regmap           *regmap;
+       struct list_head        mdio_mux_list;
+};
+
+static struct regmap_config qixis_regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static int fsl_qixis_i2c_probe(struct i2c_client *client)
+{
+       struct device_node *child;
+       struct qixis_priv *priv;
+       int ret;
+       u32 qver;
+       struct mdio_mux_data *mux_data;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+               return -EOPNOTSUPP;
+
+       priv = devm_kzalloc(&client->dev, sizeof(struct qixis_priv),
+                           GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->regmap = regmap_init_i2c(client, &qixis_regmap_config);
+       INIT_LIST_HEAD(&priv->mdio_mux_list);
+
+       regmap_read(priv->regmap, offsetof(struct fsl_qixis_regs, qixis_ver),
+                   &qver);
+       pr_info("Freescale QIXIS Version: 0x%08x\n", qver);
+
+       for_each_child_of_node(client->dev.of_node, child) {
+               if (of_node_name_prefix(child, "mdio-mux")) {
+                       mux_data = devm_kzalloc(&client->dev,
+                                               sizeof(struct mdio_mux_data),
+                                               GFP_KERNEL);
+                       if (!mux_data)
+                               return -ENOMEM;
+                       ret = mdio_mux_regmap_init(&client->dev, child,
+                                                  &mux_data->data);
+                       if (ret)
+                               return ret;
+                       list_add(&mux_data->link, &priv->mdio_mux_list);
+               }
+       };
+
+       i2c_set_clientdata(client, priv);
+
+       return 0;
+}
+
+static int fsl_qixis_i2c_remove(struct i2c_client *client)
+{
+       struct qixis_priv *priv;
+       struct list_head *pos;
+       struct mdio_mux_data *mux_data;
+
+       priv = i2c_get_clientdata(client);
+       list_for_each(pos, &priv->mdio_mux_list) {
+               mux_data = list_entry(pos, struct mdio_mux_data, link);
+               mdio_mux_regmap_uninit(mux_data->data);
+       }
+       regmap_exit(priv->regmap);
+
+       return 0;
+}
+
+static const struct of_device_id fsl_qixis_of_match[] = {
+       { .compatible = "fsl,fpga-qixis-i2c" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, fsl_qixis_of_match);
+
+static struct i2c_driver fsl_qixis_i2c_driver = {
+       .driver = {
+               .name   = "qixis_ctrl",
+               .owner  = THIS_MODULE,
+               .of_match_table = of_match_ptr(fsl_qixis_of_match),
+       },
+       .probe_new      = fsl_qixis_i2c_probe,
+       .remove         = fsl_qixis_i2c_remove,
+};
+module_i2c_driver(fsl_qixis_i2c_driver);
+
+MODULE_AUTHOR("Wang Dongsheng <dongsheng.w...@freescale.com>");
+MODULE_DESCRIPTION("Freescale QIXIS system controller driver");
+MODULE_LICENSE("GPL v2");
-- 
2.17.1

Reply via email to