diff options
Diffstat (limited to 'arch/arm/mach-tegra/board-enterprise-sensors.c')
-rw-r--r-- | arch/arm/mach-tegra/board-enterprise-sensors.c | 673 |
1 files changed, 673 insertions, 0 deletions
diff --git a/arch/arm/mach-tegra/board-enterprise-sensors.c b/arch/arm/mach-tegra/board-enterprise-sensors.c new file mode 100644 index 00000000000..f775c2bd3b3 --- /dev/null +++ b/arch/arm/mach-tegra/board-enterprise-sensors.c | |||
@@ -0,0 +1,673 @@ | |||
1 | /* | ||
2 | * arch/arm/mach-tegra/board-enterprise-sensors.c | ||
3 | * | ||
4 | * Copyright (c) 2011, NVIDIA CORPORATION, All rights reserved. | ||
5 | * | ||
6 | * Redistribution and use in source and binary forms, with or without | ||
7 | * modification, are permitted provided that the following conditions are | ||
8 | * met: | ||
9 | * | ||
10 | * Redistributions of source code must retain the above copyright notice, | ||
11 | * this list of conditions and the following disclaimer. | ||
12 | * | ||
13 | * Redistributions in binary form must reproduce the above copyright | ||
14 | * notice, this list of conditions and the following disclaimer in the | ||
15 | * documentation and/or other materials provided with the distribution. | ||
16 | * | ||
17 | * Neither the name of NVIDIA CORPORATION nor the names of its contributors | ||
18 | * may be used to endorse or promote products derived from this software | ||
19 | * without specific prior written permission. | ||
20 | * | ||
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | ||
22 | * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||
23 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | ||
24 | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
25 | * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
26 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED | ||
27 | * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
28 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
29 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
30 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
31 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
32 | */ | ||
33 | |||
34 | #include <linux/i2c.h> | ||
35 | #include <linux/delay.h> | ||
36 | #include <linux/i2c/pca954x.h> | ||
37 | #include <linux/nct1008.h> | ||
38 | #include <linux/err.h> | ||
39 | #include <linux/mpu.h> | ||
40 | #include <linux/platform_data/ina230.h> | ||
41 | #include <linux/regulator/consumer.h> | ||
42 | #include <linux/slab.h> | ||
43 | #include <mach/gpio.h> | ||
44 | #include <media/ar0832_main.h> | ||
45 | #include <media/tps61050.h> | ||
46 | #include <media/ov9726.h> | ||
47 | #include <mach/edp.h> | ||
48 | #include <mach/thermal.h> | ||
49 | #include "cpu-tegra.h" | ||
50 | #include "gpio-names.h" | ||
51 | #include "board-enterprise.h" | ||
52 | #include "board.h" | ||
53 | |||
54 | static int nct_get_temp(void *_data, long *temp) | ||
55 | { | ||
56 | struct nct1008_data *data = _data; | ||
57 | return nct1008_thermal_get_temp(data, temp); | ||
58 | } | ||
59 | |||
60 | static int nct_get_temp_low(void *_data, long *temp) | ||
61 | { | ||
62 | struct nct1008_data *data = _data; | ||
63 | return nct1008_thermal_get_temp_low(data, temp); | ||
64 | } | ||
65 | |||
66 | static int nct_set_limits(void *_data, | ||
67 | long lo_limit_milli, | ||
68 | long hi_limit_milli) | ||
69 | { | ||
70 | struct nct1008_data *data = _data; | ||
71 | return nct1008_thermal_set_limits(data, | ||
72 | lo_limit_milli, | ||
73 | hi_limit_milli); | ||
74 | } | ||
75 | |||
76 | static int nct_set_alert(void *_data, | ||
77 | void (*alert_func)(void *), | ||
78 | void *alert_data) | ||
79 | { | ||
80 | struct nct1008_data *data = _data; | ||
81 | return nct1008_thermal_set_alert(data, alert_func, alert_data); | ||
82 | } | ||
83 | |||
84 | static int nct_set_shutdown_temp(void *_data, long shutdown_temp) | ||
85 | { | ||
86 | struct nct1008_data *data = _data; | ||
87 | return nct1008_thermal_set_shutdown_temp(data, | ||
88 | shutdown_temp); | ||
89 | } | ||
90 | |||
91 | static void nct1008_probe_callback(struct nct1008_data *data) | ||
92 | { | ||
93 | struct tegra_thermal_device *thermal_device; | ||
94 | |||
95 | thermal_device = kzalloc(sizeof(struct tegra_thermal_device), | ||
96 | GFP_KERNEL); | ||
97 | if (!thermal_device) { | ||
98 | pr_err("unable to allocate thermal device\n"); | ||
99 | return; | ||
100 | } | ||
101 | |||
102 | thermal_device->name = "nct1008"; | ||
103 | thermal_device->data = data; | ||
104 | thermal_device->offset = TDIODE_OFFSET; | ||
105 | thermal_device->get_temp = nct_get_temp; | ||
106 | thermal_device->get_temp_low = nct_get_temp_low; | ||
107 | thermal_device->set_limits = nct_set_limits; | ||
108 | thermal_device->set_alert = nct_set_alert; | ||
109 | thermal_device->set_shutdown_temp = nct_set_shutdown_temp; | ||
110 | |||
111 | tegra_thermal_set_device(thermal_device); | ||
112 | } | ||
113 | |||
114 | static struct nct1008_platform_data enterprise_nct1008_pdata = { | ||
115 | .supported_hwrev = true, | ||
116 | .ext_range = true, | ||
117 | .conv_rate = 0x08, | ||
118 | .offset = 8, /* 4 * 2C. Bug 844025 - 1C for device accuracies */ | ||
119 | .probe_callback = nct1008_probe_callback, | ||
120 | }; | ||
121 | |||
122 | static struct i2c_board_info enterprise_i2c4_nct1008_board_info[] = { | ||
123 | { | ||
124 | I2C_BOARD_INFO("nct1008", 0x4C), | ||
125 | .irq = TEGRA_GPIO_TO_IRQ(TEGRA_GPIO_PH7), | ||
126 | .platform_data = &enterprise_nct1008_pdata, | ||
127 | } | ||
128 | }; | ||
129 | |||
130 | static void enterprise_nct1008_init(void) | ||
131 | { | ||
132 | int ret; | ||
133 | |||
134 | tegra_gpio_enable(TEGRA_GPIO_PH7); | ||
135 | ret = gpio_request(TEGRA_GPIO_PH7, "temp_alert"); | ||
136 | if (ret < 0) { | ||
137 | pr_err("%s: gpio_request failed %d\n", __func__, ret); | ||
138 | return; | ||
139 | } | ||
140 | |||
141 | ret = gpio_direction_input(TEGRA_GPIO_PH7); | ||
142 | if (ret < 0) { | ||
143 | pr_err("%s: gpio_direction_input failed %d\n", __func__, ret); | ||
144 | gpio_free(TEGRA_GPIO_PH7); | ||
145 | return; | ||
146 | } | ||
147 | |||
148 | i2c_register_board_info(4, enterprise_i2c4_nct1008_board_info, | ||
149 | ARRAY_SIZE(enterprise_i2c4_nct1008_board_info)); | ||
150 | } | ||
151 | |||
152 | /* MPU board file definition */ | ||
153 | #if (MPU_GYRO_TYPE == MPU_TYPE_MPU3050) | ||
154 | #define MPU_GYRO_NAME "mpu3050" | ||
155 | #endif | ||
156 | #if (MPU_GYRO_TYPE == MPU_TYPE_MPU6050) | ||
157 | #define MPU_GYRO_NAME "mpu6050" | ||
158 | #endif | ||
159 | static struct mpu_platform_data mpu_gyro_data = { | ||
160 | .int_config = 0x10, | ||
161 | .level_shifter = 0, | ||
162 | .orientation = MPU_GYRO_ORIENTATION, /* Located in board_[platformname].h */ | ||
163 | }; | ||
164 | |||
165 | #if (MPU_GYRO_TYPE == MPU_TYPE_MPU3050) | ||
166 | static struct ext_slave_platform_data mpu_accel_data = { | ||
167 | .address = MPU_ACCEL_ADDR, | ||
168 | .irq = 0, | ||
169 | .adapt_num = MPU_ACCEL_BUS_NUM, | ||
170 | .bus = EXT_SLAVE_BUS_SECONDARY, | ||
171 | .orientation = MPU_ACCEL_ORIENTATION, /* Located in board_[platformname].h */ | ||
172 | }; | ||
173 | #endif | ||
174 | |||
175 | static struct ext_slave_platform_data mpu_compass_data = { | ||
176 | .address = MPU_COMPASS_ADDR, | ||
177 | .irq = 0, | ||
178 | .adapt_num = MPU_COMPASS_BUS_NUM, | ||
179 | .bus = EXT_SLAVE_BUS_PRIMARY, | ||
180 | .orientation = MPU_COMPASS_ORIENTATION, /* Located in board_[platformname].h */ | ||
181 | }; | ||
182 | |||
183 | static struct i2c_board_info __initdata inv_mpu_i2c2_board_info[] = { | ||
184 | { | ||
185 | I2C_BOARD_INFO(MPU_GYRO_NAME, MPU_GYRO_ADDR), | ||
186 | .irq = TEGRA_GPIO_TO_IRQ(MPU_GYRO_IRQ_GPIO), | ||
187 | .platform_data = &mpu_gyro_data, | ||
188 | }, | ||
189 | #if (MPU_GYRO_TYPE == MPU_TYPE_MPU3050) | ||
190 | { | ||
191 | I2C_BOARD_INFO(MPU_ACCEL_NAME, MPU_ACCEL_ADDR), | ||
192 | #if MPU_ACCEL_IRQ_GPIO | ||
193 | .irq = TEGRA_GPIO_TO_IRQ(MPU_ACCEL_IRQ_GPIO), | ||
194 | #endif | ||
195 | .platform_data = &mpu_accel_data, | ||
196 | }, | ||
197 | #endif | ||
198 | { | ||
199 | I2C_BOARD_INFO(MPU_COMPASS_NAME, MPU_COMPASS_ADDR), | ||
200 | #if MPU_COMPASS_IRQ_GPIO | ||
201 | .irq = TEGRA_GPIO_TO_IRQ(MPU_COMPASS_IRQ_GPIO), | ||
202 | #endif | ||
203 | .platform_data = &mpu_compass_data, | ||
204 | }, | ||
205 | }; | ||
206 | |||
207 | static void mpuirq_init(void) | ||
208 | { | ||
209 | int ret = 0; | ||
210 | |||
211 | pr_info("*** MPU START *** mpuirq_init...\n"); | ||
212 | |||
213 | #if (MPU_GYRO_TYPE == MPU_TYPE_MPU3050) | ||
214 | #if MPU_ACCEL_IRQ_GPIO | ||
215 | /* ACCEL-IRQ assignment */ | ||
216 | tegra_gpio_enable(MPU_ACCEL_IRQ_GPIO); | ||
217 | ret = gpio_request(MPU_ACCEL_IRQ_GPIO, MPU_ACCEL_NAME); | ||
218 | if (ret < 0) { | ||
219 | pr_err("%s: gpio_request failed %d\n", __func__, ret); | ||
220 | return; | ||
221 | } | ||
222 | |||
223 | ret = gpio_direction_input(MPU_ACCEL_IRQ_GPIO); | ||
224 | if (ret < 0) { | ||
225 | pr_err("%s: gpio_direction_input failed %d\n", __func__, ret); | ||
226 | gpio_free(MPU_ACCEL_IRQ_GPIO); | ||
227 | return; | ||
228 | } | ||
229 | #endif | ||
230 | #endif | ||
231 | |||
232 | /* MPU-IRQ assignment */ | ||
233 | tegra_gpio_enable(MPU_GYRO_IRQ_GPIO); | ||
234 | ret = gpio_request(MPU_GYRO_IRQ_GPIO, MPU_GYRO_NAME); | ||
235 | if (ret < 0) { | ||
236 | pr_err("%s: gpio_request failed %d\n", __func__, ret); | ||
237 | return; | ||
238 | } | ||
239 | |||
240 | ret = gpio_direction_input(MPU_GYRO_IRQ_GPIO); | ||
241 | if (ret < 0) { | ||
242 | pr_err("%s: gpio_direction_input failed %d\n", __func__, ret); | ||
243 | gpio_free(MPU_GYRO_IRQ_GPIO); | ||
244 | return; | ||
245 | } | ||
246 | pr_info("*** MPU END *** mpuirq_init...\n"); | ||
247 | |||
248 | i2c_register_board_info(MPU_GYRO_BUS_NUM, inv_mpu_i2c2_board_info, | ||
249 | ARRAY_SIZE(inv_mpu_i2c2_board_info)); | ||
250 | } | ||
251 | |||
252 | static inline void enterprise_msleep(u32 t) | ||
253 | { | ||
254 | /* | ||
255 | If timer value is between ( 10us - 20ms), | ||
256 | usleep_range() is recommended. | ||
257 | Please read Documentation/timers/timers-howto.txt. | ||
258 | */ | ||
259 | usleep_range(t*1000, t*1000 + 500); | ||
260 | } | ||
261 | |||
262 | static struct i2c_board_info enterprise_i2c0_isl_board_info[] = { | ||
263 | { | ||
264 | I2C_BOARD_INFO("isl29028", 0x44), | ||
265 | } | ||
266 | }; | ||
267 | |||
268 | static void enterprise_isl_init(void) | ||
269 | { | ||
270 | i2c_register_board_info(0, enterprise_i2c0_isl_board_info, | ||
271 | ARRAY_SIZE(enterprise_i2c0_isl_board_info)); | ||
272 | } | ||
273 | |||
274 | enum CAMERA_INDEX { | ||
275 | CAM_REAR_LEFT, | ||
276 | CAM_REAR_RIGHT, | ||
277 | CAM_FRONT, | ||
278 | NUM_OF_CAM | ||
279 | }; | ||
280 | |||
281 | struct enterprise_power_rail { | ||
282 | struct regulator *cam_reg; | ||
283 | struct regulator *csi_reg; | ||
284 | }; | ||
285 | |||
286 | static struct enterprise_power_rail ent_vicsi_pwr[NUM_OF_CAM]; | ||
287 | |||
288 | static int enterprise_cam_pwr(enum CAMERA_INDEX cam, bool pwr_on) | ||
289 | { | ||
290 | struct enterprise_power_rail *reg_cam = &ent_vicsi_pwr[cam]; | ||
291 | int ret = 0; | ||
292 | |||
293 | /* | ||
294 | * SW must turn on 1.8V first then 2.8V | ||
295 | * SW must turn off 2.8V first then 1.8V | ||
296 | */ | ||
297 | if (pwr_on) { | ||
298 | if (reg_cam->csi_reg == NULL) { | ||
299 | reg_cam->csi_reg = regulator_get(NULL, | ||
300 | "avdd_dsi_csi"); | ||
301 | if (IS_ERR_OR_NULL(reg_cam->csi_reg)) { | ||
302 | pr_err("%s: csi pwr err\n", __func__); | ||
303 | ret = PTR_ERR(reg_cam->csi_reg); | ||
304 | goto enterprise_cam_pwr_fail; | ||
305 | } | ||
306 | } | ||
307 | |||
308 | ret = regulator_enable(reg_cam->csi_reg); | ||
309 | if (ret) { | ||
310 | pr_err("%s: enable csi pwr err\n", __func__); | ||
311 | goto enterprise_cam_pwr_fail; | ||
312 | } | ||
313 | |||
314 | if (reg_cam->cam_reg == NULL) { | ||
315 | reg_cam->cam_reg = regulator_get(NULL, | ||
316 | "vddio_cam"); | ||
317 | if (IS_ERR_OR_NULL(reg_cam->cam_reg)) { | ||
318 | pr_err("%s: vddio pwr err\n", __func__); | ||
319 | ret = PTR_ERR(reg_cam->cam_reg); | ||
320 | regulator_disable(reg_cam->csi_reg); | ||
321 | goto enterprise_cam_pwr_fail; | ||
322 | } | ||
323 | } | ||
324 | |||
325 | ret = regulator_enable(reg_cam->cam_reg); | ||
326 | if (ret) { | ||
327 | pr_err("%s: enable vddio pwr err\n", __func__); | ||
328 | regulator_disable(reg_cam->csi_reg); | ||
329 | goto enterprise_cam_pwr_fail; | ||
330 | } | ||
331 | } else { | ||
332 | if (reg_cam->cam_reg) | ||
333 | regulator_disable(reg_cam->cam_reg); | ||
334 | |||
335 | if (reg_cam->csi_reg) | ||
336 | regulator_disable(reg_cam->csi_reg); | ||
337 | } | ||
338 | return 0; | ||
339 | |||
340 | enterprise_cam_pwr_fail: | ||
341 | if (!IS_ERR_OR_NULL(reg_cam->cam_reg)) | ||
342 | regulator_put(reg_cam->cam_reg); | ||
343 | reg_cam->cam_reg = NULL; | ||
344 | |||
345 | if (!IS_ERR_OR_NULL(reg_cam->csi_reg)) | ||
346 | regulator_put(reg_cam->csi_reg); | ||
347 | reg_cam->csi_reg = NULL; | ||
348 | |||
349 | return ret; | ||
350 | } | ||
351 | |||
352 | static int enterprise_ar0832_ri_power_on(int is_stereo) | ||
353 | { | ||
354 | int ret = 0; | ||
355 | |||
356 | pr_info("%s: ++\n", __func__); | ||
357 | ret = enterprise_cam_pwr(CAM_REAR_RIGHT, true); | ||
358 | |||
359 | /* Release Reset */ | ||
360 | if (is_stereo) { | ||
361 | gpio_set_value(CAM1_RST_L_GPIO, 1); | ||
362 | gpio_set_value(CAM2_RST_L_GPIO, 1); | ||
363 | } else | ||
364 | gpio_set_value(CAM1_RST_L_GPIO, 1); | ||
365 | /* | ||
366 | It takes 2400 EXTCLK for ar0832 to be ready for I2c. | ||
367 | EXTCLK is 10 ~ 24MHz. 1 ms should be enough to cover | ||
368 | at least 2400 EXTCLK within frequency range. | ||
369 | */ | ||
370 | enterprise_msleep(1); | ||
371 | |||
372 | return ret; | ||
373 | } | ||
374 | |||
375 | static int enterprise_ar0832_le_power_on(int is_stereo) | ||
376 | { | ||
377 | int ret = 0; | ||
378 | |||
379 | pr_info("%s: ++\n", __func__); | ||
380 | ret = enterprise_cam_pwr(CAM_REAR_LEFT, true); | ||
381 | |||
382 | /* Release Reset */ | ||
383 | gpio_set_value(CAM2_RST_L_GPIO, 1); | ||
384 | |||
385 | /* | ||
386 | It takes 2400 EXTCLK for ar0832 to be ready for I2c. | ||
387 | EXTCLK is 10 ~ 24MHz. 1 ms should be enough to cover | ||
388 | at least 2400 EXTCLK within frequency range. | ||
389 | */ | ||
390 | enterprise_msleep(1); | ||
391 | |||
392 | /* CSI B is shared between Front camera and Rear Left camera */ | ||
393 | gpio_set_value(CAM_CSI_MUX_SEL_GPIO, 1); | ||
394 | |||
395 | return ret; | ||
396 | } | ||
397 | |||
398 | static int enterprise_ar0832_ri_power_off(int is_stereo) | ||
399 | { | ||
400 | int ret; | ||
401 | |||
402 | pr_info("%s: ++\n", __func__); | ||
403 | ret = enterprise_cam_pwr(CAM_REAR_RIGHT, false); | ||
404 | |||
405 | /* Assert Reset */ | ||
406 | if (is_stereo) { | ||
407 | gpio_set_value(CAM1_RST_L_GPIO, 0); | ||
408 | gpio_set_value(CAM2_RST_L_GPIO, 0); | ||
409 | } else | ||
410 | gpio_set_value(CAM1_RST_L_GPIO, 0); | ||
411 | |||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | static int enterprise_ar0832_le_power_off(int is_stereo) | ||
416 | { | ||
417 | int ret; | ||
418 | |||
419 | pr_info("%s: ++\n", __func__); | ||
420 | ret = enterprise_cam_pwr(CAM_REAR_LEFT, false); | ||
421 | |||
422 | /* Assert Reset */ | ||
423 | gpio_set_value(CAM2_RST_L_GPIO, 0); | ||
424 | |||
425 | return ret; | ||
426 | } | ||
427 | |||
428 | static int enterprise_ov9726_power_on(void) | ||
429 | { | ||
430 | pr_info("ov9726 power on\n"); | ||
431 | |||
432 | /* switch mipi mux to front camera */ | ||
433 | gpio_set_value(CAM_CSI_MUX_SEL_GPIO, CAM_CSI_MUX_SEL_FRONT); | ||
434 | enterprise_cam_pwr(CAM_FRONT, true); | ||
435 | |||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static int enterprise_ov9726_power_off(void) | ||
440 | { | ||
441 | pr_info("ov9726 power off\n"); | ||
442 | |||
443 | enterprise_cam_pwr(CAM_FRONT, false); | ||
444 | |||
445 | return 0; | ||
446 | } | ||
447 | |||
448 | struct ov9726_platform_data enterprise_ov9726_data = { | ||
449 | .power_on = enterprise_ov9726_power_on, | ||
450 | .power_off = enterprise_ov9726_power_off, | ||
451 | .gpio_rst = CAM3_RST_L_GPIO, | ||
452 | .rst_low_active = true, | ||
453 | .gpio_pwdn = CAM3_PWDN_GPIO, | ||
454 | .pwdn_low_active = false, | ||
455 | }; | ||
456 | |||
457 | static struct nvc_torch_pin_state enterprise_tps61050_pinstate = { | ||
458 | .mask = 0x0008, /*VGP3*/ | ||
459 | .values = 0x0008, | ||
460 | }; | ||
461 | |||
462 | static struct tps61050_platform_data enterprise_tps61050_pdata = { | ||
463 | .dev_name = "torch", | ||
464 | .pinstate = &enterprise_tps61050_pinstate, | ||
465 | }; | ||
466 | |||
467 | |||
468 | struct enterprise_cam_gpio { | ||
469 | int gpio; | ||
470 | const char *label; | ||
471 | int value; | ||
472 | }; | ||
473 | |||
474 | #define TEGRA_CAMERA_GPIO(_gpio, _label, _value) \ | ||
475 | { \ | ||
476 | .gpio = _gpio, \ | ||
477 | .label = _label, \ | ||
478 | .value = _value, \ | ||
479 | } | ||
480 | |||
481 | static struct enterprise_cam_gpio enterprise_cam_gpio_data[] = { | ||
482 | [0] = TEGRA_CAMERA_GPIO(CAM_CSI_MUX_SEL_GPIO, "cam_csi_sel", 1), | ||
483 | [1] = TEGRA_CAMERA_GPIO(CAM1_RST_L_GPIO, "cam1_rst_lo", 0), | ||
484 | [2] = TEGRA_CAMERA_GPIO(CAM2_RST_L_GPIO, "cam2_rst_lo", 0), | ||
485 | [3] = TEGRA_CAMERA_GPIO(CAM3_RST_L_GPIO, "cam3_rst_lo", 0), | ||
486 | [4] = TEGRA_CAMERA_GPIO(CAM3_PWDN_GPIO, "cam3_pwdn", 1), | ||
487 | [5] = TEGRA_CAMERA_GPIO(CAM_FLASH_EN_GPIO, "flash_en", 1), | ||
488 | [6] = TEGRA_CAMERA_GPIO(CAM_I2C_MUX_RST_EXP, "cam_i2c_mux_rst", 1), | ||
489 | }; | ||
490 | |||
491 | static struct pca954x_platform_mode enterprise_pca954x_modes[] = { | ||
492 | { .adap_id = PCA954x_I2C_BUS0, .deselect_on_exit = true, }, | ||
493 | { .adap_id = PCA954x_I2C_BUS1, .deselect_on_exit = true, }, | ||
494 | { .adap_id = PCA954x_I2C_BUS2, .deselect_on_exit = true, }, | ||
495 | { .adap_id = PCA954x_I2C_BUS3, .deselect_on_exit = true, }, | ||
496 | }; | ||
497 | |||
498 | static struct pca954x_platform_data enterprise_pca954x_data = { | ||
499 | .modes = enterprise_pca954x_modes, | ||
500 | .num_modes = ARRAY_SIZE(enterprise_pca954x_modes), | ||
501 | }; | ||
502 | |||
503 | static struct ar0832_platform_data enterprise_ar0832_ri_data = { | ||
504 | .power_on = enterprise_ar0832_ri_power_on, | ||
505 | .power_off = enterprise_ar0832_ri_power_off, | ||
506 | .id = "right", | ||
507 | }; | ||
508 | |||
509 | static struct ar0832_platform_data enterprise_ar0832_le_data = { | ||
510 | .power_on = enterprise_ar0832_le_power_on, | ||
511 | .power_off = enterprise_ar0832_le_power_off, | ||
512 | .id = "left", | ||
513 | }; | ||
514 | |||
515 | static const struct i2c_board_info enterprise_i2c2_boardinfo[] = { | ||
516 | { | ||
517 | I2C_BOARD_INFO("pca9546", 0x70), | ||
518 | .platform_data = &enterprise_pca954x_data, | ||
519 | }, | ||
520 | { | ||
521 | I2C_BOARD_INFO("tps61050", 0x33), | ||
522 | .platform_data = &enterprise_tps61050_pdata, | ||
523 | }, | ||
524 | { | ||
525 | I2C_BOARD_INFO("ov9726", OV9726_I2C_ADDR >> 1), | ||
526 | .platform_data = &enterprise_ov9726_data, | ||
527 | }, | ||
528 | }; | ||
529 | |||
530 | /* | ||
531 | * Since ar0832 driver should support multiple devices, slave | ||
532 | * address should be changed after it is open. Default slave | ||
533 | * address of ar0832 is 0x36. It will be changed to alternate | ||
534 | * address defined below when device is open. | ||
535 | */ | ||
536 | static struct i2c_board_info ar0832_i2c2_boardinfo[] = { | ||
537 | { | ||
538 | /* 0x36: alternative slave address */ | ||
539 | I2C_BOARD_INFO("ar0832", 0x36), | ||
540 | .platform_data = &enterprise_ar0832_ri_data, | ||
541 | }, | ||
542 | { | ||
543 | /* 0x32: alternative slave address */ | ||
544 | I2C_BOARD_INFO("ar0832", 0x32), | ||
545 | .platform_data = &enterprise_ar0832_le_data, | ||
546 | }, | ||
547 | { | ||
548 | I2C_BOARD_INFO("tps61050", 0x33), | ||
549 | .platform_data = &enterprise_tps61050_pdata, | ||
550 | }, | ||
551 | { | ||
552 | I2C_BOARD_INFO("ov9726", OV9726_I2C_ADDR >> 1), | ||
553 | .platform_data = &enterprise_ov9726_data, | ||
554 | }, | ||
555 | }; | ||
556 | |||
557 | static struct i2c_board_info enterprise_i2c6_boardinfo[] = { | ||
558 | { | ||
559 | I2C_BOARD_INFO("ar0832", 0x36), | ||
560 | .platform_data = &enterprise_ar0832_le_data, | ||
561 | }, | ||
562 | }; | ||
563 | |||
564 | static struct i2c_board_info enterprise_i2c7_boardinfo[] = { | ||
565 | { | ||
566 | I2C_BOARD_INFO("ar0832", 0x36), | ||
567 | .platform_data = &enterprise_ar0832_ri_data, | ||
568 | }, | ||
569 | }; | ||
570 | |||
571 | static int enterprise_cam_init(void) | ||
572 | { | ||
573 | int ret; | ||
574 | int i; | ||
575 | struct board_info bi; | ||
576 | struct board_info cam_bi; | ||
577 | bool i2c_mux = false; | ||
578 | |||
579 | pr_info("%s:++\n", __func__); | ||
580 | memset(ent_vicsi_pwr, 0, sizeof(ent_vicsi_pwr)); | ||
581 | for (i = 0; i < ARRAY_SIZE(enterprise_cam_gpio_data); i++) { | ||
582 | ret = gpio_request(enterprise_cam_gpio_data[i].gpio, | ||
583 | enterprise_cam_gpio_data[i].label); | ||
584 | if (ret < 0) { | ||
585 | pr_err("%s: gpio_request failed for gpio #%d\n", | ||
586 | __func__, i); | ||
587 | goto fail_free_gpio; | ||
588 | } | ||
589 | gpio_direction_output(enterprise_cam_gpio_data[i].gpio, | ||
590 | enterprise_cam_gpio_data[i].value); | ||
591 | gpio_export(enterprise_cam_gpio_data[i].gpio, false); | ||
592 | tegra_gpio_enable(enterprise_cam_gpio_data[i].gpio); | ||
593 | } | ||
594 | |||
595 | tegra_get_board_info(&bi); | ||
596 | tegra_get_camera_board_info(&cam_bi); | ||
597 | |||
598 | if (bi.board_id == BOARD_E1205) { | ||
599 | if (bi.fab == BOARD_FAB_A00 || bi.fab == BOARD_FAB_A01) | ||
600 | i2c_mux = false; | ||
601 | else if (bi.fab == BOARD_FAB_A02) | ||
602 | i2c_mux = true; | ||
603 | } else if (bi.board_id == BOARD_E1197) { | ||
604 | if (cam_bi.fab == BOARD_FAB_A00) | ||
605 | i2c_mux = false; | ||
606 | else if (cam_bi.fab == BOARD_FAB_A01) | ||
607 | i2c_mux = true; | ||
608 | } | ||
609 | |||
610 | if (!i2c_mux) | ||
611 | i2c_register_board_info(2, ar0832_i2c2_boardinfo, | ||
612 | ARRAY_SIZE(ar0832_i2c2_boardinfo)); | ||
613 | else { | ||
614 | i2c_register_board_info(2, enterprise_i2c2_boardinfo, | ||
615 | ARRAY_SIZE(enterprise_i2c2_boardinfo)); | ||
616 | /* | ||
617 | * Right camera is on PCA954x's I2C BUS1, | ||
618 | * Left camera is on BUS0 | ||
619 | */ | ||
620 | i2c_register_board_info(PCA954x_I2C_BUS0, enterprise_i2c6_boardinfo, | ||
621 | ARRAY_SIZE(enterprise_i2c6_boardinfo)); | ||
622 | i2c_register_board_info(PCA954x_I2C_BUS1, enterprise_i2c7_boardinfo, | ||
623 | ARRAY_SIZE(enterprise_i2c7_boardinfo)); | ||
624 | } | ||
625 | return 0; | ||
626 | |||
627 | fail_free_gpio: | ||
628 | pr_err("%s enterprise_cam_init failed!\n", __func__); | ||
629 | while (i--) | ||
630 | gpio_free(enterprise_cam_gpio_data[i].gpio); | ||
631 | return ret; | ||
632 | } | ||
633 | |||
634 | #define ENTERPRISE_INA230_ENABLED 0 | ||
635 | |||
636 | #if ENTERPRISE_INA230_ENABLED | ||
637 | static struct ina230_platform_data ina230_platform = { | ||
638 | .rail_name = "VDD_AC_BAT", | ||
639 | .current_threshold = TEGRA_CUR_MON_THRESHOLD, | ||
640 | .resistor = TEGRA_CUR_MON_RESISTOR, | ||
641 | .min_cores_online = TEGRA_CUR_MON_MIN_CORES, | ||
642 | }; | ||
643 | |||
644 | static struct i2c_board_info enterprise_i2c0_ina230_info[] = { | ||
645 | { | ||
646 | I2C_BOARD_INFO("ina230", 0x42), | ||
647 | .platform_data = &ina230_platform, | ||
648 | .irq = -1, | ||
649 | }, | ||
650 | }; | ||
651 | |||
652 | static int __init enterprise_ina230_init(void) | ||
653 | { | ||
654 | return i2c_register_board_info(0, enterprise_i2c0_ina230_info, | ||
655 | ARRAY_SIZE(enterprise_i2c0_ina230_info)); | ||
656 | } | ||
657 | #endif | ||
658 | |||
659 | int __init enterprise_sensors_init(void) | ||
660 | { | ||
661 | int ret; | ||
662 | |||
663 | enterprise_isl_init(); | ||
664 | enterprise_nct1008_init(); | ||
665 | mpuirq_init(); | ||
666 | #if ENTERPRISE_INA230_ENABLED | ||
667 | enterprise_ina230_init(); | ||
668 | #endif | ||
669 | ret = enterprise_cam_init(); | ||
670 | |||
671 | return ret; | ||
672 | } | ||
673 | |||