Esempio n. 1
0
static irqreturn_t mfgpt_tick(int irq, void *dev_id)
{
    u16 val = geode_mfgpt_read(mfgpt_event_clock, MFGPT_REG_SETUP);

    /* See if the interrupt was for us */
    if (!(val & (MFGPT_SETUP_SETUP  | MFGPT_SETUP_CMP2 | MFGPT_SETUP_CMP1)))
        return IRQ_NONE;

    /* Turn off the clock (and clear the event) */
    mfgpt_disable_timer(mfgpt_event_clock);

    if (mfgpt_tick_mode == CLOCK_EVT_MODE_SHUTDOWN)
        return IRQ_HANDLED;

    /* Clear the counter */
    geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0);

    /* Restart the clock in periodic mode */

    if (mfgpt_tick_mode == CLOCK_EVT_MODE_PERIODIC) {
        geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP,
                  MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2);
    }

    mfgpt_clockevent.event_handler(&mfgpt_clockevent);
    return IRQ_HANDLED;
}
Esempio n. 2
0
static void mfgpt_start_timer(u16 delta)
{
    geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_CMP2, (u16) delta);
    geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_COUNTER, 0);

    geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP,
              MFGPT_SETUP_CNTEN | MFGPT_SETUP_CMP2);
}
static void geodewdt_ping(void)
{
	/* Stop the counter */
	geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0);

	/* Reset the counter */
	geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0);

	/* Enable the counter */
	geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN);
}
static int geodewdt_set_heartbeat(int val)
{
	if (val < 1 || val > GEODEWDT_MAX_SECONDS)
		return -EINVAL;

	geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0);
	geode_mfgpt_write(wdt_timer, MFGPT_REG_CMP2, val * GEODEWDT_HZ);
	geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0);
	geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, MFGPT_SETUP_CNTEN);

	timeout = val;
	return 0;
}
Esempio n. 5
0
int __init mfgpt_timer_setup(void)
{
    int timer, ret;
    u16 val;

    timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING);
    if (timer < 0) {
        printk(KERN_ERR
               "mfgpt-timer:  Could not allocate a MFPGT timer\n");
        return -ENODEV;
    }

    mfgpt_event_clock = timer;

    /* Set up the IRQ on the MFGPT side */
    if (geode_mfgpt_setup_irq(mfgpt_event_clock, MFGPT_CMP2, irq)) {
        printk(KERN_ERR "mfgpt-timer:  Could not set up IRQ %d\n", irq);
        return -EIO;
    }

    /* And register it with the kernel */
    ret = setup_irq(irq, &mfgptirq);

    if (ret) {
        printk(KERN_ERR
               "mfgpt-timer:  Unable to set up the interrupt.\n");
        goto err;
    }

    /* Set the clock scale and enable the event mode for CMP2 */
    val = MFGPT_SCALE | (3 << 8);

    geode_mfgpt_write(mfgpt_event_clock, MFGPT_REG_SETUP, val);

    /* Set up the clock event */
    mfgpt_clockevent.mult = div_sc(MFGPT_HZ, NSEC_PER_SEC,
                       mfgpt_clockevent.shift);
    mfgpt_clockevent.min_delta_ns = clockevent_delta2ns(0xF,
            &mfgpt_clockevent);
    mfgpt_clockevent.max_delta_ns = clockevent_delta2ns(0xFFFE,
            &mfgpt_clockevent);

    printk(KERN_INFO
           "mfgpt-timer:  registering the MFGPT timer as a clock event.\n");
    clockevents_register_device(&mfgpt_clockevent);

    return 0;

err:
    geode_mfgpt_release_irq(mfgpt_event_clock, MFGPT_CMP2, irq);
    printk(KERN_ERR
           "mfgpt-timer:  Unable to set up the MFGPT clock source\n");
    return -EIO;
}
static void geodewdt_disable(void)
{
	geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP, 0);
	geode_mfgpt_write(wdt_timer, MFGPT_REG_COUNTER, 0);
}
static long geodewdt_ioctl(struct file *file, unsigned int cmd,
				unsigned long arg)
{
	void __user *argp = (void __user *)arg;
	int __user *p = argp;
	int interval;

	static struct watchdog_info ident = {
		.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING
		| WDIOF_MAGICCLOSE,
		.firmware_version =     1,
		.identity =             WATCHDOG_NAME,
	};

	switch (cmd) {
	case WDIOC_GETSUPPORT:
		return copy_to_user(argp, &ident,
				    sizeof(ident)) ? -EFAULT : 0;
		break;

	case WDIOC_GETSTATUS:
	case WDIOC_GETBOOTSTATUS:
		return put_user(0, p);

	case WDIOC_SETOPTIONS:
	{
		int options, ret = -EINVAL;

		if (get_user(options, p))
			return -EFAULT;

		if (options & WDIOS_DISABLECARD) {
			geodewdt_disable();
			ret = 0;
		}

		if (options & WDIOS_ENABLECARD) {
			geodewdt_ping();
			ret = 0;
		}

		return ret;
	}
	case WDIOC_KEEPALIVE:
		geodewdt_ping();
		return 0;

	case WDIOC_SETTIMEOUT:
		if (get_user(interval, p))
			return -EFAULT;

		if (geodewdt_set_heartbeat(interval))
			return -EINVAL;
	/* Fall through */
	case WDIOC_GETTIMEOUT:
		return put_user(timeout, p);

	default:
		return -ENOTTY;
	}

	return 0;
}

static const struct file_operations geodewdt_fops = {
	.owner          = THIS_MODULE,
	.llseek         = no_llseek,
	.write          = geodewdt_write,
	.unlocked_ioctl = geodewdt_ioctl,
	.open           = geodewdt_open,
	.release        = geodewdt_release,
};

static struct miscdevice geodewdt_miscdev = {
	.minor = WATCHDOG_MINOR,
	.name = "watchdog",
	.fops = &geodewdt_fops,
};

static int __devinit geodewdt_probe(struct platform_device *dev)
{
	int ret, timer;

	timer = geode_mfgpt_alloc_timer(MFGPT_TIMER_ANY, MFGPT_DOMAIN_WORKING);

	if (timer == -1) {
		printk(KERN_ERR "geodewdt:  No timers were available\n");
		return -ENODEV;
	}

	wdt_timer = timer;

	/* Set up the timer */

	geode_mfgpt_write(wdt_timer, MFGPT_REG_SETUP,
			  GEODEWDT_SCALE | (3 << 8));

	/* Set up comparator 2 to reset when the event fires */
	geode_mfgpt_toggle_event(wdt_timer, MFGPT_CMP2, MFGPT_EVENT_RESET, 1);

	/* Set up the initial timeout */

	geode_mfgpt_write(wdt_timer, MFGPT_REG_CMP2,
		timeout * GEODEWDT_HZ);

	ret = misc_register(&geodewdt_miscdev);

	return ret;
}

static int __devexit geodewdt_remove(struct platform_device *dev)
{
	misc_deregister(&geodewdt_miscdev);
	return 0;
}
Esempio n. 8
0
static void mfgpt_disable_timer(u16 clock)
{
    /* avoid races by clearing CMP1 and CMP2 unconditionally */
    geode_mfgpt_write(clock, MFGPT_REG_SETUP, (u16) ~MFGPT_SETUP_CNTEN |
            MFGPT_SETUP_CMP1 | MFGPT_SETUP_CMP2);
}