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