Пример #1
0
static int
pmu_todr_get(todr_chip_handle_t tch, struct timeval *tvp)
{
	struct pmu_softc *sc = tch->cookie;
	uint32_t sec;
	int count = 10;
	int ok = FALSE;
	uint8_t resp[16];

	DPRINTF("pmu_todr_get\n");
	while ((count > 0) && (!ok)) {
		pmu_send(sc, PMU_READ_RTC, 0, NULL, 16, resp);

		memcpy(&sec, &resp[1], 4);
		tvp->tv_sec = sec - DIFF19041970;
		ok = (sec > DIFF19041970) && (sec < 0xf0000000);
		if (!ok) aprint_error_dev(sc->sc_dev,
		    "got garbage from rtc (%08x)\n", sec);
		count--;
	}
	if (count == 0) {
		aprint_error_dev(sc->sc_dev,
		    "unable to get a sane time value\n");
		tvp->tv_sec = 0;
	}
	DPRINTF("tod: %" PRIo64 "\n", tvp->tv_sec);
	tvp->tv_usec = 0;
	return 0;
}
Пример #2
0
static void
pmu_autopoll(void *cookie, int flag)
{
	struct pmu_softc *sc = cookie;
	/* magical incantation to re-enable autopolling */
	uint8_t cmd[] = {0, PMU_SET_POLL_MASK, (flag >> 8) & 0xff, flag & 0xff};
	uint8_t resp[16];

	if (sc->sc_autopoll == flag)
		return;

	if (flag) {
		pmu_send(sc, PMU_ADB_CMD, 4, cmd, 16, resp);
	} else {
		pmu_send(sc, PMU_ADB_POLL_OFF, 0, NULL, 16, resp);
	}
	sc->sc_autopoll = flag & 0xffff;
}
Пример #3
0
void
pmu_restart(void)
{
	struct pmu_softc *sc;
	uint8_t resp[16];

	if (pmu0 == NULL)
		return;
	sc = pmu0;
	if (pmu_send(sc, PMU_RESET_CPU, 0, NULL, 16, resp) >= 0)
		while (1);
}
Пример #4
0
static int
pmu_todr_set(todr_chip_handle_t tch, struct timeval *tvp)
{
	struct pmu_softc *sc = tch->cookie;
	uint32_t sec;
	uint8_t resp[16];

	sec = tvp->tv_sec + DIFF19041970;
	if (pmu_send(sc, PMU_SET_RTC, 4, (uint8_t *)&sec, 16, resp) >= 0)
		return 0;
	return -1;		
}
Пример #5
0
void
pmu_modem(int on)
{
	struct pmu_softc *sc;
	uint8_t resp[16], cmd[2] = {0, 0};

	if (pmu0 == NULL)
		return;

	sc = pmu0;
	cmd[0] = PMU_POW0_MODEM | (on ? PMU_POW0_ON : 0);
	pmu_send(sc, PMU_POWER_CTRL0, 1, cmd, 16, resp);
}
Пример #6
0
void
pmu_poweroff(void)
{
	struct pmu_softc *sc;
	uint8_t cmd[] = {'M', 'A', 'T', 'T'};
	uint8_t resp[16];

	if (pmu0 == NULL)
		return;
	sc = pmu0;
	if (pmu_send(sc, PMU_POWER_OFF, 4, cmd, 16, resp) >= 0)
		while (1);
}
Пример #7
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 */
}
Пример #8
0
static int
pmu_adb_handler(void *cookie, int len, uint8_t *data)
{
	struct pmu_softc *sc = cookie;
	uint8_t resp[16];

	if (sc->sc_adb_handler != NULL) {
		sc->sc_adb_handler(sc->sc_adb_cookie, len, data);
		/*
		 * the PMU will turn off autopolling after each LISTEN so we
		 * need to re-enable it here whenever we receive an ACK for a
		 * LISTEN command
		 */
		if ((data[1] & 0x0c) == 0x08) {
			uint8_t cmd[] = {0, 0x86, (sc->sc_autopoll >> 8) & 0xff,
			    sc->sc_autopoll & 0xff};
			pmu_send(sc, PMU_ADB_CMD, 4, cmd, 16, resp);
		}
Пример #9
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;
}
Пример #10
0
static void
pmu_attach(device_t parent, device_t self, void *aux)
{
	struct confargs *ca = aux;
	struct pmu_softc *sc = device_private(self);
#if notyet
	struct i2cbus_attach_args iba;
#endif
	uint32_t regs[16];
	int irq = ca->ca_intr[0];
	int node, extint_node, root_node;
	int nbat = 1, i, pmnode;
	int type = IST_EDGE;
	uint8_t cmd[2] = {2, 0};
	uint8_t resp[16];
	char name[256];

	extint_node = of_getnode_byname(OF_parent(ca->ca_node), "extint-gpio1");
	if (extint_node) {

		OF_getprop(extint_node, "interrupts", &irq, 4);
		type = IST_LEVEL;
	}

	aprint_normal(" irq %d: ", irq);

	sc->sc_dev = self;
	sc->sc_node = ca->ca_node;
	sc->sc_memt = ca->ca_tag;

	root_node = OF_finddevice("/");

	sc->sc_error = 0;
	sc->sc_autopoll = 0;
	sc->sc_pending_eject = 0;
	sc->sc_brightness = sc->sc_brightness_wanted = 0x80;
	sc->sc_volume = sc->sc_volume_wanted = 0x80;
	sc->sc_flags = 0;
	sc->sc_callback = NULL;
	sc->sc_lid_closed = 0;

	if (bus_space_map(sc->sc_memt, ca->ca_reg[0] + ca->ca_baseaddr,
	    ca->ca_reg[1], 0, &sc->sc_memh) != 0) {
		aprint_error_dev(self, "unable to map registers\n");
		return;
	}
	sc->sc_ih = intr_establish(irq, type, IPL_TTY, pmu_intr, sc);

	pmu_init(sc);

	sc->sc_pmu_ops.cookie = sc;
	sc->sc_pmu_ops.do_command = pmu_send;
	sc->sc_pmu_ops.register_callback = pmu_register_callback;

	if (pmu0 == NULL)
		pmu0 = sc;

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

	/* check what kind of PMU we're talking to */
	if (pmu_send(sc, PMU_GET_VERSION, 0, cmd, 16, resp) > 1)
		aprint_normal(" rev. %d", resp[1]);
	aprint_normal("\n");

	node = OF_child(sc->sc_node);

	while (node != 0) {

		if (OF_getprop(node, "name", name, 256) == 0)
			goto next;

		if (strncmp(name, "pmu-i2c", 8) == 0) {
			aprint_normal_dev(self, "initializing IIC bus\n");
			goto next;
		}
		if (strncmp(name, "adb", 4) == 0) {
			aprint_normal_dev(self, "initializing ADB\n");
			sc->sc_adbops.cookie = sc;
			sc->sc_adbops.send = pmu_adb_send;
			sc->sc_adbops.poll = pmu_adb_poll;
			sc->sc_adbops.autopoll = pmu_autopoll;
			sc->sc_adbops.set_handler = pmu_adb_set_handler;
#if NNADB > 0
			config_found_ia(self, "adb_bus", &sc->sc_adbops,
			    nadb_print);
#endif
			goto next;
		}
		if (strncmp(name, "rtc", 4) == 0) {

			aprint_normal_dev(self, "initializing RTC\n");
			sc->sc_todr.todr_gettime = pmu_todr_get;
			sc->sc_todr.todr_settime = pmu_todr_set;
			sc->sc_todr.cookie = sc;
			todr_attach(&sc->sc_todr);
			goto next;
		}
		if (strncmp(name, "battery", 8) == 0)
			goto next;

		aprint_normal_dev(self, "%s not configured\n", name);
next:
		node = OF_peer(node);
	}

	if (OF_finddevice("/bandit/ohare") != -1) {
		aprint_normal_dev(self, "enabling ohare backlight control\n");
		sc->sc_flags |= PMU_HAS_BACKLIGHT_CONTROL;
		cmd[0] = 0;
		cmd[1] = 0;
		memset(resp, 0, 6);
		if (pmu_send(sc, PMU_READ_BRIGHTNESS, 1, cmd, 16, resp) > 1) {
			sc->sc_brightness_wanted = resp[1];
			pmu_update_brightness(sc);
		}
	}

	/* attach batteries */
	if (of_compatible(root_node, has_legacy_battery) != -1) {

		pmu_attach_legacy_battery(sc);
	} else if (of_compatible(root_node, has_two_smart_batteries) != -1) {

		pmu_attach_smart_battery(sc, 0);
		pmu_attach_smart_battery(sc, 1);
	} else {

		/* check how many batteries we have */
		pmnode = of_getnode_byname(ca->ca_node, "power-mgt");
		if (pmnode == -1)
			goto bat_done;
		if (OF_getprop(pmnode, "prim-info", regs, sizeof(regs)) < 24)
			goto bat_done;
		nbat = regs[6] >> 16;
		for (i = 0; i < nbat; i++)
			pmu_attach_smart_battery(sc, i);
	}
bat_done:

#if notyet
	memset(&iba, 0, sizeof(iba));
	iba.iba_tag = &sc->sc_i2c;
	sc->sc_i2c.ic_cookie = sc;
	sc->sc_i2c.ic_acquire_bus = pmu_i2c_acquire_bus;
	sc->sc_i2c.ic_release_bus = pmu_i2c_release_bus;
	sc->sc_i2c.ic_send_start = NULL;
	sc->sc_i2c.ic_send_stop = NULL;
	sc->sc_i2c.ic_initiate_xfer = NULL;
	sc->sc_i2c.ic_read_byte = NULL;
	sc->sc_i2c.ic_write_byte = NULL;
	sc->sc_i2c.ic_exec = pmu_i2c_exec;
	config_found_ia(sc->sc_dev, "i2cbus", &iba, iicbus_print);
#endif
	
	if (kthread_create(PRI_NONE, 0, NULL, pmu_thread, sc, &sc->sc_thread,
	    "%s", "pmu") != 0) {
		aprint_error_dev(self, "unable to create event kthread\n");
	}

	sc->sc_lidswitch.smpsw_name = "Lid switch";
	sc->sc_lidswitch.smpsw_type = PSWITCH_TYPE_LID;
	if (sysmon_pswitch_register(&sc->sc_lidswitch) != 0)
		aprint_error_dev(self,
		    "unable to register lid switch with sysmon\n");
}
Пример #11
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);
        }
    }