static void r_tpu_start_stop_ch(struct r_tpu_priv *p, int start) { struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data; unsigned long flags, value; /* start stop register shared by multiple timer channels */ spin_lock_irqsave(&r_tpu_lock, flags); value = r_tpu_read(p, TSTR); if (start) value |= 1 << cfg->timer_bit; else value &= ~(1 << cfg->timer_bit); r_tpu_write(p, TSTR, value); spin_unlock_irqrestore(&r_tpu_lock, flags); }
static int r_tpu_enable(struct r_tpu_priv *p, enum led_brightness brightness) { struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data; int prescaler[] = { 1, 4, 16, 64 }; int k, ret; unsigned long rate, tmp; if (p->timer_state == R_TPU_TIMER_ON) return 0; /* wake up device and enable clock */ pm_runtime_get_sync(&p->pdev->dev); ret = clk_enable(p->clk); if (ret) { dev_err(&p->pdev->dev, "cannot enable clock\n"); return ret; } /* make sure channel is disabled */ r_tpu_start_stop_ch(p, 0); /* get clock rate after enabling it */ rate = clk_get_rate(p->clk); /* pick the lowest acceptable rate */ for (k = 0; k < ARRAY_SIZE(prescaler); k++) if ((rate / prescaler[k]) < p->min_rate) break; if (!k) { dev_err(&p->pdev->dev, "clock rate mismatch\n"); goto err0; } dev_dbg(&p->pdev->dev, "rate = %lu, prescaler %u\n", rate, prescaler[k - 1]); /* clear TCNT on TGRB match, count on rising edge, set prescaler */ r_tpu_write(p, TCR, 0x0040 | (k - 1)); /* output 0 until TGRA, output 1 until TGRB */ r_tpu_write(p, TIOR, 0x0002); rate /= prescaler[k - 1] * p->refresh_rate; r_tpu_write(p, TGRB, rate); dev_dbg(&p->pdev->dev, "TRGB = 0x%04lx\n", rate); tmp = (cfg->max_brightness - brightness) * rate; r_tpu_write(p, TGRA, tmp / cfg->max_brightness); dev_dbg(&p->pdev->dev, "TRGA = 0x%04lx\n", tmp / cfg->max_brightness); /* PWM mode */ r_tpu_write(p, TMDR, 0x0002); /* enable channel */ r_tpu_start_stop_ch(p, 1); p->timer_state = R_TPU_TIMER_ON; return 0; err0: clk_disable(p->clk); pm_runtime_put_sync(&p->pdev->dev); return -ENOTSUPP; }
static int r_tpu_enable(struct r_tpu_priv *p, enum led_brightness brightness) { struct led_renesas_tpu_config *cfg = p->pdev->dev.platform_data; int prescaler[] = { 1, 4, 16, 64 }; int k, ret; unsigned long rate, tmp; if (p->timer_state == R_TPU_TIMER_ON) return 0; pm_runtime_get_sync(&p->pdev->dev); ret = clk_enable(p->clk); if (ret) { dev_err(&p->pdev->dev, "cannot enable clock\n"); return ret; } r_tpu_start_stop_ch(p, 0); rate = clk_get_rate(p->clk); for (k = 0; k < ARRAY_SIZE(prescaler); k++) if ((rate / prescaler[k]) < p->min_rate) break; if (!k) { dev_err(&p->pdev->dev, "clock rate mismatch\n"); goto err0; } dev_dbg(&p->pdev->dev, "rate = %lu, prescaler %u\n", rate, prescaler[k - 1]); r_tpu_write(p, TCR, 0x0040 | (k - 1)); r_tpu_write(p, TIOR, 0x0002); rate /= prescaler[k - 1] * p->refresh_rate; r_tpu_write(p, TGRB, rate); dev_dbg(&p->pdev->dev, "TRGB = 0x%04lx\n", rate); tmp = (cfg->max_brightness - brightness) * rate; r_tpu_write(p, TGRA, tmp / cfg->max_brightness); dev_dbg(&p->pdev->dev, "TRGA = 0x%04lx\n", tmp / cfg->max_brightness); r_tpu_write(p, TMDR, 0x0002); r_tpu_start_stop_ch(p, 1); p->timer_state = R_TPU_TIMER_ON; return 0; err0: clk_disable(p->clk); pm_runtime_put_sync(&p->pdev->dev); return -ENOTSUPP; }