aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/clocksource/tcb_clksrc.c2
-rw-r--r--drivers/misc/atmel_tclib.c71
-rw-r--r--drivers/pwm/pwm-atmel-tcb.c2
-rw-r--r--include/linux/atmel_tc.h8
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 */
44struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name) 43struct 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
83out:
84 spin_unlock(&tc_list_lock); 60 spin_unlock(&tc_list_lock);
85 return tc;
86 61
87fail_ioremap: 62 return pdev ? tc : NULL;
88 release_mem_region(r->start, size);
89fail:
90 tc = NULL;
91 goto out;
92} 63}
93EXPORT_SYMBOL_GPL(atmel_tc_alloc); 64EXPORT_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 */
103void atmel_tc_free(struct atmel_tc *tc) 73void 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}
114EXPORT_SYMBOL_GPL(atmel_tc_free); 80EXPORT_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 */
62struct atmel_tc { 63struct 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
72extern struct atmel_tc *atmel_tc_alloc(unsigned block, const char *name); 74extern struct atmel_tc *atmel_tc_alloc(unsigned block);
73extern void atmel_tc_free(struct atmel_tc *tc); 75extern 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) */