1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // |
3 | // Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ |
4 | // |
5 | |
6 | #include <linux/clk.h> |
7 | #include <linux/io.h> |
8 | #include <linux/kernel.h> |
9 | #include <linux/module.h> |
10 | #include <linux/of_platform.h> |
11 | #include <linux/platform_device.h> |
12 | #include <linux/pm_runtime.h> |
13 | |
14 | #define TI_UFS_SS_CTRL 0x4 |
15 | #define TI_UFS_SS_RST_N_PCS BIT(0) |
16 | #define TI_UFS_SS_CLK_26MHZ BIT(4) |
17 | |
18 | static int ti_j721e_ufs_probe(struct platform_device *pdev) |
19 | { |
20 | struct device *dev = &pdev->dev; |
21 | unsigned long clk_rate; |
22 | void __iomem *regbase; |
23 | struct clk *clk; |
24 | u32 reg = 0; |
25 | int ret; |
26 | |
27 | regbase = devm_platform_ioremap_resource(pdev, index: 0); |
28 | if (IS_ERR(ptr: regbase)) |
29 | return PTR_ERR(ptr: regbase); |
30 | |
31 | pm_runtime_enable(dev); |
32 | ret = pm_runtime_resume_and_get(dev); |
33 | if (ret < 0) |
34 | goto disable_pm; |
35 | |
36 | /* Select MPHY refclk frequency */ |
37 | clk = devm_clk_get(dev, NULL); |
38 | if (IS_ERR(ptr: clk)) { |
39 | ret = PTR_ERR(ptr: clk); |
40 | dev_err(dev, "Cannot claim MPHY clock.\n" ); |
41 | goto clk_err; |
42 | } |
43 | clk_rate = clk_get_rate(clk); |
44 | if (clk_rate == 26000000) |
45 | reg |= TI_UFS_SS_CLK_26MHZ; |
46 | devm_clk_put(dev, clk); |
47 | |
48 | /* Take UFS slave device out of reset */ |
49 | reg |= TI_UFS_SS_RST_N_PCS; |
50 | writel(val: reg, addr: regbase + TI_UFS_SS_CTRL); |
51 | |
52 | ret = of_platform_populate(root: pdev->dev.of_node, NULL, NULL, |
53 | parent: dev); |
54 | if (ret) { |
55 | dev_err(dev, "failed to populate child nodes %d\n" , ret); |
56 | goto clk_err; |
57 | } |
58 | |
59 | return ret; |
60 | |
61 | clk_err: |
62 | pm_runtime_put_sync(dev); |
63 | disable_pm: |
64 | pm_runtime_disable(dev); |
65 | return ret; |
66 | } |
67 | |
68 | static void ti_j721e_ufs_remove(struct platform_device *pdev) |
69 | { |
70 | of_platform_depopulate(parent: &pdev->dev); |
71 | pm_runtime_put_sync(dev: &pdev->dev); |
72 | pm_runtime_disable(dev: &pdev->dev); |
73 | } |
74 | |
75 | static const struct of_device_id ti_j721e_ufs_of_match[] = { |
76 | { |
77 | .compatible = "ti,j721e-ufs" , |
78 | }, |
79 | { }, |
80 | }; |
81 | |
82 | MODULE_DEVICE_TABLE(of, ti_j721e_ufs_of_match); |
83 | |
84 | static struct platform_driver ti_j721e_ufs_driver = { |
85 | .probe = ti_j721e_ufs_probe, |
86 | .remove_new = ti_j721e_ufs_remove, |
87 | .driver = { |
88 | .name = "ti-j721e-ufs" , |
89 | .of_match_table = ti_j721e_ufs_of_match, |
90 | }, |
91 | }; |
92 | module_platform_driver(ti_j721e_ufs_driver); |
93 | |
94 | MODULE_AUTHOR("Vignesh Raghavendra <vigneshr@ti.com>" ); |
95 | MODULE_DESCRIPTION("TI UFS host controller glue driver" ); |
96 | MODULE_LICENSE("GPL v2" ); |
97 | |