forked from mirrors/linux
		
	pwm: atmel-tcb: Add sama5d2 support
Add sama5d2 support. The sama5d2 has a new clock input, its gclk. Index 0 of the clock selector is the gclk instead of the peripheral clock divided by 2. For now, the gclk is not used because the peripheral clock divided by 8 already gives a 9.6ns resolution which is enough for most use cases. Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com> Signed-off-by: Thierry Reding <thierry.reding@gmail.com>
This commit is contained in:
		
							parent
							
								
									061f8572a3
								
							
						
					
					
						commit
						34cbcd7258
					
				
					 1 changed files with 20 additions and 3 deletions
				
			
		|  | @ -55,6 +55,7 @@ struct atmel_tcb_pwm_chip { | ||||||
| 	u8 width; | 	u8 width; | ||||||
| 	struct regmap *regmap; | 	struct regmap *regmap; | ||||||
| 	struct clk *clk; | 	struct clk *clk; | ||||||
|  | 	struct clk *gclk; | ||||||
| 	struct clk *slow_clk; | 	struct clk *slow_clk; | ||||||
| 	struct atmel_tcb_pwm_device *pwms[NPWM]; | 	struct atmel_tcb_pwm_device *pwms[NPWM]; | ||||||
| 	struct atmel_tcb_channel bkup; | 	struct atmel_tcb_channel bkup; | ||||||
|  | @ -292,7 +293,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | ||||||
| 	struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); | 	struct atmel_tcb_pwm_chip *tcbpwmc = to_tcb_chip(chip); | ||||||
| 	struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm); | 	struct atmel_tcb_pwm_device *tcbpwm = pwm_get_chip_data(pwm); | ||||||
| 	struct atmel_tcb_pwm_device *atcbpwm = NULL; | 	struct atmel_tcb_pwm_device *atcbpwm = NULL; | ||||||
| 	int i; | 	int i = 0; | ||||||
| 	int slowclk = 0; | 	int slowclk = 0; | ||||||
| 	unsigned period; | 	unsigned period; | ||||||
| 	unsigned duty; | 	unsigned duty; | ||||||
|  | @ -303,8 +304,11 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm, | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Find best clk divisor: | 	 * Find best clk divisor: | ||||||
| 	 * the smallest divisor which can fulfill the period_ns requirements. | 	 * the smallest divisor which can fulfill the period_ns requirements. | ||||||
|  | 	 * If there is a gclk, the first divisor is actuallly the gclk selector | ||||||
| 	 */ | 	 */ | ||||||
| 	for (i = 0; i < ARRAY_SIZE(atmel_tcb_divisors); ++i) { | 	if (tcbpwmc->gclk) | ||||||
|  | 		i = 1; | ||||||
|  | 	for (; i < ARRAY_SIZE(atmel_tcb_divisors); ++i) { | ||||||
| 		if (atmel_tcb_divisors[i] == 0) { | 		if (atmel_tcb_divisors[i] == 0) { | ||||||
| 			slowclk = i; | 			slowclk = i; | ||||||
| 			continue; | 			continue; | ||||||
|  | @ -383,9 +387,15 @@ static struct atmel_tcb_config tcb_sam9x5_config = { | ||||||
| 	.counter_width = 32, | 	.counter_width = 32, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | static struct atmel_tcb_config tcb_sama5d2_config = { | ||||||
|  | 	.counter_width = 32, | ||||||
|  | 	.has_gclk = 1, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
| static const struct of_device_id atmel_tcb_of_match[] = { | static const struct of_device_id atmel_tcb_of_match[] = { | ||||||
| 	{ .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, }, | 	{ .compatible = "atmel,at91rm9200-tcb", .data = &tcb_rm9200_config, }, | ||||||
| 	{ .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, }, | 	{ .compatible = "atmel,at91sam9x5-tcb", .data = &tcb_sam9x5_config, }, | ||||||
|  | 	{ .compatible = "atmel,sama5d2-tcb", .data = &tcb_sama5d2_config, }, | ||||||
| 	{ /* sentinel */ } | 	{ /* sentinel */ } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | @ -396,7 +406,7 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) | ||||||
| 	const struct atmel_tcb_config *config; | 	const struct atmel_tcb_config *config; | ||||||
| 	struct device_node *np = pdev->dev.of_node; | 	struct device_node *np = pdev->dev.of_node; | ||||||
| 	struct regmap *regmap; | 	struct regmap *regmap; | ||||||
| 	struct clk *clk; | 	struct clk *clk, *gclk = NULL; | ||||||
| 	struct clk *slow_clk; | 	struct clk *slow_clk; | ||||||
| 	char clk_name[] = "t0_clk"; | 	char clk_name[] = "t0_clk"; | ||||||
| 	int err; | 	int err; | ||||||
|  | @ -428,6 +438,12 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) | ||||||
| 	match = of_match_node(atmel_tcb_of_match, np->parent); | 	match = of_match_node(atmel_tcb_of_match, np->parent); | ||||||
| 	config = match->data; | 	config = match->data; | ||||||
| 
 | 
 | ||||||
|  | 	if (config->has_gclk) { | ||||||
|  | 		gclk = of_clk_get_by_name(np->parent, "gclk"); | ||||||
|  | 		if (IS_ERR(gclk)) | ||||||
|  | 			return PTR_ERR(gclk); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	tcbpwm = devm_kzalloc(&pdev->dev, sizeof(*tcbpwm), GFP_KERNEL); | 	tcbpwm = devm_kzalloc(&pdev->dev, sizeof(*tcbpwm), GFP_KERNEL); | ||||||
| 	if (tcbpwm == NULL) { | 	if (tcbpwm == NULL) { | ||||||
| 		err = -ENOMEM; | 		err = -ENOMEM; | ||||||
|  | @ -443,6 +459,7 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) | ||||||
| 	tcbpwm->channel = channel; | 	tcbpwm->channel = channel; | ||||||
| 	tcbpwm->regmap = regmap; | 	tcbpwm->regmap = regmap; | ||||||
| 	tcbpwm->clk = clk; | 	tcbpwm->clk = clk; | ||||||
|  | 	tcbpwm->gclk = gclk; | ||||||
| 	tcbpwm->slow_clk = slow_clk; | 	tcbpwm->slow_clk = slow_clk; | ||||||
| 	tcbpwm->width = config->counter_width; | 	tcbpwm->width = config->counter_width; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Alexandre Belloni
						Alexandre Belloni