Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Yaniv Gardi and committed by
Martin K. Petersen
47555a5c 0263bcd0

+207 -74
+58
Documentation/devicetree/bindings/ufs/ufs-qcom.txt
··· 1 + * Qualcomm Technologies Inc Universal Flash Storage (UFS) PHY 2 + 3 + UFSPHY nodes are defined to describe on-chip UFS PHY hardware macro. 4 + Each UFS PHY node should have its own node. 5 + 6 + To bind UFS PHY with UFS host controller, the controller node should 7 + contain a phandle reference to UFS PHY node. 8 + 9 + Required 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 + 24 + Optional 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 + 31 + Example: 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 + };
+10 -1
Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt
··· 4 4 Each UFS controller instance should have its own node. 5 5 6 6 Required 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 12 - interrupts : <interrupt mapping for UFS host controller IRQ> 9 13 - reg : <registers mapping> 10 14 11 15 Optional 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 19 - vdd-hba-supply : phandle to UFS host controller supply regulator node 13 20 - vcc-supply : phandle to VCC supply regulator node 14 21 - vccq-supply : phandle to VCCQ supply regulator node ··· 61 54 clocks = <&core 0>, <&ref 0>, <&iface 0>; 62 55 clock-names = "core_clk", "ref_clk", "iface_clk"; 63 56 freq-table-hz = <100000000 200000000>, <0 0>, <0 0>; 57 + phys = <&ufsphy1>; 58 + phy-names = "ufsphy"; 64 59 };
+61 -1
drivers/scsi/ufs/ufs-qcom.c
··· 19 19 20 20 #include <linux/phy/phy-qcom-ufs.h> 21 21 #include "ufshcd.h" 22 + #include "ufshcd-pltfrm.h" 22 23 #include "unipro.h" 23 24 #include "ufs-qcom.h" 24 25 #include "ufshci.h" ··· 1037 1036 * The variant operations configure the necessary controller and PHY 1038 1037 * handshake during initialization. 1039 1038 */ 1040 - static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = { 1039 + static struct ufs_hba_variant_ops ufs_hba_qcom_vops = { 1041 1040 .name = "qcom", 1042 1041 .init = ufs_qcom_init, 1043 1042 .exit = ufs_qcom_exit, ··· 1050 1049 .suspend = ufs_qcom_suspend, 1051 1050 .resume = ufs_qcom_resume, 1052 1051 }; 1052 + 1053 + /** 1054 + * ufs_qcom_probe - probe routine of the driver 1055 + * @pdev: pointer to Platform device handle 1056 + * 1057 + * Return zero for success and non-zero for failure 1058 + */ 1059 + static int ufs_qcom_probe(struct platform_device *pdev) 1060 + { 1061 + int err; 1062 + struct device *dev = &pdev->dev; 1063 + 1064 + /* Perform generic probe */ 1065 + err = ufshcd_pltfrm_init(pdev, &ufs_hba_qcom_vops); 1066 + if (err) 1067 + dev_err(dev, "ufshcd_pltfrm_init() failed %d\n", err); 1068 + 1069 + return err; 1070 + } 1071 + 1072 + /** 1073 + * ufs_qcom_remove - set driver_data of the device to NULL 1074 + * @pdev: pointer to platform device handle 1075 + * 1076 + * Always return 0 1077 + */ 1078 + static int ufs_qcom_remove(struct platform_device *pdev) 1079 + { 1080 + struct ufs_hba *hba = platform_get_drvdata(pdev); 1081 + 1082 + pm_runtime_get_sync(&(pdev)->dev); 1083 + ufshcd_remove(hba); 1084 + return 0; 1085 + } 1086 + 1087 + static const struct of_device_id ufs_qcom_of_match[] = { 1088 + { .compatible = "qcom,ufshc"}, 1089 + {}, 1090 + }; 1091 + 1092 + static const struct dev_pm_ops ufs_qcom_pm_ops = { 1093 + .suspend = ufshcd_pltfrm_suspend, 1094 + .resume = ufshcd_pltfrm_resume, 1095 + .runtime_suspend = ufshcd_pltfrm_runtime_suspend, 1096 + .runtime_resume = ufshcd_pltfrm_runtime_resume, 1097 + .runtime_idle = ufshcd_pltfrm_runtime_idle, 1098 + }; 1099 + 1100 + static struct platform_driver ufs_qcom_pltform = { 1101 + .probe = ufs_qcom_probe, 1102 + .remove = ufs_qcom_remove, 1103 + .shutdown = ufshcd_pltfrm_shutdown, 1104 + .driver = { 1105 + .name = "ufshcd-qcom", 1106 + .pm = &ufs_qcom_pm_ops, 1107 + .of_match_table = of_match_ptr(ufs_qcom_of_match), 1108 + }, 1109 + }; 1110 + module_platform_driver(ufs_qcom_pltform); 1053 1111 1054 1112 MODULE_LICENSE("GPL v2");
+26 -72
drivers/scsi/ufs/ufshcd-pltfrm.c
··· 38 38 #include <linux/of.h> 39 39 40 40 #include "ufshcd.h" 41 - 42 - static const struct of_device_id ufs_of_match[]; 43 - static 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 - } 41 + #include "ufshcd-pltfrm.h" 55 42 56 43 static int ufshcd_parse_clock_info(struct ufs_hba *hba) 57 44 { ··· 232 245 * Returns 0 if successful 233 246 * Returns non-zero otherwise 234 247 */ 235 - static int ufshcd_pltfrm_suspend(struct device *dev) 248 + int ufshcd_pltfrm_suspend(struct device *dev) 236 249 { 237 250 return ufshcd_system_suspend(dev_get_drvdata(dev)); 238 251 } 252 + EXPORT_SYMBOL_GPL(ufshcd_pltfrm_suspend); 239 253 240 254 /** 241 255 * ufshcd_pltfrm_resume - resume power management function ··· 245 257 * Returns 0 if successful 246 258 * Returns non-zero otherwise 247 259 */ 248 - static int ufshcd_pltfrm_resume(struct device *dev) 260 + int ufshcd_pltfrm_resume(struct device *dev) 249 261 { 250 262 return ufshcd_system_resume(dev_get_drvdata(dev)); 251 263 } 264 + EXPORT_SYMBOL_GPL(ufshcd_pltfrm_resume); 252 265 253 - static int ufshcd_pltfrm_runtime_suspend(struct device *dev) 266 + int ufshcd_pltfrm_runtime_suspend(struct device *dev) 254 267 { 255 268 return ufshcd_runtime_suspend(dev_get_drvdata(dev)); 256 269 } 257 - static int ufshcd_pltfrm_runtime_resume(struct device *dev) 270 + EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_suspend); 271 + 272 + int ufshcd_pltfrm_runtime_resume(struct device *dev) 258 273 { 259 274 return ufshcd_runtime_resume(dev_get_drvdata(dev)); 260 275 } 261 - static int ufshcd_pltfrm_runtime_idle(struct device *dev) 276 + EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_resume); 277 + 278 + int ufshcd_pltfrm_runtime_idle(struct device *dev) 262 279 { 263 280 return ufshcd_runtime_idle(dev_get_drvdata(dev)); 264 281 } 265 - #else /* !CONFIG_PM */ 266 - #define ufshcd_pltfrm_suspend NULL 267 - #define ufshcd_pltfrm_resume NULL 268 - #define ufshcd_pltfrm_runtime_suspend NULL 269 - #define ufshcd_pltfrm_runtime_resume NULL 270 - #define ufshcd_pltfrm_runtime_idle NULL 282 + EXPORT_SYMBOL_GPL(ufshcd_pltfrm_runtime_idle); 283 + 271 284 #endif /* CONFIG_PM */ 272 285 273 - static void ufshcd_pltfrm_shutdown(struct platform_device *pdev) 286 + void ufshcd_pltfrm_shutdown(struct platform_device *pdev) 274 287 { 275 288 ufshcd_shutdown((struct ufs_hba *)platform_get_drvdata(pdev)); 276 289 } 290 + EXPORT_SYMBOL_GPL(ufshcd_pltfrm_shutdown); 277 291 278 292 /** 279 - * ufshcd_pltfrm_probe - probe routine of the driver 293 + * ufshcd_pltfrm_init - probe routine of the driver 280 294 * @pdev: pointer to Platform device handle 295 + * @vops: pointer to variant ops 281 296 * 282 297 * Returns 0 on success, non-zero value on failure 283 298 */ 284 - static int ufshcd_pltfrm_probe(struct platform_device *pdev) 299 + int ufshcd_pltfrm_init(struct platform_device *pdev, 300 + struct ufs_hba_variant_ops *vops) 285 301 { 286 302 struct ufs_hba *hba; 287 303 void __iomem *mmio_base; ··· 313 321 goto out; 314 322 } 315 323 316 - hba->vops = get_variant_ops(&pdev->dev); 324 + hba->vops = vops; 317 325 318 326 err = ufshcd_parse_clock_info(hba); 319 327 if (err) { 320 328 dev_err(&pdev->dev, "%s: clock parse failed %d\n", 321 329 __func__, err); 322 - goto out; 330 + goto dealloc_host; 323 331 } 324 332 err = ufshcd_parse_regulator_info(hba); 325 333 if (err) { 326 334 dev_err(&pdev->dev, "%s: regulator init failed %d\n", 327 335 __func__, err); 328 - goto out; 336 + goto dealloc_host; 329 337 } 330 338 331 339 pm_runtime_set_active(&pdev->dev); ··· 344 352 out_disable_rpm: 345 353 pm_runtime_disable(&pdev->dev); 346 354 pm_runtime_set_suspended(&pdev->dev); 355 + dealloc_host: 356 + ufshcd_dealloc_host(hba); 347 357 out: 348 358 return err; 349 359 } 350 - 351 - /** 352 - * ufshcd_pltfrm_remove - remove platform driver routine 353 - * @pdev: pointer to platform device handle 354 - * 355 - * Returns 0 on success, non-zero value on failure 356 - */ 357 - static int ufshcd_pltfrm_remove(struct platform_device *pdev) 358 - { 359 - struct ufs_hba *hba = platform_get_drvdata(pdev); 360 - 361 - pm_runtime_get_sync(&(pdev)->dev); 362 - ufshcd_remove(hba); 363 - return 0; 364 - } 365 - 366 - static const struct of_device_id ufs_of_match[] = { 367 - { .compatible = "jedec,ufs-1.1"}, 368 - {}, 369 - }; 370 - 371 - static const struct dev_pm_ops ufshcd_dev_pm_ops = { 372 - .suspend = ufshcd_pltfrm_suspend, 373 - .resume = ufshcd_pltfrm_resume, 374 - .runtime_suspend = ufshcd_pltfrm_runtime_suspend, 375 - .runtime_resume = ufshcd_pltfrm_runtime_resume, 376 - .runtime_idle = ufshcd_pltfrm_runtime_idle, 377 - }; 378 - 379 - static struct platform_driver ufshcd_pltfrm_driver = { 380 - .probe = ufshcd_pltfrm_probe, 381 - .remove = ufshcd_pltfrm_remove, 382 - .shutdown = ufshcd_pltfrm_shutdown, 383 - .driver = { 384 - .name = "ufshcd", 385 - .pm = &ufshcd_dev_pm_ops, 386 - .of_match_table = ufs_of_match, 387 - }, 388 - }; 389 - 390 - module_platform_driver(ufshcd_pltfrm_driver); 360 + EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init); 391 361 392 362 MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>"); 393 363 MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
+41
drivers/scsi/ufs/ufshcd-pltfrm.h
··· 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 + 19 + int ufshcd_pltfrm_init(struct platform_device *pdev, 20 + struct ufs_hba_variant_ops *vops); 21 + void ufshcd_pltfrm_shutdown(struct platform_device *pdev); 22 + 23 + #ifdef CONFIG_PM 24 + 25 + int ufshcd_pltfrm_suspend(struct device *dev); 26 + int ufshcd_pltfrm_resume(struct device *dev); 27 + int ufshcd_pltfrm_runtime_suspend(struct device *dev); 28 + int ufshcd_pltfrm_runtime_resume(struct device *dev); 29 + int 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_ */
+10
drivers/scsi/ufs/ufshcd.c
··· 5348 5348 EXPORT_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 + */ 5354 + void ufshcd_dealloc_host(struct ufs_hba *hba) 5355 + { 5356 + scsi_host_put(hba->host); 5357 + } 5358 + EXPORT_SYMBOL_GPL(ufshcd_dealloc_host); 5359 + 5360 + /** 5351 5361 * ufshcd_set_dma_mask - Set dma mask based on the controller 5352 5362 * addressing capability 5353 5363 * @hba: per adapter instance
+1
drivers/scsi/ufs/ufshcd.h
··· 576 576 } 577 577 578 578 int ufshcd_alloc_host(struct device *, struct ufs_hba **); 579 + void ufshcd_dealloc_host(struct ufs_hba *); 579 580 int ufshcd_init(struct ufs_hba * , void __iomem * , unsigned int); 580 581 void ufshcd_remove(struct ufs_hba *); 581 582