Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: at91/tclib: move initialization from alloc to probe

Move resource retrieval from atmel_tc_alloc to tc_probe to avoid lately
reporting resource related issues when a TC block user request a TC block.

Moreover, resources retrieval are usually done in the probe function,
thus moving them add some consistency with other drivers.

Initialization is done once, ie not every time a tc block is requested.
If it fails, the device is not appended to the list of tc blocks.

Furhermore, the device id is retrieved at probe as well, avoiding parsing
DT every time the user requests of tc block.

Signed-off-by: Gaël PORTAY <gael.portay@gmail.com>
Acked-by: Thierry Reding <thierry.reding@gmail.com>
Acked-by: Boris Brezillon <boris.brezillon@free-electrons.com>
Signed-off-by: Nicolas Ferre <nicolas.ferre@atmel.com>

authored by

Gaël PORTAY and committed by
Nicolas Ferre
4930d247 8495497f

+29 -54
+1 -1
drivers/clocksource/tcb_clksrc.c
··· 279 279 int i; 280 280 int ret; 281 281 282 - tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK, clksrc.name); 282 + tc = atmel_tc_alloc(CONFIG_ATMEL_TCB_CLKSRC_BLOCK); 283 283 if (!tc) { 284 284 pr_debug("can't alloc TC for clocksource\n"); 285 285 return -ENODEV;
+22 -49
drivers/misc/atmel_tclib.c
··· 35 35 /** 36 36 * atmel_tc_alloc - allocate a specified TC block 37 37 * @block: which block to allocate 38 - * @name: name to be associated with the iomem resource 39 38 * 40 39 * Caller allocates a block. If it is available, a pointer to a 41 40 * pre-initialized struct atmel_tc is returned. The caller can access 42 41 * the registers directly through the "regs" field. 43 42 */ 44 - struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name) 43 + struct atmel_tc *atmel_tc_alloc(unsigned block) 45 44 { 46 45 struct atmel_tc *tc; 47 46 struct platform_device *pdev = NULL; 48 - struct resource *r; 49 - size_t size; 50 47 51 48 spin_lock(&tc_list_lock); 52 49 list_for_each_entry(tc, &tc_list, node) { 53 - if (tc->pdev->dev.of_node) { 54 - if (of_alias_get_id(tc->pdev->dev.of_node, "tcb") 55 - == block) { 56 - pdev = tc->pdev; 57 - break; 58 - } 59 - } else if (tc->pdev->id == block) { 50 + if (tc->allocated) 51 + continue; 52 + 53 + if ((tc->pdev->dev.of_node && tc->id == block) || 54 + (tc->pdev->id == block)) { 60 55 pdev = tc->pdev; 56 + tc->allocated = true; 61 57 break; 62 58 } 63 59 } 64 - 65 - if (!pdev || tc->iomem) 66 - goto fail; 67 - 68 - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 69 - if (!r) 70 - goto fail; 71 - 72 - size = resource_size(r); 73 - r = request_mem_region(r->start, size, name); 74 - if (!r) 75 - goto fail; 76 - 77 - tc->regs = ioremap(r->start, size); 78 - if (!tc->regs) 79 - goto fail_ioremap; 80 - 81 - tc->iomem = r; 82 - 83 - out: 84 60 spin_unlock(&tc_list_lock); 85 - return tc; 86 61 87 - fail_ioremap: 88 - release_mem_region(r->start, size); 89 - fail: 90 - tc = NULL; 91 - goto out; 62 + return pdev ? tc : NULL; 92 63 } 93 64 EXPORT_SYMBOL_GPL(atmel_tc_alloc); 94 65 ··· 67 96 * atmel_tc_free - release a specified TC block 68 97 * @tc: Timer/counter block that was returned by atmel_tc_alloc() 69 98 * 70 - * This reverses the effect of atmel_tc_alloc(), unmapping the I/O 71 - * registers, invalidating the resource returned by that routine and 72 - * making the TC available to other drivers. 99 + * This reverses the effect of atmel_tc_alloc(), invalidating the resource 100 + * returned by that routine and making the TC available to other drivers. 73 101 */ 74 102 void atmel_tc_free(struct atmel_tc *tc) 75 103 { 76 104 spin_lock(&tc_list_lock); 77 - if (tc->regs) { 78 - iounmap(tc->regs); 79 - release_mem_region(tc->iomem->start, resource_size(tc->iomem)); 80 - tc->regs = NULL; 81 - tc->iomem = NULL; 82 - } 105 + if (tc->allocated) 106 + tc->allocated = false; 83 107 spin_unlock(&tc_list_lock); 84 108 } 85 109 EXPORT_SYMBOL_GPL(atmel_tc_free); ··· 108 142 struct atmel_tc *tc; 109 143 struct clk *clk; 110 144 int irq; 111 - 112 - if (!platform_get_resource(pdev, IORESOURCE_MEM, 0)) 113 - return -EINVAL; 145 + struct resource *r; 114 146 115 147 irq = platform_get_irq(pdev, 0); 116 148 if (irq < 0) ··· 124 160 if (IS_ERR(clk)) 125 161 return PTR_ERR(clk); 126 162 163 + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 164 + tc->regs = devm_ioremap_resource(&pdev->dev, r); 165 + if (IS_ERR(tc->regs)) 166 + return PTR_ERR(tc->regs); 167 + 127 168 /* Now take SoC information if available */ 128 169 if (pdev->dev.of_node) { 129 170 const struct of_device_id *match; 130 171 match = of_match_node(atmel_tcb_dt_ids, pdev->dev.of_node); 131 172 if (match) 132 173 tc->tcb_config = match->data; 174 + 175 + tc->id = of_alias_get_id(tc->pdev->dev.of_node, "tcb"); 176 + } else { 177 + tc->id = pdev->id; 133 178 } 134 179 135 180 tc->clk[0] = clk;
+1 -1
drivers/pwm/pwm-atmel-tcb.c
··· 379 379 return err; 380 380 } 381 381 382 - tc = atmel_tc_alloc(tcblock, "tcb-pwm"); 382 + tc = atmel_tc_alloc(tcblock); 383 383 if (tc == NULL) { 384 384 dev_err(&pdev->dev, "failed to allocate Timer Counter Block\n"); 385 385 return -ENOMEM;
+5 -3
include/linux/atmel_tc.h
··· 44 44 /** 45 45 * struct atmel_tc - information about a Timer/Counter Block 46 46 * @pdev: physical device 47 - * @iomem: resource associated with the I/O register 48 47 * @regs: mapping through which the I/O registers can be accessed 48 + * @id: block id 49 49 * @tcb_config: configuration data from SoC 50 50 * @irq: irq for each of the three channels 51 51 * @clk: internal clock source for each of the three channels 52 52 * @node: list node, for tclib internal use 53 + * @allocated: if already used, for tclib internal use 53 54 * 54 55 * On some platforms, each TC channel has its own clocks and IRQs, 55 56 * while on others, all TC channels share the same clock and IRQ. ··· 62 61 */ 63 62 struct atmel_tc { 64 63 struct platform_device *pdev; 65 - struct resource *iomem; 66 64 void __iomem *regs; 65 + int id; 67 66 const struct atmel_tcb_config *tcb_config; 68 67 int irq[3]; 69 68 struct clk *clk[3]; 70 69 struct list_head node; 70 + bool allocated; 71 71 }; 72 72 73 - extern struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name); 73 + extern struct atmel_tc *atmel_tc_alloc(unsigned block); 74 74 extern void atmel_tc_free(struct atmel_tc *tc); 75 75 76 76 /* platform-specific ATMEL_TC_TIMER_CLOCKx divisors (0 means 32KiHz) */