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