Initial commit
[kernel/linux-3.0.git] / arch / arm / mach-exynos / dev.c
1 /* linux/arch/arm/mach-exynos/dev.c
2  *
3  * Copyright (c) 2011 Samsung Electronics Co., Ltd.
4  *              http://www.samsung.com
5  *
6  * EXYNOS4 Device List support
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11 */
12
13 #include <linux/device.h>
14 #include <linux/list.h>
15 #include <linux/mutex.h>
16 #include <linux/err.h>
17 #include <linux/slab.h>
18
19 #include <mach/dev.h>
20 #ifdef CONFIG_ARCH_EXYNOS4
21 #include <mach/busfreq_exynos4.h>
22 #else
23 #include <mach/busfreq_exynos5.h>
24 #endif
25
26 static LIST_HEAD(domains_list);
27 static DEFINE_MUTEX(domains_mutex);
28
29 static struct device_domain *find_device_domain(struct device *dev)
30 {
31         struct device_domain *tmp_domain, *domain = ERR_PTR(-ENODEV);
32
33         mutex_lock(&domains_mutex);
34         list_for_each_entry(tmp_domain, &domains_list, node) {
35                 if (tmp_domain->device == dev) {
36                         domain = tmp_domain;
37                         break;
38                 }
39         }
40
41         mutex_unlock(&domains_mutex);
42         return domain;
43 }
44
45 int dev_add(struct device_domain *dev, struct device *device)
46 {
47         if (!dev || !device)
48                 return -EINVAL;
49
50         mutex_lock(&domains_mutex);
51         INIT_LIST_HEAD(&dev->domain_list);
52         dev->device = device;
53         list_add(&dev->node, &domains_list);
54         mutex_unlock(&domains_mutex);
55
56         return 0;
57 }
58
59 struct device *dev_get(const char *name)
60 {
61         struct device_domain *domain;
62
63         mutex_lock(&domains_mutex);
64         list_for_each_entry(domain, &domains_list, node)
65                 if (strcmp(name, dev_name(domain->device)) == 0)
66                         goto found;
67
68         mutex_unlock(&domains_mutex);
69         return ERR_PTR(-ENODEV);
70 found:
71         mutex_unlock(&domains_mutex);
72         return domain->device;
73 }
74
75 void dev_put(const char *name)
76 {
77         return;
78 }
79
80 int dev_lock(struct device *device, struct device *dev,
81                 unsigned long freq)
82 {
83         struct device_domain *domain;
84         struct domain_lock *lock;
85         int ret = 0;
86
87         domain = find_device_domain(device);
88
89         if (IS_ERR(domain)) {
90                 dev_err(dev, "Can't find device domain.\n");
91                 return -EINVAL;
92         }
93
94         mutex_lock(&domains_mutex);
95         list_for_each_entry(lock, &domain->domain_list, node) {
96                 if (lock->device == dev) {
97                         /* If the lock already exist, only update the freq */
98                         lock->freq = freq;
99                         goto out;
100                 }
101         }
102
103         lock = kzalloc(sizeof(struct domain_lock), GFP_KERNEL);
104         if (!lock) {
105                 dev_err(device, "Unable to create domain_lock");
106                 ret = -ENOMEM;
107                 goto out;
108         }
109
110         lock->device = dev;
111         lock->freq = freq;
112         list_add(&lock->node, &domain->domain_list);
113
114 out:
115         mutex_unlock(&domains_mutex);
116         exynos_request_apply(freq);
117         return ret;
118 }
119
120 int dev_unlock(struct device *device, struct device *dev)
121 {
122         struct device_domain *domain;
123         struct domain_lock *lock;
124
125         domain = find_device_domain(device);
126
127         if (IS_ERR(domain)) {
128                 dev_err(dev, "Can't find device domain.\n");
129                 return -EINVAL;
130         }
131
132         mutex_lock(&domains_mutex);
133         list_for_each_entry(lock, &domain->domain_list, node) {
134                 if (lock->device == dev) {
135                         list_del(&lock->node);
136                         kfree(lock);
137                         break;
138                 }
139         }
140
141         mutex_unlock(&domains_mutex);
142
143         return 0;
144 }
145
146 unsigned long dev_max_freq(struct device *device)
147 {
148         struct device_domain *domain;
149         struct domain_lock *lock;
150         unsigned long freq = 0;
151
152         domain = find_device_domain(device);
153         if (IS_ERR(domain)) {
154                 dev_dbg(device, "Can't find device domain.\n");
155                 return freq;
156         }
157
158         mutex_lock(&domains_mutex);
159         list_for_each_entry(lock, &domain->domain_list, node)
160                 if (lock->freq > freq)
161                         freq = lock->freq;
162
163         mutex_unlock(&domains_mutex);
164
165         return freq;
166 }
167
168 int dev_lock_list(struct device *device, char *buf)
169 {
170         struct device_domain *domain;
171         struct domain_lock *lock;
172         int count = 0;
173
174         domain = find_device_domain(device);
175         if (IS_ERR(domain)) {
176                 dev_dbg(device, "Can't find device domain.\n");
177                 return 0;
178         }
179
180         mutex_lock(&domains_mutex);
181         count = sprintf(buf, "Lock List\n");
182         list_for_each_entry(lock, &domain->domain_list, node)
183                 count += sprintf(buf + count, "%s : %lu\n", dev_name(lock->device), lock->freq);
184
185         mutex_unlock(&domains_mutex);
186
187         return count;
188 }