2 * Copyright (c) 2015-2016 MediaTek Inc.
3 * Author: Yong Wu <yong.wu@mediatek.com>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 #include <linux/clk.h>
15 #include <linux/component.h>
16 #include <linux/device.h>
17 #include <linux/err.h>
20 #include <linux/of_platform.h>
21 #include <linux/platform_device.h>
22 #include <linux/pm_runtime.h>
23 #include <soc/mediatek/smi.h>
25 #define SMI_LARB_MMU_EN 0xf00
29 struct clk
*clk_apb
, *clk_smi
;
32 struct mtk_smi_larb
{ /* larb: local arbiter */
35 struct device
*smi_common_dev
;
39 static int mtk_smi_enable(const struct mtk_smi
*smi
)
43 ret
= pm_runtime_get_sync(smi
->dev
);
47 ret
= clk_prepare_enable(smi
->clk_apb
);
51 ret
= clk_prepare_enable(smi
->clk_smi
);
58 clk_disable_unprepare(smi
->clk_apb
);
60 pm_runtime_put_sync(smi
->dev
);
64 static void mtk_smi_disable(const struct mtk_smi
*smi
)
66 clk_disable_unprepare(smi
->clk_smi
);
67 clk_disable_unprepare(smi
->clk_apb
);
68 pm_runtime_put_sync(smi
->dev
);
71 int mtk_smi_larb_get(struct device
*larbdev
)
73 struct mtk_smi_larb
*larb
= dev_get_drvdata(larbdev
);
74 struct mtk_smi
*common
= dev_get_drvdata(larb
->smi_common_dev
);
77 /* Enable the smi-common's power and clocks */
78 ret
= mtk_smi_enable(common
);
82 /* Enable the larb's power and clocks */
83 ret
= mtk_smi_enable(&larb
->smi
);
85 mtk_smi_disable(common
);
89 /* Configure the iommu info for this larb */
90 writel(*larb
->mmu
, larb
->base
+ SMI_LARB_MMU_EN
);
94 EXPORT_SYMBOL_GPL(mtk_smi_larb_get
);
96 void mtk_smi_larb_put(struct device
*larbdev
)
98 struct mtk_smi_larb
*larb
= dev_get_drvdata(larbdev
);
99 struct mtk_smi
*common
= dev_get_drvdata(larb
->smi_common_dev
);
102 * Don't de-configure the iommu info for this larb since there may be
103 * several modules in this larb.
104 * The iommu info will be reset after power off.
107 mtk_smi_disable(&larb
->smi
);
108 mtk_smi_disable(common
);
110 EXPORT_SYMBOL_GPL(mtk_smi_larb_put
);
113 mtk_smi_larb_bind(struct device
*dev
, struct device
*master
, void *data
)
115 struct mtk_smi_larb
*larb
= dev_get_drvdata(dev
);
116 struct mtk_smi_iommu
*smi_iommu
= data
;
119 for (i
= 0; i
< smi_iommu
->larb_nr
; i
++) {
120 if (dev
== smi_iommu
->larb_imu
[i
].dev
) {
121 /* The 'mmu' may be updated in iommu-attach/detach. */
122 larb
->mmu
= &smi_iommu
->larb_imu
[i
].mmu
;
130 mtk_smi_larb_unbind(struct device
*dev
, struct device
*master
, void *data
)
132 /* Do nothing as the iommu is always enabled. */
135 static const struct component_ops mtk_smi_larb_component_ops
= {
136 .bind
= mtk_smi_larb_bind
,
137 .unbind
= mtk_smi_larb_unbind
,
140 static int mtk_smi_larb_probe(struct platform_device
*pdev
)
142 struct mtk_smi_larb
*larb
;
143 struct resource
*res
;
144 struct device
*dev
= &pdev
->dev
;
145 struct device_node
*smi_node
;
146 struct platform_device
*smi_pdev
;
149 return -EPROBE_DEFER
;
151 larb
= devm_kzalloc(dev
, sizeof(*larb
), GFP_KERNEL
);
155 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
156 larb
->base
= devm_ioremap_resource(dev
, res
);
157 if (IS_ERR(larb
->base
))
158 return PTR_ERR(larb
->base
);
160 larb
->smi
.clk_apb
= devm_clk_get(dev
, "apb");
161 if (IS_ERR(larb
->smi
.clk_apb
))
162 return PTR_ERR(larb
->smi
.clk_apb
);
164 larb
->smi
.clk_smi
= devm_clk_get(dev
, "smi");
165 if (IS_ERR(larb
->smi
.clk_smi
))
166 return PTR_ERR(larb
->smi
.clk_smi
);
169 smi_node
= of_parse_phandle(dev
->of_node
, "mediatek,smi", 0);
173 smi_pdev
= of_find_device_by_node(smi_node
);
174 of_node_put(smi_node
);
176 larb
->smi_common_dev
= &smi_pdev
->dev
;
178 dev_err(dev
, "Failed to get the smi_common device\n");
182 pm_runtime_enable(dev
);
183 platform_set_drvdata(pdev
, larb
);
184 return component_add(dev
, &mtk_smi_larb_component_ops
);
187 static int mtk_smi_larb_remove(struct platform_device
*pdev
)
189 pm_runtime_disable(&pdev
->dev
);
190 component_del(&pdev
->dev
, &mtk_smi_larb_component_ops
);
194 static const struct of_device_id mtk_smi_larb_of_ids
[] = {
195 { .compatible
= "mediatek,mt8173-smi-larb",},
199 static struct platform_driver mtk_smi_larb_driver
= {
200 .probe
= mtk_smi_larb_probe
,
201 .remove
= mtk_smi_larb_remove
,
203 .name
= "mtk-smi-larb",
204 .of_match_table
= mtk_smi_larb_of_ids
,
208 static int mtk_smi_common_probe(struct platform_device
*pdev
)
210 struct device
*dev
= &pdev
->dev
;
211 struct mtk_smi
*common
;
214 return -EPROBE_DEFER
;
216 common
= devm_kzalloc(dev
, sizeof(*common
), GFP_KERNEL
);
221 common
->clk_apb
= devm_clk_get(dev
, "apb");
222 if (IS_ERR(common
->clk_apb
))
223 return PTR_ERR(common
->clk_apb
);
225 common
->clk_smi
= devm_clk_get(dev
, "smi");
226 if (IS_ERR(common
->clk_smi
))
227 return PTR_ERR(common
->clk_smi
);
229 pm_runtime_enable(dev
);
230 platform_set_drvdata(pdev
, common
);
234 static int mtk_smi_common_remove(struct platform_device
*pdev
)
236 pm_runtime_disable(&pdev
->dev
);
240 static const struct of_device_id mtk_smi_common_of_ids
[] = {
241 { .compatible
= "mediatek,mt8173-smi-common", },
245 static struct platform_driver mtk_smi_common_driver
= {
246 .probe
= mtk_smi_common_probe
,
247 .remove
= mtk_smi_common_remove
,
249 .name
= "mtk-smi-common",
250 .of_match_table
= mtk_smi_common_of_ids
,
254 static int __init
mtk_smi_init(void)
258 ret
= platform_driver_register(&mtk_smi_common_driver
);
260 pr_err("Failed to register SMI driver\n");
264 ret
= platform_driver_register(&mtk_smi_larb_driver
);
266 pr_err("Failed to register SMI-LARB driver\n");
272 platform_driver_unregister(&mtk_smi_common_driver
);
275 subsys_initcall(mtk_smi_init
);