Ejemplo n.º 1
0
static int query_adc(int mux) {
	uint8_t buf[2];
	uint32_t mux_masked, result = 0;
	uint64_t startTime;

	mux_masked = mux & 0xF;
	result = pmu_get_reg(PMU_ADC_REG);
	
	if (mux == 3) {
		mux_masked |= 0x20;
		pmu_write_reg(PMU_MUXSEL_REG, mux_masked, 0);
		udelay(80000);
	}
	
	pmu_write_reg(PMU_MUXSEL_REG, mux_masked | 0x10, 0);
	
	startTime = timer_get_system_microtime();
	do {
		udelay(1000);
		if (has_elapsed(startTime, 50000))
			return -1;
			
		result = pmu_get_reg(PMU_ADC_REG);
	} while (!(result & 0x20));
	
	pmu_get_regs(PMU_ADCVAL_REG, buf, 2);
	pmu_write_reg(PMU_MUXSEL_REG, 0, 0);
	
	return (buf[1] << 4) | (buf[0] & 0xF);
}
Ejemplo n.º 2
0
void pmu_write_oocshdwn(int data) {
	uint8_t poweroffData[] = {0xC0, 0xFF, 0xBF, 0xFF, 0xAE, 0xFF};
	uint8_t buffer[sizeof(poweroffData) + 1];
	
	pmu_get_reg(PMU_UNK2_REG);
	
	buffer[0] = PMU_UNK1_REG;
	memcpy(&buffer[1], poweroffData, sizeof(poweroffData));
	
	i2c_tx(PMU_I2C_BUS, PMU_SETADDR, buffer, sizeof(buffer));
	
	if (data == 1) {
		uint8_t result, reg;
		
		// sub_5FF0D99C();  // Something to do with gas gauge.
		
		for (reg = PMU_UNKREG_START; reg <= PMU_UNKREG_END; reg++) {
			result = pmu_get_reg(reg);
			
			if (!((result & 0xE0) <= 0x5F || (result & 2) == 0))
				pmu_write_reg(reg, result & 0xFD, FALSE);
		}
	}
	
	pmu_write_reg(PMU_OOCSHDWN_REG, data, FALSE);
	
	while(TRUE) {
		udelay(100000);
	}
}
Ejemplo n.º 3
0
static int
pmu_send(void *cookie, int cmd, int length, uint8_t *in_msg, int rlen,
    uint8_t *out_msg)
{
	struct pmu_softc *sc = cookie;
	int i, rcv_len = -1, s;
	uint8_t out_len, intreg;

	DPRINTF("pmu_send: ");

	s = splhigh();
	intreg = pmu_read_reg(sc, vIER);
	intreg &= 0x10;
	pmu_write_reg(sc, vIER, intreg);

	/* wait idle */
	do {} while (pmu_intr_state(sc));
	sc->sc_error = 0;

	/* send command */
	pmu_send_byte(sc, cmd);

	/* send length if necessary */
	if (pm_send_cmd_type[cmd] < 0) {
		pmu_send_byte(sc, length);
	}

	for (i = 0; i < length; i++) {
		pmu_send_byte(sc, in_msg[i]);
		DPRINTF(" next ");
	}
	DPRINTF("done sending\n");

	/* see if there's data to read */
	rcv_len = pm_receive_cmd_type[cmd];
	if (rcv_len == 0) 
		goto done;

	/* read command */
	if (rcv_len == 1) {
		pmu_read_byte(sc, out_msg);
		goto done;
	} else
		out_msg[0] = cmd;
	if (rcv_len < 0) {
		pmu_read_byte(sc, &out_len);
		rcv_len = out_len + 1;
	}
	for (i = 1; i < min(rcv_len, rlen); i++)
		pmu_read_byte(sc, &out_msg[i]);

done:
	DPRINTF("\n");
	pmu_write_reg(sc, vIER, (intreg == 0) ? 0 : 0x90);
	splx(s);

	return rcv_len;
}
Ejemplo n.º 4
0
int pmu_write_unk(uint8_t regidx, int flag1, int flag2)
{
	uint8_t registers = PMU_UNKREG_START + regidx;
	uint8_t recv_buff = 0;
	uint8_t data = 0;
	int result;

	if (regidx > PMU_UNKREG_END - PMU_UNKREG_START)
		return -1;
	
	result = i2c_rx(PMU_I2C_BUS, PMU_GETADDR, (void*)&registers, 1, (void*)&recv_buff, 1);
	if (result != I2CNoError)
		return result;
	
	recv_buff &= 0x1D;
	
	if (!flag1) {
		data = recv_buff | 0x60;
	} else {
		data = recv_buff;
		if (flag2)
			data |= 2;
	}
	
	pmu_write_reg(registers, data, 1);
	return 0;
}
Ejemplo n.º 5
0
error_t pmu_setup_gpio(int _idx, int _dir, int _pol)
{
	uint8_t reg = PMU_GPIO + _idx;
	uint8_t val;

	if (_idx >= PMU_GPIO_COUNT)
		return EINVAL;

	val = pmu_get_reg(reg);
	val &= 0x1D;
	
	if(!_dir) // Input
	{
		val |= 0x40;
	}
	else // Output
	{
		if(_pol)
			val |= 2; // High
		else
			val &=~ 2; // Low
	}
	
	pmu_write_reg(reg, val, 1);
	return SUCCESS;
}
Ejemplo n.º 6
0
int pmu_write_regs(const PMURegisterData* regs, int num) {
	int i;
	for(i = 0; i < num; i++) {
		pmu_write_reg(regs[i].reg, regs[i].data, 1);
	}

	return 0;
}
Ejemplo n.º 7
0
static void
pmu_ack_on(struct pmu_softc *sc)
{
	uint8_t reg;

	reg = pmu_read_reg(sc, vBufB);
	reg |= vPB4;
	pmu_write_reg(sc, vBufB, reg);
}
Ejemplo n.º 8
0
int pmu_set_gpmem_reg(int reg, uint8_t data) {
	if(pmu_write_reg(reg + 0x67, data, TRUE) == 0) {
		GPMemCache[reg] = data;
		GPMemCachedPresent |= (0x1 << reg);
		return 0;
	}

	return -1;
}
Ejemplo n.º 9
0
static void
pmu_out(struct pmu_softc *sc)
{
	uint8_t reg;

	reg = pmu_read_reg(sc, vACR);
	reg |= vSR_OUT;
	reg |= 0x0c;
	pmu_write_reg(sc, vACR, reg);
}
Ejemplo n.º 10
0
static void
pmu_init(struct pmu_softc *sc)
{
	uint8_t pmu_imask, resp[16];

	pmu_imask =
	    PMU_INT_PCEJECT | PMU_INT_SNDBRT | PMU_INT_ADB/* | PMU_INT_TICK*/;
	pmu_imask |= PMU_INT_BATTERY;
	pmu_imask |= PMU_INT_ENVIRONMENT;
	pmu_send(sc, PMU_SET_IMASK, 1, &pmu_imask, 16, resp);

	pmu_write_reg(sc, vIER, 0x90);	/* enable VIA interrupts */
}
Ejemplo n.º 11
0
int pmu_set_gpmem_reg(int reg, uint8_t data) {
	if (reg > PMU_MAXREG)
		return -1;
	
	// If the data isn't cached,
	// Or if the cached data differs than what we write, write it.
	if ((GPMemCachedPresent & (0x1 << reg)) == 0 || GPMemCache[reg] != data) {
		GPMemCache[reg] = data;
		GPMemCachedPresent |= (0x1 << reg);
		pmu_write_reg(reg ^ 0x80, data, FALSE);
	}

	return 0;
}
Ejemplo n.º 12
0
int query_adc(int flags, uint32_t* result) {
	// clear the done bit if it is set
	pmu_get_reg(PMU_ADCSTS);
	
	// set up flags
	if (flags == 0x3) {
		pmu_write_reg(PMU_ADCCON, flags | 0x20, FALSE);
		udelay(80000);
	}
	pmu_write_reg(PMU_ADCCON, flags | 0x10, FALSE);
	
	// wait until done
	uint64_t startTime = timer_get_system_microtime();
	while (!(pmu_get_reg(PMU_ADCSTS) & 0x2)) {
		if (has_elapsed(startTime, 40000)) {
			return -1;
		}
	}

	uint8_t out[2];
	pmu_get_regs(PMU_ADCOUT1, out, 2);
	*result = (out[1] << 2) | (out[0] & 0x3);
	return 0;
}
Ejemplo n.º 13
0
static inline int
pmu_send_byte(struct pmu_softc *sc, uint8_t data)
{

	pmu_out(sc);
	pmu_write_reg(sc, vSR, data);
	pmu_ack_off(sc);
	/* wait for intr to come up */
	/* XXX should add a timeout and bail if it expires */
	do {} while (pmu_intr_state(sc) == 0);
	pmu_ack_on(sc);
	do {} while (pmu_intr_state(sc));
	pmu_ack_on(sc);
	DPRINTF(" %02x>", data);
	return 0;
}
Ejemplo n.º 14
0
void pmu_write_oocshdwn(int data) {
	uint8_t registers[1];
	uint8_t discardData[5];
	uint8_t poweroffData[] = {7, 0xD1, 0xFF, 0xF0};
	registers[0] = 1;
	i2c_rx(PMU_I2C_BUS, PMU_GETADDR, registers, sizeof(registers), discardData, 3);

	i2c_tx(PMU_I2C_BUS, PMU_SETADDR, poweroffData, sizeof(poweroffData));
	pmu_write_reg(PMU_OOCSHDWN, data, FALSE);

	// Wait for the hardware to shut down
	EnterCriticalSection();

	while(TRUE) {
		udelay(100000);
	}
}
Ejemplo n.º 15
0
static int
pmu_intr(void *arg)
{
	struct pmu_softc *sc = arg;
	unsigned int len, i;
	uint8_t resp[16];

	DPRINTF(":");

	pmu_write_reg(sc, vIFR, 0x90);	/* Clear 'em */
	len = pmu_send(sc, PMU_INT_ACK, 0, NULL, 16, resp);
	if ((len < 1) || (resp[1] == 0))
		goto done;
#ifdef PMU_DEBUG
	{
		DPRINTF("intr: %02x", resp[0]);
		for (i = 1; i < len; i++)
			DPRINTF(" %02x", resp[i]);
		DPRINTF("\n");
	}
#endif
	if (resp[1] & PMU_INT_ADB) {
		pmu_adb_handler(sc, len - 1, &resp[1]);
		goto done;
	}
	if (resp[1] & PMU_INT_SNDBRT) {
		/* deal with the brightness / volume control buttons */
		DPRINTF("brightness: %d volume %d\n", resp[2], resp[3]);
		sc->sc_brightness_wanted = resp[2];
		sc->sc_volume_wanted = resp[3];
		wakeup(&sc->sc_event);
		goto done;
	}
	if (resp[1] & PMU_INT_PCEJECT) {
		/* deal with PCMCIA eject buttons */
		DPRINTF("card eject %d\n", resp[3]);
		sc->sc_pending_eject |= (resp[3] & 3);
		wakeup(&sc->sc_event);
		goto done;
	}
	if (resp[1] & PMU_INT_BATTERY) {
		/* deal with battery messages */
		printf("battery:");
		for (i = 2; i < len; i++)
			printf(" %02x", resp[i]);
		printf("\n");
		goto done;
	}
	if (resp[1] & PMU_INT_ENVIRONMENT) {
		int closed;
#ifdef PMU_VERBOSE
		/* deal with environment messages */
		printf("environment:");
		for (i = 2; i < len; i++)
			printf(" %02x", resp[i]);
		printf("\n");
#endif
		closed = (resp[2] & PMU_ENV_LID_CLOSED) != 0;
		if (closed != sc->sc_lid_closed) {
			sc->sc_lid_closed = closed;
			sysmon_pswitch_event(&sc->sc_lidswitch, 
	    		    closed ? PSWITCH_EVENT_PRESSED : 
			    PSWITCH_EVENT_RELEASED);
		}
		goto done;
	}
	if (resp[1] & PMU_INT_TICK) {
		/* don't bother */
		goto done;
	}

	/* unknown interrupt code?! */
#ifdef PMU_DEBUG
	printf("pmu intr: %02x:", resp[1]);
	for (i = 2; i < len; i++)
		printf(" %02x", resp[i]);
	printf("\n");
#endif
done:
	return 1;
}
Ejemplo n.º 16
0
static int
pmu_attach(device_t dev)
{
    struct pmu_softc *sc;

    int i;
    uint8_t reg;
    uint8_t cmd[2] = {2, 0};
    uint8_t resp[16];
    phandle_t node,child;
    struct sysctl_ctx_list *ctx;
    struct sysctl_oid *tree;

    sc = device_get_softc(dev);
    sc->sc_dev = dev;

    sc->sc_memrid = 0;
    sc->sc_memr = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
                                         &sc->sc_memrid, RF_ACTIVE);

    mtx_init(&sc->sc_mutex,"pmu",NULL,MTX_DEF | MTX_RECURSE);

    if (sc->sc_memr == NULL) {
        device_printf(dev, "Could not alloc mem resource!\n");
        return (ENXIO);
    }

    /*
     * Our interrupt is attached to a GPIO pin. Depending on probe order,
     * we may not have found it yet. If we haven't, it will find us, and
     * attach our interrupt then.
     */
    pmu = dev;
    if (pmu_extint != NULL) {
        if (setup_pmu_intr(dev,pmu_extint) != 0)
            return (ENXIO);
    }

    sc->sc_autopoll = 0;
    sc->sc_batteries = 0;
    sc->adb_bus = NULL;
    sc->sc_leddev = NULL;

    /* Init PMU */

    reg = PMU_INT_TICK | PMU_INT_ADB | PMU_INT_PCEJECT | PMU_INT_SNDBRT;
    reg |= PMU_INT_BATTERY;
    reg |= PMU_INT_ENVIRONMENT;
    pmu_send(sc, PMU_SET_IMASK, 1, &reg, 16, resp);

    pmu_write_reg(sc, vIER, 0x90); /* make sure VIA interrupts are on */

    pmu_send(sc, PMU_SYSTEM_READY, 1, cmd, 16, resp);
    pmu_send(sc, PMU_GET_VERSION, 1, cmd, 16, resp);

    /* Initialize child buses (ADB) */
    node = ofw_bus_get_node(dev);

    for (child = OF_child(node); child != 0; child = OF_peer(child)) {
        char name[32];

        memset(name, 0, sizeof(name));
        OF_getprop(child, "name", name, sizeof(name));

        if (bootverbose)
            device_printf(dev, "PMU child <%s>\n",name);

        if (strncmp(name, "adb", 4) == 0) {
            sc->adb_bus = device_add_child(dev,"adb",-1);
        }

        if (strncmp(name, "power-mgt", 9) == 0) {
            uint32_t prim_info[9];

            if (OF_getprop(child, "prim-info", prim_info,
                           sizeof(prim_info)) >= 7)
                sc->sc_batteries = (prim_info[6] >> 16) & 0xff;

            if (bootverbose && sc->sc_batteries > 0)
                device_printf(dev, "%d batteries detected\n",
                              sc->sc_batteries);
        }
    }
