blob: 18bf8dff0f86ba24d9fbc2fd271e09bdbf24592c [file] [log] [blame]
Greg Kroah-Hartmanf91121b2014-09-11 08:22:06 -07001/*
2 * Greybus kernel "version" glue logic.
3 *
4 * Copyright 2014 Google Inc.
Alex Eldera46e9672014-12-12 12:08:42 -06005 * Copyright 2014 Linaro Ltd.
Greg Kroah-Hartmanf91121b2014-09-11 08:22:06 -07006 *
7 * Released under the GPLv2 only.
8 *
9 * Backports of newer kernel apis to allow the code to build properly on older
10 * kernel versions. Remove this file when merging to upstream, it should not be
11 * needed at all
12 */
13
14#ifndef __GREYBUS_KERNEL_VER_H
15#define __GREYBUS_KERNEL_VER_H
16
Viresh Kumare2cb6ca2015-03-27 16:32:56 +053017#include <linux/kernel.h>
Alex Elder5c586402015-05-07 13:00:21 -050018#include <linux/version.h>
19
20#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 1, 0)
21/* Commit: 297d716 power_supply: Change ownership from driver to core */
22#define DRIVER_OWNS_PSY_STRUCT
23#endif
Viresh Kumare2cb6ca2015-03-27 16:32:56 +053024
Greg Kroah-Hartman4efe6062014-11-17 16:55:54 -080025#ifndef __ATTR_WO
26#define __ATTR_WO(_name) { \
Greg Kroah-Hartman99a4bd52015-05-01 21:04:47 +020027 .attr = { .name = __stringify(_name), .mode = S_IWUSR }, \
28 .store = _name##_store, \
Greg Kroah-Hartman4efe6062014-11-17 16:55:54 -080029}
30#endif
31
Greg Kroah-Hartmandf671552014-12-21 14:10:26 -080032#ifndef __ATTR_RW
33#define __ATTR_RW(_name) __ATTR(_name, (S_IWUSR | S_IRUGO), \
Greg Kroah-Hartman99a4bd52015-05-01 21:04:47 +020034 _name##_show, _name##_store)
Greg Kroah-Hartmandf671552014-12-21 14:10:26 -080035#endif
36
Greg Kroah-Hartmanf91121b2014-09-11 08:22:06 -070037#ifndef DEVICE_ATTR_RO
38#define DEVICE_ATTR_RO(_name) \
39 struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
40#endif
41
Greg Kroah-Hartmanac4029f2014-11-17 16:03:34 -080042#ifndef DEVICE_ATTR_WO
43#define DEVICE_ATTR_WO(_name) \
44 struct device_attribute dev_attr_##_name = __ATTR_WO(_name)
45#endif
46
Greg Kroah-Hartmandf671552014-12-21 14:10:26 -080047#ifndef DEVICE_ATTR_RW
48#define DEVICE_ATTR_RW(_name) \
49 struct device_attribute dev_attr_##_name = __ATTR_RW(_name)
50#endif
51
Alex Elder1cfc6672014-09-30 19:25:21 -050052#ifndef U8_MAX
53#define U8_MAX ((u8)~0U)
54#endif /* ! U8_MAX */
Greg Kroah-Hartmanf91121b2014-09-11 08:22:06 -070055
Alex Eldere88afa52014-10-01 21:54:15 -050056#ifndef U16_MAX
57#define U16_MAX ((u16)(~0U))
58#endif /* !U16_MAX */
59
Alex Elder47a96852015-08-04 13:44:10 -050060#ifndef U32_MAX
61#define U32_MAX ((u32)(~0U))
62#endif /* !U32_MAX */
63
64#ifndef U64_MAX
65#define U64_MAX ((u64)(~0U))
66#endif /* !U64_MAX */
67
Greg Kroah-Hartman213aefe2014-10-20 13:40:02 +080068/*
69 * The GPIO api sucks rocks in places, like removal, so work around their
70 * explicit requirements of catching the return value for kernels older than
71 * 3.17, which they explicitly changed in the 3.17 kernel. Consistency is
72 * overrated.
73 */
Greg Kroah-Hartman213aefe2014-10-20 13:40:02 +080074#include <linux/gpio.h>
75
Greg Kroah-Hartman3906a592015-05-01 21:05:03 +020076#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
Greg Kroah-Hartman213aefe2014-10-20 13:40:02 +080077static inline void gb_gpiochip_remove(struct gpio_chip *chip)
78{
79 gpiochip_remove(chip);
80}
81#else
82static inline void gb_gpiochip_remove(struct gpio_chip *chip)
83{
84 int ret;
Greg Kroah-Hartman63ca78b2015-05-01 21:05:29 +020085
Greg Kroah-Hartman213aefe2014-10-20 13:40:02 +080086 ret = gpiochip_remove(chip);
87}
88#endif
89
Greg Kroah-Hartmanf3489642014-10-28 09:27:50 +080090/*
91 * ATTRIBUTE_GROUPS showed up in 3.11-rc2, but we need to build on 3.10, so add
92 * it here.
93 */
Greg Kroah-Hartman3906a592015-05-01 21:05:03 +020094#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
Greg Kroah-Hartman66c98982015-04-01 01:36:23 +020095#include <linux/sysfs.h>
96
Greg Kroah-Hartmanf3489642014-10-28 09:27:50 +080097#define ATTRIBUTE_GROUPS(name) \
98static const struct attribute_group name##_group = { \
99 .attrs = name##_attrs, \
100}; \
101static const struct attribute_group *name##_groups[] = { \
102 &name##_group, \
103 NULL, \
104}
Greg Kroah-Hartman66c98982015-04-01 01:36:23 +0200105
106static inline int sysfs_create_groups(struct kobject *kobj,
107 const struct attribute_group **groups)
108{
109 int error = 0;
110 int i;
111
112 if (!groups)
113 return 0;
114
115 for (i = 0; groups[i]; i++) {
116 error = sysfs_create_group(kobj, groups[i]);
117 if (error) {
118 while (--i >= 0)
119 sysfs_remove_group(kobj, groups[i]);
120 break;
121 }
122 }
123 return error;
124}
125
126static inline void sysfs_remove_groups(struct kobject *kobj,
127 const struct attribute_group **groups)
128{
129 int i;
130
131 if (!groups)
132 return;
133 for (i = 0; groups[i]; i++)
134 sysfs_remove_group(kobj, groups[i]);
135}
Greg Kroah-Hartmanf3489642014-10-28 09:27:50 +0800136#endif
137
Rui Miguel Silva5656ab92015-06-24 23:20:26 +0100138#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0)
139#define MMC_HS400_SUPPORTED
140#define MMC_DDR52_DEFINED
141#endif
142
143#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
144#define MMC_POWER_UNDEFINED_SUPPORTED
145#endif
Rui Miguel Silva8a01b402015-06-24 23:20:27 +0100146
147#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 11, 0)
148#include <linux/scatterlist.h>
149static inline bool sg_miter_get_next_page(struct sg_mapping_iter *miter)
150{
151 if (!miter->__remaining) {
152 struct scatterlist *sg;
153 unsigned long pgoffset;
154
155 if (!__sg_page_iter_next(&miter->piter))
156 return false;
157
158 sg = miter->piter.sg;
159 pgoffset = miter->piter.sg_pgoffset;
160
161 miter->__offset = pgoffset ? 0 : sg->offset;
162 miter->__remaining = sg->offset + sg->length -
163 (pgoffset << PAGE_SHIFT) - miter->__offset;
164 miter->__remaining = min_t(unsigned long, miter->__remaining,
165 PAGE_SIZE - miter->__offset);
166 }
167
168 return true;
169}
170
171static inline bool sg_miter_skip(struct sg_mapping_iter *miter, off_t offset)
172{
173 sg_miter_stop(miter);
174
175 while (offset) {
176 off_t consumed;
177
178 if (!sg_miter_get_next_page(miter))
179 return false;
180
181 consumed = min_t(off_t, offset, miter->__remaining);
182 miter->__offset += consumed;
183 miter->__remaining -= consumed;
184 offset -= consumed;
185 }
186
187 return true;
188}
189
190static inline size_t _sg_copy_buffer(struct scatterlist *sgl,
191 unsigned int nents, void *buf,
192 size_t buflen, off_t skip,
193 bool to_buffer)
194{
195 unsigned int offset = 0;
196 struct sg_mapping_iter miter;
197 unsigned long flags;
198 unsigned int sg_flags = SG_MITER_ATOMIC;
199
200 if (to_buffer)
201 sg_flags |= SG_MITER_FROM_SG;
202 else
203 sg_flags |= SG_MITER_TO_SG;
204
205 sg_miter_start(&miter, sgl, nents, sg_flags);
206
207 if (!sg_miter_skip(&miter, skip))
208 return false;
209
210 local_irq_save(flags);
211
212 while (sg_miter_next(&miter) && offset < buflen) {
213 unsigned int len;
214
215 len = min(miter.length, buflen - offset);
216
217 if (to_buffer)
218 memcpy(buf + offset, miter.addr, len);
219 else
220 memcpy(miter.addr, buf + offset, len);
221
222 offset += len;
223 }
224
225 sg_miter_stop(&miter);
226
227 local_irq_restore(flags);
228 return offset;
229}
230
231static inline size_t sg_pcopy_to_buffer(struct scatterlist *sgl,
232 unsigned int nents, void *buf,
233 size_t buflen, off_t skip)
234{
235 return _sg_copy_buffer(sgl, nents, buf, buflen, skip, true);
236}
237
238static inline size_t sg_pcopy_from_buffer(struct scatterlist *sgl,
239 unsigned int nents, void *buf,
240 size_t buflen, off_t skip)
241{
242 return _sg_copy_buffer(sgl, nents, buf, buflen, skip, false);
243}
244#endif
245
Johan Hovold93047af2015-07-16 11:44:01 +0200246#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
247#define list_last_entry(ptr, type, member) \
248 list_entry((ptr)->prev, type, member)
249#endif
250
Rui Miguel Silva2870b522015-08-14 13:58:19 +0100251#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 17, 0)
252/*
253 * Before this version the led classdev did not support groups
254 */
255#define LED_HAVE_GROUPS
256#endif
257
258#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 19, 0)
259/*
260 * At this time the internal API for the set brightness was changed to the async
261 * version, and one sync API was added to handle cases that need immediate
262 * effect. Also, the led class flash and lock for sysfs access was introduced.
263 */
264#define LED_HAVE_SET_SYNC
265#define LED_HAVE_FLASH
266#define LED_HAVE_LOCK
267#include <linux/led-class-flash.h>
268#endif
269
Rui Miguel Silvab827e112016-01-12 14:35:48 +0000270#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
271/*
272 * New change in LED api, the set_sync operation was renamed to set_blocking and
273 * the workqueue is now handle by core. So, only one set operation is need.
274 */
275#undef LED_HAVE_SET_SYNC
276#define LED_HAVE_SET_BLOCKING
277#endif
278
Rui Miguel Silva2870b522015-08-14 13:58:19 +0100279#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 18, 0)
280/*
281 * From this version upper it was introduced the possibility to disable led
282 * sysfs entries to handle control of the led device to v4l2, which was
283 * implemented later. So, before that this should return false.
284 */
285#include <linux/leds.h>
286static inline bool led_sysfs_is_disabled(struct led_classdev *led_cdev)
287{
288 return false;
289}
290#endif
291
292#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
293/*
294 * New helper functions for registering/unregistering flash led devices as v4l2
295 * subdevices were added.
296 */
297#define V4L2_HAVE_FLASH
298#include <media/v4l2-flash-led-class.h>
299#endif
300
Rui Miguel Silvaffe2e242015-11-12 15:36:02 +0000301#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0)
302/*
303 * Power supply get by name need to drop reference after call
304 */
305#define PSY_HAVE_PUT
306#endif
307
Rui Miguel Silva02730382016-02-02 14:23:16 +0000308#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 16, 0)
309#define SPI_DEV_MODALIAS "spidev"
310#define SPI_NOR_MODALIAS "spi-nor"
311#else
312#define SPI_DEV_MODALIAS "spidev"
313#define SPI_NOR_MODALIAS "m25p80"
314#endif
315
Greg Kroah-Hartmanf91121b2014-09-11 08:22:06 -0700316#endif /* __GREYBUS_KERNEL_VER_H */