1dd11376bSBart Van Assche // SPDX-License-Identifier: GPL-2.0-or-later
2dd11376bSBart Van Assche /*
3dd11376bSBart Van Assche * Universal Flash Storage Host controller Platform bus based glue driver
4dd11376bSBart Van Assche * Copyright (C) 2011-2013 Samsung India Software Operations
5dd11376bSBart Van Assche *
6dd11376bSBart Van Assche * Authors:
7dd11376bSBart Van Assche * Santosh Yaraganavi <santosh.sy@samsung.com>
8dd11376bSBart Van Assche * Vinayak Holikatti <h.vinayak@samsung.com>
9dd11376bSBart Van Assche */
10dd11376bSBart Van Assche
11dd11376bSBart Van Assche #include <linux/module.h>
12dd11376bSBart Van Assche #include <linux/platform_device.h>
13dd11376bSBart Van Assche #include <linux/pm_runtime.h>
14dd11376bSBart Van Assche #include <linux/of.h>
15dd11376bSBart Van Assche
16dd11376bSBart Van Assche #include <ufs/ufshcd.h>
17dd11376bSBart Van Assche #include "ufshcd-pltfrm.h"
18dd11376bSBart Van Assche #include <ufs/unipro.h>
19dd11376bSBart Van Assche
20dd11376bSBart Van Assche #define UFSHCD_DEFAULT_LANES_PER_DIRECTION 2
21dd11376bSBart Van Assche
ufshcd_parse_clock_info(struct ufs_hba * hba)22dd11376bSBart Van Assche static int ufshcd_parse_clock_info(struct ufs_hba *hba)
23dd11376bSBart Van Assche {
24dd11376bSBart Van Assche int ret = 0;
25dd11376bSBart Van Assche int cnt;
26dd11376bSBart Van Assche int i;
27dd11376bSBart Van Assche struct device *dev = hba->dev;
28dd11376bSBart Van Assche struct device_node *np = dev->of_node;
29a48aac5dSKrzysztof Kozlowski const char *name;
30dd11376bSBart Van Assche u32 *clkfreq = NULL;
31dd11376bSBart Van Assche struct ufs_clk_info *clki;
32dd11376bSBart Van Assche int len = 0;
33dd11376bSBart Van Assche size_t sz = 0;
34dd11376bSBart Van Assche
35dd11376bSBart Van Assche if (!np)
36dd11376bSBart Van Assche goto out;
37dd11376bSBart Van Assche
38dd11376bSBart Van Assche cnt = of_property_count_strings(np, "clock-names");
39dd11376bSBart Van Assche if (!cnt || (cnt == -EINVAL)) {
40dd11376bSBart Van Assche dev_info(dev, "%s: Unable to find clocks, assuming enabled\n",
41dd11376bSBart Van Assche __func__);
42dd11376bSBart Van Assche } else if (cnt < 0) {
43dd11376bSBart Van Assche dev_err(dev, "%s: count clock strings failed, err %d\n",
44dd11376bSBart Van Assche __func__, cnt);
45dd11376bSBart Van Assche ret = cnt;
46dd11376bSBart Van Assche }
47dd11376bSBart Van Assche
48dd11376bSBart Van Assche if (cnt <= 0)
49dd11376bSBart Van Assche goto out;
50dd11376bSBart Van Assche
51dd11376bSBart Van Assche if (!of_get_property(np, "freq-table-hz", &len)) {
52dd11376bSBart Van Assche dev_info(dev, "freq-table-hz property not specified\n");
53dd11376bSBart Van Assche goto out;
54dd11376bSBart Van Assche }
55dd11376bSBart Van Assche
56dd11376bSBart Van Assche if (len <= 0)
57dd11376bSBart Van Assche goto out;
58dd11376bSBart Van Assche
59dd11376bSBart Van Assche sz = len / sizeof(*clkfreq);
60dd11376bSBart Van Assche if (sz != 2 * cnt) {
61dd11376bSBart Van Assche dev_err(dev, "%s len mismatch\n", "freq-table-hz");
62dd11376bSBart Van Assche ret = -EINVAL;
63dd11376bSBart Van Assche goto out;
64dd11376bSBart Van Assche }
65dd11376bSBart Van Assche
66dd11376bSBart Van Assche clkfreq = devm_kcalloc(dev, sz, sizeof(*clkfreq),
67dd11376bSBart Van Assche GFP_KERNEL);
68dd11376bSBart Van Assche if (!clkfreq) {
69dd11376bSBart Van Assche ret = -ENOMEM;
70dd11376bSBart Van Assche goto out;
71dd11376bSBart Van Assche }
72dd11376bSBart Van Assche
73dd11376bSBart Van Assche ret = of_property_read_u32_array(np, "freq-table-hz",
74dd11376bSBart Van Assche clkfreq, sz);
75dd11376bSBart Van Assche if (ret && (ret != -EINVAL)) {
76dd11376bSBart Van Assche dev_err(dev, "%s: error reading array %d\n",
77dd11376bSBart Van Assche "freq-table-hz", ret);
78dd11376bSBart Van Assche return ret;
79dd11376bSBart Van Assche }
80dd11376bSBart Van Assche
81dd11376bSBart Van Assche for (i = 0; i < sz; i += 2) {
82a48aac5dSKrzysztof Kozlowski ret = of_property_read_string_index(np, "clock-names", i/2,
83a48aac5dSKrzysztof Kozlowski &name);
84dd11376bSBart Van Assche if (ret)
85dd11376bSBart Van Assche goto out;
86dd11376bSBart Van Assche
87dd11376bSBart Van Assche clki = devm_kzalloc(dev, sizeof(*clki), GFP_KERNEL);
88dd11376bSBart Van Assche if (!clki) {
89dd11376bSBart Van Assche ret = -ENOMEM;
90dd11376bSBart Van Assche goto out;
91dd11376bSBart Van Assche }
92dd11376bSBart Van Assche
93dd11376bSBart Van Assche clki->min_freq = clkfreq[i];
94dd11376bSBart Van Assche clki->max_freq = clkfreq[i+1];
95dd11376bSBart Van Assche clki->name = devm_kstrdup(dev, name, GFP_KERNEL);
96dd11376bSBart Van Assche if (!clki->name) {
97dd11376bSBart Van Assche ret = -ENOMEM;
98dd11376bSBart Van Assche goto out;
99dd11376bSBart Van Assche }
100dd11376bSBart Van Assche
101dd11376bSBart Van Assche if (!strcmp(name, "ref_clk"))
102dd11376bSBart Van Assche clki->keep_link_active = true;
103dd11376bSBart Van Assche dev_dbg(dev, "%s: min %u max %u name %s\n", "freq-table-hz",
104dd11376bSBart Van Assche clki->min_freq, clki->max_freq, clki->name);
105dd11376bSBart Van Assche list_add_tail(&clki->list, &hba->clk_list_head);
106dd11376bSBart Van Assche }
107dd11376bSBart Van Assche out:
108dd11376bSBart Van Assche return ret;
109dd11376bSBart Van Assche }
110dd11376bSBart Van Assche
phandle_exists(const struct device_node * np,const char * phandle_name,int index)111a3435afbSLiang He static bool phandle_exists(const struct device_node *np,
112a3435afbSLiang He const char *phandle_name, int index)
113a3435afbSLiang He {
114a3435afbSLiang He struct device_node *parse_np = of_parse_phandle(np, phandle_name, index);
115a3435afbSLiang He
116a3435afbSLiang He if (parse_np)
117a3435afbSLiang He of_node_put(parse_np);
118a3435afbSLiang He
119a3435afbSLiang He return parse_np != NULL;
120a3435afbSLiang He }
121a3435afbSLiang He
122dd11376bSBart Van Assche #define MAX_PROP_SIZE 32
ufshcd_populate_vreg(struct device * dev,const char * name,struct ufs_vreg ** out_vreg)1231d6f9decSStanley Chu int ufshcd_populate_vreg(struct device *dev, const char *name,
124dd11376bSBart Van Assche struct ufs_vreg **out_vreg)
125dd11376bSBart Van Assche {
126dd11376bSBart Van Assche char prop_name[MAX_PROP_SIZE];
127dd11376bSBart Van Assche struct ufs_vreg *vreg = NULL;
128dd11376bSBart Van Assche struct device_node *np = dev->of_node;
129dd11376bSBart Van Assche
130dd11376bSBart Van Assche if (!np) {
131dd11376bSBart Van Assche dev_err(dev, "%s: non DT initialization\n", __func__);
132dd11376bSBart Van Assche goto out;
133dd11376bSBart Van Assche }
134dd11376bSBart Van Assche
135dd11376bSBart Van Assche snprintf(prop_name, MAX_PROP_SIZE, "%s-supply", name);
136a3435afbSLiang He if (!phandle_exists(np, prop_name, 0)) {
137dd11376bSBart Van Assche dev_info(dev, "%s: Unable to find %s regulator, assuming enabled\n",
138dd11376bSBart Van Assche __func__, prop_name);
139dd11376bSBart Van Assche goto out;
140dd11376bSBart Van Assche }
141dd11376bSBart Van Assche
142dd11376bSBart Van Assche vreg = devm_kzalloc(dev, sizeof(*vreg), GFP_KERNEL);
143dd11376bSBart Van Assche if (!vreg)
144dd11376bSBart Van Assche return -ENOMEM;
145dd11376bSBart Van Assche
146dd11376bSBart Van Assche vreg->name = devm_kstrdup(dev, name, GFP_KERNEL);
147dd11376bSBart Van Assche if (!vreg->name)
148dd11376bSBart Van Assche return -ENOMEM;
149dd11376bSBart Van Assche
150dd11376bSBart Van Assche snprintf(prop_name, MAX_PROP_SIZE, "%s-max-microamp", name);
151dd11376bSBart Van Assche if (of_property_read_u32(np, prop_name, &vreg->max_uA)) {
152dd11376bSBart Van Assche dev_info(dev, "%s: unable to find %s\n", __func__, prop_name);
153dd11376bSBart Van Assche vreg->max_uA = 0;
154dd11376bSBart Van Assche }
155dd11376bSBart Van Assche out:
156dd11376bSBart Van Assche *out_vreg = vreg;
157dd11376bSBart Van Assche return 0;
158dd11376bSBart Van Assche }
1591d6f9decSStanley Chu EXPORT_SYMBOL_GPL(ufshcd_populate_vreg);
160dd11376bSBart Van Assche
161dd11376bSBart Van Assche /**
162dd11376bSBart Van Assche * ufshcd_parse_regulator_info - get regulator info from device tree
163dd11376bSBart Van Assche * @hba: per adapter instance
164dd11376bSBart Van Assche *
165dd11376bSBart Van Assche * Get regulator info from device tree for vcc, vccq, vccq2 power supplies.
166dd11376bSBart Van Assche * If any of the supplies are not defined it is assumed that they are always-on
167dd11376bSBart Van Assche * and hence return zero. If the property is defined but parsing is failed
168dd11376bSBart Van Assche * then return corresponding error.
169fd4bffb5SBart Van Assche *
170fd4bffb5SBart Van Assche * Return: 0 upon success; < 0 upon failure.
171dd11376bSBart Van Assche */
ufshcd_parse_regulator_info(struct ufs_hba * hba)172dd11376bSBart Van Assche static int ufshcd_parse_regulator_info(struct ufs_hba *hba)
173dd11376bSBart Van Assche {
174dd11376bSBart Van Assche int err;
175dd11376bSBart Van Assche struct device *dev = hba->dev;
176dd11376bSBart Van Assche struct ufs_vreg_info *info = &hba->vreg_info;
177dd11376bSBart Van Assche
178dd11376bSBart Van Assche err = ufshcd_populate_vreg(dev, "vdd-hba", &info->vdd_hba);
179dd11376bSBart Van Assche if (err)
180dd11376bSBart Van Assche goto out;
181dd11376bSBart Van Assche
182dd11376bSBart Van Assche err = ufshcd_populate_vreg(dev, "vcc", &info->vcc);
183dd11376bSBart Van Assche if (err)
184dd11376bSBart Van Assche goto out;
185dd11376bSBart Van Assche
186dd11376bSBart Van Assche err = ufshcd_populate_vreg(dev, "vccq", &info->vccq);
187dd11376bSBart Van Assche if (err)
188dd11376bSBart Van Assche goto out;
189dd11376bSBart Van Assche
190dd11376bSBart Van Assche err = ufshcd_populate_vreg(dev, "vccq2", &info->vccq2);
191dd11376bSBart Van Assche out:
192dd11376bSBart Van Assche return err;
193dd11376bSBart Van Assche }
194dd11376bSBart Van Assche
ufshcd_init_lanes_per_dir(struct ufs_hba * hba)195dd11376bSBart Van Assche static void ufshcd_init_lanes_per_dir(struct ufs_hba *hba)
196dd11376bSBart Van Assche {
197dd11376bSBart Van Assche struct device *dev = hba->dev;
198dd11376bSBart Van Assche int ret;
199dd11376bSBart Van Assche
200dd11376bSBart Van Assche ret = of_property_read_u32(dev->of_node, "lanes-per-direction",
201dd11376bSBart Van Assche &hba->lanes_per_direction);
202dd11376bSBart Van Assche if (ret) {
203dd11376bSBart Van Assche dev_dbg(hba->dev,
204dd11376bSBart Van Assche "%s: failed to read lanes-per-direction, ret=%d\n",
205dd11376bSBart Van Assche __func__, ret);
206dd11376bSBart Van Assche hba->lanes_per_direction = UFSHCD_DEFAULT_LANES_PER_DIRECTION;
207dd11376bSBart Van Assche }
208dd11376bSBart Van Assche }
209dd11376bSBart Van Assche
210dd11376bSBart Van Assche /**
211dd11376bSBart Van Assche * ufshcd_get_pwr_dev_param - get finally agreed attributes for
212dd11376bSBart Van Assche * power mode change
213dd11376bSBart Van Assche * @pltfrm_param: pointer to platform parameters
214dd11376bSBart Van Assche * @dev_max: pointer to device attributes
215dd11376bSBart Van Assche * @agreed_pwr: returned agreed attributes
216dd11376bSBart Van Assche *
2173a17fefeSBart Van Assche * Return: 0 on success, non-zero value on failure.
218dd11376bSBart Van Assche */
ufshcd_get_pwr_dev_param(const struct ufs_dev_params * pltfrm_param,const struct ufs_pa_layer_attr * dev_max,struct ufs_pa_layer_attr * agreed_pwr)219a48aac5dSKrzysztof Kozlowski int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param,
220a48aac5dSKrzysztof Kozlowski const struct ufs_pa_layer_attr *dev_max,
221dd11376bSBart Van Assche struct ufs_pa_layer_attr *agreed_pwr)
222dd11376bSBart Van Assche {
223dd11376bSBart Van Assche int min_pltfrm_gear;
224dd11376bSBart Van Assche int min_dev_gear;
225dd11376bSBart Van Assche bool is_dev_sup_hs = false;
226dd11376bSBart Van Assche bool is_pltfrm_max_hs = false;
227dd11376bSBart Van Assche
228dd11376bSBart Van Assche if (dev_max->pwr_rx == FAST_MODE)
229dd11376bSBart Van Assche is_dev_sup_hs = true;
230dd11376bSBart Van Assche
231dd11376bSBart Van Assche if (pltfrm_param->desired_working_mode == UFS_HS_MODE) {
232dd11376bSBart Van Assche is_pltfrm_max_hs = true;
233dd11376bSBart Van Assche min_pltfrm_gear = min_t(u32, pltfrm_param->hs_rx_gear,
234dd11376bSBart Van Assche pltfrm_param->hs_tx_gear);
235dd11376bSBart Van Assche } else {
236dd11376bSBart Van Assche min_pltfrm_gear = min_t(u32, pltfrm_param->pwm_rx_gear,
237dd11376bSBart Van Assche pltfrm_param->pwm_tx_gear);
238dd11376bSBart Van Assche }
239dd11376bSBart Van Assche
240dd11376bSBart Van Assche /*
241dd11376bSBart Van Assche * device doesn't support HS but
242dd11376bSBart Van Assche * pltfrm_param->desired_working_mode is HS,
243dd11376bSBart Van Assche * thus device and pltfrm_param don't agree
244dd11376bSBart Van Assche */
245dd11376bSBart Van Assche if (!is_dev_sup_hs && is_pltfrm_max_hs) {
246dd11376bSBart Van Assche pr_info("%s: device doesn't support HS\n",
247dd11376bSBart Van Assche __func__);
248dd11376bSBart Van Assche return -ENOTSUPP;
249dd11376bSBart Van Assche } else if (is_dev_sup_hs && is_pltfrm_max_hs) {
250dd11376bSBart Van Assche /*
251dd11376bSBart Van Assche * since device supports HS, it supports FAST_MODE.
252dd11376bSBart Van Assche * since pltfrm_param->desired_working_mode is also HS
253dd11376bSBart Van Assche * then final decision (FAST/FASTAUTO) is done according
254dd11376bSBart Van Assche * to pltfrm_params as it is the restricting factor
255dd11376bSBart Van Assche */
256dd11376bSBart Van Assche agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_hs;
257dd11376bSBart Van Assche agreed_pwr->pwr_tx = agreed_pwr->pwr_rx;
258dd11376bSBart Van Assche } else {
259dd11376bSBart Van Assche /*
260dd11376bSBart Van Assche * here pltfrm_param->desired_working_mode is PWM.
261dd11376bSBart Van Assche * it doesn't matter whether device supports HS or PWM,
262dd11376bSBart Van Assche * in both cases pltfrm_param->desired_working_mode will
263dd11376bSBart Van Assche * determine the mode
264dd11376bSBart Van Assche */
265dd11376bSBart Van Assche agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_pwm;
266dd11376bSBart Van Assche agreed_pwr->pwr_tx = agreed_pwr->pwr_rx;
267dd11376bSBart Van Assche }
268dd11376bSBart Van Assche
269dd11376bSBart Van Assche /*
270dd11376bSBart Van Assche * we would like tx to work in the minimum number of lanes
271dd11376bSBart Van Assche * between device capability and vendor preferences.
272dd11376bSBart Van Assche * the same decision will be made for rx
273dd11376bSBart Van Assche */
274dd11376bSBart Van Assche agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx,
275dd11376bSBart Van Assche pltfrm_param->tx_lanes);
276dd11376bSBart Van Assche agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx,
277dd11376bSBart Van Assche pltfrm_param->rx_lanes);
278dd11376bSBart Van Assche
279dd11376bSBart Van Assche /* device maximum gear is the minimum between device rx and tx gears */
280dd11376bSBart Van Assche min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx);
281dd11376bSBart Van Assche
282dd11376bSBart Van Assche /*
283dd11376bSBart Van Assche * if both device capabilities and vendor pre-defined preferences are
284dd11376bSBart Van Assche * both HS or both PWM then set the minimum gear to be the chosen
285dd11376bSBart Van Assche * working gear.
286dd11376bSBart Van Assche * if one is PWM and one is HS then the one that is PWM get to decide
287dd11376bSBart Van Assche * what is the gear, as it is the one that also decided previously what
288dd11376bSBart Van Assche * pwr the device will be configured to.
289dd11376bSBart Van Assche */
290dd11376bSBart Van Assche if ((is_dev_sup_hs && is_pltfrm_max_hs) ||
291dd11376bSBart Van Assche (!is_dev_sup_hs && !is_pltfrm_max_hs)) {
292dd11376bSBart Van Assche agreed_pwr->gear_rx =
293dd11376bSBart Van Assche min_t(u32, min_dev_gear, min_pltfrm_gear);
294dd11376bSBart Van Assche } else if (!is_dev_sup_hs) {
295dd11376bSBart Van Assche agreed_pwr->gear_rx = min_dev_gear;
296dd11376bSBart Van Assche } else {
297dd11376bSBart Van Assche agreed_pwr->gear_rx = min_pltfrm_gear;
298dd11376bSBart Van Assche }
299dd11376bSBart Van Assche agreed_pwr->gear_tx = agreed_pwr->gear_rx;
300dd11376bSBart Van Assche
301dd11376bSBart Van Assche agreed_pwr->hs_rate = pltfrm_param->hs_rate;
302dd11376bSBart Van Assche
303dd11376bSBart Van Assche return 0;
304dd11376bSBart Van Assche }
305dd11376bSBart Van Assche EXPORT_SYMBOL_GPL(ufshcd_get_pwr_dev_param);
306dd11376bSBart Van Assche
ufshcd_init_pwr_dev_param(struct ufs_dev_params * dev_param)307dd11376bSBart Van Assche void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param)
308dd11376bSBart Van Assche {
309dd11376bSBart Van Assche *dev_param = (struct ufs_dev_params){
310e0d01da2SManivannan Sadhasivam .tx_lanes = UFS_LANE_2,
311e0d01da2SManivannan Sadhasivam .rx_lanes = UFS_LANE_2,
312dd11376bSBart Van Assche .hs_rx_gear = UFS_HS_G3,
313dd11376bSBart Van Assche .hs_tx_gear = UFS_HS_G3,
314dd11376bSBart Van Assche .pwm_rx_gear = UFS_PWM_G4,
315dd11376bSBart Van Assche .pwm_tx_gear = UFS_PWM_G4,
316dd11376bSBart Van Assche .rx_pwr_pwm = SLOW_MODE,
317dd11376bSBart Van Assche .tx_pwr_pwm = SLOW_MODE,
318dd11376bSBart Van Assche .rx_pwr_hs = FAST_MODE,
319dd11376bSBart Van Assche .tx_pwr_hs = FAST_MODE,
320dd11376bSBart Van Assche .hs_rate = PA_HS_MODE_B,
321dd11376bSBart Van Assche .desired_working_mode = UFS_HS_MODE,
322dd11376bSBart Van Assche };
323dd11376bSBart Van Assche }
324dd11376bSBart Van Assche EXPORT_SYMBOL_GPL(ufshcd_init_pwr_dev_param);
325dd11376bSBart Van Assche
326dd11376bSBart Van Assche /**
327dd11376bSBart Van Assche * ufshcd_pltfrm_init - probe routine of the driver
328dd11376bSBart Van Assche * @pdev: pointer to Platform device handle
329dd11376bSBart Van Assche * @vops: pointer to variant ops
330dd11376bSBart Van Assche *
3313a17fefeSBart Van Assche * Return: 0 on success, non-zero value on failure.
332dd11376bSBart Van Assche */
ufshcd_pltfrm_init(struct platform_device * pdev,const struct ufs_hba_variant_ops * vops)333dd11376bSBart Van Assche int ufshcd_pltfrm_init(struct platform_device *pdev,
334dd11376bSBart Van Assche const struct ufs_hba_variant_ops *vops)
335dd11376bSBart Van Assche {
336dd11376bSBart Van Assche struct ufs_hba *hba;
337dd11376bSBart Van Assche void __iomem *mmio_base;
338dd11376bSBart Van Assche int irq, err;
339dd11376bSBart Van Assche struct device *dev = &pdev->dev;
340dd11376bSBart Van Assche
341dd11376bSBart Van Assche mmio_base = devm_platform_ioremap_resource(pdev, 0);
342dd11376bSBart Van Assche if (IS_ERR(mmio_base)) {
343dd11376bSBart Van Assche err = PTR_ERR(mmio_base);
344dd11376bSBart Van Assche goto out;
345dd11376bSBart Van Assche }
346dd11376bSBart Van Assche
347dd11376bSBart Van Assche irq = platform_get_irq(pdev, 0);
348dd11376bSBart Van Assche if (irq < 0) {
349dd11376bSBart Van Assche err = irq;
350dd11376bSBart Van Assche goto out;
351dd11376bSBart Van Assche }
352dd11376bSBart Van Assche
353dd11376bSBart Van Assche err = ufshcd_alloc_host(dev, &hba);
354dd11376bSBart Van Assche if (err) {
355dd11376bSBart Van Assche dev_err(dev, "Allocation failed\n");
356dd11376bSBart Van Assche goto out;
357dd11376bSBart Van Assche }
358dd11376bSBart Van Assche
359dd11376bSBart Van Assche hba->vops = vops;
360dd11376bSBart Van Assche
361dd11376bSBart Van Assche err = ufshcd_parse_clock_info(hba);
362dd11376bSBart Van Assche if (err) {
363dd11376bSBart Van Assche dev_err(dev, "%s: clock parse failed %d\n",
364dd11376bSBart Van Assche __func__, err);
365dd11376bSBart Van Assche goto dealloc_host;
366dd11376bSBart Van Assche }
367dd11376bSBart Van Assche err = ufshcd_parse_regulator_info(hba);
368dd11376bSBart Van Assche if (err) {
369dd11376bSBart Van Assche dev_err(dev, "%s: regulator init failed %d\n",
370dd11376bSBart Van Assche __func__, err);
371dd11376bSBart Van Assche goto dealloc_host;
372dd11376bSBart Van Assche }
373dd11376bSBart Van Assche
374dd11376bSBart Van Assche ufshcd_init_lanes_per_dir(hba);
375dd11376bSBart Van Assche
376dd11376bSBart Van Assche err = ufshcd_init(hba, mmio_base, irq);
377dd11376bSBart Van Assche if (err) {
378*517f8eb3SBrian Masney dev_err_probe(dev, err, "Initialization failed with error %d\n",
379*517f8eb3SBrian Masney err);
380dd11376bSBart Van Assche goto dealloc_host;
381dd11376bSBart Van Assche }
382dd11376bSBart Van Assche
383dd11376bSBart Van Assche pm_runtime_set_active(dev);
384dd11376bSBart Van Assche pm_runtime_enable(dev);
385dd11376bSBart Van Assche
386dd11376bSBart Van Assche return 0;
387dd11376bSBart Van Assche
388dd11376bSBart Van Assche dealloc_host:
389dd11376bSBart Van Assche ufshcd_dealloc_host(hba);
390dd11376bSBart Van Assche out:
391dd11376bSBart Van Assche return err;
392dd11376bSBart Van Assche }
393dd11376bSBart Van Assche EXPORT_SYMBOL_GPL(ufshcd_pltfrm_init);
394dd11376bSBart Van Assche
395dd11376bSBart Van Assche MODULE_AUTHOR("Santosh Yaragnavi <santosh.sy@samsung.com>");
396dd11376bSBart Van Assche MODULE_AUTHOR("Vinayak Holikatti <h.vinayak@samsung.com>");
397dd11376bSBart Van Assche MODULE_DESCRIPTION("UFS host controller Platform bus based glue driver");
398dd11376bSBart Van Assche MODULE_LICENSE("GPL");
399