int BattOff(void)
{
	uint8 data[20];
	int i;

	/* 16 no-ops to clear MPI buffer */
	for (i = 0; i < 16; i++)
		data[i] = VP880_NO_OP;

	VpMpiCmd(gDev1Id, EC_BOTH, VP880_NO_OP, 16, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_NO_OP, 16, data);

	/* Read RCN/PCN and check that the devices are what we expect */
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_DEVTYPE_CMD, VP880_DEVTYPE_LEN, data);
	if (data[0] != VP880_REV_JE || data[1] != VP880_DEV_PCN_88506) {
		mvOsPrintf("Invalid device 1, RCN/PCN 0x%02X%02X", data[0], data[1]);
		return -1;
	}
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_DEVTYPE_CMD, VP880_DEVTYPE_LEN, data);
	if (data[0] != VP880_REV_JE || data[1] != VP880_DEV_PCN_88506) {
		mvOsPrintf("Invalid device 2, RCN/PCN 0x%02X%02X", data[0], data[1]);
		return -1;
	}

	/* Run MPI checks on both devices to make sure that it's safe to start
	 * programming the devices.  If the signal integrity is bad, it could be
	 * dangerous to continue. */
	if (MpiTest(gDev1Id) < 0 || MpiTest(gDev2Id) < 0)
		return -1;

	/* Turn switchers off */
	data[0] = VP880_SWY_OFF | VP880_SWZ_OFF;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_REGULATOR_CTRL_WRT, VP880_REGULATOR_CTRL_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_REGULATOR_CTRL_WRT, VP880_REGULATOR_CTRL_LEN, data);

	/* Doubly make sure the switchers are off by setting ontimes to 0 */
	data[0] = 0x00;
	data[1] = 0x40;
	data[2] = 0x00;
	data[3] = 0x40;
	data[4] = 0x00;
	data[5] = 0x40;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_INT_SWREG_PARAM_WRT, VP880_INT_SWREG_PARAM_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_INT_SWREG_PARAM_WRT, VP880_INT_SWREG_PARAM_LEN, data);

	/* Turn off the LEDs */
	data[0] = 0;
	VpMpiCmd(gDev1Id, EC_1, VP880_IODATA_REG_WRT, VP880_IODATA_REG_LEN, data);
	VpMpiCmd(gDev2Id, EC_1, VP880_IODATA_REG_WRT, VP880_IODATA_REG_LEN, data);

	return 0;
}
Beispiel #2
0
static int vpapi_reg_read(unsigned long arg)
{
	VpModRegOpType data;
	VpLineIdType	line_id;
	unsigned char	cmd;
	unsigned short  cmd_len;
	unsigned char *buff_p = NULL;
	unsigned char ec_val[] = {0x1, 0x2};

	/* Get user data */
	if(copy_from_user(&data, (void*)arg, sizeof(VpModRegOpType))) {
			printk("%s: copy_from_user failed\n", __func__);
			return -EFAULT;
	}

	line_id = data.lineId;
	cmd = data.cmd;
	cmd_len = data.cmdLen;
	buff_p = data.buff;

	VpMpiCmd(GET_DEVICE(line_id), ec_val[GET_LINE(line_id)], (cmd | 1), cmd_len, buff_p);

	/* Copy status and event info back to user */
	if(copy_to_user((void*)arg, &data, sizeof(VpModRegOpType))) {
		printk("%s: copy_to_user failed\n", __func__);
		return  -EFAULT;
	}

	return 0;
}
/*
 * This function performs a series of writes and reads to verify the signal
 * integrity of the MPI interface.
 */
