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
);
95 void mtk_smi_larb_put(struct device
*larbdev
)
97 struct mtk_smi_larb
*larb
= dev_get_drvdata(larbdev
);
98 struct mtk_smi
*common
= dev_get_drvdata(larb
->smi_common_dev
);
101 * Don't de-configure the iommu info for this larb since there may be
102 * several modules in this larb.
103 * The iommu info will be reset after power off.
106 mtk_smi_disable(&larb
->smi
);
107 mtk_smi_disable(common
);
111 mtk_smi_larb_bind(struct device
*dev
, struct device
*master
, void *data
)
113 struct mtk_smi_larb
*larb
= dev_get_drvdata(dev
);
114 struct mtk_smi_iommu
*smi_iommu
= data
;
117 for (i
= 0; i
< smi_iommu
->larb_nr
; i
++) {
118 if (dev
== smi_iommu
->larb_imu
[i
].dev
) {
119 /* The 'mmu' may be updated in iommu-attach/detach. */
120 larb
->mmu
= &smi_iommu
->larb_imu
[i
].mmu
;
128 mtk_smi_larb_unbind(struct device
*dev
, struct device
*master
, void *data
)
130 /* Do nothing as the iommu is always enabled. */
133 static const struct component_ops mtk_smi_larb_component_ops
= {
134 .bind
= mtk_smi_larb_bind
,
135 .unbind
= mtk_smi_larb_unbind
,
138 static int mtk_smi_larb_probe(struct platform_device
*pdev
)
140 struct mtk_smi_larb
*larb
;
141 struct resource
*res
;
142 struct device
*dev
= &pdev
->dev
;
143 struct device_node
*smi_node
;
144 struct platform_device
*smi_pdev
;
147 return -EPROBE_DEFER
;
149 larb
= devm_kzalloc(dev
, sizeof(*larb
), GFP_KERNEL
);
153 res
= platform_get_resource(pdev
, IORESOURCE_MEM
, 0);
154 larb
->base
= devm_ioremap_resource(dev
, res
);
155 if (IS_ERR(larb
->base
))
156 return PTR_ERR(larb
->base
);
158 larb
->smi
.clk_apb
= devm_clk_get(dev
, "apb");
159 if (IS_ERR(larb
->smi
.clk_apb
))
160 return PTR_ERR(larb
->smi
.clk_apb
);
162 larb
->smi
.clk_smi
= devm_clk_get(dev
, "smi");
163 if (IS_ERR(larb
->smi
.clk_smi
))
164 return PTR_ERR(larb
->smi
.clk_smi
);
167 smi_node
= of_parse_phandle(dev
->of_node
, "mediatek,smi", 0);
171 smi_pdev
= of_find_device_by_node(smi_node
);
172 of_node_put(smi_node
);
174 larb
->smi_common_dev
= &smi_pdev
->dev
;
176 dev_err(dev
, "Failed to get the smi_common device\n");
180 pm_runtime_enable(dev
);
181 platform_set_drvdata(pdev
, larb
);
182 return component_add(dev
, &mtk_smi_larb_component_ops
);
185 static int mtk_smi_larb_remove(struct platform_device
*pdev
)
187 pm_runtime_disable(&pdev
->dev
);
188 component_del(&pdev
->dev
, &mtk_smi_larb_component_ops
);
192 static const struct of_device_id mtk_smi_larb_of_ids
[] = {
193 { .compatible
= "mediatek,mt8173-smi-larb",},
197 static struct platform_driver mtk_smi_larb_driver
= {
198 .probe
= mtk_smi_larb_probe
,
199 .remove
= mtk_smi_larb_remove
,
201 .name
= "mtk-smi-larb",
202 .of_match_table
= mtk_smi_larb_of_ids
,
206 static int mtk_smi_common_probe(struct platform_device
*pdev
)
208 struct device
*dev
= &pdev
->dev
;
209 struct mtk_smi
*common
;
212 return -EPROBE_DEFER
;
214 common
= devm_kzalloc(dev
, sizeof(*common
), GFP_KERNEL
);
219 common
->clk_apb
= devm_clk_get(dev
, "apb");
220 if (IS_ERR(common
->clk_apb
))
221 return PTR_ERR(common
->clk_apb
);
223 common
->clk_smi
= devm_clk_get(dev
, "smi");
224 if (IS_ERR(common
->clk_smi
))
225 return PTR_ERR(common
->clk_smi
);
227 pm_runtime_enable(dev
);
228 platform_set_drvdata(pdev
, common
);
232 static int mtk_smi_common_remove(struct platform_device
*pdev
)
234 pm_runtime_disable(&pdev
->dev
);
238 static const struct of_device_id mtk_smi_common_of_ids
[] = {
239 { .compatible
= "mediatek,mt8173-smi-common", },
243 static struct platform_driver mtk_smi_common_driver
= {
244 .probe
= mtk_smi_common_probe
,
245 .remove
= mtk_smi_common_remove
,
247 .name
= "mtk-smi-common",
248 .of_match_table
= mtk_smi_common_of_ids
,
252 static int __init
mtk_smi_init(void)
256 ret
= platform_driver_register(&mtk_smi_common_driver
);
258 pr_err("Failed to register SMI driver\n");
262 ret
= platform_driver_register(&mtk_smi_larb_driver
);
264 pr_err("Failed to register SMI-LARB driver\n");
270 platform_driver_unregister(&mtk_smi_common_driver
);
273 subsys_initcall(mtk_smi_init
);