aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYaniv Gardi <ygardi@codeaurora.org>2015-10-28 07:15:49 -0400
committerMartin K. Petersen <martin.petersen@oracle.com>2015-11-09 18:00:02 -0500
commit47555a5c8a11a423e6767f942941c745766c99a2 (patch)
treeaabb08b80d01dc9e4d38e302a615fbafcf0ddeac
parent0263bcd0e8319642440fa29c184b0d7f4b2d5857 (diff)
scsi: ufs: make the UFS variant a platform device
This change turns the UFS variant (SCSI_UFS_QCOM) into a UFS a platform device. In order to do so a few additional changes are required: 1. The ufshcd-pltfrm is no longer serves as a platform device. Now it only serves as a group of platform APIs such as PM APIs (runtime suspend/resume, system suspend/resume etc), parsers of clocks, regulators and pm_levels from DT. 2. What used to be the old platform "probe" is now "only" a pltfrm_init() routine, that does exactly the same, but only being called by the new probe function of the UFS variant. Reviewed-by: Rob Herring <robherring2@gmail.com> Reviewed-by: Gilad Broner <gbroner@codeaurora.org> Signed-off-by: Yaniv Gardi <ygardi@codeaurora.org> Tested-by: Alim Akhtar <alim.akhtar@samsung.com> Reviewed-by: Hannes Reinecke <hare@suse.de> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--Documentation/devicetree/bindings/ufs/ufs-qcom.txt58
-rw-r--r--Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt11
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c62
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.c98
-rw-r--r--drivers/scsi/ufs/ufshcd-pltfrm.h41
-rw-r--r--drivers/scsi/ufs/ufshcd.c10
-rw-r--r--drivers/scsi/ufs/ufshcd.h1
7 files changed, 207 insertions, 74 deletions
diff --git a/Documentation/devicetree/bindings/ufs/ufs-qcom.txt b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt
new file mode 100644
index 000000000000..070baf4d7d97
--- /dev/null
+++ b/Documentation/devicetree/bindings/ufs/ufs-qcom.txt
@@ -0,0 +1,58 @@
1* Qualcomm Technologies Inc Universal Flash Storage (UFS) PHY
2
3UFSPHY nodes are defined to describe on-chip UFS PHY hardware macro.
4Each UFS PHY node should have its own node.
5
6To bind UFS PHY with UFS host controller, the controller node should
7contain a phandle reference to UFS PHY node.
8
9Required properties:
10- compatible : compatible list, contains "qcom,ufs-phy-qmp-20nm"
11 or "qcom,ufs-phy-qmp-14nm" according to the relevant phy in use.
12- reg : should contain PHY register address space (mandatory),
13- reg-names : indicates various resources passed to driver (via reg proptery) by name.
14 Required "reg-names" is "phy_mem".
15- #phy-cells : This property shall be set to 0
16- vdda-phy-supply : phandle to main PHY supply for analog domain
17- vdda-pll-supply : phandle to PHY PLL and Power-Gen block power supply
18- clocks : List of phandle and clock specifier pairs
19- clock-names : List of clock input name strings sorted in the same
20 order as the clocks property. "ref_clk_src", "ref_clk",
21 "tx_iface_clk" & "rx_iface_clk" are mandatory but
22 "ref_clk_parent" is optional
23
24Optional properties:
25- vdda-phy-max-microamp : specifies max. load that can be drawn from phy supply
26- vdda-pll-max-microamp : specifies max. load that can be drawn from pll supply
27- vddp-ref-clk-supply : phandle to UFS device ref_clk pad power supply
28- vddp-ref-clk-max-microamp : specifies max. load that can be drawn from this supply
29- vddp-ref-clk-always-on : specifies if this supply needs to be kept always on
30
31Example:
32
33 ufsphy1: ufsphy@0xfc597000 {
34 compatible = "qcom,ufs-phy-qmp-20nm";
35 reg = <0xfc597000 0x800>;
36 reg-names = "phy_mem";
37 #phy-cells = <0>;
38 vdda-phy-supply = <&pma8084_l4>;
39 vdda-pll-supply = <&pma8084_l12>;
40 vdda-phy-max-microamp = <50000>;
41 vdda-pll-max-microamp = <1000>;
42 clock-names = "ref_clk_src",
43 "ref_clk_parent",
44 "ref_clk",
45 "tx_iface_clk",
46 "rx_iface_clk";
47 clocks = <&clock_rpm clk_ln_bb_clk>,
48 <&clock_gcc clk_pcie_1_phy_ldo >,
49 <&clock_gcc clk_ufs_phy_ldo>,
50 <&clock_gcc clk_gcc_ufs_tx_cfg_clk>,
51 <&clock_gcc clk_gcc_ufs_rx_cfg_clk>;
52 };
53
54 ufshc@0xfc598000 {
55 ...
56 phys = <&ufsphy1>;
57 phy-names = "ufsphy";
58 };
diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
index 53579197eca2..03c0e989e020 100644
--- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
+++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
@@ -4,11 +4,18 @@ UFSHC nodes are defined to describe on-chip UFS host controllers.
4Each UFS controller instance should have its own node. 4Each UFS controller instance should have its own node.
5 5
6Required properties: 6Required properties:
7- compatible : compatible list, contains "jedec,ufs-1.1" 7- compatible : must contain "jedec,ufs-1.1", may also list one or more
8 of the following:
9 "qcom,msm8994-ufshc"
10 "qcom,msm8996-ufshc"
11 "qcom,ufshc"
8- interrupts : <interrupt mapping for UFS host controller IRQ> 12- interrupts : <interrupt mapping for UFS host controller IRQ>
9- reg : <registers mapping> 13- reg : <registers mapping>
10 14
11Optional properties: 15Optional properties:
16- phys : phandle to UFS PHY node
17- phy-names : the string "ufsphy" when is found in a node, along
18 with "phys" attribute, provides phandle to UFS PHY node
12- vdd-hba-supply : phandle to UFS host controller supply regulator node 19- vdd-hba-supply : phandle to UFS host controller supply regulator node
13- vcc-supply : phandle to VCC supply regulator node 20- vcc-supply : phandle to VCC supply regulator node
14- vccq-supply : phandle to VCCQ supply regulator node 21- vccq-supply : phandle to VCCQ supply regulator node
@@ -54,4 +61,6 @@ Example:
54 clocks = <&core 0>, <&ref 0>, <&iface 0>; 61 clocks = <&core 0>, <&ref 0>, <&iface 0>;
55 clock-names = "core_clk", "ref_clk", "iface_clk"; 62 clock-names = "core_clk", "ref_clk", "iface_clk";
56 freq-table-hz = <100000000 200000000>, <0 0>, <0 0>; 63 freq-table-hz = <100000000 200000000>, <0 0>, <0 0>;
64 phys = <&ufsphy1>;
65 phy-names = "ufsphy";
57 }; 66 };
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
index 329ac846befe..b275a9a3b4d5 100644
--- a/drivers/scsi/ufs/ufs-qcom.c
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -19,6 +19,7 @@
19 19
20#include <linux/phy/phy-qcom-ufs.h> 20#include <linux/phy/phy-qcom-ufs.h>
21#include "ufshcd.h" 21#include "ufshcd.h"
22#include "ufshcd-pltfrm.h"
22#include "unipro.h" 23#include "unipro.h"
23#include "ufs-qcom.h" 24#include "ufs-qcom.h"
24#include "ufshci.h" 25#include "ufshci.h"
@@ -1036,7 +1037,7 @@ void ufs_qcom_clk_scale_notify(struct ufs_hba *hba)
1036 * The variant operations configure the necessary controller and PHY 1037 * The variant operations configure the necessary controller and PHY
1037 * handshake during initialization. 1038 * handshake during initialization.
1038 */ 1039 */
1039static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { 1040static struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
1040 .name = "qcom", 1041 .name = "qcom",
1041 .init = ufs_qcom_init, 1042 .init = ufs_qcom_init,
1042 .exit = ufs_qcom_exit, 1043 .exit = ufs_qcom_exit,
@@ -1050,4 +1051,63 @@ static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
1050 .resume = ufs_qcom_resume, 1051 .resume = ufs_qcom_resume,
1051}; 1052};
1052 1053
1054/**
1055 * ufs_qcom_probe - probe routine of the driver
1056 * @pdev: pointer to Platform device handle
1057 *
1058 * Return zero for success and non-zero for failure
1059 */
1060static int ufs_qcom_probe(struct platform_device *pdev)
1061{
1062 int err;
1063 struct device *dev = &pdev->dev;
1064
1065 /* Perform generic probe */
1066 err = ufshcd_pltfrm_init(pdev, &ufs_hba_qcom_vops);
1067 if (err)
1068 dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err);
1069
1070 return err;
1071}
1072
1073/**
1074 * ufs_qcom_remove - set driver_data of the device to NULL
1075 * @pdev: pointer to platform device handle
1076 *
1077 * Always return 0
1078 */
1079static int ufs_qcom_remove(struct platform_device *pdev)
1080{
1081 struct ufs_hba *hba = platform_get_drvdata(pdev);
1082
1083 pm_runtime_get_sync(&(pdev)->dev);
1084 ufshcd_remove(hba);
1085 return 0;
1086}
1087
1088static const struct of_device_id ufs_qcom_of_match[] = {
1089 { .compatible = "qcom,ufshc"},
1090 {},
1091};
1092
1093static const struct dev_pm_ops ufs_qcom_pm_ops = {
1094 .suspend = ufshcd_pltfrm_suspend,
1095 .resume = ufshcd_pltfrm_resume,
1096 .runtime_suspend = ufshcd_pltfrm_runtime_suspend,
1097 .runtime_resume = ufshcd_pltfrm_runtime_resume,
1098 .runtime_idle = ufshcd_pltfrm_runtime_idle,
1099};
1100
1101static struct platform_driver ufs_qcom_pltform = {
1102 .probe = ufs_qcom_probe,
1103 .remove = ufs_qcom_remove,
1104 .shutdown = ufshcd_pltfrm_shutdown,
1105 .driver = {
1106 .name = "ufshcd-qcom",
1107 .pm = &ufs_qcom_pm_ops,
1108 .of_match_table = of_match_ptr(ufs_qcom_of_match),
1109 },
1110};
1111module_platform_driver(ufs_qcom_pltform);
1112
1053MODULE_LICENSE("GPL v2"); 1113MODULE_LICENSE("GPL v2");
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c
index 7db9564f507d..9714f2a8b329 100644
--- a/drivers/scsi/ufs/ufshcd-pltfrm.c
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.c
@@ -38,20 +38,7 @@
38#include <linux/of.h> 38#include <linux/of.h>
39 39
40#include "ufshcd.h" 40#include "ufshcd.h"
41 41#include "ufshcd-pltfrm.h"
42static const struct of_device_id ufs_of_match[];
43static struct ufs_hba_variant_ops *get_variant_ops(struct device *dev)
44{
45 if (dev->of_node) {
46 const struct of_device_id *match;
47
48 match = of_match_node(ufs_of_match, dev->of_node);
49 if (match)
50 return (struct ufs_hba_variant_ops *)match->data;
51 }
52
53 return NULL;
54}
55 42
56static int ufshcd_parse_clock_info(struct ufs_hba *hba) 43static int ufshcd_parse_clock_info(struct ufs_hba *hba)
57{ 44{
@@ -245,10 +232,11 @@ out:
245 * Returns 0 if successful 232 * Returns 0 if successful
246 * Returns non-zero otherwise 233 * Returns non-zero otherwise
247 */ 234 */
248static int ufshcd_pltfrm_suspend(struct device *dev) 235int ufshcd_pltfrm_suspend(struct device *dev)
249{ 236{
250 return ufshcd_system_suspend(dev_get_drvdata(dev)); 237 return ufshcd_system_suspend(dev_get_drvdata(dev));
251} 238}
239EXPORT_SYMBOL_GPL(ufshcd_pltfrm_suspend);
252 240
253/** 241/**
254 * ufshcd_pltfrm_resume - resume power management function 242 * ufshcd_pltfrm_resume - resume power management function
@@ -257,43 +245,47 @@ static int ufshcd_pltfrm_suspend(struct device *dev)
257 * Returns 0 if successful 245 * Returns 0 if successful
258 * Returns non-zero otherwise 246 * Returns non-zero otherwise
259 */ 247 */
260static int ufshcd_pltfrm_resume(struct device *dev) 248int ufshcd_pltfrm_resume(struct device *dev)
261{ 249{
262 return ufshcd_system_resume(dev_get_drvdata(dev)); 250 return ufshcd_system_resume(dev_get_drvdata(dev));
263} 251}
252EXPORT_SYMBOL_GPL(ufshcd_pltfrm_resume);
264 253
265static int ufshcd_pltfrm_runtime_suspend(struct device *dev) 254int ufshcd_pltfrm_runtime_suspend(struct device *dev)
266{ 255{
267 return ufshcd_runtime_suspend(dev_get_drvdata(dev)); 256 return ufshcd_runtime_suspend(dev_get_drvdata(dev));
268} 257}
269static int ufshcd_pltfrm_runtime_resume(struct device *dev) 258EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_suspend);
259
260int ufshcd_pltfrm_runtime_resume(struct device *dev)
270{ 261{
271 return ufshcd_runtime_resume(dev_get_drvdata(dev)); 262 return ufshcd_runtime_resume(dev_get_drvdata(dev));
272} 263}
273static int ufshcd_pltfrm_runtime_idle(struct device *dev) 264EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_resume);
265
266int ufshcd_pltfrm_runtime_idle(struct device *dev)
274{ 267{
275 return ufshcd_runtime_idle(dev_get_drvdata(dev)); 268 return ufshcd_runtime_idle(dev_get_drvdata(dev));
276} 269}
277#else /* !CONFIG_PM */ 270EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_idle);
278#define ufshcd_pltfrm_suspend NULL 271
279#define ufshcd_pltfrm_resume NULL
280#define ufshcd_pltfrm_runtime_suspend NULL
281#define ufshcd_pltfrm_runtime_resume NULL
282#define ufshcd_pltfrm_runtime_idle NULL
283#endif /* CONFIG_PM */ 272#endif /* CONFIG_PM */
284 273
285static void ufshcd_pltfrm_shutdown(struct platform_device *pdev) 274void ufshcd_pltfrm_shutdown(struct platform_device *pdev)
286{ 275{
287 ufshcd_shutdown((struct ufs_hba *)platform_get_drvdata(pdev)); 276 ufshcd_shutdown((struct ufs_hba *)platform_get_drvdata(pdev));
288} 277}
278EXPORT_SYMBOL_GPL(ufshcd_pltfrm_shutdown);
289 279
290/** 280/**
291 * ufshcd_pltfrm_probe - probe routine of the driver 281 * ufshcd_pltfrm_init - probe routine of the driver
292 * @pdev: pointer to Platform device handle 282 * @pdev: pointer to Platform device handle
283 * @vops: pointer to variant ops
293 * 284 *
294 * Returns 0 on success, non-zero value on failure 285 * Returns 0 on success, non-zero value on failure
295 */ 286 */
296static int ufshcd_pltfrm_probe(struct platform_device *pdev) 287int ufshcd_pltfrm_init(struct platform_device *pdev,
288 struct ufs_hba_variant_ops *vops)
297{ 289{
298 struct ufs_hba *hba; 290 struct ufs_hba *hba;
299 void __iomem *mmio_base; 291 void __iomem *mmio_base;
@@ -321,19 +313,19 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
321 goto out; 313 goto out;
322 } 314 }
323 315
324 hba->vops = get_variant_ops(&pdev->dev); 316 hba->vops = vops;
325 317
326 err = ufshcd_parse_clock_info(hba); 318 err = ufshcd_parse_clock_info(hba);
327 if (err) { 319 if (err) {
328 dev_err(&pdev->dev, "%s: clock parse failed %d\n", 320 dev_err(&pdev->dev, "%s: clock parse failed %d\n",
329 __func__, err); 321 __func__, err);
330 goto out; 322 goto dealloc_host;
331 } 323 }
332 err = ufshcd_parse_regulator_info(hba); 324 err = ufshcd_parse_regulator_info(hba);
333 if (err) { 325 if (err) {
334 dev_err(&pdev->dev, "%s: regulator init failed %d\n", 326 dev_err(&pdev->dev, "%s: regulator init failed %d\n",
335 __func__, err); 327 __func__, err);
336 goto out; 328 goto dealloc_host;
337 } 329 }
338 330
339 pm_runtime_set_active(&pdev->dev); 331 pm_runtime_set_active(&pdev->dev);
@@ -352,50 +344,12 @@ static int ufshcd_pltfrm_probe(struct platform_device *pdev)
352out_disable_rpm: 344out_disable_rpm:
353 pm_runtime_disable(&pdev->dev); 345 pm_runtime_disable(&pdev->dev);
354 pm_runtime_set_suspended(&pdev->dev); 346 pm_runtime_set_suspended(&pdev->dev);
347dealloc_host:
348 ufshcd_dealloc_host(hba);
355out: 349out:
356 return err; 350 return err;
357} 351}
358 352EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init);
359/**
360 * ufshcd_pltfrm_remove - remove platform driver routine
361 * @pdev: pointer to platform device handle
362 *
363 * Returns 0 on success, non-zero value on failure
364 */
365static int ufshcd_pltfrm_remove(struct platform_device *pdev)
366{
367 struct ufs_hba *hba = platform_get_drvdata(pdev);
368
369 pm_runtime_get_sync(&(pdev)->dev);
370 ufshcd_remove(hba);
371 return 0;
372}
373
374static const struct of_device_id ufs_of_match[] = {
375 { .compatible = "jedec,ufs-1.1"},
376 {},
377};
378
379static const struct dev_pm_ops ufshcd_dev_pm_ops = {
380 .suspend = ufshcd_pltfrm_suspend,
381 .resume = ufshcd_pltfrm_resume,
382 .runtime_suspend = ufshcd_pltfrm_runtime_suspend,
383 .runtime_resume = ufshcd_pltfrm_runtime_resume,
384 .runtime_idle = ufshcd_pltfrm_runtime_idle,
385};
386
387static struct platform_driver ufshcd_pltfrm_driver = {
388 .probe = ufshcd_pltfrm_probe,
389 .remove = ufshcd_pltfrm_remove,
390 .shutdown = ufshcd_pltfrm_shutdown,
391 .driver = {
392 .name = "ufshcd",
393 .pm = &ufshcd_dev_pm_ops,
394 .of_match_table = ufs_of_match,
395 },
396};
397
398module_platform_driver(ufshcd_pltfrm_driver);
399 353
400MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>"); 354MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
401MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>"); 355MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.h b/drivers/scsi/ufs/ufshcd-pltfrm.h
new file mode 100644
index 000000000000..df64c4180340
--- /dev/null
+++ b/drivers/scsi/ufs/ufshcd-pltfrm.h
@@ -0,0 +1,41 @@
1/* Copyright (c) 2015, The Linux Foundation. All rights reserved.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13
14#ifndef UFSHCD_PLTFRM_H_
15#define UFSHCD_PLTFRM_H_
16
17#include "ufshcd.h"
18
19int ufshcd_pltfrm_init(struct platform_device *pdev,
20 struct ufs_hba_variant_ops *vops);
21void ufshcd_pltfrm_shutdown(struct platform_device *pdev);
22
23#ifdef CONFIG_PM
24
25int ufshcd_pltfrm_suspend(struct device *dev);
26int ufshcd_pltfrm_resume(struct device *dev);
27int ufshcd_pltfrm_runtime_suspend(struct device *dev);
28int ufshcd_pltfrm_runtime_resume(struct device *dev);
29int ufshcd_pltfrm_runtime_idle(struct device *dev);
30
31#else /* !CONFIG_PM */
32
33#define ufshcd_pltfrm_suspend NULL
34#define ufshcd_pltfrm_resume NULL
35#define ufshcd_pltfrm_runtime_suspend NULL
36#define ufshcd_pltfrm_runtime_resume NULL
37#define ufshcd_pltfrm_runtime_idle NULL
38
39#endif /* CONFIG_PM */
40
41#endif /* UFSHCD_PLTFRM_H_ */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 9e79c33ea897..2ef98346dc6e 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5348,6 +5348,16 @@ void ufshcd_remove(struct ufs_hba *hba)
5348EXPORT_SYMBOL_GPL(ufshcd_remove); 5348EXPORT_SYMBOL_GPL(ufshcd_remove);
5349 5349
5350/** 5350/**
5351 * ufshcd_dealloc_host - deallocate Host Bus Adapter (HBA)
5352 * @hba: pointer to Host Bus Adapter (HBA)
5353 */
5354void ufshcd_dealloc_host(struct ufs_hba *hba)
5355{
5356 scsi_host_put(hba->host);
5357}
5358EXPORT_SYMBOL_GPL(ufshcd_dealloc_host);
5359
5360/**
5351 * ufshcd_set_dma_mask - Set dma mask based on the controller 5361 * ufshcd_set_dma_mask - Set dma mask based on the controller
5352 * addressing capability 5362 * addressing capability
5353 * @hba: per adapter instance 5363 * @hba: per adapter instance
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index ce756266b0af..f2aa47e15b13 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -576,6 +576,7 @@ static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg)
576} 576}
577 577
578int ufshcd_alloc_host(struct device *, struct ufs_hba **); 578int ufshcd_alloc_host(struct device *, struct ufs_hba **);
579void ufshcd_dealloc_host(struct ufs_hba *);
579int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int); 580int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int);
580void ufshcd_remove(struct ufs_hba *); 581void ufshcd_remove(struct ufs_hba *);
581 582