Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * omap-ocp2scp.c - transform ocp interface protocol to scp protocol
0004  *
0005  * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
0006  * Author: Kishon Vijay Abraham I <kishon@ti.com>
0007  */
0008 
0009 #include <linux/io.h>
0010 #include <linux/module.h>
0011 #include <linux/platform_device.h>
0012 #include <linux/err.h>
0013 #include <linux/pm_runtime.h>
0014 #include <linux/of.h>
0015 #include <linux/of_platform.h>
0016 
0017 #define OCP2SCP_TIMING 0x18
0018 #define SYNC2_MASK 0xf
0019 
0020 static int ocp2scp_remove_devices(struct device *dev, void *c)
0021 {
0022     struct platform_device *pdev = to_platform_device(dev);
0023 
0024     platform_device_unregister(pdev);
0025 
0026     return 0;
0027 }
0028 
0029 static int omap_ocp2scp_probe(struct platform_device *pdev)
0030 {
0031     int ret;
0032     u32 reg;
0033     void __iomem *regs;
0034     struct resource *res;
0035     struct device_node *np = pdev->dev.of_node;
0036 
0037     if (np) {
0038         ret = of_platform_populate(np, NULL, NULL, &pdev->dev);
0039         if (ret) {
0040             dev_err(&pdev->dev,
0041                 "failed to add resources for ocp2scp child\n");
0042             goto err0;
0043         }
0044     }
0045 
0046     pm_runtime_enable(&pdev->dev);
0047     /*
0048      * As per AM572x TRM: http://www.ti.com/lit/ug/spruhz6/spruhz6.pdf
0049      * under section 26.3.2.2, table 26-26 OCP2SCP TIMING Caution;
0050      * As per OMAP4430 TRM: http://www.ti.com/lit/ug/swpu231ap/swpu231ap.pdf
0051      * under section 23.12.6.2.2 , Table 23-1213 OCP2SCP TIMING Caution;
0052      * As per OMAP4460 TRM: http://www.ti.com/lit/ug/swpu235ab/swpu235ab.pdf
0053      * under section 23.12.6.2.2, Table 23-1213 OCP2SCP TIMING Caution;
0054      * As per OMAP543x TRM http://www.ti.com/lit/pdf/swpu249
0055      * under section 27.3.2.2, Table 27-27 OCP2SCP TIMING Caution;
0056      *
0057      * Read path of OCP2SCP is not working properly due to low reset value
0058      * of SYNC2 parameter in OCP2SCP. Suggested reset value is 0x6 or more.
0059      */
0060     if (!of_device_is_compatible(np, "ti,am437x-ocp2scp")) {
0061         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
0062         regs = devm_ioremap_resource(&pdev->dev, res);
0063         if (IS_ERR(regs)) {
0064             ret = PTR_ERR(regs);
0065             goto err1;
0066         }
0067 
0068         pm_runtime_get_sync(&pdev->dev);
0069         reg = readl_relaxed(regs + OCP2SCP_TIMING);
0070         reg &= ~(SYNC2_MASK);
0071         reg |= 0x6;
0072         writel_relaxed(reg, regs + OCP2SCP_TIMING);
0073         pm_runtime_put_sync(&pdev->dev);
0074     }
0075 
0076     return 0;
0077 
0078 err1:
0079     pm_runtime_disable(&pdev->dev);
0080 
0081 err0:
0082     device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices);
0083 
0084     return ret;
0085 }
0086 
0087 static int omap_ocp2scp_remove(struct platform_device *pdev)
0088 {
0089     pm_runtime_disable(&pdev->dev);
0090     device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices);
0091 
0092     return 0;
0093 }
0094 
0095 #ifdef CONFIG_OF
0096 static const struct of_device_id omap_ocp2scp_id_table[] = {
0097     { .compatible = "ti,omap-ocp2scp" },
0098     { .compatible = "ti,am437x-ocp2scp" },
0099     {}
0100 };
0101 MODULE_DEVICE_TABLE(of, omap_ocp2scp_id_table);
0102 #endif
0103 
0104 static struct platform_driver omap_ocp2scp_driver = {
0105     .probe      = omap_ocp2scp_probe,
0106     .remove     = omap_ocp2scp_remove,
0107     .driver     = {
0108         .name   = "omap-ocp2scp",
0109         .of_match_table = of_match_ptr(omap_ocp2scp_id_table),
0110     },
0111 };
0112 
0113 module_platform_driver(omap_ocp2scp_driver);
0114 
0115 MODULE_ALIAS("platform:omap-ocp2scp");
0116 MODULE_AUTHOR("Texas Instruments Inc.");
0117 MODULE_DESCRIPTION("OMAP OCP2SCP driver");
0118 MODULE_LICENSE("GPL v2");