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