]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/staging/fbtft/fbtft-sysfs.c
Merge tag 'gvt-next-2017-02-24' of https://github.com/01org/gvt-linux into drm-intel...
[mirror_ubuntu-artful-kernel.git] / drivers / staging / fbtft / fbtft-sysfs.c
1 #include "fbtft.h"
2 #include "internal.h"
3
4 static int get_next_ulong(char **str_p, unsigned long *val, char *sep, int base)
5 {
6 char *p_val;
7
8 if (!str_p || !(*str_p))
9 return -EINVAL;
10
11 p_val = strsep(str_p, sep);
12
13 if (!p_val)
14 return -EINVAL;
15
16 return kstrtoul(p_val, base, val);
17 }
18
19 int fbtft_gamma_parse_str(struct fbtft_par *par, u32 *curves,
20 const char *str, int size)
21 {
22 char *str_p, *curve_p = NULL;
23 char *tmp;
24 unsigned long val = 0;
25 int ret = 0;
26 int curve_counter, value_counter;
27
28 fbtft_par_dbg(DEBUG_SYSFS, par, "%s() str=\n", __func__);
29
30 if (!str || !curves)
31 return -EINVAL;
32
33 fbtft_par_dbg(DEBUG_SYSFS, par, "%s\n", str);
34
35 tmp = kmemdup(str, size + 1, GFP_KERNEL);
36 if (!tmp)
37 return -ENOMEM;
38
39 /* replace optional separators */
40 str_p = tmp;
41 while (*str_p) {
42 if (*str_p == ',')
43 *str_p = ' ';
44 if (*str_p == ';')
45 *str_p = '\n';
46 str_p++;
47 }
48
49 str_p = strim(tmp);
50
51 curve_counter = 0;
52 while (str_p) {
53 if (curve_counter == par->gamma.num_curves) {
54 dev_err(par->info->device, "Gamma: Too many curves\n");
55 ret = -EINVAL;
56 goto out;
57 }
58 curve_p = strsep(&str_p, "\n");
59 value_counter = 0;
60 while (curve_p) {
61 if (value_counter == par->gamma.num_values) {
62 dev_err(par->info->device,
63 "Gamma: Too many values\n");
64 ret = -EINVAL;
65 goto out;
66 }
67 ret = get_next_ulong(&curve_p, &val, " ", 16);
68 if (ret)
69 goto out;
70 curves[curve_counter * par->gamma.num_values + value_counter] = val;
71 value_counter++;
72 }
73 if (value_counter != par->gamma.num_values) {
74 dev_err(par->info->device, "Gamma: Too few values\n");
75 ret = -EINVAL;
76 goto out;
77 }
78 curve_counter++;
79 }
80 if (curve_counter != par->gamma.num_curves) {
81 dev_err(par->info->device, "Gamma: Too few curves\n");
82 ret = -EINVAL;
83 goto out;
84 }
85
86 out:
87 kfree(tmp);
88 return ret;
89 }
90
91 static ssize_t
92 sprintf_gamma(struct fbtft_par *par, u32 *curves, char *buf)
93 {
94 ssize_t len = 0;
95 unsigned int i, j;
96
97 mutex_lock(&par->gamma.lock);
98 for (i = 0; i < par->gamma.num_curves; i++) {
99 for (j = 0; j < par->gamma.num_values; j++)
100 len += scnprintf(&buf[len], PAGE_SIZE,
101 "%04x ", curves[i * par->gamma.num_values + j]);
102 buf[len - 1] = '\n';
103 }
104 mutex_unlock(&par->gamma.lock);
105
106 return len;
107 }
108
109 static ssize_t store_gamma_curve(struct device *device,
110 struct device_attribute *attr,
111 const char *buf, size_t count)
112 {
113 struct fb_info *fb_info = dev_get_drvdata(device);
114 struct fbtft_par *par = fb_info->par;
115 u32 tmp_curves[FBTFT_GAMMA_MAX_VALUES_TOTAL];
116 int ret;
117
118 ret = fbtft_gamma_parse_str(par, tmp_curves, buf, count);
119 if (ret)
120 return ret;
121
122 ret = par->fbtftops.set_gamma(par, tmp_curves);
123 if (ret)
124 return ret;
125
126 mutex_lock(&par->gamma.lock);
127 memcpy(par->gamma.curves, tmp_curves,
128 par->gamma.num_curves * par->gamma.num_values * sizeof(tmp_curves[0]));
129 mutex_unlock(&par->gamma.lock);
130
131 return count;
132 }
133
134 static ssize_t show_gamma_curve(struct device *device,
135 struct device_attribute *attr, char *buf)
136 {
137 struct fb_info *fb_info = dev_get_drvdata(device);
138 struct fbtft_par *par = fb_info->par;
139
140 return sprintf_gamma(par, par->gamma.curves, buf);
141 }
142
143 static struct device_attribute gamma_device_attrs[] = {
144 __ATTR(gamma, 0660, show_gamma_curve, store_gamma_curve),
145 };
146
147 void fbtft_expand_debug_value(unsigned long *debug)
148 {
149 switch (*debug & 0x7) {
150 case 1:
151 *debug |= DEBUG_LEVEL_1;
152 break;
153 case 2:
154 *debug |= DEBUG_LEVEL_2;
155 break;
156 case 3:
157 *debug |= DEBUG_LEVEL_3;
158 break;
159 case 4:
160 *debug |= DEBUG_LEVEL_4;
161 break;
162 case 5:
163 *debug |= DEBUG_LEVEL_5;
164 break;
165 case 6:
166 *debug |= DEBUG_LEVEL_6;
167 break;
168 case 7:
169 *debug = 0xFFFFFFFF;
170 break;
171 }
172 }
173
174 static ssize_t store_debug(struct device *device,
175 struct device_attribute *attr,
176 const char *buf, size_t count)
177 {
178 struct fb_info *fb_info = dev_get_drvdata(device);
179 struct fbtft_par *par = fb_info->par;
180 int ret;
181
182 ret = kstrtoul(buf, 10, &par->debug);
183 if (ret)
184 return ret;
185 fbtft_expand_debug_value(&par->debug);
186
187 return count;
188 }
189
190 static ssize_t show_debug(struct device *device,
191 struct device_attribute *attr, char *buf)
192 {
193 struct fb_info *fb_info = dev_get_drvdata(device);
194 struct fbtft_par *par = fb_info->par;
195
196 return snprintf(buf, PAGE_SIZE, "%lu\n", par->debug);
197 }
198
199 static struct device_attribute debug_device_attr = \
200 __ATTR(debug, 0660, show_debug, store_debug);
201
202 void fbtft_sysfs_init(struct fbtft_par *par)
203 {
204 device_create_file(par->info->dev, &debug_device_attr);
205 if (par->gamma.curves && par->fbtftops.set_gamma)
206 device_create_file(par->info->dev, &gamma_device_attrs[0]);
207 }
208
209 void fbtft_sysfs_exit(struct fbtft_par *par)
210 {
211 device_remove_file(par->info->dev, &debug_device_attr);
212 if (par->gamma.curves && par->fbtftops.set_gamma)
213 device_remove_file(par->info->dev, &gamma_device_attrs[0]);
214 }