aboutsummaryrefslogtreecommitdiff
path: root/drivers/video/mxc/mxc_dispdrv.c
blob: b455a6ab06f11680b7e3c1c73a061142d3df8e3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/*
 * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
 */

/*
 * The code contained herein is licensed under the GNU General Public
 * License. You may obtain a copy of the GNU General Public License
 * Version 2 or later at the following locations:
 *
 * http://www.opensource.org/licenses/gpl-license.html
 * http://www.gnu.org/copyleft/gpl.html
 */

/*!
 * @file mxc_dispdrv.c
 * @brief mxc display driver framework.
 *
 * A display device driver could call mxc_dispdrv_register(drv) in its dev_probe() function.
 * Move all dev_probe() things into mxc_dispdrv_driver->init(), init() function should init
 * and feedback setting;
 * Move all dev_remove() things into mxc_dispdrv_driver->deinit();
 * Move all dev_suspend() things into fb_notifier for SUSPEND, if there is;
 * Move all dev_resume() things into fb_notifier for RESUME, if there is;
 *
 * ipuv3 fb driver could call mxc_dispdrv_gethandle(name, setting) before a fb
 * need be added, with fbi param passing by setting, after
 * mxc_dispdrv_gethandle() return, FB driver should get the basic setting
 * about fbi info and ipuv3-hw (ipu_id and disp_id).
 *
 * @ingroup Framebuffer
 */

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/string.h>
#include "mxc_dispdrv.h"

static LIST_HEAD(dispdrv_list);
static DEFINE_MUTEX(dispdrv_lock);

struct mxc_dispdrv_entry {
	/* Note: drv always the first element */
	struct mxc_dispdrv_driver *drv;
	bool active;
	struct mxc_dispdrv_setting setting;
	void *priv;
	struct list_head list;
};

struct mxc_dispdrv_handle *mxc_dispdrv_register(struct mxc_dispdrv_driver *drv)
{
	struct mxc_dispdrv_entry *new;

	mutex_lock(&dispdrv_lock);

	new = kzalloc(sizeof(struct mxc_dispdrv_entry), GFP_KERNEL);
	if (!new) {
		mutex_unlock(&dispdrv_lock);
		return ERR_PTR(-ENOMEM);
	}

	new->drv = drv;
	list_add_tail(&new->list, &dispdrv_list);
	mutex_unlock(&dispdrv_lock);

	return (struct mxc_dispdrv_handle *)new;
}
EXPORT_SYMBOL_GPL(mxc_dispdrv_register);

int mxc_dispdrv_unregister(struct mxc_dispdrv_handle *handle)
{
	struct mxc_dispdrv_entry *entry = (struct mxc_dispdrv_entry *)handle;

	if (entry) {
		mutex_lock(&dispdrv_lock);
		list_del(&entry->list);
		mutex_unlock(&dispdrv_lock);
		kfree(entry);
		return 0;
	} else
		return -EINVAL;
}
EXPORT_SYMBOL_GPL(mxc_dispdrv_unregister);

struct mxc_dispdrv_handle *mxc_dispdrv_gethandle(char *name,
	struct mxc_dispdrv_setting *setting)
{
	int ret, found = 0;
	struct mxc_dispdrv_entry *entry;

	mutex_lock(&dispdrv_lock);
	list_for_each_entry(entry, &dispdrv_list, list) {
		if (!strcmp(entry->drv->name, name) && (entry->drv->init)) {
			ret = entry->drv->init((struct mxc_dispdrv_handle *)
					entry, setting);
			if (ret >= 0) {
				entry->active = true;
				found = 1;
				break;
			}
		}
	}

	mutex_unlock(&dispdrv_lock);

	return found ? (struct mxc_dispdrv_handle *)entry:ERR_PTR(-ENODEV);
}
EXPORT_SYMBOL_GPL(mxc_dispdrv_gethandle);

void mxc_dispdrv_puthandle(struct mxc_dispdrv_handle *handle)
{
	struct mxc_dispdrv_entry *entry = (struct mxc_dispdrv_entry *)handle;

	mutex_lock(&dispdrv_lock);
	if (entry && entry->active && entry->drv->deinit) {
		entry->drv->deinit(handle);
		entry->active = false;
	}
	mutex_unlock(&dispdrv_lock);
}
EXPORT_SYMBOL_GPL(mxc_dispdrv_puthandle);

int mxc_dispdrv_setdata(struct mxc_dispdrv_handle *handle, void *data)
{
	struct mxc_dispdrv_entry *entry = (struct mxc_dispdrv_entry *)handle;

	if (entry) {
		entry->priv = data;
		return 0;
	} else
		return -EINVAL;
}
EXPORT_SYMBOL_GPL(mxc_dispdrv_setdata);

void *mxc_dispdrv_getdata(struct mxc_dispdrv_handle *handle)
{
	struct mxc_dispdrv_entry *entry = (struct mxc_dispdrv_entry *)handle;

	if (entry) {
		return entry->priv;
	} else
		return ERR_PTR(-EINVAL);
}
EXPORT_SYMBOL_GPL(mxc_dispdrv_getdata);