예제 #1
0
/* From Xiaomi */
static int drv2604_probe(struct i2c_client* client, const struct i2c_device_id* id)
{
    char status;
#if SKIP_LRA_AUTOCAL == 0
    int nCalibrationCount = 0;
#endif
    unsigned char tmp[] = { MODE_REG, MODE_STANDBY };

    if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
        DbgOut((DBL_ERROR, "drv2604 on M3 probe failed"));
        return -ENODEV;
    }

    /* Enable power to the chip */
    gpio_direction_output(GPIO_VIBTONE_EN1, GPIO_LEVEL_HIGH);

    /* Wait 30 us */
    udelay(30);
    g_pTheClient = client;
    g_hw_version = get_hw_version_major();
    if(g_hw_version == 5)
        if(get_hw_version_minor() != 1)
            g_hw_version = 6;

    /* compatible with x3,x5 (LRA) and x4 (ERM) */
    if (g_hw_version == 4) {
        DRV_init_sequence = ERM_init_sequence;
        seq_size = sizeof(ERM_init_sequence);
    } else if (g_hw_version == 5) {
        DRV_init_sequence = NID_init_sequence;
        seq_size = sizeof(NID_init_sequence);
    } else if (g_hw_version == 6) {
        DRV_init_sequence = X5LRA_init_sequence;
        seq_size = sizeof(X5LRA_init_sequence);
        g_autotune_brake_enabled = true;
    } else {
        DRV_init_sequence = LRA_init_sequence;
        seq_size = sizeof(LRA_init_sequence);
        g_autotune_brake_enabled = true;
    }

#if SKIP_LRA_AUTOCAL == 1
    drv2604_write_reg_val(DRV_init_sequence, seq_size);
    status = drv2604_read_reg(STATUS_REG);
#else
    /* Run auto-calibration */
    do {
        drv2604_write_reg_val(LRA_autocal_sequence, sizeof(LRA_autocal_sequence));
        /* Wait until the procedure is done */
        drv2604_poll_go_bit();

        /* Read status */
        status = drv2604_read_reg(STATUS_REG);

        nCalibrationCount++;
    } while (((status & DIAG_RESULT_MASK) == AUTO_CAL_FAILED) && (nCalibrationCount < MAX_AUTOCALIBRATION_ATTEMPT));

    /* Check result */
    if ((status & DIAG_RESULT_MASK) == AUTO_CAL_FAILED) {
        DbgOut((DBL_ERROR, "drv2604 auto-calibration failed after %d attempts.\n", nCalibrationCount));
    } else {
        /* restore 0x1a */
        drv2604_write_reg_val(LRA_autocal_done_seq, sizeof(LRA_autocal_done_seq));
        /* Read calibration results */
        drv2604_read_reg(AUTO_CALI_RESULT_REG);
        drv2604_read_reg(AUTO_CALI_BACK_EMF_RESULT_REG);
        drv2604_read_reg(FEEDBACK_CONTROL_REG);
    }
#endif

    /* Read device ID */
    g_nDeviceID = (status & DEV_ID_MASK);
    switch (g_nDeviceID) {
    case DRV2605:
        DbgOut((DBL_INFO, "drv2604 driver found: drv2605.\n"));
        break;
    case DRV2604:
        DbgOut((DBL_INFO, "drv2604 driver found: drv2604.\n"));
        break;
    default:
        DbgOut((DBL_INFO, "drv2604 driver found: unknown.\n"));
        break;
    }

#if USE_DRV2604_STANDBY
    /* Put hardware in standby */
    drv2604_write_reg_val(tmp, sizeof(tmp));
#elif USE_DRV2604_EN_PIN
    /* enable RTP mode that will be toggled on/off with EN pin */
    drv2604_change_mode(MODE_REAL_TIME_PLAYBACK);
#endif

#if USE_DRV2604_EN_PIN
    /* turn off chip */
    drv2604_set_en(false);
#endif

    debugfs_create_file("drv2604", 0644, NULL, NULL, &drv2604_dbg);

    DbgOut((DBL_INFO, "drv2604 on M3 probe succeeded"));

    /* From Xiaomi start */
#if SUPPORT_WRITE_PAT
    INIT_WORK(&vibdata.pat_work, drv2604_pat_work);
    vibdata.hap_wq = alloc_workqueue("haptic_wq", WQ_HIGHPRI, 0);
    if (vibdata.hap_wq  == NULL) {
        printk("drv2604 alloc workqueue failed");
    }
    vibdata.pat = pattern;
