static struct device_t * cs_samsung_timer_probe(struct driver_t * drv, struct dtnode_t * n) { struct cs_samsung_timer_pdata_t * pdat; struct clocksource_t * cs; struct device_t * dev; virtual_addr_t virt = phys_to_virt(dt_read_address(n)); char * clk = dt_read_string(n, "clock-name", NULL); int channel = dt_read_int(n, "timer-channel", -1); u64_t rate; if(!search_clk(clk)) return NULL; if(channel < 0 || channel > 3) return NULL; pdat = malloc(sizeof(struct cs_samsung_timer_pdata_t)); if(!pdat) return NULL; cs = malloc(sizeof(struct clocksource_t)); if(!cs) { free(pdat); return NULL; } pdat->virt = virt; pdat->clk = strdup(clk); pdat->channel = channel; clk_enable(pdat->clk); rate = samsung_timer_calc_tin(pdat->virt, pdat->clk, pdat->channel, 13); clocksource_calc_mult_shift(&cs->mult, &cs->shift, rate, 1000000000ULL, 10); cs->name = alloc_device_name(dt_read_name(n), -1); cs->mask = CLOCKSOURCE_MASK(32); cs->read = cs_samsung_timer_read; cs->priv = pdat; samsung_timer_enable(pdat->virt, pdat->channel, 0); samsung_timer_count(pdat->virt, pdat->channel, 0xffffffff); samsung_timer_start(pdat->virt, pdat->channel, 0); if(!register_clocksource(&dev, cs)) { samsung_timer_stop(pdat->virt, pdat->channel); samsung_timer_disable(pdat->virt, pdat->channel); clk_disable(pdat->clk); free(pdat->clk); free_device_name(cs->name); free(cs->priv); free(cs); return NULL; } dev->driver = drv; return dev; }
static bool_t ce_samsung_timer_next(struct clockevent_t * ce, u64_t evt) { struct ce_samsung_timer_pdata_t * pdat = (struct ce_samsung_timer_pdata_t *)ce->priv; samsung_timer_count(pdat->virt, pdat->channel, (evt & 0xffffffff)); samsung_timer_start(pdat->virt, pdat->channel, 1); return TRUE; }