static int MpiTest(VpDeviceIdType devId)
{
	uint8 writeData[20] = { 0 };
	uint8 readData[20] = { 0 };
	int x;
	int y;
	int i;

	for (x = 0; x <= 0xFF; x++) {
		for (i = 0; i < VP880_R_FILTER_LEN; i++)
			writeData[i] = x;

		VpMpiCmd(devId, EC_1, VP880_R_FILTER_WRT, VP880_R_FILTER_LEN, writeData);
		VpMpiCmd(devId, EC_1, VP880_R_FILTER_RD, VP880_R_FILTER_LEN, readData);
		for (i = 0; i < VP880_R_FILTER_LEN; i++) {
			if (writeData[i] != readData[i]) {
				mvOsPrintf("Failed MPI test 1-%d on devId 0x%X", x, devId);
				return -1;
			}
		}
	}

	for (x = 0; x <= 0xFF; x++) {
		y = x % 0x10;
		for (i = 0; i < VP880_R_FILTER_LEN; i++) {
			writeData[i] = y << 4;
			y = (y + 1) % 0x10;
			writeData[i] |= y;
			y = (y + 1) % 0x10;
		}
		VpMpiCmd(devId, EC_1, VP880_R_FILTER_WRT, VP880_R_FILTER_LEN, writeData);
		VpMpiCmd(devId, EC_1, VP880_R_FILTER_RD, VP880_R_FILTER_LEN, readData);
		for (i = 0; i < VP880_R_FILTER_LEN; i++) {
			if (writeData[i] != readData[i]) {
				mvOsPrintf("Failed MPI test 2-%d on devId 0x%X", x, devId);
				return -1;
			}
		}
	}

	return 0;
}
int Zarlink_ver(int deviceId)
{
	#if 1 // read revision
    unsigned char res[14]={0};
    int i;
    uint8 reg, len;
        
    reg = 0x73;
    len= 2;
    VpMpiCmd(deviceId, 0x3, reg, len, res);
    printk("Revision: ");
        
    for (i=0; i<len; i++)
        printk("\nbyte%d = 0x%x", i, res[i]);
    printk("\n");
	#endif

	return 0;
}
int BattOn(int vbhIn, int vblIn, int vbpIn)
{
	uint8 data[20] = { 0 };
	int i;
	uint16 vbhTarget;
	uint16 vblTarget;
	uint16 vbpTarget;
	uint8 vbhHex;
	uint8 vblHex;
	uint8 vbpHex;
	uint8 calVbhHex;
	uint8 calVblHex;
	uint8 calVbpHex;

	/* Argument checking */
	if (vblIn > 0) {
		mvOsPrintf("  VBL must be negative or zero\n");
		return -1;
	}
	if (vbhIn > 0) {
		mvOsPrintf("  VBH must be negative or zero\n");
		return -1;
	}
	if (vbpIn < 0) {
		mvOsPrintf("  VBP must be positive or zero\n");
		return -1;
	}
	if (vblIn - vbhIn < 5 && vblIn != 0) {
		mvOsPrintf("  VBH must be at least 5V more negative than VBL\n");
		return -1;
	}

	/* 16 no-ops to clear MPI buffer */
	for (i = 0; i < 16; i++)
		data[i] = VP880_NO_OP;

	VpMpiCmd(gDev1Id, EC_BOTH, VP880_NO_OP, 16, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_NO_OP, 16, data);

	/* Read RCN/PCN and check that the devices are what we expect */
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_DEVTYPE_CMD, VP880_DEVTYPE_LEN, data);
	if (data[0] != VP880_REV_JE || data[1] != VP880_DEV_PCN_88506) {
		mvOsPrintf("Invalid device 1, RCN/PCN 0x%02X%02X\n", data[0], data[1]);
		return -1;
	}
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_DEVTYPE_CMD, VP880_DEVTYPE_LEN, data);
	if (data[0] != VP880_REV_JE || data[1] != VP880_DEV_PCN_88506) {
		mvOsPrintf("Invalid device 2, RCN/PCN 0x%02X%02X\n", data[0], data[1]);
		return -1;
	}

	/* Run MPI checks on both devices to make sure that it's safe to start
	 * programming the devices.  If the signal integrity is bad, it could be
	 * dangerous to continue. */
	if (MpiTest(gDev1Id) < 0 || MpiTest(gDev2Id) < 0)
		return -1;

	/* HW reset */
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_HW_RESET_CMD, 0, NULL);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_HW_RESET_CMD, 0, NULL);

	/* Configure 8.192MHz mclk */
	data[0] = 0x8A;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_MCLK_CNT_WRT, VP880_MCLK_CNT_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_MCLK_CNT_WRT, VP880_MCLK_CNT_LEN, data);

	/* Unmask CFAIL */
	data[0] = 0xFF & ~(VP880_CFAIL_MASK);
	data[1] = 0xFF;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_INT_MASK_WRT, VP880_INT_MASK_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_INT_MASK_WRT, VP880_INT_MASK_LEN, data);

	/* Make sure CFAIL clears on both devices */
	for (i = 0; i < 11; i++) {
		VpMpiCmd(gDev1Id, EC_BOTH, VP880_UL_SIGREG_RD, VP880_UL_SIGREG_LEN, data);
		if ((data[0] & VP880_CFAIL_MASK) == 0)
			break;

		if (i == 10) {
			mvOsPrintf("Couldn't clear CFAIL on dev 1");
			return -1;
		}
		mvOsDelay(10);
	}
	for (i = 0; i < 11; i++) {
		VpMpiCmd(gDev2Id, EC_BOTH, VP880_UL_SIGREG_RD, VP880_UL_SIGREG_LEN, data);
		if ((data[0] & VP880_CFAIL_MASK) == 0)
			break;

		if (i == 10) {
			mvOsPrintf("Couldn't clear CFAIL on dev 2");
			return -1;
		}
		mvOsDelay(10);
	}

	/* Set the switcher timings */
	data[0] = 0xB2;		/* Device defaults */
	data[1] = 0x00;
	data[2] = 0xB1;
	data[3] = 0x00;
	data[4] = 0xB0;
	data[5] = 0x40;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_INT_SWREG_PARAM_WRT, VP880_INT_SWREG_PARAM_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_INT_SWREG_PARAM_WRT, VP880_INT_SWREG_PARAM_LEN, data);

	/* ICR2 settings: c_tip_on and c_ring_on for measuring in disconnect,
	 * 150V battery limit */
	data[0] = VP880_ICR2_TIP_SENSE | VP880_ICR2_RING_SENSE;
	data[1] = VP880_ICR2_TIP_SENSE | VP880_ICR2_RING_SENSE;
	data[2] = VP880_ICR2_SWY_LIM_CTRL | VP880_ICR2_SWY_LIM_CTRL1;
	data[3] = VP880_ICR2_SWY_LIM_CTRL | VP880_ICR2_SWY_LIM_CTRL1;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_ICR2_WRT, VP880_ICR2_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_ICR2_WRT, VP880_ICR2_LEN, data);

	/* ICR3 settings: VREF ctrl, "line block control circuitry override" for
	 * measuring in disconnect */
	data[0] = VP880_ICR3_VREF_CTRL | VP880_ICR3_LINE_CTRL;
	data[1] = VP880_ICR3_VREF_CTRL | VP880_ICR3_LINE_CTRL;
	data[2] = 0;
	data[3] = 0;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_ICR3_WRT, VP880_ICR3_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_ICR3_WRT, VP880_ICR3_LEN, data);

	/* ICR4 settings: voice ADC override for measuring in disconnect */
	data[0] = VP880_ICR4_VOICE_ADC_CTRL;
	data[1] = VP880_ICR4_VOICE_ADC_CTRL;
	data[2] = 0;
	data[3] = 0;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_ICR4_WRT, VP880_ICR4_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_ICR4_WRT, VP880_ICR4_LEN, data);

	/* Wait for VREF to stabilize */
	mvOsDelay(20);

	/* Disable auto system state ctrl, zero cross ringing, auto clock fail
	 * switching, and thermal fault switching.  Enable auto battery shutdown */
	data[0] = VP880_ACFS_DIS | VP880_ATFS_DIS | VP880_ZXR_DIS | VP880_AUTO_SSC_DIS | VP880_AUTO_BAT_SHUTDOWN_EN;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_SS_CONFIG_WRT, VP880_SS_CONFIG_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_SS_CONFIG_WRT, VP880_SS_CONFIG_LEN, data);

	/* Zero out signal generator params for the channel (ch2 on dev1) that will
	 * be in ringing */
	for (i = 0; i < VP880_SIGA_PARAMS_LEN; i++)
		data[i] = 0;

	VpMpiCmd(gDev1Id, EC_2, VP880_SIGA_PARAMS_WRT, VP880_SIGA_PARAMS_LEN, data);

	/* Calculate the register settings.  Calculations are performed  based on
	 * units of cV and unsigned, for example -65.3 V == 6530 */
	vbhTarget = (ABS(vbhIn) * 100);
	vblTarget = (ABS(vblIn) * 100);
	vbpTarget = (ABS(vbpIn) * 100);

	DBG("VBH Calibration:\n");
	CalculateRegisters(vbhTarget, gVbhCalAry, &vbhHex, &calVbhHex);
	DBG("VBH results, vbhHex %02X, calVbhHex %02X\n\n", vbhHex, calVbhHex);

	DBG("VBL Calibration:\n");
	CalculateRegisters(vblTarget, gVblCalAry, &vblHex, &calVblHex);
	DBG("VBL results, vblHex %02X, calVblHex %02X\n\n", vblHex, calVblHex);

	DBG("VBP Calibration:\n");
	CalculateRegisters(vbpTarget, gVbpCalAry, &vbpHex, &calVbpHex);
	DBG("VBP results, vbpHex %02X, calVbpHex %02X\n\n", vbpHex, calVbpHex);

	/* Set up switching regulator params - fixed, programmable */
	data[0] = VP880_FLYBACK_MODE | VP880_ZRING_TRACK_DIS | VP880_YRING_TRACK_DIS;
	data[1] = VP880_SWY_AUTOPOWER_DIS | vbhHex;
	data[2] = VP880_SWZ_AUTOPOWER_DIS | vblHex;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_REGULATOR_PARAM_WRT, VP880_REGULATOR_PARAM_LEN, data);

	data[0] = VP880_FLYBACK_MODE | VP880_ZRING_TRACK_DIS | VP880_YRING_TRACK_DIS;
	data[1] = VP880_SWY_AUTOPOWER_DIS | vbpHex;
	data[2] = VP880_SWZ_AUTOPOWER_DIS;
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_REGULATOR_PARAM_WRT, VP880_REGULATOR_PARAM_LEN, data);

	/* Set battery calibration registers */
	data[1] = 0;
	data[0] = calVbhHex << 3;
	VpMpiCmd(gDev1Id, EC_1, VP880_BAT_CALIBRATION_WRT, VP880_BAT_CALIBRATION_LEN, data);
	data[0] = calVblHex << 3;
	VpMpiCmd(gDev1Id, EC_2, VP880_BAT_CALIBRATION_WRT, VP880_BAT_CALIBRATION_LEN, data);
	data[0] = calVbpHex << 3;
	VpMpiCmd(gDev2Id, EC_1, VP880_BAT_CALIBRATION_WRT, VP880_BAT_CALIBRATION_LEN, data);

	/* Disable high-pass filter, cut off TX/RX */
	data[0] = VP880_HIGH_PASS_DIS | VP880_CUT_TXPATH | VP880_CUT_RXPATH;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_OP_COND_WRT, VP880_OP_COND_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_OP_COND_WRT, VP880_OP_COND_LEN, data);

	/* Set to linear mode, use default filters */
	data[0] = VP880_LINEAR_CODEC | VP880_DEFAULT_OP_FUNC_MODE;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_OP_FUNC_WRT, VP880_OP_FUNC_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_OP_FUNC_WRT, VP880_OP_FUNC_LEN, data);

	/* Set default DISN (00) */
	data[0] = VP880_DEFAULT_DISN_GAIN;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_DISN_WRT, VP880_DISN_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_DISN_WRT, VP880_DISN_LEN, data);

	mvOsDelay(50);

    /*** Bring up HBAT ***/
	/* Set HBAT switcher to low power. */
	data[0] = 0;
	if (vbhTarget != 0)
		data[0] |= VP880_SWY_LP;

	VpMpiCmd(gDev1Id, EC_BOTH, VP880_REGULATOR_CTRL_WRT, VP880_REGULATOR_CTRL_LEN, data);

	mvOsDelay(10);

	/* Set the line state:
	 *  Dev 1 ch 1: disconnect (switcher Y)
	 * Disconnect is needed so that the voltages don't track to VOC */
	data[0] = VP880_SS_DISCONNECT | VP880_SS_ACTIVATE_MASK;
	VpMpiCmd(gDev1Id, EC_1, VP880_SYS_STATE_WRT, VP880_SYS_STATE_LEN, data);

	mvOsDelay(100);

    /*** Bring up LBAT ***/
	/* Do a read/modify/write of ICR2 to override the LBAT switcher (Z) to off
	 * so that we can set the line state to ringing before turning it on */
	VpMpiCmd(gDev1Id, EC_2, VP880_ICR2_RD, VP880_ICR2_LEN, data);
	data[2] |= VP880_ICR2_SWY_CTRL_EN;
	data[3] &= ~VP880_ICR2_SWY_CTRL_EN;
	VpMpiCmd(gDev1Id, EC_2, VP880_ICR2_WRT, VP880_ICR2_LEN, data);

	/* Set the switcher control to low power.  It won't actually turn on yet
	 * because of the ICR2 command above, but setting the register will allow
	 * the line state to be set to ringing. */
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_REGULATOR_CTRL_RD, VP880_REGULATOR_CTRL_LEN, data);
	data[0] = 0;
	if (vblTarget != 0)
		data[0] |= VP880_SWZ_LP;

	VpMpiCmd(gDev1Id, EC_BOTH, VP880_REGULATOR_CTRL_WRT, VP880_REGULATOR_CTRL_LEN, data);

	mvOsDelay(10);

	/* Set the line state:
	 *  Dev 1 ch 2: ringing (switcher Z) */
	data[0] = VP880_SS_BALANCED_RINGING;
	VpMpiCmd(gDev1Id, EC_2, VP880_SYS_STATE_WRT, VP880_SYS_STATE_LEN, data);

	mvOsDelay(10);

	/* Turn the switcher on */
	VpMpiCmd(gDev1Id, EC_2, VP880_ICR2_RD, VP880_ICR2_LEN, data);
	data[2] |= VP880_ICR2_SWY_CTRL_EN;
	data[3] |= VP880_ICR2_SWY_CTRL_EN;
	VpMpiCmd(gDev1Id, EC_2, VP880_ICR2_WRT, VP880_ICR2_LEN, data);

	mvOsDelay(100);

    /*** Bring up PBAT ***/
	/* Set PBAT switcher to low power. */
	data[0] = 0;
	if (vbpTarget != 0)
		data[0] |= VP880_SWY_LP;

	VpMpiCmd(gDev2Id, EC_BOTH, VP880_REGULATOR_CTRL_WRT, VP880_REGULATOR_CTRL_LEN, data);

	mvOsDelay(10);

	/* Set the line states:
	 *  Dev 2 ch 1: disconnect (switcher Y)
	 * Disconnect is needed so that the voltages don't track to VOC */
	data[0] = VP880_SS_DISCONNECT | VP880_SS_ACTIVATE_MASK;
	VpMpiCmd(gDev2Id, EC_1, VP880_SYS_STATE_WRT, VP880_SYS_STATE_LEN, data);

	mvOsDelay(100);

	/* Set switchers to high power for non-zero batteries, one at a time */
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_REGULATOR_CTRL_RD, VP880_REGULATOR_CTRL_LEN, data);

	if (vbhTarget != 0) {
		data[0] &= ~VP880_SWY_MODE_MASK;
		data[0] |= VP880_SWY_HP;
		VpMpiCmd(gDev1Id, EC_BOTH, VP880_REGULATOR_CTRL_WRT, VP880_REGULATOR_CTRL_LEN, data);
	}

	mvOsDelay(20);

	if (vblTarget != 0) {
		data[0] &= ~VP880_SWZ_MODE_MASK;
		data[0] |= VP880_SWZ_HP;
		VpMpiCmd(gDev1Id, EC_BOTH, VP880_REGULATOR_CTRL_WRT, VP880_REGULATOR_CTRL_LEN, data);
	}

	mvOsDelay(20);

	data[0] = 0;
	if (vbpTarget != 0) {
		data[0] |= VP880_SWY_HP;
		VpMpiCmd(gDev2Id, EC_BOTH, VP880_REGULATOR_CTRL_WRT, VP880_REGULATOR_CTRL_LEN, data);
	}

	/* Set IOs to outputs to control the module LEDs */
	data[0] = VP880_IODIR_IO1_OUTPUT | VP880_IODIR_IO2_OUTPUT;
	VpMpiCmd(gDev1Id, EC_BOTH, VP880_IODIR_REG_WRT, VP880_IODIR_REG_LEN, data);
	VpMpiCmd(gDev2Id, EC_BOTH, VP880_IODIR_REG_WRT, VP880_IODIR_REG_LEN, data);

	/* Turn on the LEDs for non-zero batteries. */
	data[0] = 0;
	if (vbhTarget != 0) {
		/* gDev1Id IO1 controls the VBH (v1) LED */
		data[0] |= VP880_IODATA_IO1;
	}
	if (vblTarget != 0) {
		/* gDev1Id IO2 controls the VBL (v2) LED */
		data[0] |= VP880_IODATA_IO2;
	}
	VpMpiCmd(gDev1Id, EC_1, VP880_IODATA_REG_WRT, VP880_IODATA_REG_LEN, data);

	data[0] = 0;
	if (vbpTarget != 0) {
		/* gDev2Id IO1 controls the VBP (v3) LED */
		data[0] |= VP880_IODATA_IO1;
	}
	VpMpiCmd(gDev2Id, EC_1, VP880_IODATA_REG_WRT, VP880_IODATA_REG_LEN, data);

	mvOsPrintf("Power supply initialized successfully\n");

	return 0;
}