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