/* * arch/arm/mach-tegra/board-pluto-sensors.c * * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved. * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gpio-names.h" #include "board.h" #include "board-common.h" #include "board-pluto.h" #include "cpu-tegra.h" #include "devices.h" #include "tegra-board-id.h" #include "dvfs.h" #define NTC_10K_TGAIN 0xE6A2 #define NTC_10K_TOFF 0x2694 #define MAX77665_CHARGER_INT TEGRA_GPIO_PJ2 static struct nvc_gpio_pdata imx091_gpio_pdata[] = { {IMX091_GPIO_RESET, CAM_RSTN, true, false}, {IMX091_GPIO_PWDN, CAM1_POWER_DWN_GPIO, true, false}, {IMX091_GPIO_GP1, CAM_GPIO1, true, false} }; static struct board_info board_info; static struct max17042_config_data conf_data = { .valrt_thresh = 0xff00, .talrt_thresh = 0xff00, .soc_alrt_thresh = 0xff00, .shdntimer = 0xe000, .design_cap = 0x07d0, .at_rate = 0x0000, .tgain = NTC_10K_TGAIN, .toff = NTC_10K_TOFF, .vempty = 0xACDA, .qrtbl00 = 0x5C80, .qrtbl10 = 0x438C, .qrtbl20 = 0x1198, .qrtbl30 = 0x0E19, .full_soc_thresh = 0x5A00, .rcomp0 = 0x0077, .tcompc0 = 0x1F2A, .ichgt_term = 0x0320, .temp_nom = 0x1400, .temp_lim = 0x2305, .filter_cfg = 0x87A4, .config = 0x2210, .learn_cfg = 0x2606, .misc_cfg = 0x0810, .fullcap = 0x07d0, .fullcapnom = 0x07d0, .lavg_empty = 0x1000, .dqacc = 0x01f4, .dpacc = 0x3200, .fctc = 0x05e0, .kempty0 = 0x0600, .cell_technology = POWER_SUPPLY_TECHNOLOGY_LION, .cell_char_tbl = { /* Data to be written from 0x80h */ 0x9180, 0xA4C0, 0xB6A0, 0xB760, 0xB980, 0xBB30, 0xBBC0, 0xBC50, 0xBD50, 0xBE50, 0xBF80, 0xC290, 0xC470, 0xC7D0, 0xCC40, 0xCFB0, /* Data to be written from 0x90h */ 0x00C0, 0x0200, 0x1C10, 0x0B00, 0x0900, 0x1F00, 0x1F00, 0x23C0, 0x1990, 0x19F0, 0x09A0, 0x0CE0, 0x0BE0, 0x07D0, 0x0990, 0x0990, /* Data to be written from 0xA0h */ 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, }, }; static unsigned int bat_depl_states[] = { 5400, 4800, 4200, 3600, 3000, 2400, 1800, 1200, 600, 0 }; static struct edp_client bat_depl_client = { .states = bat_depl_states, .num_states = ARRAY_SIZE(bat_depl_states), .e0_index = 0, .priority = EDP_MAX_PRIO }; static struct max17042_platform_data max17042_pdata = { .config_data = &conf_data, .init_data = NULL, .num_init_data = 0, .enable_por_init = 1, /* Use POR init from Maxim appnote */ .enable_current_sense = 1, .r_sns = 0, .edp_client = &bat_depl_client }; static struct i2c_board_info max17042_device[] = { { I2C_BOARD_INFO("max17042", 0x36), .platform_data = &max17042_pdata, }, }; static struct nvc_torch_lumi_level_v1 pluto_max77665_lumi_tbl[] = { {0, 100000}, {1, 201690}, {2, 298080}, {3, 387700}, {4, 479050}, {5, 562000}, {6, 652560}, {7, 732150}, {8, 816050}, {9, 896710}, {10, 976890}, {11, 1070160}, {12, 1151000}, {13, 1227790}, {14, 1287690}, {15, 1375060}, }; static unsigned max77665_f_estates[] = { 3500, 2375, 560, 456, 0 }; static struct max77665_f_platform_data pluto_max77665_flash_pdata = { .config = { .led_mask = 3, /* set to true only when using the torch strobe input * to trigger the flash. */ .flash_on_torch = false, /* use ONE-SHOOT flash mode - flash triggered at the * raising edge of strobe or strobe signal. */ .flash_mode = 1, /* .flash_on_torch = true, */ .max_total_current_mA = 1000, .max_peak_current_mA = 600, .led_config[0] = { .flash_torch_ratio = 18100, .granularity = 1000, .flash_levels = ARRAY_SIZE(pluto_max77665_lumi_tbl), .lumi_levels = pluto_max77665_lumi_tbl, }, .led_config[1] = { .flash_torch_ratio = 18100, .granularity = 1000, .flash_levels = ARRAY_SIZE(pluto_max77665_lumi_tbl), .lumi_levels = pluto_max77665_lumi_tbl, }, }, .pinstate = { .mask = 1 << (CAM_FLASH_STROBE - TEGRA_GPIO_PBB0), .values = 1 << (CAM_FLASH_STROBE - TEGRA_GPIO_PBB0), }, .dev_name = "torch", .gpio_strobe = CAM_FLASH_STROBE, .edpc_config = { .states = max77665_f_estates, .num_states = ARRAY_SIZE(max77665_f_estates), .e0_index = 3, .priority = EDP_MAX_PRIO + 2, }, }; static struct max77665_haptic_platform_data max77665_haptic_pdata = { .pwm_channel_id = 2, .pwm_period = 50, .type = MAX77665_HAPTIC_LRA, .mode = MAX77665_INTERNAL_MODE, .internal_mode_pattern = 0, .pattern_cycle = 10, .pattern_signal_period = 0xD0, .pwm_divisor = MAX77665_PWM_DIVISOR_128, .feedback_duty_cycle = 12, .invert = MAX77665_INVERT_OFF, .cont_mode = MAX77665_CONT_MODE, .motor_startup_val = 0, .scf_val = 2, .edp_states = { 360, 0 }, }; static struct max77665_charger_cable maxim_cable[] = { { .name = "USB", }, { .name = "USB-Host", }, { .name = "TA", }, { .name = "Fast-charger", }, { .name = "Slow-charger", }, { .name = "Charge-downstream", }, }; static struct max77665_charger_plat_data max77665_charger = { .fast_chg_cc = 1500, /* fast charger current*/ .term_volt = 3700, /* charger termination voltage */ .curr_lim = 1500, /* input current limit */ .num_cables = MAX_CABLES, .cables = maxim_cable, .irq_base = MAX77665_TEGRA_IRQ_BASE, .update_status = max17042_update_status, }; static struct max77665_muic_platform_data max77665_muic = { .irq_base = 0, }; static struct max77665_platform_data pluto_max77665_pdata = { .irq_base = MAX77665_TEGRA_IRQ_BASE, .irq_flag = IRQF_ONESHOT | IRQF_TRIGGER_FALLING, .muic_platform_data = { .pdata = &max77665_muic, .size = sizeof(max77665_muic), }, .charger_platform_data = { .pdata = &max77665_charger, .size = sizeof(max77665_charger), }, .flash_platform_data = { .pdata = &pluto_max77665_flash_pdata, .size = sizeof(pluto_max77665_flash_pdata), }, .haptic_platform_data = { .pdata = &max77665_haptic_pdata, .size = sizeof(max77665_haptic_pdata), }, }; static struct i2c_board_info pluto_i2c_board_info_max77665[] = { { I2C_BOARD_INFO("max77665", 0x66), .platform_data = &pluto_max77665_pdata, }, }; /* isl29029 support is provided by isl29028*/ static struct i2c_board_info pluto_i2c1_isl_board_info[] = { { I2C_BOARD_INFO("isl29028", 0x44), } }; static struct throttle_table tj_throttle_table[] = { /* CPU_THROT_LOW cannot be used by other than CPU */ /* NO_CAP cannot be used by CPU */ /* CPU, C2BUS, C3BUS, SCLK, EMC */ { { 1530000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1428000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1326000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1224000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1122000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1020000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 918000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 816000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 714000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 612000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 612000, 564000, 564000, NO_CAP, NO_CAP } }, { { 612000, 528000, 528000, NO_CAP, NO_CAP } }, { { 612000, 492000, 492000, NO_CAP, NO_CAP } }, { { 612000, 420000, 420000, NO_CAP, NO_CAP } }, { { 612000, 408000, 408000, NO_CAP, NO_CAP } }, { { 612000, 360000, 360000, NO_CAP, NO_CAP } }, { { 612000, 360000, 360000, 312000, NO_CAP } }, { { 510000, 360000, 360000, 312000, 480000 } }, { { 468000, 360000, 360000, 312000, 480000 } }, { { 468000, 276000, 276000, 208000, 480000 } }, { { 372000, 276000, 276000, 208000, 204000 } }, { { 288000, 276000, 276000, 208000, 204000 } }, { { 252000, 276000, 228000, 208000, 102000 } }, { { 204000, 276000, 228000, 208000, 102000 } }, { { 102000, 276000, 228000, 208000, 102000 } }, { { CPU_THROT_LOW, 276000, 228000, 208000, 102000 } }, }; static struct balanced_throttle tj_throttle = { .throt_tab_size = ARRAY_SIZE(tj_throttle_table), .throt_tab = tj_throttle_table, }; static int __init pluto_throttle_init(void) { if (machine_is_tegra_pluto()) balanced_throttle_register(&tj_throttle, "tegra-balanced"); return 0; } module_init(pluto_throttle_init); static struct nct1008_platform_data pluto_nct1008_pdata = { .supported_hwrev = true, .ext_range = true, .conv_rate = 0x08, .offset = 0, .shutdown_ext_limit = 105, /* C */ .shutdown_local_limit = 120, /* C */ }; static struct i2c_board_info pluto_i2c4_nct1008_board_info[] = { { I2C_BOARD_INFO("nct1008", 0x4C), .platform_data = &pluto_nct1008_pdata, .irq = -1, } }; #define VI_PINMUX(_pingroup, _mux, _pupd, _tri, _io, _lock, _ioreset) \ { \ .pingroup = TEGRA_PINGROUP_##_pingroup, \ .func = TEGRA_MUX_##_mux, \ .pupd = TEGRA_PUPD_##_pupd, \ .tristate = TEGRA_TRI_##_tri, \ .io = TEGRA_PIN_##_io, \ .lock = TEGRA_PIN_LOCK_##_lock, \ .od = TEGRA_PIN_OD_DEFAULT, \ .ioreset = TEGRA_PIN_IO_RESET_##_ioreset \ } static int pluto_focuser_power_on(struct ad5816_power_rail *pw) { int err; if (unlikely(WARN_ON(!pw || !pw->vdd || !pw->vdd_i2c))) return -EFAULT; err = regulator_enable(pw->vdd_i2c); if (unlikely(err)) goto ad5816_vdd_i2c_fail; err = regulator_enable(pw->vdd); if (unlikely(err)) goto ad5816_vdd_fail; return 0; ad5816_vdd_fail: regulator_disable(pw->vdd_i2c); ad5816_vdd_i2c_fail: pr_err("%s FAILED\n", __func__); return -ENODEV; } static int pluto_focuser_power_off(struct ad5816_power_rail *pw) { if (unlikely(WARN_ON(!pw || !pw->vdd || !pw->vdd_i2c))) return -EFAULT; regulator_disable(pw->vdd); regulator_disable(pw->vdd_i2c); return 0; } static struct tegra_pingroup_config mclk_disable = VI_PINMUX(CAM_MCLK, VI, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT); static struct tegra_pingroup_config mclk_enable = VI_PINMUX(CAM_MCLK, VI_ALT3, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT); static struct tegra_pingroup_config pbb0_disable = VI_PINMUX(GPIO_PBB0, VI, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT); static struct tegra_pingroup_config pbb0_enable = VI_PINMUX(GPIO_PBB0, VI_ALT3, NORMAL, NORMAL, OUTPUT, DEFAULT, DEFAULT); /* * more regulators need to be allocated to activate the sensor devices. * pluto_vcmvdd: this is a workaround due to the focuser device(AD5816) will * hook up the i2c bus if it is not powered up. * pluto_i2cvdd: by default, the power supply on the i2c bus is OFF. So it * should be turned on every time any sensor device is activated. */ static struct regulator *pluto_vcmvdd; static struct regulator *pluto_i2cvdd; static int pluto_get_extra_regulators(void) { if (!pluto_vcmvdd) { pluto_vcmvdd = regulator_get(NULL, "vdd_af_cam1"); if (WARN_ON(IS_ERR(pluto_vcmvdd))) { pr_err("%s: can't get regulator vdd_af_cam1: %ld\n", __func__, PTR_ERR(pluto_vcmvdd)); pluto_vcmvdd = NULL; return -ENODEV; } } if (!pluto_i2cvdd) { pluto_i2cvdd = regulator_get(NULL, "vddio_cam_mb"); if (unlikely(WARN_ON(IS_ERR(pluto_i2cvdd)))) { pr_err("%s: can't get regulator vddio_cam_mb: %ld\n", __func__, PTR_ERR(pluto_i2cvdd)); pluto_i2cvdd = NULL; return -ENODEV; } } return 0; } static int pluto_imx091_power_on(struct nvc_regulator *vreg) { int err; if (unlikely(WARN_ON(!vreg))) return -EFAULT; if (pluto_get_extra_regulators()) goto imx091_poweron_fail; gpio_set_value(CAM1_POWER_DWN_GPIO, 0); usleep_range(10, 20); err = regulator_enable(vreg[IMX091_VREG_AVDD].vreg); if (unlikely(err)) goto imx091_avdd_fail; err = regulator_enable(vreg[IMX091_VREG_DVDD].vreg); if (unlikely(err)) goto imx091_dvdd_fail; err = regulator_enable(vreg[IMX091_VREG_IOVDD].vreg); if (unlikely(err)) goto imx091_iovdd_fail; usleep_range(1, 2); gpio_set_value(CAM1_POWER_DWN_GPIO, 1); tegra_pinmux_config_table(&mclk_enable, 1); err = regulator_enable(pluto_i2cvdd); if (unlikely(err)) goto imx091_i2c_fail; err = regulator_enable(pluto_vcmvdd); if (unlikely(err)) goto imx091_vcm_fail; usleep_range(300, 310); return 0; imx091_vcm_fail: regulator_disable(pluto_i2cvdd); imx091_i2c_fail: tegra_pinmux_config_table(&mclk_disable, 1); gpio_set_value(CAM1_POWER_DWN_GPIO, 0); regulator_disable(vreg[IMX091_VREG_IOVDD].vreg); imx091_iovdd_fail: regulator_disable(vreg[IMX091_VREG_DVDD].vreg); imx091_dvdd_fail: regulator_disable(vreg[IMX091_VREG_AVDD].vreg); imx091_avdd_fail: imx091_poweron_fail: pr_err("%s FAILED\n", __func__); return -ENODEV; } static int pluto_imx091_power_off(struct nvc_regulator *vreg) { if (unlikely(WARN_ON(!vreg))) return -EFAULT; usleep_range(1, 2); tegra_pinmux_config_table(&mclk_disable, 1); gpio_set_value(CAM1_POWER_DWN_GPIO, 0); usleep_range(1, 2); regulator_disable(vreg[IMX091_VREG_IOVDD].vreg); regulator_disable(vreg[IMX091_VREG_DVDD].vreg); regulator_disable(vreg[IMX091_VREG_AVDD].vreg); regulator_disable(pluto_i2cvdd); regulator_disable(pluto_vcmvdd); return 0; } static struct nvc_imager_cap imx091_cap = { .identifier = "IMX091", .sensor_nvc_interface = 3, .pixel_types[0] = 0x100, .orientation = 0, .direction = 0, .initial_clock_rate_khz = 6000, .clock_profiles[0] = { .external_clock_khz = 24000, .clock_multiplier = 850000, /* value / 1,000,000 */ }, .clock_profiles[1] = { .external_clock_khz = 0, .clock_multiplier = 0, }, .h_sync_edge = 0, .v_sync_edge = 0, .mclk_on_vgp0 = 0, .csi_port = 0, .data_lanes = 4, .virtual_channel_id = 0, .discontinuous_clk_mode = 1, .cil_threshold_settle = 0x0, .min_blank_time_width = 16, .min_blank_time_height = 16, .preferred_mode_index = 0, .focuser_guid = NVC_FOCUS_GUID(0), .torch_guid = NVC_TORCH_GUID(0), .cap_version = NVC_IMAGER_CAPABILITIES_VERSION2, }; static unsigned imx091_estates[] = { 876, 656, 220, 0 }; static struct imx091_platform_data imx091_pdata = { .num = 0, .sync = 0, .dev_name = "camera", .gpio_count = ARRAY_SIZE(imx091_gpio_pdata), .gpio = imx091_gpio_pdata, .flash_cap = { .sdo_trigger_enabled = 1, .adjustable_flash_timing = 1, }, .cap = &imx091_cap, .edpc_config = { .states = imx091_estates, .num_states = ARRAY_SIZE(imx091_estates), .e0_index = 0, .priority = EDP_MAX_PRIO + 1, }, .power_on = pluto_imx091_power_on, .power_off = pluto_imx091_power_off, }; static int pluto_imx132_power_on(struct imx132_power_rail *pw) { int err; if (unlikely(WARN_ON(!pw || !pw->avdd || !pw->iovdd || !pw->dvdd))) return -EFAULT; if (pluto_get_extra_regulators()) goto pluto_imx132_poweron_fail; gpio_set_value(CAM2_POWER_DWN_GPIO, 0); tegra_pinmux_config_table(&pbb0_enable, 1); err = regulator_enable(pluto_i2cvdd); if (unlikely(err)) goto imx132_i2c_fail; err = regulator_enable(pluto_vcmvdd); if (unlikely(err)) goto imx132_vcm_fail; err = regulator_enable(pw->avdd); if (unlikely(err)) goto imx132_avdd_fail; err = regulator_enable(pw->dvdd); if (unlikely(err)) goto imx132_dvdd_fail; err = regulator_enable(pw->iovdd); if (unlikely(err)) goto imx132_iovdd_fail; usleep_range(1, 2); gpio_set_value(CAM2_POWER_DWN_GPIO, 1); return 0; imx132_iovdd_fail: regulator_disable(pw->dvdd); imx132_dvdd_fail: regulator_disable(pw->avdd); imx132_avdd_fail: regulator_disable(pluto_vcmvdd); imx132_vcm_fail: regulator_disable(pluto_i2cvdd); imx132_i2c_fail: tegra_pinmux_config_table(&pbb0_disable, 1); pluto_imx132_poweron_fail: pr_err("%s failed.\n", __func__); return -ENODEV; } static int pluto_imx132_power_off(struct imx132_power_rail *pw) { if (unlikely(WARN_ON(!pw || !pw->avdd || !pw->iovdd || !pw->dvdd || !pluto_i2cvdd || !pluto_vcmvdd))) return -EFAULT; gpio_set_value(CAM2_POWER_DWN_GPIO, 0); usleep_range(1, 2); regulator_disable(pw->iovdd); regulator_disable(pw->dvdd); regulator_disable(pw->avdd); tegra_pinmux_config_table(&pbb0_disable, 1); regulator_disable(pluto_vcmvdd); regulator_disable(pluto_i2cvdd); return 0; } struct imx132_platform_data pluto_imx132_data = { .power_on = pluto_imx132_power_on, .power_off = pluto_imx132_power_off, }; static struct ad5816_platform_data pluto_ad5816_pdata = { .cfg = 0, .num = 0, .sync = 0, .dev_name = "focuser", .power_on = pluto_focuser_power_on, .power_off = pluto_focuser_power_off, }; static struct regulator *dvdd_1v8; static struct regulator *avdd_cam2; static struct regulator *vdd_af1; static int pluto_ov5640_power_on(struct device *dev) { if (avdd_cam2 == NULL) { avdd_cam2 = regulator_get(dev, "avdd_cam2"); if (WARN_ON(IS_ERR(avdd_cam2))) { pr_err("%s: couldn't get regulator avdd_cam2: %ld\n", __func__, PTR_ERR(avdd_cam2)); avdd_cam2 = NULL; goto avdd_cam2_fail; } } if (dvdd_1v8 == NULL) { dvdd_1v8 = regulator_get(dev, "vdd_1v8_cam12"); if (WARN_ON(IS_ERR(dvdd_1v8))) { pr_err("%s: couldn't get regulator vdd_1v8_cam: %ld\n", __func__, PTR_ERR(dvdd_1v8)); dvdd_1v8 = NULL; goto dvdd_1v8_fail; } } if (vdd_af1 == NULL) { vdd_af1 = regulator_get(dev, "vdd_af_cam1"); if (WARN_ON(IS_ERR(vdd_af1))) { pr_err("%s: couldn't get regulator vdd_af_cam1: %ld\n", __func__, PTR_ERR(vdd_af1)); vdd_af1 = NULL; goto vdd_af1_fail; } } /* power up sequence */ gpio_set_value(CAM2_POWER_DWN_GPIO, 1); gpio_set_value(CAM_RSTN, 0); mdelay(1); regulator_enable(vdd_af1); regulator_enable(dvdd_1v8); regulator_enable(avdd_cam2); tegra_pinmux_config_table(&pbb0_enable, 1); mdelay(5); gpio_set_value(CAM2_POWER_DWN_GPIO, 0); mdelay(1); gpio_set_value(CAM_RSTN, 1); mdelay(20); return 0; vdd_af1_fail: regulator_disable(dvdd_1v8); dvdd_1v8_fail: regulator_disable(avdd_cam2); avdd_cam2_fail: return -ENODEV; } static int pluto_ov5640_power_off(struct device *dev) { gpio_set_value(CAM_RSTN, 0); tegra_pinmux_config_table(&pbb0_disable, 1); if (avdd_cam2) regulator_disable(avdd_cam2); if (dvdd_1v8) regulator_disable(dvdd_1v8); if (vdd_af1) regulator_disable(vdd_af1); gpio_set_value(CAM2_POWER_DWN_GPIO, 1); return 0; } struct ov5640_platform_data pluto_ov5640_data = { .power_on = pluto_ov5640_power_on, .power_off = pluto_ov5640_power_off, }; static struct i2c_board_info pluto_board_info_ov5640[] = { { I2C_BOARD_INFO("ov5640", 0x3c), .platform_data = &pluto_ov5640_data, } }; static struct i2c_board_info pluto_i2c_board_info_e1625[] = { { I2C_BOARD_INFO("imx091", 0x10), .platform_data = &imx091_pdata, }, { I2C_BOARD_INFO("imx132", 0x36), .platform_data = &pluto_imx132_data, }, { I2C_BOARD_INFO("ad5816", 0x0E), .platform_data = &pluto_ad5816_pdata, }, }; /* Detect ov5640 adapter by toggling the CAM_GPIO1 and read it back * from CAM_GPIO2. * On the ov5640 adapter board (E1633) for pluto, pin 5 & 6 of connector J9 * should be shorted. */ static int ov5640_installed(void) { int val; int ret; ret = gpio_request(CAM_GPIO1, "camera_gpio1"); if (ret < 0) { pr_err("%s, gpio_request failed for CAM_GPIO1\n", __func__); return 0; } ret = gpio_request(CAM_GPIO2, "camera_gpio2"); if (ret < 0) { pr_err("%s, gpio_request failed for CAM_GPIO2\n", __func__); gpio_free(CAM_GPIO1); return 0; } gpio_direction_output(CAM_GPIO1, 1); gpio_direction_input(CAM_GPIO2); val = gpio_get_value(CAM_GPIO1); ret = gpio_get_value(CAM_GPIO2); pr_info("%s round 1: %d vs %d\n", __func__, val, ret); if (ret != val) { gpio_free(CAM_GPIO1); gpio_free(CAM_GPIO2); return 0; } /* toggle CAM_GPIO1 and read back from detect pin */ val ^= 1; gpio_set_value(CAM_GPIO1, val & 1); ret = gpio_get_value(CAM_GPIO2); /* resume CAM_GPIO1 state */ gpio_set_value(CAM_GPIO1, (~val) & 1); gpio_free(CAM_GPIO2); gpio_free(CAM_GPIO1); pr_info("%s round 2: %d vs %d\n", __func__, val, ret); if (ret != val) return 0; return 1; } static int pluto_camera_init(void) { pr_debug("%s: ++\n", __func__); tegra_pinmux_config_table(&mclk_disable, 1); tegra_pinmux_config_table(&pbb0_disable, 1); if (ov5640_installed()) { pr_info("%s ov5640 installed.\n", __func__); i2c_register_board_info(2, pluto_board_info_ov5640, ARRAY_SIZE(pluto_board_info_ov5640)); } else i2c_register_board_info(2, pluto_i2c_board_info_e1625, ARRAY_SIZE(pluto_i2c_board_info_e1625)); return 0; } /* MPU board file definition */ static struct mpu_platform_data mpu_gyro_data = { .int_config = 0x00, .level_shifter = 0, .orientation = MPU_GYRO_ORIENTATION, .sec_slave_type = SECONDARY_SLAVE_TYPE_NONE, .key = {0x4E, 0xCC, 0x7E, 0xEB, 0xF6, 0x1E, 0x35, 0x22, 0x00, 0x34, 0x0D, 0x65, 0x32, 0xE9, 0x94, 0x89}, }; static struct mpu_platform_data mpu_compass_data = { .orientation = MPU_COMPASS_ORIENTATION, .config = NVI_CONFIG_BOOT_MPU, }; static struct mpu_platform_data bmp180_pdata = { .config = NVI_CONFIG_BOOT_MPU, }; static struct i2c_board_info __initdata inv_mpu_i2c0_board_info[] = { { I2C_BOARD_INFO(MPU_GYRO_NAME, MPU_GYRO_ADDR), .platform_data = &mpu_gyro_data, }, { /* The actual BMP180 address is 0x77 but because this conflicts * with another device, this address is hacked so Linux will * call the driver. The conflict is technically okay since the * BMP180 is behind the MPU. Also, the BMP180 driver uses a * hard-coded address of 0x77 since it can't be changed anyway. */ I2C_BOARD_INFO("bmp180", 0x78), .platform_data = &bmp180_pdata, }, { I2C_BOARD_INFO(MPU_COMPASS_NAME, MPU_COMPASS_ADDR), .platform_data = &mpu_compass_data, }, }; static void mpuirq_init(void) { int ret = 0; int i = 0; pr_info("*** MPU START *** mpuirq_init...\n"); /* MPU-IRQ assignment */ ret = gpio_request(MPU_GYRO_IRQ_GPIO, MPU_GYRO_NAME); if (ret < 0) { pr_err("%s: gpio_request failed %d\n", __func__, ret); return; } ret = gpio_direction_input(MPU_GYRO_IRQ_GPIO); if (ret < 0) { pr_err("%s: gpio_direction_input failed %d\n", __func__, ret); gpio_free(MPU_GYRO_IRQ_GPIO); return; } pr_info("*** MPU END *** mpuirq_init...\n"); inv_mpu_i2c0_board_info[i++].irq = gpio_to_irq(MPU_GYRO_IRQ_GPIO); #if MPU_COMPASS_IRQ_GPIO inv_mpu_i2c0_board_info[i++].irq = gpio_to_irq(MPU_COMPASS_IRQ_GPIO); #endif i2c_register_board_info(MPU_GYRO_BUS_NUM, inv_mpu_i2c0_board_info, ARRAY_SIZE(inv_mpu_i2c0_board_info)); } static int pluto_nct1008_init(void) { int nct1008_port; int ret = 0; if (board_info.board_id == BOARD_E1580 || board_info.board_id == BOARD_E1575 || board_info.board_id == BOARD_E1577) { nct1008_port = TEGRA_GPIO_PX6; } else { nct1008_port = TEGRA_GPIO_PX6; pr_err("Warning: nct alert port assumed TEGRA_GPIO_PX6 for unknown pluto board id E%d\n", board_info.board_id); } tegra_add_cdev_trips(pluto_nct1008_pdata.trips, &pluto_nct1008_pdata.num_trips); pluto_i2c4_nct1008_board_info[0].irq = gpio_to_irq(nct1008_port); pr_info("%s: pluto nct1008 irq %d", __func__, pluto_i2c4_nct1008_board_info[0].irq); ret = gpio_request(nct1008_port, "temp_alert"); if (ret < 0) return ret; ret = gpio_direction_input(nct1008_port); if (ret < 0) { pr_info("%s: calling gpio_free(nct1008_port)", __func__); gpio_free(nct1008_port); } /* pluto has thermal sensor on GEN1-I2C i.e. instance 0 */ i2c_register_board_info(0, pluto_i2c4_nct1008_board_info, ARRAY_SIZE(pluto_i2c4_nct1008_board_info)); return ret; } #ifdef CONFIG_TEGRA_SKIN_THROTTLE static int tegra_skin_match(struct thermal_zone_device *thz, void *data) { return strcmp((char *)data, thz->type) == 0; } static int tegra_skin_get_temp(void *data, long *temp) { struct thermal_zone_device *thz; thz = thermal_zone_device_find(data, tegra_skin_match); if (!thz || thz->ops->get_temp(thz, temp)) *temp = 25000; return 0; } static struct therm_est_data skin_data = { .cdev_type = "skin-balanced", .toffset = 9793, .polling_period = 1100, .ndevs = 2, .tc1 = 10, .tc2 = 1, .devs = { { .dev_data = "nct_ext", .get_temp = tegra_skin_get_temp, .coeffs = { 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, -1, -7 }, }, { .dev_data = "nct_int", .get_temp = tegra_skin_get_temp, .coeffs = { -11, -7, -5, -3, -3, -2, -1, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 6, 11, 18 }, }, }, .trip_temp = 45000, .passive_delay = 15000, }; static struct throttle_table skin_throttle_table[] = { /* CPU_THROT_LOW cannot be used by other than CPU */ /* NO_CAP cannot be used by CPU */ /* CPU, C2BUS, C3BUS, SCLK, EMC */ { { 1530000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1530000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1326000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1326000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1326000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1326000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1326000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1122000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1122000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1122000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1122000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1122000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1122000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1020000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1020000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1020000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1020000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1020000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 1020000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 918000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 918000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 918000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 918000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 918000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 918000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 816000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 816000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 816000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 816000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 816000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 816000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 714000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 714000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 714000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 714000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 714000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 714000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 612000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 612000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 612000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 612000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 612000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 612000, NO_CAP, NO_CAP, NO_CAP, NO_CAP } }, { { 612000, 564000, 564000, NO_CAP, NO_CAP } }, { { 612000, 564000, 564000, NO_CAP, NO_CAP } }, { { 612000, 528000, 528000, NO_CAP, NO_CAP } }, { { 612000, 528000, 528000, NO_CAP, NO_CAP } }, { { 612000, 492000, 492000, NO_CAP, NO_CAP } }, { { 612000, 492000, 492000, NO_CAP, NO_CAP } }, { { 612000, 420000, 420000, NO_CAP, NO_CAP } }, { { 612000, 420000, 420000, NO_CAP, NO_CAP } }, { { 612000, 408000, 408000, NO_CAP, NO_CAP } }, { { 612000, 408000, 408000, NO_CAP, NO_CAP } }, { { 612000, 360000, 360000, NO_CAP, NO_CAP } }, { { 612000, 360000, 360000, NO_CAP, NO_CAP } }, { { 510000, 360000, 360000, 312000, NO_CAP } }, { { 510000, 360000, 360000, 312000, NO_CAP } }, { { 510000, 360000, 360000, 312000, 480000 } }, { { 510000, 360000, 360000, 312000, 480000 } }, { { 510000, 360000, 360000, 312000, 480000 } }, { { 510000, 360000, 360000, 312000, 480000 } }, { { 510000, 360000, 360000, 312000, 480000 } }, { { 510000, 360000, 360000, 312000, 480000 } }, { { 468000, 360000, 360000, 312000, 480000 } }, { { 468000, 360000, 360000, 312000, 480000 } }, { { 468000, 276000, 276000, 208000, 480000 } }, { { 468000, 276000, 276000, 208000, 480000 } }, { { 372000, 276000, 276000, 208000, 204000 } }, { { 372000, 276000, 276000, 208000, 204000 } }, { { 288000, 276000, 276000, 208000, 204000 } }, { { 288000, 276000, 276000, 208000, 204000 } }, { { 252000, 276000, 228000, 208000, 102000 } }, { { 252000, 276000, 228000, 208000, 102000 } }, { { 204000, 276000, 228000, 208000, 102000 } }, { { 204000, 276000, 228000, 208000, 102000 } }, { { 102000, 276000, 228000, 208000, 102000 } }, { { CPU_THROT_LOW, 276000, 228000, 208000, 102000 } }, }; static struct balanced_throttle skin_throttle = { .throt_tab_size = ARRAY_SIZE(skin_throttle_table), .throt_tab = skin_throttle_table, }; static int __init pluto_skin_init(void) { if (machine_is_tegra_pluto()) { balanced_throttle_register(&skin_throttle, "skin-balanced"); tegra_skin_therm_est_device.dev.platform_data = &skin_data; platform_device_register(&tegra_skin_therm_est_device); } return 0; } late_initcall(pluto_skin_init); #endif void __init max77665_init(void) { int err; err = gpio_request(MAX77665_CHARGER_INT, "CHARGER_INT"); if (err < 0) { pr_err("%s: gpio_request failed %d\n", __func__, err); goto fail_init_irq; } err = gpio_direction_input(MAX77665_CHARGER_INT); if (err < 0) { pr_err("%s: gpio_direction_input failed %d\n", __func__, err); goto fail_init_irq; } pluto_i2c_board_info_max77665[0].irq = gpio_to_irq(MAX77665_CHARGER_INT); fail_init_irq: err = i2c_register_board_info(4, pluto_i2c_board_info_max77665, ARRAY_SIZE(pluto_i2c_board_info_max77665)); if (err) pr_err("%s: max77665 device register failed.\n", __func__); return; } int __init pluto_sensors_init(void) { int err; tegra_get_board_info(&board_info); pr_debug("%s: ++\n", __func__); pluto_camera_init(); err = pluto_nct1008_init(); if (err) return err; err = i2c_register_board_info(0, pluto_i2c1_isl_board_info, ARRAY_SIZE(pluto_i2c1_isl_board_info)); if (err) pr_err("%s: isl board register failed.\n", __func__); mpuirq_init(); max77665_init(); pluto_i2c_board_info_max77665[0].irq = gpio_to_irq(TEGRA_GPIO_PJ0); err = i2c_register_board_info(0, max17042_device, ARRAY_SIZE(max17042_device)); if (err) pr_err("%s: max17042 device register failed.\n", __func__); return 0; }