#endif
    /* From Xiaomi end */

    printk(KERN_ALERT"drv2604 probe succeeded");

    return 0;
}
static int __devinit drv2604_vibrator_i2c_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
{

	int nRet, i,error;   /* initialized below */
	char status;
#if SKIP_AUTOCAL == 0
	int nCalibrationCount = 0;
#endif
        DbgOut((KERN_INFO "tspdrv: Probe called.\n"));

        vibrator_drvdata.client = client;
        if(!(client->dev.of_node)){
                        DbgOut(KERN_ERR "tspdrv: tspdrv probe failed, DT is NULL");
                        return -ENODEV;
        }
        error = drv2604_parse_dt(&client->dev);
        if (error)
                return error;

        if( gpio_request(vibrator_drvdata.motor_en, "MOTOR_EN") < 0)
        {
                return -EINVAL;
        }

        gpio_direction_output(vibrator_drvdata.motor_en, 0);
        gpio_export(vibrator_drvdata.motor_en, 0);


        nRet = misc_register(&miscdev);
        if (nRet)
        {
        DbgOut((KERN_ERR "tspdrv: misc_register failed.\n"));
                return nRet;
        }

#if USE_DRV2604_EN_PIN
    drv2604_set_en(true);
#endif
#if USE_DRV2604_STANDBY
    /* Wait 1000 us for chip power to stabilize */
    usleep_range(100000, 100000);
    drv2604_change_mode(MODE_DEVICE_READY);
#endif
    /* Wait 1000 us for chip power to stabilize */
    usleep_range(1000, 1000);

#if SKIP_AUTOCAL
    usleep_range(100000, 100000);
    drv2604_write_reg_val(init_sequence, sizeof(init_sequence));
    status = drv2604_read_reg(STATUS_REG);
#else
    /* Run auto-calibration */
    do{
        drv2604_write_reg_val(autocal_sequence, sizeof(autocal_sequence));

        /* Wait until the procedure is done */
        drv2604_poll_go_bit();

        /* Read status */
        status = drv2604_read_reg(STATUS_REG);
        nCalibrationCount++;

    } while (((status & DIAG_RESULT_MASK) == AUTO_CAL_FAILED) && (nCalibrationCount < MAX_AUTOCALIBRATION_ATTEMPT));

    /* Check result */
    if ((status & DIAG_RESULT_MASK) == AUTO_CAL_FAILED)
    {
      DbgOut((DBL_ERROR, "drv2604 auto-calibration failed after %d attempts.\n", nCalibrationCount));
    }
    else
    {
        /* Read calibration results */
        drv2604_read_reg(AUTO_CALI_RESULT_REG);
        drv2604_read_reg(AUTO_CALI_BACK_EMF_RESULT_REG);
        drv2604_read_reg(FEEDBACK_CONTROL_REG);
    }
#endif

    /* Read device ID */
    g_nDeviceID = (status & DEV_ID_MASK);

    switch (g_nDeviceID)
    {
        case DRV2605:
            DbgOut((DBL_INFO, "drv2604 driver found: drv2605.\n"));
            break;
        case DRV2604:
            DbgOut((DBL_INFO, "drv2604 driver found: drv2604.\n"));
            break;
        case DRV2604L:
            DbgOut((DBL_INFO, "drv2604 driver found: drv2604L.\n"));
            break;
        case DRV2605L:
            DbgOut((DBL_INFO, "drv2604 driver found: drv2605L.\n"));
            break;
        default:
            DbgOut((DBL_INFO, "drv2604 driver found: unknown.\n"));
            break;
    }

#if USE_DRV2604_STANDBY
    /* Put hardware in standby */
    drv2604_change_mode(MODE_STANDBY);
#elif USE_DRV2604_EN_PIN
    /* enable RTP mode that will be toggled on/off with EN pin */
#endif

#if USE_DRV2604_EN_PIN
    /* turn off chip */
    drv2604_set_en(false);
#endif

    DbgRecorderInit(());

    ImmVibeSPI_ForceOut_Initialize();
    VibeOSKernelLinuxInitTimer();
    ResetOutputData();

    /* Get and concatenate device name and initialize data buffer */
    g_cchDeviceName = 0;
    for (i=0; i<NUM_ACTUATORS; i++)
    {
        char *szName = g_szDeviceName + g_cchDeviceName;
        ImmVibeSPI_Device_GetName(i, szName, VIBE_MAX_DEVICE_NAME_LENGTH);

        /* Append version information and get buffer length */
        strcat(szName, VERSION_STR);
        g_cchDeviceName += strlen(szName);

    }
    vibetonz_start();
    return 0;
}