• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * for modules (sensor/actuator/flash) power supply helper.
3  *
4  * Copyright (c) 2017 by Allwinnertech Co., Ltd.  http://www.allwinnertech.com
5  *
6  * Authors:  Zhao Wei <zhaowei@allwinnertech.com>
7  *	Yang Feng <yangfeng@allwinnertech.com>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13 
14 #include <linux/device.h>
15 #include <linux/module.h>
16 
17 #include "../vin-video/vin_core.h"
18 #include "vin_os.h"
19 #include "vin_supply.h"
20 #include "../platform/platform_cfg.h"
21 #include "../vin-csi/sunxi_csi.h"
22 #include "../vin-cci/cci_helper.h"
23 #include "../modules/sensor/sensor_helper.h"
24 #include "../vin.h"
25 
26 extern struct sensor_helper_dev *glb_sensor_helper[VIN_MAX_CSI];
27 
28 /*
29  * called by subdev in power on/off sequency
30  */
sd_to_modules(struct v4l2_subdev * sd)31 struct modules_config *sd_to_modules(struct v4l2_subdev *sd)
32 {
33 	struct vin_md *vind = dev_get_drvdata(sd->v4l2_dev->dev);
34 	struct modules_config *module = NULL;
35 	int i, j;
36 
37 	for (i = 0; i < VIN_MAX_DEV; i++) {
38 		module = &vind->modules[i];
39 
40 		for (j = 0; j < MAX_DETECT_NUM; j++) {
41 			if (!strcmp(module->sensors.inst[j].cam_name, sd->name))
42 				return module;
43 
44 			if ((sd == module->modules.sensor[j].sd) ||
45 			    (sd == module->modules.act[j].sd) ||
46 			    (sd == module->modules.flash.sd))
47 				return module;
48 		}
49 	}
50 	vin_err("%s cannot find the match modules\n", sd->name);
51 	return NULL;
52 }
53 EXPORT_SYMBOL_GPL(sd_to_modules);
54 
find_power_pmic(struct v4l2_subdev * sd,struct vin_power * power,enum pmic_channel pmic_ch)55 static int find_power_pmic(struct v4l2_subdev *sd, struct vin_power *power, enum pmic_channel pmic_ch)
56 {
57 	int i, j;
58 	struct modules_config *module = sd_to_modules(sd);
59 
60 	if (!module) {
61 		vin_err("%s get module fail\n", __func__);
62 		return -1;
63 	}
64 
65 	if (module->sensors.use_sensor_list == 1) {
66 		for (i = 0; i < MAX_DETECT_NUM; i++) {
67 			for (j = 0; j < VIN_MAX_CSI; j++) {
68 				if (!glb_sensor_helper[j])
69 					continue;
70 				if (!strcmp(glb_sensor_helper[j]->name, module->sensors.inst[i].cam_name)) {
71 					if (!glb_sensor_helper[j]->pmic[pmic_ch])
72 						return -1;
73 					power[pmic_ch].pmic = glb_sensor_helper[j]->pmic[pmic_ch];
74 					return 0;
75 				}
76 			}
77 		}
78 		vin_err("sensor defined in dts need be defined sensor list init file\n");
79 	} else {
80 		for (i = 0; i < VIN_MAX_CSI; i++) {
81 			if (glb_sensor_helper[i] && (!strcmp(glb_sensor_helper[i]->name, sd->name))) {
82 				if (!glb_sensor_helper[i]->pmic[pmic_ch])
83 					return -1;
84 				power[pmic_ch].pmic = glb_sensor_helper[i]->pmic[pmic_ch];
85 				return 0;
86 			}
87 		}
88 	}
89 
90 	power[pmic_ch].pmic = NULL;
91 	vin_err("%s cannot find the match sensor_helper\n", sd->name);
92 	return -1;
93 }
94 
95 /*
96  *enable/disable pmic channel
97  */
vin_set_pmu_channel(struct v4l2_subdev * sd,enum pmic_channel pmic_ch,enum on_off on_off)98 int vin_set_pmu_channel(struct v4l2_subdev *sd, enum pmic_channel pmic_ch,
99 			enum on_off on_off)
100 {
101 	int ret = 0;
102 
103 #ifndef FPGA_VER
104 	struct modules_config *modules = sd_to_modules(sd);
105 	static int def_vol[MAX_POW_NUM] = {3300000, 3300000, 1800000,
106 					3300000, 3300000, 3300000};
107 	struct vin_power *power = NULL;
108 
109 	if (modules == NULL)
110 		return -1;
111 
112 	power = &modules->sensors.power[0];
113 	if (on_off == OFF) {
114 		if (power[pmic_ch].pmic == NULL)
115 			return 0;
116 		ret = regulator_disable(power[pmic_ch].pmic);
117 		ret = regulator_set_voltage(power[pmic_ch].pmic,
118 					  0, def_vol[pmic_ch]);
119 		power[pmic_ch].pmic = NULL;
120 		vin_log(VIN_LOG_POWER, "regulator_is already disabled\n");
121 	} else {
122 		ret = find_power_pmic(sd, power, pmic_ch);
123 		if (ret)
124 			return ret;
125 
126 		ret = regulator_set_voltage(power[pmic_ch].pmic,
127 					  power[pmic_ch].power_vol,
128 					  def_vol[pmic_ch]);
129 		vin_log(VIN_LOG_POWER, "set regulator %s = %d,return %x\n",
130 			power[pmic_ch].power_str, power[pmic_ch].power_vol, ret);
131 		ret = regulator_enable(power[pmic_ch].pmic);
132 	}
133 #endif
134 	return ret;
135 }
136 EXPORT_SYMBOL_GPL(vin_set_pmu_channel);
137 
138 /*
139  *enable/disable master clock
140  */
vin_set_mclk(struct v4l2_subdev * sd,enum on_off on_off)141 int vin_set_mclk(struct v4l2_subdev *sd, enum on_off on_off)
142 {
143 	struct vin_md *vind = dev_get_drvdata(sd->v4l2_dev->dev);
144 	struct modules_config *modules = sd_to_modules(sd);
145 	struct vin_mclk_info *mclk = NULL;
146 	struct vin_power *power = NULL;
147 	unsigned int mclk_mode;
148 	char pin_name[20] = "";
149 	int mclk_id = 0;
150 
151 	if (modules == NULL)
152 		return -1;
153 
154 	if (modules->sensors.mclk_id == -1)
155 		mclk_id = modules->sensors.csi_sel;
156 	else
157 		mclk_id = modules->sensors.mclk_id;
158 	if (mclk_id < 0) {
159 		vin_err("get mclk id failed\n");
160 		return -1;
161 	}
162 
163 	mclk = &vind->mclk[mclk_id];
164 
165 	switch (on_off) {
166 	case ON:
167 		csi_cci_init_helper(modules->sensors.sensor_bus_sel);
168 		sprintf(pin_name, "mclk%d-default", mclk_id);
169 		break;
170 	case OFF:
171 		csi_cci_exit_helper(modules->sensors.sensor_bus_sel);
172 		sprintf(pin_name, "mclk%d-sleep", mclk_id);
173 		break;
174 	default:
175 		return -1;
176 	}
177 #ifndef FPGA_VER
178 
179 	if (on_off && mclk->use_count++ > 0)
180 		return 0;
181 	else if (!on_off && (mclk->use_count == 0 || --mclk->use_count > 0))
182 		return 0;
183 
184 	switch (on_off) {
185 	case ON:
186 		vin_log(VIN_LOG_POWER, "sensor mclk on, use_count %d!\n", mclk->use_count);
187 		if (mclk->mclk) {
188 			if (clk_prepare_enable(mclk->mclk)) {
189 				vin_err("csi master clock enable error\n");
190 				return -1;
191 			}
192 		} else {
193 			vin_err("csi master%d clock is null\n", mclk_id);
194 			return -1;
195 		}
196 		break;
197 	case OFF:
198 		vin_log(VIN_LOG_POWER, "sensor mclk off, use_count %d!\n", mclk->use_count);
199 		if (mclk->mclk) {
200 			clk_disable_unprepare(mclk->mclk);
201 		} else {
202 			vin_err("csi master%d clock is null\n", mclk_id);
203 			return -1;
204 		}
205 		break;
206 	default:
207 		return -1;
208 	}
209 
210 	mclk->pin = devm_pinctrl_get_select(&vind->pdev->dev, pin_name);
211 	if (IS_ERR_OR_NULL(mclk->pin)) {
212 		vin_err("mclk%d request pin handle failed!\n", mclk_id);
213 		return -EINVAL;
214 	}
215 
216 	if (on_off) {
217 		power = &modules->sensors.power[0];
218 		if (power[IOVDD].power_vol && (power[IOVDD].power_vol <= 1800000))
219 			mclk_mode = MCLK_POWER_VOLTAGE_1800;
220 		else
221 			mclk_mode = MCLK_POWER_VOLTAGE_3300;
222 		vin_log(VIN_LOG_POWER, "IOVDD power vol is %d, mclk mode is %d\n", power[IOVDD].power_vol, mclk_mode);
223 	}
224 #endif
225 	return 0;
226 }
227 EXPORT_SYMBOL_GPL(vin_set_mclk);
228 
229 /*
230  *set frequency of master clock
231  */
vin_set_mclk_freq(struct v4l2_subdev * sd,unsigned long freq)232 int vin_set_mclk_freq(struct v4l2_subdev *sd, unsigned long freq)
233 {
234 #ifndef FPGA_VER
235 	struct vin_md *vind = dev_get_drvdata(sd->v4l2_dev->dev);
236 	struct modules_config *modules = sd_to_modules(sd);
237 	struct clk *mclk_src = NULL;
238 	int mclk_id = 0;
239 
240 	if (modules == NULL)
241 		return -1;
242 
243 	if (modules->sensors.mclk_id == -1)
244 		mclk_id = modules->sensors.csi_sel;
245 	else
246 		mclk_id = modules->sensors.mclk_id;
247 	if (mclk_id < 0) {
248 		vin_err("get mclk id failed\n");
249 		return -1;
250 	}
251 
252 	if (freq == 24000000 || freq == 12000000 || freq == 6000000) {
253 		if (vind->mclk[mclk_id].clk_24m) {
254 			mclk_src = vind->mclk[mclk_id].clk_24m;
255 		} else {
256 			vin_err("csi master clock 24M source is null\n");
257 			return -1;
258 		}
259 	} else {
260 		if (vind->mclk[mclk_id].clk_pll) {
261 			mclk_src = vind->mclk[mclk_id].clk_pll;
262 		} else {
263 			vin_err("csi master clock pll source is null\n");
264 			return -1;
265 		}
266 	}
267 
268 	if (vind->mclk[mclk_id].mclk) {
269 		if (clk_set_parent(vind->mclk[mclk_id].mclk, mclk_src)) {
270 			vin_err("set mclk%d source failed!\n", mclk_id);
271 			return -1;
272 		}
273 		if (clk_set_rate(vind->mclk[mclk_id].mclk, freq)) {
274 			vin_err("set csi master%d clock error\n", mclk_id);
275 			return -1;
276 		}
277 		vin_log(VIN_LOG_POWER, "mclk%d set rate %ld, get rate %ld\n", mclk_id,
278 			freq, clk_get_rate(vind->mclk[mclk_id].mclk));
279 	} else {
280 		vin_err("csi master clock is null\n");
281 		return -1;
282 	}
283 #endif
284 	return 0;
285 }
286 EXPORT_SYMBOL_GPL(vin_set_mclk_freq);
287 
vin_set_sync_mclk(struct v4l2_subdev * sd,int id,unsigned long freq,enum on_off on_off)288 int vin_set_sync_mclk(struct v4l2_subdev *sd, int id, unsigned long freq, enum on_off on_off)
289 {
290 	struct vin_md *vind = dev_get_drvdata(sd->v4l2_dev->dev);
291 	struct modules_config *modules = sd_to_modules(sd);
292 	struct vin_mclk_info *mclk = NULL;
293 	struct clk *mclk_src = NULL;
294 
295 	if (modules == NULL)
296 		return -1;
297 
298 	if (id < 0) {
299 		vin_err("get mclk id failed\n");
300 		return -1;
301 	}
302 
303 	mclk = &vind->mclk[id];
304 
305 	if (on_off && mclk->use_count++ > 0)
306 		return 0;
307 	else if (!on_off && (mclk->use_count == 0 || --mclk->use_count > 0))
308 		return 0;
309 
310 	switch (on_off) {
311 	case ON:
312 		vin_log(VIN_LOG_POWER, "sensor mclk on, use_count %d!\n", mclk->use_count);
313 		if (freq == 24000000 || freq == 12000000 || freq == 6000000) {
314 			if (mclk->clk_24m) {
315 				mclk_src = mclk->clk_24m;
316 			} else {
317 				vin_err("mclk%d 24M source is null\n", id);
318 				return -1;
319 			}
320 		} else {
321 			if (mclk->clk_pll) {
322 				mclk_src =  mclk->clk_pll;
323 			} else {
324 				vin_err("mclk%d pll source is null\n", id);
325 				return -1;
326 			}
327 		}
328 
329 		if (mclk->mclk) {
330 			if (clk_set_parent(mclk->mclk, mclk_src)) {
331 				vin_err("set mclk%d source failed!\n", id);
332 				return -1;
333 			}
334 			if (clk_set_rate(mclk->mclk, freq)) {
335 				vin_err("set mclk%d error\n", id);
336 				return -1;
337 			}
338 			vin_log(VIN_LOG_POWER, "mclk%d set rate %ld, get rate %ld\n", id,
339 				freq, clk_get_rate(vind->mclk[id].mclk));
340 			if (clk_prepare_enable(mclk->mclk)) {
341 				vin_err("mclk%d enable error\n", id);
342 				return -1;
343 			}
344 		} else {
345 			vin_err("mclk%d is null\n", id);
346 			return -1;
347 		}
348 		break;
349 	case OFF:
350 		vin_log(VIN_LOG_POWER, "sensor mclk off, use_count %d!\n", mclk->use_count);
351 		if (mclk->mclk) {
352 			clk_disable_unprepare(mclk->mclk);
353 		} else {
354 			vin_err("mclk%d is null\n", id);
355 			return -1;
356 		}
357 		break;
358 	default:
359 		return -1;
360 	}
361 
362 	return 0;
363 }
364 EXPORT_SYMBOL_GPL(vin_set_sync_mclk);
365 
366 /*
367  *set the gpio io status
368  */
vin_gpio_write(struct v4l2_subdev * sd,enum gpio_type gpio_id,unsigned int out_value)369 int vin_gpio_write(struct v4l2_subdev *sd, enum gpio_type gpio_id,
370 		   unsigned int out_value)
371 {
372 #ifndef FPGA_VER
373 	int force_value_flag = 1;
374 	struct modules_config *modules = sd_to_modules(sd);
375 	int gpio;
376 
377 	if (modules == NULL)
378 		return -1;
379 
380 	gpio = modules->sensors.gpio[gpio_id];
381 
382 	if (gpio < 0)
383 		return -1;
384 	return os_gpio_write(gpio, out_value, force_value_flag);
385 #endif
386 	return 0;
387 }
388 EXPORT_SYMBOL_GPL(vin_gpio_write);
389 
390 /*
391  *set the gpio io status
392  */
vin_gpio_set_status(struct v4l2_subdev * sd,enum gpio_type gpio_id,unsigned int status)393 int vin_gpio_set_status(struct v4l2_subdev *sd, enum gpio_type gpio_id,
394 			unsigned int status)
395 {
396 #ifndef FPGA_VER
397 	struct modules_config *modules = sd_to_modules(sd);
398 	int gc;
399 
400 	if (modules == NULL)
401 		return -1;
402 
403 	gc = modules->sensors.gpio[gpio_id];
404 
405 	if (gc < 0)
406 		return 0;
407 
408 	vin_log(VIN_LOG_POWER, "[%s] pin%d, set status %d\n", __func__, gc, status);
409 
410 	if (status == 1)
411 		gpio_direction_output(gc, 0);
412 	else
413 		gpio_direction_input(gc);
414 
415 #endif
416 	return 0;
417 }
418 EXPORT_SYMBOL_GPL(vin_gpio_set_status);
419 
420 MODULE_AUTHOR("raymonxiu");
421 MODULE_LICENSE("Dual BSD/GPL");
422 MODULE_DESCRIPTION("Video front end subdev for sunxi");
423