Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2020 NovaTech LLC
0004  * George McCollister <george.mccollister@gmail.com>
0005  */
0006 
0007 #include <linux/bitfield.h>
0008 #include <linux/bits.h>
0009 #include <linux/mdio.h>
0010 #include <linux/module.h>
0011 #include <linux/phy.h>
0012 #include <linux/if_vlan.h>
0013 #include <linux/of.h>
0014 #include "xrs700x.h"
0015 #include "xrs700x_reg.h"
0016 
0017 #define XRS_MDIO_IBA0   0x10
0018 #define XRS_MDIO_IBA1   0x11
0019 #define XRS_MDIO_IBD    0x14
0020 
0021 #define XRS_IB_READ 0x0
0022 #define XRS_IB_WRITE    0x1
0023 
0024 static int xrs700x_mdio_reg_read(void *context, unsigned int reg,
0025                  unsigned int *val)
0026 {
0027     struct mdio_device *mdiodev = context;
0028     struct device *dev = &mdiodev->dev;
0029     u16 uval;
0030     int ret;
0031 
0032     uval = (u16)FIELD_GET(GENMASK(31, 16), reg);
0033 
0034     ret = mdiodev_write(mdiodev, XRS_MDIO_IBA1, uval);
0035     if (ret < 0) {
0036         dev_err(dev, "xrs mdiobus_write returned %d\n", ret);
0037         return ret;
0038     }
0039 
0040     uval = (u16)((reg & GENMASK(15, 1)) | XRS_IB_READ);
0041 
0042     ret = mdiodev_write(mdiodev, XRS_MDIO_IBA0, uval);
0043     if (ret < 0) {
0044         dev_err(dev, "xrs mdiobus_write returned %d\n", ret);
0045         return ret;
0046     }
0047 
0048     ret = mdiodev_read(mdiodev, XRS_MDIO_IBD);
0049     if (ret < 0) {
0050         dev_err(dev, "xrs mdiobus_read returned %d\n", ret);
0051         return ret;
0052     }
0053 
0054     *val = (unsigned int)ret;
0055 
0056     return 0;
0057 }
0058 
0059 static int xrs700x_mdio_reg_write(void *context, unsigned int reg,
0060                   unsigned int val)
0061 {
0062     struct mdio_device *mdiodev = context;
0063     struct device *dev = &mdiodev->dev;
0064     u16 uval;
0065     int ret;
0066 
0067     ret = mdiodev_write(mdiodev, XRS_MDIO_IBD, (u16)val);
0068     if (ret < 0) {
0069         dev_err(dev, "xrs mdiobus_write returned %d\n", ret);
0070         return ret;
0071     }
0072 
0073     uval = (u16)FIELD_GET(GENMASK(31, 16), reg);
0074 
0075     ret = mdiodev_write(mdiodev, XRS_MDIO_IBA1, uval);
0076     if (ret < 0) {
0077         dev_err(dev, "xrs mdiobus_write returned %d\n", ret);
0078         return ret;
0079     }
0080 
0081     uval = (u16)((reg & GENMASK(15, 1)) | XRS_IB_WRITE);
0082 
0083     ret = mdiodev_write(mdiodev, XRS_MDIO_IBA0, uval);
0084     if (ret < 0) {
0085         dev_err(dev, "xrs mdiobus_write returned %d\n", ret);
0086         return ret;
0087     }
0088 
0089     return 0;
0090 }
0091 
0092 static const struct regmap_config xrs700x_mdio_regmap_config = {
0093     .val_bits = 16,
0094     .reg_stride = 2,
0095     .reg_bits = 32,
0096     .pad_bits = 0,
0097     .write_flag_mask = 0,
0098     .read_flag_mask = 0,
0099     .reg_read = xrs700x_mdio_reg_read,
0100     .reg_write = xrs700x_mdio_reg_write,
0101     .max_register = XRS_VLAN(VLAN_N_VID - 1),
0102     .cache_type = REGCACHE_NONE,
0103     .reg_format_endian = REGMAP_ENDIAN_BIG,
0104     .val_format_endian = REGMAP_ENDIAN_BIG
0105 };
0106 
0107 static int xrs700x_mdio_probe(struct mdio_device *mdiodev)
0108 {
0109     struct xrs700x *priv;
0110     int ret;
0111 
0112     priv = xrs700x_switch_alloc(&mdiodev->dev, mdiodev);
0113     if (!priv)
0114         return -ENOMEM;
0115 
0116     priv->regmap = devm_regmap_init(&mdiodev->dev, NULL, mdiodev,
0117                     &xrs700x_mdio_regmap_config);
0118     if (IS_ERR(priv->regmap)) {
0119         ret = PTR_ERR(priv->regmap);
0120         dev_err(&mdiodev->dev, "Failed to initialize regmap: %d\n", ret);
0121         return ret;
0122     }
0123 
0124     dev_set_drvdata(&mdiodev->dev, priv);
0125 
0126     ret = xrs700x_switch_register(priv);
0127 
0128     /* Main DSA driver may not be started yet. */
0129     if (ret)
0130         return ret;
0131 
0132     return 0;
0133 }
0134 
0135 static void xrs700x_mdio_remove(struct mdio_device *mdiodev)
0136 {
0137     struct xrs700x *priv = dev_get_drvdata(&mdiodev->dev);
0138 
0139     if (!priv)
0140         return;
0141 
0142     xrs700x_switch_remove(priv);
0143 
0144     dev_set_drvdata(&mdiodev->dev, NULL);
0145 }
0146 
0147 static void xrs700x_mdio_shutdown(struct mdio_device *mdiodev)
0148 {
0149     struct xrs700x *priv = dev_get_drvdata(&mdiodev->dev);
0150 
0151     if (!priv)
0152         return;
0153 
0154     xrs700x_switch_shutdown(priv);
0155 
0156     dev_set_drvdata(&mdiodev->dev, NULL);
0157 }
0158 
0159 static const struct of_device_id __maybe_unused xrs700x_mdio_dt_ids[] = {
0160     { .compatible = "arrow,xrs7003e", .data = &xrs7003e_info },
0161     { .compatible = "arrow,xrs7003f", .data = &xrs7003f_info },
0162     { .compatible = "arrow,xrs7004e", .data = &xrs7004e_info },
0163     { .compatible = "arrow,xrs7004f", .data = &xrs7004f_info },
0164     {},
0165 };
0166 MODULE_DEVICE_TABLE(of, xrs700x_mdio_dt_ids);
0167 
0168 static struct mdio_driver xrs700x_mdio_driver = {
0169     .mdiodrv.driver = {
0170         .name   = "xrs700x-mdio",
0171         .of_match_table = of_match_ptr(xrs700x_mdio_dt_ids),
0172     },
0173     .probe  = xrs700x_mdio_probe,
0174     .remove = xrs700x_mdio_remove,
0175     .shutdown = xrs700x_mdio_shutdown,
0176 };
0177 
0178 mdio_module_driver(xrs700x_mdio_driver);
0179 
0180 MODULE_AUTHOR("George McCollister <george.mccollister@gmail.com>");
0181 MODULE_DESCRIPTION("Arrow SpeedChips XRS700x DSA MDIO driver");
0182 MODULE_LICENSE("GPL v2");