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 struct device_t * ce_samsung_timer_probe(struct driver_t * drv, struct dtnode_t * n) { struct ce_samsung_timer_pdata_t * pdat; struct clockevent_t * ce; 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 irq = dt_read_int(n, "interrupt", -1); int channel = dt_read_int(n, "timer-channel", -1); u64_t rate; if(!search_clk(clk)) return NULL; if(!irq_is_valid(irq)) return NULL; if(channel < 0 || channel > 3) return NULL; pdat = malloc(sizeof(struct ce_samsung_timer_pdata_t)); if(!pdat) return NULL; ce = malloc(sizeof(struct clockevent_t)); if(!ce) { free(pdat); return NULL; } pdat->virt = virt; pdat->clk = strdup(clk); pdat->irq = irq; pdat->channel = channel; clk_enable(pdat->clk); rate = samsung_timer_calc_tin(pdat->virt, pdat->clk, pdat->channel, 107); clockevent_calc_mult_shift(ce, rate, 10); ce->name = alloc_device_name(dt_read_name(n), -1); ce->min_delta_ns = clockevent_delta2ns(ce, 0x1); ce->max_delta_ns = clockevent_delta2ns(ce, 0xffffffff); ce->next = ce_samsung_timer_next, ce->priv = pdat; if(!request_irq(pdat->irq, ce_samsung_timer_interrupt, IRQ_TYPE_NONE, ce)) { clk_disable(pdat->clk); free(pdat->clk); free(ce->priv); free(ce); return NULL; } samsung_timer_enable(pdat->virt, pdat->channel, 1); samsung_timer_count(pdat->virt, pdat->channel, 0); samsung_timer_stop(pdat->virt, pdat->channel); if(!register_clockevent(&dev, ce)) { samsung_timer_irq_clear(pdat->virt, pdat->channel); samsung_timer_stop(pdat->virt, pdat->channel); samsung_timer_disable(pdat->virt, pdat->channel); clk_disable(pdat->clk); free_irq(pdat->irq); free(pdat->clk); free_device_name(ce->name); free(ce->priv); free(ce); return NULL; } dev->driver = drv; return dev; }