18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PRU-ICSS platform driver for various TI SoCs 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014-2020 Texas Instruments Incorporated - http://www.ti.com/ 68c2ecf20Sopenharmony_ci * Author(s): 78c2ecf20Sopenharmony_ci * Suman Anna <s-anna@ti.com> 88c2ecf20Sopenharmony_ci * Andrew F. Davis <afd@ti.com> 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 128c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/of_address.h> 178c2ecf20Sopenharmony_ci#include <linux/of_device.h> 188c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 198c2ecf20Sopenharmony_ci#include <linux/pruss_driver.h> 208c2ecf20Sopenharmony_ci#include <linux/regmap.h> 218c2ecf20Sopenharmony_ci#include <linux/slab.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/** 248c2ecf20Sopenharmony_ci * struct pruss_private_data - PRUSS driver private data 258c2ecf20Sopenharmony_ci * @has_no_sharedram: flag to indicate the absence of PRUSS Shared Data RAM 268c2ecf20Sopenharmony_ci * @has_core_mux_clock: flag to indicate the presence of PRUSS core clock 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_cistruct pruss_private_data { 298c2ecf20Sopenharmony_ci bool has_no_sharedram; 308c2ecf20Sopenharmony_ci bool has_core_mux_clock; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic void pruss_of_free_clk_provider(void *data) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci struct device_node *clk_mux_np = data; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci of_clk_del_provider(clk_mux_np); 388c2ecf20Sopenharmony_ci of_node_put(clk_mux_np); 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic int pruss_clk_mux_setup(struct pruss *pruss, struct clk *clk_mux, 428c2ecf20Sopenharmony_ci char *mux_name, struct device_node *clks_np) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci struct device_node *clk_mux_np; 458c2ecf20Sopenharmony_ci struct device *dev = pruss->dev; 468c2ecf20Sopenharmony_ci char *clk_mux_name; 478c2ecf20Sopenharmony_ci unsigned int num_parents; 488c2ecf20Sopenharmony_ci const char **parent_names; 498c2ecf20Sopenharmony_ci void __iomem *reg; 508c2ecf20Sopenharmony_ci u32 reg_offset; 518c2ecf20Sopenharmony_ci int ret; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci clk_mux_np = of_get_child_by_name(clks_np, mux_name); 548c2ecf20Sopenharmony_ci if (!clk_mux_np) { 558c2ecf20Sopenharmony_ci dev_err(dev, "%pOF is missing its '%s' node\n", clks_np, 568c2ecf20Sopenharmony_ci mux_name); 578c2ecf20Sopenharmony_ci return -ENODEV; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci num_parents = of_clk_get_parent_count(clk_mux_np); 618c2ecf20Sopenharmony_ci if (num_parents < 1) { 628c2ecf20Sopenharmony_ci dev_err(dev, "mux-clock %pOF must have parents\n", clk_mux_np); 638c2ecf20Sopenharmony_ci ret = -EINVAL; 648c2ecf20Sopenharmony_ci goto put_clk_mux_np; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci parent_names = devm_kcalloc(dev, sizeof(*parent_names), num_parents, 688c2ecf20Sopenharmony_ci GFP_KERNEL); 698c2ecf20Sopenharmony_ci if (!parent_names) { 708c2ecf20Sopenharmony_ci ret = -ENOMEM; 718c2ecf20Sopenharmony_ci goto put_clk_mux_np; 728c2ecf20Sopenharmony_ci } 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci of_clk_parent_fill(clk_mux_np, parent_names, num_parents); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci clk_mux_name = devm_kasprintf(dev, GFP_KERNEL, "%s.%pOFn", 778c2ecf20Sopenharmony_ci dev_name(dev), clk_mux_np); 788c2ecf20Sopenharmony_ci if (!clk_mux_name) { 798c2ecf20Sopenharmony_ci ret = -ENOMEM; 808c2ecf20Sopenharmony_ci goto put_clk_mux_np; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci ret = of_property_read_u32(clk_mux_np, "reg", ®_offset); 848c2ecf20Sopenharmony_ci if (ret) 858c2ecf20Sopenharmony_ci goto put_clk_mux_np; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci reg = pruss->cfg_base + reg_offset; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci clk_mux = clk_register_mux(NULL, clk_mux_name, parent_names, 908c2ecf20Sopenharmony_ci num_parents, 0, reg, 0, 1, 0, NULL); 918c2ecf20Sopenharmony_ci if (IS_ERR(clk_mux)) { 928c2ecf20Sopenharmony_ci ret = PTR_ERR(clk_mux); 938c2ecf20Sopenharmony_ci goto put_clk_mux_np; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci ret = devm_add_action_or_reset(dev, (void(*)(void *))clk_unregister_mux, 978c2ecf20Sopenharmony_ci clk_mux); 988c2ecf20Sopenharmony_ci if (ret) { 998c2ecf20Sopenharmony_ci dev_err(dev, "failed to add clkmux unregister action %d", ret); 1008c2ecf20Sopenharmony_ci goto put_clk_mux_np; 1018c2ecf20Sopenharmony_ci } 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci ret = of_clk_add_provider(clk_mux_np, of_clk_src_simple_get, clk_mux); 1048c2ecf20Sopenharmony_ci if (ret) 1058c2ecf20Sopenharmony_ci goto put_clk_mux_np; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci ret = devm_add_action_or_reset(dev, pruss_of_free_clk_provider, 1088c2ecf20Sopenharmony_ci clk_mux_np); 1098c2ecf20Sopenharmony_ci if (ret) { 1108c2ecf20Sopenharmony_ci dev_err(dev, "failed to add clkmux free action %d", ret); 1118c2ecf20Sopenharmony_ci goto put_clk_mux_np; 1128c2ecf20Sopenharmony_ci } 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ciput_clk_mux_np: 1178c2ecf20Sopenharmony_ci of_node_put(clk_mux_np); 1188c2ecf20Sopenharmony_ci return ret; 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int pruss_clk_init(struct pruss *pruss, struct device_node *cfg_node) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci const struct pruss_private_data *data; 1248c2ecf20Sopenharmony_ci struct device_node *clks_np; 1258c2ecf20Sopenharmony_ci struct device *dev = pruss->dev; 1268c2ecf20Sopenharmony_ci int ret = 0; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci data = of_device_get_match_data(dev); 1298c2ecf20Sopenharmony_ci if (IS_ERR(data)) 1308c2ecf20Sopenharmony_ci return -ENODEV; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci clks_np = of_get_child_by_name(cfg_node, "clocks"); 1338c2ecf20Sopenharmony_ci if (!clks_np) { 1348c2ecf20Sopenharmony_ci dev_err(dev, "%pOF is missing its 'clocks' node\n", cfg_node); 1358c2ecf20Sopenharmony_ci return -ENODEV; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (data && data->has_core_mux_clock) { 1398c2ecf20Sopenharmony_ci ret = pruss_clk_mux_setup(pruss, pruss->core_clk_mux, 1408c2ecf20Sopenharmony_ci "coreclk-mux", clks_np); 1418c2ecf20Sopenharmony_ci if (ret) { 1428c2ecf20Sopenharmony_ci dev_err(dev, "failed to setup coreclk-mux\n"); 1438c2ecf20Sopenharmony_ci goto put_clks_node; 1448c2ecf20Sopenharmony_ci } 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci ret = pruss_clk_mux_setup(pruss, pruss->iep_clk_mux, "iepclk-mux", 1488c2ecf20Sopenharmony_ci clks_np); 1498c2ecf20Sopenharmony_ci if (ret) { 1508c2ecf20Sopenharmony_ci dev_err(dev, "failed to setup iepclk-mux\n"); 1518c2ecf20Sopenharmony_ci goto put_clks_node; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ciput_clks_node: 1558c2ecf20Sopenharmony_ci of_node_put(clks_np); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return ret; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic struct regmap_config regmap_conf = { 1618c2ecf20Sopenharmony_ci .reg_bits = 32, 1628c2ecf20Sopenharmony_ci .val_bits = 32, 1638c2ecf20Sopenharmony_ci .reg_stride = 4, 1648c2ecf20Sopenharmony_ci}; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int pruss_probe(struct platform_device *pdev) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 1698c2ecf20Sopenharmony_ci struct device_node *np = dev_of_node(dev); 1708c2ecf20Sopenharmony_ci struct device_node *child; 1718c2ecf20Sopenharmony_ci struct pruss *pruss; 1728c2ecf20Sopenharmony_ci struct resource res; 1738c2ecf20Sopenharmony_ci int ret, i, index; 1748c2ecf20Sopenharmony_ci const struct pruss_private_data *data; 1758c2ecf20Sopenharmony_ci const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" }; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci data = of_device_get_match_data(&pdev->dev); 1788c2ecf20Sopenharmony_ci if (IS_ERR(data)) { 1798c2ecf20Sopenharmony_ci dev_err(dev, "missing private data\n"); 1808c2ecf20Sopenharmony_ci return -ENODEV; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); 1848c2ecf20Sopenharmony_ci if (ret) { 1858c2ecf20Sopenharmony_ci dev_err(dev, "failed to set the DMA coherent mask"); 1868c2ecf20Sopenharmony_ci return ret; 1878c2ecf20Sopenharmony_ci } 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci pruss = devm_kzalloc(dev, sizeof(*pruss), GFP_KERNEL); 1908c2ecf20Sopenharmony_ci if (!pruss) 1918c2ecf20Sopenharmony_ci return -ENOMEM; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci pruss->dev = dev; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci child = of_get_child_by_name(np, "memories"); 1968c2ecf20Sopenharmony_ci if (!child) { 1978c2ecf20Sopenharmony_ci dev_err(dev, "%pOF is missing its 'memories' node\n", child); 1988c2ecf20Sopenharmony_ci return -ENODEV; 1998c2ecf20Sopenharmony_ci } 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci for (i = 0; i < PRUSS_MEM_MAX; i++) { 2028c2ecf20Sopenharmony_ci /* 2038c2ecf20Sopenharmony_ci * On AM437x one of two PRUSS units don't contain Shared RAM, 2048c2ecf20Sopenharmony_ci * skip it 2058c2ecf20Sopenharmony_ci */ 2068c2ecf20Sopenharmony_ci if (data && data->has_no_sharedram && i == PRUSS_MEM_SHRD_RAM2) 2078c2ecf20Sopenharmony_ci continue; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci index = of_property_match_string(child, "reg-names", 2108c2ecf20Sopenharmony_ci mem_names[i]); 2118c2ecf20Sopenharmony_ci if (index < 0) { 2128c2ecf20Sopenharmony_ci of_node_put(child); 2138c2ecf20Sopenharmony_ci return index; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci if (of_address_to_resource(child, index, &res)) { 2178c2ecf20Sopenharmony_ci of_node_put(child); 2188c2ecf20Sopenharmony_ci return -EINVAL; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci pruss->mem_regions[i].va = devm_ioremap(dev, res.start, 2228c2ecf20Sopenharmony_ci resource_size(&res)); 2238c2ecf20Sopenharmony_ci if (!pruss->mem_regions[i].va) { 2248c2ecf20Sopenharmony_ci dev_err(dev, "failed to parse and map memory resource %d %s\n", 2258c2ecf20Sopenharmony_ci i, mem_names[i]); 2268c2ecf20Sopenharmony_ci of_node_put(child); 2278c2ecf20Sopenharmony_ci return -ENOMEM; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci pruss->mem_regions[i].pa = res.start; 2308c2ecf20Sopenharmony_ci pruss->mem_regions[i].size = resource_size(&res); 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n", 2338c2ecf20Sopenharmony_ci mem_names[i], &pruss->mem_regions[i].pa, 2348c2ecf20Sopenharmony_ci pruss->mem_regions[i].size, pruss->mem_regions[i].va); 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci of_node_put(child); 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, pruss); 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 2418c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(dev); 2428c2ecf20Sopenharmony_ci if (ret < 0) { 2438c2ecf20Sopenharmony_ci dev_err(dev, "couldn't enable module\n"); 2448c2ecf20Sopenharmony_ci pm_runtime_put_noidle(dev); 2458c2ecf20Sopenharmony_ci goto rpm_disable; 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci child = of_get_child_by_name(np, "cfg"); 2498c2ecf20Sopenharmony_ci if (!child) { 2508c2ecf20Sopenharmony_ci dev_err(dev, "%pOF is missing its 'cfg' node\n", child); 2518c2ecf20Sopenharmony_ci ret = -ENODEV; 2528c2ecf20Sopenharmony_ci goto rpm_put; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci if (of_address_to_resource(child, 0, &res)) { 2568c2ecf20Sopenharmony_ci ret = -ENOMEM; 2578c2ecf20Sopenharmony_ci goto node_put; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci pruss->cfg_base = devm_ioremap(dev, res.start, resource_size(&res)); 2618c2ecf20Sopenharmony_ci if (!pruss->cfg_base) { 2628c2ecf20Sopenharmony_ci ret = -ENOMEM; 2638c2ecf20Sopenharmony_ci goto node_put; 2648c2ecf20Sopenharmony_ci } 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci regmap_conf.name = kasprintf(GFP_KERNEL, "%pOFn@%llx", child, 2678c2ecf20Sopenharmony_ci (u64)res.start); 2688c2ecf20Sopenharmony_ci regmap_conf.max_register = resource_size(&res) - 4; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci pruss->cfg_regmap = devm_regmap_init_mmio(dev, pruss->cfg_base, 2718c2ecf20Sopenharmony_ci ®map_conf); 2728c2ecf20Sopenharmony_ci kfree(regmap_conf.name); 2738c2ecf20Sopenharmony_ci if (IS_ERR(pruss->cfg_regmap)) { 2748c2ecf20Sopenharmony_ci dev_err(dev, "regmap_init_mmio failed for cfg, ret = %ld\n", 2758c2ecf20Sopenharmony_ci PTR_ERR(pruss->cfg_regmap)); 2768c2ecf20Sopenharmony_ci ret = PTR_ERR(pruss->cfg_regmap); 2778c2ecf20Sopenharmony_ci goto node_put; 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci ret = pruss_clk_init(pruss, child); 2818c2ecf20Sopenharmony_ci if (ret) { 2828c2ecf20Sopenharmony_ci dev_err(dev, "failed to setup coreclk-mux\n"); 2838c2ecf20Sopenharmony_ci goto node_put; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci ret = devm_of_platform_populate(dev); 2878c2ecf20Sopenharmony_ci if (ret) { 2888c2ecf20Sopenharmony_ci dev_err(dev, "failed to register child devices\n"); 2898c2ecf20Sopenharmony_ci goto node_put; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci of_node_put(child); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci return 0; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cinode_put: 2978c2ecf20Sopenharmony_ci of_node_put(child); 2988c2ecf20Sopenharmony_cirpm_put: 2998c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 3008c2ecf20Sopenharmony_cirpm_disable: 3018c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 3028c2ecf20Sopenharmony_ci return ret; 3038c2ecf20Sopenharmony_ci} 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_cistatic int pruss_remove(struct platform_device *pdev) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci devm_of_platform_depopulate(dev); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 3128c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci/* instance-specific driver private data */ 3188c2ecf20Sopenharmony_cistatic const struct pruss_private_data am437x_pruss1_data = { 3198c2ecf20Sopenharmony_ci .has_no_sharedram = false, 3208c2ecf20Sopenharmony_ci}; 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic const struct pruss_private_data am437x_pruss0_data = { 3238c2ecf20Sopenharmony_ci .has_no_sharedram = true, 3248c2ecf20Sopenharmony_ci}; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_cistatic const struct pruss_private_data am65x_j721e_pruss_data = { 3278c2ecf20Sopenharmony_ci .has_core_mux_clock = true, 3288c2ecf20Sopenharmony_ci}; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic const struct of_device_id pruss_of_match[] = { 3318c2ecf20Sopenharmony_ci { .compatible = "ti,am3356-pruss" }, 3328c2ecf20Sopenharmony_ci { .compatible = "ti,am4376-pruss0", .data = &am437x_pruss0_data, }, 3338c2ecf20Sopenharmony_ci { .compatible = "ti,am4376-pruss1", .data = &am437x_pruss1_data, }, 3348c2ecf20Sopenharmony_ci { .compatible = "ti,am5728-pruss" }, 3358c2ecf20Sopenharmony_ci { .compatible = "ti,k2g-pruss" }, 3368c2ecf20Sopenharmony_ci { .compatible = "ti,am654-icssg", .data = &am65x_j721e_pruss_data, }, 3378c2ecf20Sopenharmony_ci { .compatible = "ti,j721e-icssg", .data = &am65x_j721e_pruss_data, }, 3388c2ecf20Sopenharmony_ci {}, 3398c2ecf20Sopenharmony_ci}; 3408c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, pruss_of_match); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic struct platform_driver pruss_driver = { 3438c2ecf20Sopenharmony_ci .driver = { 3448c2ecf20Sopenharmony_ci .name = "pruss", 3458c2ecf20Sopenharmony_ci .of_match_table = pruss_of_match, 3468c2ecf20Sopenharmony_ci }, 3478c2ecf20Sopenharmony_ci .probe = pruss_probe, 3488c2ecf20Sopenharmony_ci .remove = pruss_remove, 3498c2ecf20Sopenharmony_ci}; 3508c2ecf20Sopenharmony_cimodule_platform_driver(pruss_driver); 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ciMODULE_AUTHOR("Suman Anna <s-anna@ti.com>"); 3538c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PRU-ICSS Subsystem Driver"); 3548c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 355