Ejemplo n.º 17
0
error_t pmu_setup_ldo(int _idx, uint16_t _v, uint8_t _enable_gates, uint8_t _enable)
{
	uint8_t val;

	if(_idx >= PMU_LDO_COUNT)
		return	EINVAL;

	if(pmu_ldo[_idx].base_voltage && !_v)
		return EINVAL;

	if(pmu_ldo[_idx].gate_mask)
	{
		val = pmu_get_reg(PMU_LDO_GATES);
		val &=~ pmu_ldo[_idx].gate_mask;
		if(_enable && _enable_gates)
			val |= pmu_ldo[_idx].gate_mask;

		CHAIN_FAIL(pmu_write_reg(PMU_LDO_GATES, val, 1));
	}

	if(pmu_ldo[_idx].base_voltage)
	{
		uint8_t steps = (_v - pmu_ldo[_idx].base_voltage)
			/ pmu_ldo[_idx].step_size;
		if(steps > pmu_ldo[_idx].step_count)
		{
			bufferPrintf("pmu: Power too great for %d: %d > %d!\n",
					_idx, steps, pmu_ldo[_idx].step_count);
			return EINVAL;
		}

		val = pmu_get_reg(PMU_LDO_V + _idx);
		val &=~ pmu_ldo[_idx].step_mask;
		val |= (steps & pmu_ldo[_idx].step_mask);
		CHAIN_FAIL(pmu_write_reg(PMU_LDO_V + _idx, val, 1));
	}

	val = pmu_get_reg(pmu_ldo[_idx].reg);
	val &=~ pmu_ldo[_idx].mask;

	if(_enable)
		val |= pmu_ldo[_idx].mask;

	if(_idx == 0x16)
	{
		// This is some haxxy dependancy code.
		// Basically, pins 4 and 5 from 0x16
		// rely on pin 3 being enabled.
		//
		// (Actually it's broken on disable,
		//  but I'll fix it when it needs fixing.)
		//  -- Ricky26
		if(!(pmu_ldo[_idx].mask & 8))
		{
			if(val & 0x30)
				val |= 8;
			else
				val &=~ 8;
		}
	}

	CHAIN_FAIL(pmu_write_reg(pmu_ldo[_idx].reg, val, 1));
	return SUCCESS;
}