162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * omap-ocp2scp.c - transform ocp interface protocol to scp protocol 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com 662306a36Sopenharmony_ci * Author: Kishon Vijay Abraham I <kishon@ti.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/io.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/platform_device.h> 1262306a36Sopenharmony_ci#include <linux/err.h> 1362306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1462306a36Sopenharmony_ci#include <linux/of.h> 1562306a36Sopenharmony_ci#include <linux/of_platform.h> 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define OCP2SCP_TIMING 0x18 1862306a36Sopenharmony_ci#define SYNC2_MASK 0xf 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_cistatic int ocp2scp_remove_devices(struct device *dev, void *c) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci platform_device_unregister(pdev); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci return 0; 2762306a36Sopenharmony_ci} 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic int omap_ocp2scp_probe(struct platform_device *pdev) 3062306a36Sopenharmony_ci{ 3162306a36Sopenharmony_ci int ret; 3262306a36Sopenharmony_ci u32 reg; 3362306a36Sopenharmony_ci void __iomem *regs; 3462306a36Sopenharmony_ci struct resource *res; 3562306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci if (np) { 3862306a36Sopenharmony_ci ret = of_platform_populate(np, NULL, NULL, &pdev->dev); 3962306a36Sopenharmony_ci if (ret) { 4062306a36Sopenharmony_ci dev_err(&pdev->dev, 4162306a36Sopenharmony_ci "failed to add resources for ocp2scp child\n"); 4262306a36Sopenharmony_ci goto err0; 4362306a36Sopenharmony_ci } 4462306a36Sopenharmony_ci } 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 4762306a36Sopenharmony_ci /* 4862306a36Sopenharmony_ci * As per AM572x TRM: http://www.ti.com/lit/ug/spruhz6/spruhz6.pdf 4962306a36Sopenharmony_ci * under section 26.3.2.2, table 26-26 OCP2SCP TIMING Caution; 5062306a36Sopenharmony_ci * As per OMAP4430 TRM: http://www.ti.com/lit/ug/swpu231ap/swpu231ap.pdf 5162306a36Sopenharmony_ci * under section 23.12.6.2.2 , Table 23-1213 OCP2SCP TIMING Caution; 5262306a36Sopenharmony_ci * As per OMAP4460 TRM: http://www.ti.com/lit/ug/swpu235ab/swpu235ab.pdf 5362306a36Sopenharmony_ci * under section 23.12.6.2.2, Table 23-1213 OCP2SCP TIMING Caution; 5462306a36Sopenharmony_ci * As per OMAP543x TRM http://www.ti.com/lit/pdf/swpu249 5562306a36Sopenharmony_ci * under section 27.3.2.2, Table 27-27 OCP2SCP TIMING Caution; 5662306a36Sopenharmony_ci * 5762306a36Sopenharmony_ci * Read path of OCP2SCP is not working properly due to low reset value 5862306a36Sopenharmony_ci * of SYNC2 parameter in OCP2SCP. Suggested reset value is 0x6 or more. 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_ci if (!of_device_is_compatible(np, "ti,am437x-ocp2scp")) { 6162306a36Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 6262306a36Sopenharmony_ci regs = devm_ioremap_resource(&pdev->dev, res); 6362306a36Sopenharmony_ci if (IS_ERR(regs)) { 6462306a36Sopenharmony_ci ret = PTR_ERR(regs); 6562306a36Sopenharmony_ci goto err1; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci pm_runtime_get_sync(&pdev->dev); 6962306a36Sopenharmony_ci reg = readl_relaxed(regs + OCP2SCP_TIMING); 7062306a36Sopenharmony_ci reg &= ~(SYNC2_MASK); 7162306a36Sopenharmony_ci reg |= 0x6; 7262306a36Sopenharmony_ci writel_relaxed(reg, regs + OCP2SCP_TIMING); 7362306a36Sopenharmony_ci pm_runtime_put_sync(&pdev->dev); 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci return 0; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cierr1: 7962306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cierr0: 8262306a36Sopenharmony_ci device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci return ret; 8562306a36Sopenharmony_ci} 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_cistatic int omap_ocp2scp_remove(struct platform_device *pdev) 8862306a36Sopenharmony_ci{ 8962306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 9062306a36Sopenharmony_ci device_for_each_child(&pdev->dev, NULL, ocp2scp_remove_devices); 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci return 0; 9362306a36Sopenharmony_ci} 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#ifdef CONFIG_OF 9662306a36Sopenharmony_cistatic const struct of_device_id omap_ocp2scp_id_table[] = { 9762306a36Sopenharmony_ci { .compatible = "ti,omap-ocp2scp" }, 9862306a36Sopenharmony_ci { .compatible = "ti,am437x-ocp2scp" }, 9962306a36Sopenharmony_ci {} 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, omap_ocp2scp_id_table); 10262306a36Sopenharmony_ci#endif 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic struct platform_driver omap_ocp2scp_driver = { 10562306a36Sopenharmony_ci .probe = omap_ocp2scp_probe, 10662306a36Sopenharmony_ci .remove = omap_ocp2scp_remove, 10762306a36Sopenharmony_ci .driver = { 10862306a36Sopenharmony_ci .name = "omap-ocp2scp", 10962306a36Sopenharmony_ci .of_match_table = of_match_ptr(omap_ocp2scp_id_table), 11062306a36Sopenharmony_ci }, 11162306a36Sopenharmony_ci}; 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_cimodule_platform_driver(omap_ocp2scp_driver); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ciMODULE_ALIAS("platform:omap-ocp2scp"); 11662306a36Sopenharmony_ciMODULE_AUTHOR("Texas Instruments Inc."); 11762306a36Sopenharmony_ciMODULE_DESCRIPTION("OMAP OCP2SCP driver"); 11862306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 119