Commit | Line | Data |
---|---|---|
adaafaa3 YG |
1 | /* |
2 | * Copyright (c) 2013-2015, Linux Foundation. All rights reserved. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License version 2 and | |
6 | * only version 2 as published by the Free Software Foundation. | |
7 | * | |
8 | * This program is distributed in the hope that it will be useful, | |
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
11 | * GNU General Public License for more details. | |
12 | * | |
13 | */ | |
14 | ||
15 | #ifndef UFS_QCOM_PHY_I_H_ | |
16 | #define UFS_QCOM_PHY_I_H_ | |
17 | ||
39e794bf | 18 | #include <linux/module.h> |
adaafaa3 | 19 | #include <linux/clk.h> |
39e794bf | 20 | #include <linux/regulator/consumer.h> |
adaafaa3 | 21 | #include <linux/slab.h> |
39e794bf | 22 | #include <linux/phy/phy-qcom-ufs.h> |
adaafaa3 YG |
23 | #include <linux/platform_device.h> |
24 | #include <linux/io.h> | |
25 | #include <linux/delay.h> | |
26 | ||
39e794bf YG |
27 | #define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \ |
28 | ({ \ | |
29 | ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \ | |
30 | might_sleep_if(timeout_us); \ | |
31 | for (;;) { \ | |
32 | (val) = readl(addr); \ | |
33 | if (cond) \ | |
34 | break; \ | |
35 | if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \ | |
36 | (val) = readl(addr); \ | |
37 | break; \ | |
38 | } \ | |
39 | if (sleep_us) \ | |
40 | usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \ | |
41 | } \ | |
42 | (cond) ? 0 : -ETIMEDOUT; \ | |
43 | }) | |
44 | ||
45 | #define UFS_QCOM_PHY_CAL_ENTRY(reg, val) \ | |
46 | { \ | |
47 | .reg_offset = reg, \ | |
48 | .cfg_value = val, \ | |
49 | } | |
50 | ||
adaafaa3 YG |
51 | #define UFS_QCOM_PHY_NAME_LEN 30 |
52 | ||
39e794bf YG |
53 | enum { |
54 | MASK_SERDES_START = 0x1, | |
55 | MASK_PCS_READY = 0x1, | |
56 | }; | |
57 | ||
58 | enum { | |
59 | OFFSET_SERDES_START = 0x0, | |
60 | }; | |
61 | ||
62 | struct ufs_qcom_phy_stored_attributes { | |
63 | u32 att; | |
64 | u32 value; | |
65 | }; | |
66 | ||
67 | ||
adaafaa3 YG |
68 | struct ufs_qcom_phy_calibration { |
69 | u32 reg_offset; | |
70 | u32 cfg_value; | |
71 | }; | |
72 | ||
73 | struct ufs_qcom_phy_vreg { | |
74 | const char *name; | |
75 | struct regulator *reg; | |
76 | int max_uA; | |
77 | int min_uV; | |
78 | int max_uV; | |
79 | bool enabled; | |
80 | bool is_always_on; | |
81 | }; | |
82 | ||
83 | struct ufs_qcom_phy { | |
84 | struct list_head list; | |
85 | struct device *dev; | |
86 | void __iomem *mmio; | |
87 | void __iomem *dev_ref_clk_ctrl_mmio; | |
88 | struct clk *tx_iface_clk; | |
89 | struct clk *rx_iface_clk; | |
90 | bool is_iface_clk_enabled; | |
91 | struct clk *ref_clk_src; | |
92 | struct clk *ref_clk_parent; | |
93 | struct clk *ref_clk; | |
94 | bool is_ref_clk_enabled; | |
95 | bool is_dev_ref_clk_enabled; | |
96 | struct ufs_qcom_phy_vreg vdda_pll; | |
97 | struct ufs_qcom_phy_vreg vdda_phy; | |
98 | struct ufs_qcom_phy_vreg vddp_ref_clk; | |
99 | unsigned int quirks; | |
100 | ||
101 | /* | |
102 | * If UFS link is put into Hibern8 and if UFS PHY analog hardware is | |
103 | * power collapsed (by clearing UFS_PHY_POWER_DOWN_CONTROL), Hibern8 | |
104 | * exit might fail even after powering on UFS PHY analog hardware. | |
105 | * Enabling this quirk will help to solve above issue by doing | |
106 | * custom PHY settings just before PHY analog power collapse. | |
107 | */ | |
108 | #define UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE BIT(0) | |
109 | ||
110 | u8 host_ctrl_rev_major; | |
111 | u16 host_ctrl_rev_minor; | |
112 | u16 host_ctrl_rev_step; | |
113 | ||
114 | char name[UFS_QCOM_PHY_NAME_LEN]; | |
115 | struct ufs_qcom_phy_calibration *cached_regs; | |
116 | int cached_regs_table_size; | |
117 | bool is_powered_on; | |
118 | struct ufs_qcom_phy_specific_ops *phy_spec_ops; | |
119 | }; | |
120 | ||
121 | /** | |
122 | * struct ufs_qcom_phy_specific_ops - set of pointers to functions which have a | |
123 | * specific implementation per phy. Each UFS phy, should implement | |
124 | * those functions according to its spec and requirements | |
125 | * @calibrate_phy: pointer to a function that calibrate the phy | |
126 | * @start_serdes: pointer to a function that starts the serdes | |
127 | * @is_physical_coding_sublayer_ready: pointer to a function that | |
128 | * checks pcs readiness. returns 0 for success and non-zero for error. | |
129 | * @set_tx_lane_enable: pointer to a function that enable tx lanes | |
130 | * @power_control: pointer to a function that controls analog rail of phy | |
131 | * and writes to QSERDES_RX_SIGDET_CNTRL attribute | |
132 | */ | |
133 | struct ufs_qcom_phy_specific_ops { | |
134 | int (*calibrate_phy)(struct ufs_qcom_phy *phy, bool is_rate_B); | |
135 | void (*start_serdes)(struct ufs_qcom_phy *phy); | |
136 | int (*is_physical_coding_sublayer_ready)(struct ufs_qcom_phy *phy); | |
137 | void (*set_tx_lane_enable)(struct ufs_qcom_phy *phy, u32 val); | |
138 | void (*power_control)(struct ufs_qcom_phy *phy, bool val); | |
139 | }; | |
140 | ||
141 | struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy); | |
142 | int ufs_qcom_phy_power_on(struct phy *generic_phy); | |
143 | int ufs_qcom_phy_power_off(struct phy *generic_phy); | |
144 | int ufs_qcom_phy_exit(struct phy *generic_phy); | |
145 | int ufs_qcom_phy_init_clks(struct phy *generic_phy, | |
146 | struct ufs_qcom_phy *phy_common); | |
147 | int ufs_qcom_phy_init_vregulators(struct phy *generic_phy, | |
148 | struct ufs_qcom_phy *phy_common); | |
149 | int ufs_qcom_phy_remove(struct phy *generic_phy, | |
150 | struct ufs_qcom_phy *ufs_qcom_phy); | |
151 | struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev, | |
152 | struct ufs_qcom_phy *common_cfg, | |
153 | struct phy_ops *ufs_qcom_phy_gen_ops, | |
154 | struct ufs_qcom_phy_specific_ops *phy_spec_ops); | |
155 | int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy, | |
156 | struct ufs_qcom_phy_calibration *tbl_A, int tbl_size_A, | |
157 | struct ufs_qcom_phy_calibration *tbl_B, int tbl_size_B, | |
158 | bool is_rate_B); | |
159 | #endif |