1. Modes
---------------

There are four or three modes the timer runs in depending on IO mode:

1-1. Output

- edge-aligned mode (default)
- center-aligned mode 1
- center-aligned mode 2
- center-aligned mode 3

And sub-mode for each ouput mode:

- output compare mode (default)
- PWM output mode

1-2. Input

- reset mode (default)
- gated mode (not supported)
- trigger mode (not supported)

And sub-mode for each input mode:

- input capture mode (default)
- PWM input mode

1-3. Direction

Counting direction is also configuable:

1. up count (default)
2. down count

2. Channels
---------------

2-1. Output

4 channels

2-2. Input

Incase of PWM, channel 1 and 2 only supported. And PWM input capture works in a
pair of channels. like channel 2 for channel 1, channel 1 for channel 2. So
bear in mind that its pair channel gets set as opposite polarity to the channel
you are setting on. See the example below.

3. Usage
---------------

Note that you have to be in previleged context to deal with open() and ioctl().

When you open with O_WRONLY, it goes in output mode. On the other hand when you
open with O_RDONLY, it goes in input capture mode.

3-1. Structure

enum tim_mode {
	TIM_OP_EDGE,
	TIM_OP_CENTER,
	TIM_OP_CENTER2,
	TIM_OP_CENTER3,
	TIM_OP_UPCOUNT,
	TIM_OP_DNCOUNT,
};

enum tim_iomode {
	TIM_IO_FROZEN,
	TIM_IO_LO2HI,
	TIM_IO_HI2LO,
	TIM_IO_TOGGLE,
	TIM_IO_PWM,
	TIM_IO_PWM2,
};

enum tim_iochannel {
	TIM_IO_NONE,
	TIM_IO_OVERFLOW = TIM_IO_NONE,
	TIM_IO_CH1,
	TIM_IO_CH2,
	TIM_IO_CH3,
	TIM_IO_CH4,
};

The period and match are used only in output mode. You may get the captured
value from capture register by read().

struct {
	mode;
	channel;
	prescale;
	period;
	match;
	iomode;
	enable_intr; /* true or false */
	isr; /* address of user-defined-isr */
}

3-2. Example

ex1) basic
	hz = 1; /* 1Hz */
	fd = open("/dev/tim2", O_WRONLY, hz);

if hz = 0, timer does not run. run manually by ioctl(fd, C_RUN, true)

ex2) edge-aligned PWM output on CH1
	timer_t tim;
	int ccr[4];

	fd = open("/dev/tim2", O_WRONLY);
	memset(&tim, 0, sizeof(tim));
	tim.channel = TIM_IO_CH1;
	//ioctl(fd, C_GET, &tim);
	tim.pin = PIN_TIM2CH1;
	tim.iomode = TIM_IO_PWM;
	tim.prescale = 8;
	tim.period = 64000;
	tim.match = tim.period / 2;
	ioctl(fd, C_SET, &tim);

	while (1) {
		...
		tim.match += delta;
		ioctl(fd, C_RUN, &tim); /* update pulse width */
		...
	}

ex3) output with user-defined-isr
add two lines in addition to the above example:

	tim.interrupt = true;
	tim.isr = user_defined_isr;

a user-defined-isr may look like this:
	static int user_defined_isr(int flags)
	{
		/* be careful since you are in interrupt context. */
	}

ex4) input capture
fd = open("/dev/tim2", O_RDONLY); /* default: lo2hi on channel1 */

ex5) PWM input capture
	fd = open("/dev/tim2", O_RDONLY);
	memset(&tim, 0, sizeof(tim));
	tim.channel = TIM_IO_CH1;
	tim.pin = PIN_TIM2CH1;
	tim.iomode = TIM_IO_PWM;
	ioctl(fd, C_SET, &tim);

	while (1) {
		...
		/* or has_event(fd) can be used to check if an event occurs */
		if (!read(fd, ccr, sizeof(ccr)))
			continue;

		printf("ccr1 %d ccr2 %d f=%dHz %3d%%\n",
			ccr[0], ccr[1], sysclk/prescale/ccr[1], ccr[0]*100/ccr[1]);
		...
	}
