xref: /openbmc/linux/drivers/ufs/host/ufshcd-pltfrm.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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