Advertisement
Guest User

Untitled

a guest
Nov 30th, 2017
278
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.55 KB | None | 0 0
  1. /*******************************************************************************
  2.  * Copyright © 2015-2016, Shuge
  3.  *      Author: Sugar <shugeLinux@gmail.com>
  4.  *
  5.  * This file is provided under a dual BSD/GPL license.  When using or
  6.  * redistributing this file, you may do so under either license.
  7.  *
  8.  * This program is distributed in the hope that it will be useful,
  9.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  * GNU General Public License for more details.
  12.  *
  13.  ********************************************************************************/
  14. #include <linux/kernel.h>
  15. #include <linux/string.h>
  16. #include <linux/errno.h>
  17. #include <linux/unistd.h>
  18. #include <linux/interrupt.h>
  19. #include <linux/init.h>
  20. #include <linux/delay.h>
  21. #include <linux/netdevice.h>
  22. #include <linux/etherdevice.h>
  23. #include <linux/skbuff.h>
  24. #include <linux/spinlock.h>
  25. #include <linux/mm.h>
  26. #include <linux/module.h>
  27. #include <linux/mii.h>
  28. #include <linux/ethtool.h>
  29. #include <linux/phy.h>
  30. #include <linux/platform_device.h>
  31.  
  32. #include <asm/io.h>
  33. #include <asm/irq.h>
  34.  
  35. #include <linux/mfd/acx00-mfd.h>
  36. #include <linux/sunxi-sid.h>
  37.  
  38. #define EXTEPHY_CTRL0 0x0014
  39. #define EXTEPHY_CTRL1 0x0016
  40.  
  41. #define EPHY_CTRL 0x6000
  42. #define EPHY_SID 0x8004
  43.  
  44. atomic_t ephy_en;
  45.  
  46. struct ephy_res {
  47.     struct device_driver *plat_drv;
  48.     struct device_driver *phy_drv;
  49.     struct phy_device *phydev;
  50.     struct acx00 *acx;
  51. };
  52.  
  53. static struct ephy_res ephy_priv;
  54.  
  55. int ephy_is_enable(void)
  56. {
  57.     return atomic_read(&ephy_en);
  58. }
  59. EXPORT_SYMBOL_GPL(ephy_is_enable);
  60.  
  61. /**
  62.  * @name    ephy_read_sid
  63.  * @brief       read ephy sid from efuse
  64.  * @param[IN]   none
  65.  * @param[OUT]  p_ephy_cali: ephy calibration value
  66.  * @return  return 0 if success,-value if fail
  67.  */
  68. static s32 ephy_read_sid(u16 *p_ephy_cali)
  69. {
  70.     s32 ret = 0;
  71.     u8 buf[6];
  72.  
  73.     if (p_ephy_cali == NULL) {
  74.         pr_info("%s's pointer type args are NULL!\n", __func__);
  75.         return -1;
  76.     }
  77.     ret = sunxi_efuse_readn(EFUSE_OEM_NAME, buf, 6);
  78.     if (ret != 0) {
  79.         pr_info("sunxi_efuse_readn failed:%d\n", ret);
  80.         return ret;
  81.     }
  82.     *p_ephy_cali = buf[0] + (buf[1] << 8);
  83.  
  84.     return ret;
  85. }
  86.  
  87. #if 0
  88. static int ephy_reset(struct phy_device *phydev)
  89. {
  90.     int bmcr;
  91.  
  92.     /* Software Reset PHY */
  93.     bmcr = phy_read(phydev, MII_BMCR);
  94.     if (bmcr < 0)
  95.         return bmcr;
  96.  
  97.     bmcr |= BMCR_RESET;
  98.     bmcr = phy_write(phydev, MII_BMCR, bmcr);
  99.     if (bmcr < 0)
  100.         return bmcr;
  101.  
  102.     do {
  103.         bmcr = phy_read(phydev, MII_BMCR);
  104.         if (bmcr < 0)
  105.             return bmcr;
  106.     } while (bmcr & BMCR_RESET);
  107.  
  108.     return 0;
  109. }
  110. #endif
  111.  
  112. static void disable_intelligent_ieee(struct phy_device *phydev)
  113. {
  114.     unsigned int value;
  115.     phy_write(phydev, 0x1f, 0x0100); /* switch to page 1 */
  116.     value = phy_read(phydev, 0x17); /* read address 0 0x17 register */
  117.     value &= ~(1 << 3); /* reg 0x17 bit 3, set 0 to disable IEEE */
  118.     phy_write(phydev, 0x17, value);
  119.     phy_write(phydev, 0x1f, 0x0000); /* switch to page 0 */
  120. }
  121.  
  122. static void disable_802_3az_ieee(struct phy_device *phydev)
  123. {
  124.     unsigned int value;
  125.     phy_write(phydev, 0xd, 0x7);
  126.     phy_write(phydev, 0xe, 0x3c);
  127.     phy_write(phydev, 0xd, 0x1 << 14 | 0x7);
  128.     value = phy_read(phydev, 0xe);
  129.     value &= ~(0x1 << 1);
  130.     phy_write(phydev, 0xd, 0x7);
  131.     phy_write(phydev, 0xe, 0x3c);
  132.     phy_write(phydev, 0xd, 0x1 << 14 | 0x7);
  133.     phy_write(phydev, 0xe, value);
  134.  
  135.     phy_write(phydev, 0x1f, 0x0200); /* switch to page 2 */
  136.     phy_write(phydev, 0x18, 0x0000);
  137. }
  138.  
  139. static int ephy_config_init(struct phy_device *phydev)
  140. {
  141.     int value;
  142.  
  143.     /* Iint ephy */
  144.     phy_write(phydev, 0x1f, 0x0100);    /* Switch to Page 1 */
  145.     phy_write(phydev, 0x12, 0x4824);    /* Disable APS */
  146.  
  147.     phy_write(phydev, 0x1f, 0x0200);    /* Switch to Page 2 */
  148.     phy_write(phydev, 0x18, 0x0000);    /* PHYAFE TRX optimization */
  149.  
  150.     phy_write(phydev, 0x1f, 0x0600);    /* Switch to Page 6 */
  151.     phy_write(phydev, 0x14, 0x708f);    /* PHYAFE TX optimization */
  152.     phy_write(phydev, 0x13, 0xF000);    /* PHYAFE RX optimization */
  153.     phy_write(phydev, 0x15, 0x1530);
  154.  
  155.     phy_write(phydev, 0x1f, 0x0800);    /* Switch to Page 6 */
  156.     phy_write(phydev, 0x18, 0x00bc);    /* PHYAFE TRX optimization */
  157. #if 0
  158.     /* Disable Auto Power Saving mode */
  159.     phy_write(phydev, 0x1f, 0x0100);    /* Switch to Page 1 */
  160.     value = phy_read(phydev, 0x17);
  161.     value &= ~BIT(13);
  162.     phy_write(phydev, 0x17, value);
  163. #endif
  164.     disable_intelligent_ieee(phydev); /* Disable Intelligent IEEE */
  165.     disable_802_3az_ieee(phydev);     /* Disable 802.3az IEEE */
  166.     phy_write(phydev, 0x1f, 0x0000);    /* Switch to Page 0 */
  167.  
  168. #ifdef CONFIG_MFD_ACX00
  169.     value = acx00_reg_read(ephy_priv.acx, EPHY_CTRL);
  170.     if (phydev->interface == PHY_INTERFACE_MODE_RMII)
  171.         value |= (1 << 11);
  172.     else
  173.         value &= (~(1 << 11));
  174.     acx00_reg_write(ephy_priv.acx, EPHY_CTRL, value | (1 << 11));
  175. #endif
  176.  
  177. #if defined(CONFIG_ARCH_SUN50IW6)
  178.     value = phy_read(phydev, 0x13);
  179.     value |= 1 << 12;
  180.     phy_write(phydev, 0x13, value);
  181. #endif
  182.  
  183.     return 0;
  184.  
  185. }
  186.  
  187. static int ephy_probe(struct phy_device *phydev)
  188. {
  189.     struct phy_driver *drv;
  190.  
  191.     if (!phydev)
  192.         return -ENODEV;
  193.  
  194.     drv = phydev->drv;
  195.     ephy_priv.phy_drv = &drv->driver;
  196.     ephy_priv.phydev = phydev;
  197.     return 0;
  198. }
  199.  
  200. #if 0
  201. static int ephy_ack_interrupt(struct phy_device *phydev)
  202. {
  203.     int err = phy_read(phydev, IP101A_G_IRQ_CONF_STATUS);
  204.     if (err < 0)
  205.         return err;
  206.  
  207.     return 0;
  208. }
  209. #endif
  210.  
  211. static void sunxi_ephy_enable(struct ephy_res *priv)
  212. {
  213. #ifdef CONFIG_MFD_ACX00
  214.     int value;
  215. #if defined(CONFIG_ARCH_SUN50IW6)
  216.     u16 ephy_cali = 0;
  217. #endif
  218.  
  219.     if (!acx00_enable()) {
  220.         msleep(50);
  221.         if (!acx00_enable()) {
  222.             pr_err("acx00 is no enable, and sunxi_ephy_enable is fail\n");
  223.             return;
  224.         }
  225.     }
  226.  
  227.     value = acx00_reg_read(priv->acx, EXTEPHY_CTRL0);
  228.     value |= 0x03;
  229.     acx00_reg_write(priv->acx, EXTEPHY_CTRL0, value);
  230.     value = acx00_reg_read(priv->acx, EXTEPHY_CTRL1);
  231.     value |= 0x0f;
  232.     acx00_reg_write(priv->acx, EXTEPHY_CTRL1, value);
  233.     acx00_reg_write(priv->acx, EPHY_CTRL, 0x06);
  234.  
  235.     /*for ephy */
  236.     value= acx00_reg_read(priv->acx, EPHY_CTRL);
  237.     value &= ~(0xf<<12);
  238.  
  239. #if defined(CONFIG_ARCH_SUN50IW6)
  240.     ephy_read_sid(&ephy_cali);
  241.     value |= (0x0F & (0x03 + ephy_cali)) << 12;
  242. #else
  243.     value |= (0x0F & (0x03 + acx00_reg_read(priv->acx, EPHY_SID)))<<12;
  244. #endif
  245.  
  246.     acx00_reg_write(priv->acx, EPHY_CTRL, value);
  247.  
  248.     atomic_set(&ephy_en, 1);
  249. #endif
  250.     return;
  251. }
  252.  
  253. static struct phy_driver ephy_driver = {
  254.     .phy_id     = 0x00441400,
  255.     .name       = "ephy",
  256.     .phy_id_mask    = 0x0ffffff0,
  257.     .features   = PHY_BASIC_FEATURES | SUPPORTED_Pause |
  258.               SUPPORTED_Asym_Pause,
  259. #if 0
  260.     .flags      = PHY_HAS_INTERRUPT,
  261.     .ack_interrupt  = ephy_ack_interrupt,
  262. #endif
  263.     .config_init    = &ephy_config_init,
  264.     .config_aneg    = &genphy_config_aneg,
  265.     .read_status    = &genphy_read_status,
  266.     .suspend    = genphy_suspend,
  267.     .resume     = genphy_resume,
  268.     .driver     = { .owner = THIS_MODULE,},
  269.     .probe      = ephy_probe,
  270. };
  271.  
  272. static const struct platform_device_id sunxi_ephy_id[] = {
  273.     { "acx-ephy", 0},
  274.     { },
  275. };
  276. MODULE_DEVICE_TABLE(platform, sunxi_ephy_id);
  277.  
  278. static int ephy_plat_probe(struct platform_device *pdev)
  279. {
  280.     struct acx00 *ax = dev_get_drvdata(pdev->dev.parent);
  281.  
  282.     if (!ax)
  283.         return -ENODEV;
  284.  
  285.     ephy_priv.acx = ax;
  286.     platform_set_drvdata(pdev, &ephy_priv);
  287.     ephy_priv.plat_drv = pdev->dev.driver;
  288.  
  289.     atomic_set(&ephy_en, 0);
  290.  
  291.     sunxi_ephy_enable(&ephy_priv);
  292.  
  293.     return 0;
  294. }
  295.  
  296. static int ephy_plat_remove(struct platform_device *pdev)
  297. {
  298.     return 0;
  299. }
  300.  
  301. static int sunxi_phy_suspend(struct device *dev)
  302. {
  303.     atomic_set(&ephy_en, 0);
  304.     return 0;
  305. }
  306.  
  307. static int sunxi_phy_resume(struct device *dev)
  308. {
  309.     sunxi_ephy_enable(&ephy_priv);
  310.  
  311.     return 0;
  312. }
  313.  
  314. /* Suspend hook structures */
  315. static const struct dev_pm_ops sunxi_phy_pm_ops = {
  316.     .suspend = sunxi_phy_suspend,
  317.     .resume = sunxi_phy_resume,
  318. };
  319.  
  320. static struct platform_driver ephy_plat_driver = {
  321.     .driver = {
  322.         .name = "acx-ephy",
  323.         .owner = THIS_MODULE,
  324.         .pm = &sunxi_phy_pm_ops,
  325.     },
  326.     .probe = ephy_plat_probe,
  327.     .remove = ephy_plat_remove,
  328.     .id_table = sunxi_ephy_id,
  329. };
  330.  
  331. static int ephy_init(void)
  332. {
  333.     int ret = 0;
  334.  
  335.     ret = platform_driver_register(&ephy_plat_driver);
  336.     if (ret)
  337.         return -EINVAL;
  338.  
  339.     ret = phy_driver_register(&ephy_driver);
  340.     if (ret)
  341.         platform_driver_unregister(&ephy_plat_driver);
  342.  
  343.     return ret;
  344. }
  345.  
  346. static void ephy_exit(void)
  347. {
  348.     if (ephy_priv.plat_drv)
  349.         platform_driver_unregister(&ephy_plat_driver);
  350.  
  351.     phy_driver_unregister(&ephy_driver);
  352. }
  353.  
  354. module_init(ephy_init);
  355. module_exit(ephy_exit);
  356.  
  357. static struct mdio_device_id __maybe_unused ephy_tbl[] = {
  358.     { 0x00441400, 0x0ffffff0 },
  359.     { }
  360. };
  361.  
  362. MODULE_DEVICE_TABLE(mdio, ephy_tbl);
  363.  
  364. MODULE_DESCRIPTION("Allwinner EPHY drivers");
  365. MODULE_AUTHOR("Sugar <shugeLinux@gmail.com>");
  366. MODULE_LICENSE("GPL");
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement