1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * S6E63M0 AMOLED LCD drm_panel driver.
4  *
5  * Copyright (C) 2019 Paweł Chmiel <pawel.mikolaj.chmiel@gmail.com>
6  * Derived from drivers/gpu/drm/panel-samsung-ld9040.c
7  *
8  * Andrzej Hajda <a.hajda@samsung.com>
9  */
10 
11 #include <drm/drm_modes.h>
12 #include <drm/drm_panel.h>
13 
14 #include <linux/backlight.h>
15 #include <linux/delay.h>
16 #include <linux/gpio/consumer.h>
17 #include <linux/module.h>
18 #include <linux/regulator/consumer.h>
19 
20 #include <video/mipi_display.h>
21 
22 #include "panel-samsung-s6e63m0.h"
23 
24 /* Manufacturer Command Set */
25 #define MCS_ELVSS_ON                0xb1
26 #define MCS_MIECTL1                0xc0
27 #define MCS_BCMODE                              0xc1
28 #define MCS_ERROR_CHECK		0xd5
29 #define MCS_READ_ID1		0xda
30 #define MCS_READ_ID2		0xdb
31 #define MCS_READ_ID3		0xdc
32 #define MCS_LEVEL_2_KEY		0xf0
33 #define MCS_MTP_KEY		0xf1
34 #define MCS_DISCTL   0xf2
35 #define MCS_SRCCTL           0xf6
36 #define MCS_IFCTL                       0xf7
37 #define MCS_PANELCTL         0xF8
38 #define MCS_PGAMMACTL                   0xfa
39 
40 #define S6E63M0_LCD_ID_VALUE_M2		0xA4
41 #define S6E63M0_LCD_ID_VALUE_SM2	0xB4
42 #define S6E63M0_LCD_ID_VALUE_SM2_1	0xB6
43 
44 #define NUM_GAMMA_LEVELS             11
45 #define GAMMA_TABLE_COUNT           23
46 
47 #define MAX_BRIGHTNESS              (NUM_GAMMA_LEVELS - 1)
48 
49 /* array of gamma tables for gamma value 2.2 */
50 static u8 const s6e63m0_gamma_22[NUM_GAMMA_LEVELS][GAMMA_TABLE_COUNT] = {
51 	{ MCS_PGAMMACTL, 0x00,
52 	  0x18, 0x08, 0x24, 0x78, 0xEC, 0x3D, 0xC8,
53 	  0xC2, 0xB6, 0xC4, 0xC7, 0xB6, 0xD5, 0xD7,
54 	  0xCC, 0x00, 0x39, 0x00, 0x36, 0x00, 0x51 },
55 	{ MCS_PGAMMACTL, 0x00,
56 	  0x18, 0x08, 0x24, 0x73, 0x4A, 0x3D, 0xC0,
57 	  0xC2, 0xB1, 0xBB, 0xBE, 0xAC, 0xCE, 0xCF,
58 	  0xC5, 0x00, 0x5D, 0x00, 0x5E, 0x00, 0x82 },
59 	{ MCS_PGAMMACTL, 0x00,
60 	  0x18, 0x08, 0x24, 0x70, 0x51, 0x3E, 0xBF,
61 	  0xC1, 0xAF, 0xB9, 0xBC, 0xAB, 0xCC, 0xCC,
62 	  0xC2, 0x00, 0x65, 0x00, 0x67, 0x00, 0x8D },
63 	{ MCS_PGAMMACTL, 0x00,
64 	  0x18, 0x08, 0x24, 0x6C, 0x54, 0x3A, 0xBC,
65 	  0xBF, 0xAC, 0xB7, 0xBB, 0xA9, 0xC9, 0xC9,
66 	  0xBE, 0x00, 0x71, 0x00, 0x73, 0x00, 0x9E },
67 	{ MCS_PGAMMACTL, 0x00,
68 	  0x18, 0x08, 0x24, 0x69, 0x54, 0x37, 0xBB,
69 	  0xBE, 0xAC, 0xB4, 0xB7, 0xA6, 0xC7, 0xC8,
70 	  0xBC, 0x00, 0x7B, 0x00, 0x7E, 0x00, 0xAB },
71 	{ MCS_PGAMMACTL, 0x00,
72 	  0x18, 0x08, 0x24, 0x66, 0x55, 0x34, 0xBA,
73 	  0xBD, 0xAB, 0xB1, 0xB5, 0xA3, 0xC5, 0xC6,
74 	  0xB9, 0x00, 0x85, 0x00, 0x88, 0x00, 0xBA },
75 	{ MCS_PGAMMACTL, 0x00,
76 	  0x18, 0x08, 0x24, 0x63, 0x53, 0x31, 0xB8,
77 	  0xBC, 0xA9, 0xB0, 0xB5, 0xA2, 0xC4, 0xC4,
78 	  0xB8, 0x00, 0x8B, 0x00, 0x8E, 0x00, 0xC2 },
79 	{ MCS_PGAMMACTL, 0x00,
80 	  0x18, 0x08, 0x24, 0x62, 0x54, 0x30, 0xB9,
81 	  0xBB, 0xA9, 0xB0, 0xB3, 0xA1, 0xC1, 0xC3,
82 	  0xB7, 0x00, 0x91, 0x00, 0x95, 0x00, 0xDA },
83 	{ MCS_PGAMMACTL, 0x00,
84 	  0x18, 0x08, 0x24, 0x66, 0x58, 0x34, 0xB6,
85 	  0xBA, 0xA7, 0xAF, 0xB3, 0xA0, 0xC1, 0xC2,
86 	  0xB7, 0x00, 0x97, 0x00, 0x9A, 0x00, 0xD1 },
87 	{ MCS_PGAMMACTL, 0x00,
88 	  0x18, 0x08, 0x24, 0x64, 0x56, 0x33, 0xB6,
89 	  0xBA, 0xA8, 0xAC, 0xB1, 0x9D, 0xC1, 0xC1,
90 	  0xB7, 0x00, 0x9C, 0x00, 0x9F, 0x00, 0xD6 },
91 	{ MCS_PGAMMACTL, 0x00,
92 	  0x18, 0x08, 0x24, 0x5f, 0x50, 0x2d, 0xB6,
93 	  0xB9, 0xA7, 0xAd, 0xB1, 0x9f, 0xbe, 0xC0,
94 	  0xB5, 0x00, 0xa0, 0x00, 0xa4, 0x00, 0xdb },
95 };
96 
97 struct s6e63m0 {
98 	struct device *dev;
99 	int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val);
100 	int (*dcs_write)(struct device *dev, const u8 *data, size_t len);
101 	struct drm_panel panel;
102 	struct backlight_device *bl_dev;
103 	u8 lcd_type;
104 
105 	struct regulator_bulk_data supplies[2];
106 	struct gpio_desc *reset_gpio;
107 
108 	bool prepared;
109 	bool enabled;
110 
111 	/*
112 	 * This field is tested by functions directly accessing bus before
113 	 * transfer, transfer is skipped if it is set. In case of transfer
114 	 * failure or unexpected response the field is set to error value.
115 	 * Such construct allows to eliminate many checks in higher level
116 	 * functions.
117 	 */
118 	int error;
119 };
120 
121 static const struct drm_display_mode default_mode = {
122 	.clock		= 25628,
123 	.hdisplay	= 480,
124 	.hsync_start	= 480 + 16,
125 	.hsync_end	= 480 + 16 + 2,
126 	.htotal		= 480 + 16 + 2 + 16,
127 	.vdisplay	= 800,
128 	.vsync_start	= 800 + 28,
129 	.vsync_end	= 800 + 28 + 2,
130 	.vtotal		= 800 + 28 + 2 + 1,
131 	.width_mm	= 53,
132 	.height_mm	= 89,
133 	.flags		= DRM_MODE_FLAG_NVSYNC | DRM_MODE_FLAG_NHSYNC,
134 };
135 
136 static inline struct s6e63m0 *panel_to_s6e63m0(struct drm_panel *panel)
137 {
138 	return container_of(panel, struct s6e63m0, panel);
139 }
140 
141 static int s6e63m0_clear_error(struct s6e63m0 *ctx)
142 {
143 	int ret = ctx->error;
144 
145 	ctx->error = 0;
146 	return ret;
147 }
148 
149 static void s6e63m0_dcs_read(struct s6e63m0 *ctx, const u8 cmd, u8 *data)
150 {
151 	if (ctx->error < 0)
152 		return;
153 
154 	ctx->error = ctx->dcs_read(ctx->dev, cmd, data);
155 }
156 
157 static void s6e63m0_dcs_write(struct s6e63m0 *ctx, const u8 *data, size_t len)
158 {
159 	if (ctx->error < 0 || len == 0)
160 		return;
161 
162 	ctx->error = ctx->dcs_write(ctx->dev, data, len);
163 }
164 
165 #define s6e63m0_dcs_write_seq_static(ctx, seq ...) \
166 	({ \
167 		static const u8 d[] = { seq }; \
168 		s6e63m0_dcs_write(ctx, d, ARRAY_SIZE(d)); \
169 	})
170 
171 static int s6e63m0_check_lcd_type(struct s6e63m0 *ctx)
172 {
173 	u8 id1, id2, id3;
174 	int ret;
175 
176 	s6e63m0_dcs_read(ctx, MCS_READ_ID1, &id1);
177 	s6e63m0_dcs_read(ctx, MCS_READ_ID2, &id2);
178 	s6e63m0_dcs_read(ctx, MCS_READ_ID3, &id3);
179 
180 	ret = s6e63m0_clear_error(ctx);
181 	if (ret) {
182 		dev_err(ctx->dev, "error checking LCD type (%d)\n", ret);
183 		ctx->lcd_type = 0x00;
184 		return ret;
185 	}
186 
187 	dev_info(ctx->dev, "MTP ID: %02x %02x %02x\n", id1, id2, id3);
188 
189 	/* We attempt to detect what panel is mounted on the controller */
190 	switch (id2) {
191 	case S6E63M0_LCD_ID_VALUE_M2:
192 		dev_info(ctx->dev, "detected LCD panel AMS397GE MIPI M2\n");
193 		break;
194 	case S6E63M0_LCD_ID_VALUE_SM2:
195 	case S6E63M0_LCD_ID_VALUE_SM2_1:
196 		dev_info(ctx->dev, "detected LCD panel AMS397GE MIPI SM2\n");
197 		break;
198 	default:
199 		dev_info(ctx->dev, "unknown LCD panel type %02x\n", id2);
200 		break;
201 	}
202 
203 	ctx->lcd_type = id2;
204 
205 	return 0;
206 }
207 
208 static void s6e63m0_init(struct s6e63m0 *ctx)
209 {
210 	s6e63m0_dcs_write_seq_static(ctx, MCS_PANELCTL,
211 				     0x01, 0x27, 0x27, 0x07, 0x07, 0x54, 0x9f,
212 				     0x63, 0x86, 0x1a, 0x33, 0x0d, 0x00, 0x00);
213 
214 	s6e63m0_dcs_write_seq_static(ctx, MCS_DISCTL,
215 				     0x02, 0x03, 0x1c, 0x10, 0x10);
216 	s6e63m0_dcs_write_seq_static(ctx, MCS_IFCTL,
217 				     0x03, 0x00, 0x00);
218 
219 	s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL,
220 				     0x00, 0x18, 0x08, 0x24, 0x64, 0x56, 0x33,
221 				     0xb6, 0xba, 0xa8, 0xac, 0xb1, 0x9d, 0xc1,
222 				     0xc1, 0xb7, 0x00, 0x9c, 0x00, 0x9f, 0x00,
223 				     0xd6);
224 	s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL,
225 				     0x01);
226 
227 	s6e63m0_dcs_write_seq_static(ctx, MCS_SRCCTL,
228 				     0x00, 0x8c, 0x07);
229 	s6e63m0_dcs_write_seq_static(ctx, 0xb3,
230 				     0xc);
231 
232 	s6e63m0_dcs_write_seq_static(ctx, 0xb5,
233 				     0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17,
234 				     0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b,
235 				     0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a,
236 				     0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23,
237 				     0x21, 0x20, 0x1e, 0x1e);
238 
239 	s6e63m0_dcs_write_seq_static(ctx, 0xb6,
240 				     0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44,
241 				     0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66,
242 				     0x66, 0x66);
243 
244 	s6e63m0_dcs_write_seq_static(ctx, 0xb7,
245 				     0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17,
246 				     0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b,
247 				     0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a,
248 				     0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23,
249 				     0x21, 0x20, 0x1e, 0x1e, 0x00, 0x00, 0x11,
250 				     0x22, 0x33, 0x44, 0x44, 0x44, 0x55, 0x55,
251 				     0x66, 0x66, 0x66, 0x66, 0x66, 0x66);
252 
253 	s6e63m0_dcs_write_seq_static(ctx, 0xb9,
254 				     0x2c, 0x12, 0x0c, 0x0a, 0x10, 0x0e, 0x17,
255 				     0x13, 0x1f, 0x1a, 0x2a, 0x24, 0x1f, 0x1b,
256 				     0x1a, 0x17, 0x2b, 0x26, 0x22, 0x20, 0x3a,
257 				     0x34, 0x30, 0x2c, 0x29, 0x26, 0x25, 0x23,
258 				     0x21, 0x20, 0x1e, 0x1e);
259 
260 	s6e63m0_dcs_write_seq_static(ctx, 0xba,
261 				     0x00, 0x00, 0x11, 0x22, 0x33, 0x44, 0x44,
262 				     0x44, 0x55, 0x55, 0x66, 0x66, 0x66, 0x66,
263 				     0x66, 0x66);
264 
265 	s6e63m0_dcs_write_seq_static(ctx, MCS_BCMODE,
266 				     0x4d, 0x96, 0x1d, 0x00, 0x00, 0x01, 0xdf,
267 				     0x00, 0x00, 0x03, 0x1f, 0x00, 0x00, 0x00,
268 				     0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x06,
269 				     0x09, 0x0d, 0x0f, 0x12, 0x15, 0x18);
270 
271 	s6e63m0_dcs_write_seq_static(ctx, 0xb2,
272 				     0x10, 0x10, 0x0b, 0x05);
273 
274 	s6e63m0_dcs_write_seq_static(ctx, MCS_MIECTL1,
275 				     0x01);
276 
277 	s6e63m0_dcs_write_seq_static(ctx, MCS_ELVSS_ON,
278 				     0x0b);
279 }
280 
281 static int s6e63m0_power_on(struct s6e63m0 *ctx)
282 {
283 	int ret;
284 
285 	ret = regulator_bulk_enable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
286 	if (ret < 0)
287 		return ret;
288 
289 	msleep(25);
290 
291 	/* Be sure to send a reset pulse */
292 	gpiod_set_value(ctx->reset_gpio, 1);
293 	msleep(5);
294 	gpiod_set_value(ctx->reset_gpio, 0);
295 	msleep(120);
296 
297 	return 0;
298 }
299 
300 static int s6e63m0_power_off(struct s6e63m0 *ctx)
301 {
302 	int ret;
303 
304 	gpiod_set_value(ctx->reset_gpio, 1);
305 	msleep(120);
306 
307 	ret = regulator_bulk_disable(ARRAY_SIZE(ctx->supplies), ctx->supplies);
308 	if (ret < 0)
309 		return ret;
310 
311 	return 0;
312 }
313 
314 static int s6e63m0_disable(struct drm_panel *panel)
315 {
316 	struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
317 
318 	if (!ctx->enabled)
319 		return 0;
320 
321 	backlight_disable(ctx->bl_dev);
322 
323 	s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_OFF);
324 	msleep(10);
325 	s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_ENTER_SLEEP_MODE);
326 	msleep(120);
327 
328 	ctx->enabled = false;
329 
330 	return 0;
331 }
332 
333 static int s6e63m0_unprepare(struct drm_panel *panel)
334 {
335 	struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
336 	int ret;
337 
338 	if (!ctx->prepared)
339 		return 0;
340 
341 	s6e63m0_clear_error(ctx);
342 
343 	ret = s6e63m0_power_off(ctx);
344 	if (ret < 0)
345 		return ret;
346 
347 	ctx->prepared = false;
348 
349 	return 0;
350 }
351 
352 static int s6e63m0_prepare(struct drm_panel *panel)
353 {
354 	struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
355 	int ret;
356 
357 	if (ctx->prepared)
358 		return 0;
359 
360 	ret = s6e63m0_power_on(ctx);
361 	if (ret < 0)
362 		return ret;
363 
364 	/* Magic to unlock level 2 control of the display */
365 	s6e63m0_dcs_write_seq_static(ctx, MCS_LEVEL_2_KEY, 0x5a, 0x5a);
366 	/* Magic to unlock MTP reading */
367 	s6e63m0_dcs_write_seq_static(ctx, MCS_MTP_KEY, 0x5a, 0x5a);
368 
369 	ret = s6e63m0_check_lcd_type(ctx);
370 	if (ret < 0)
371 		return ret;
372 
373 	s6e63m0_init(ctx);
374 
375 	ret = s6e63m0_clear_error(ctx);
376 
377 	if (ret < 0)
378 		s6e63m0_unprepare(panel);
379 
380 	ctx->prepared = true;
381 
382 	return ret;
383 }
384 
385 static int s6e63m0_enable(struct drm_panel *panel)
386 {
387 	struct s6e63m0 *ctx = panel_to_s6e63m0(panel);
388 
389 	if (ctx->enabled)
390 		return 0;
391 
392 	s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_EXIT_SLEEP_MODE);
393 	msleep(120);
394 	s6e63m0_dcs_write_seq_static(ctx, MIPI_DCS_SET_DISPLAY_ON);
395 	msleep(10);
396 
397 	s6e63m0_dcs_write_seq_static(ctx, MCS_ERROR_CHECK,
398 				     0xE7, 0x14, 0x60, 0x17, 0x0A, 0x49, 0xC3,
399 				     0x8F, 0x19, 0x64, 0x91, 0x84, 0x76, 0x20,
400 				     0x0F, 0x00);
401 
402 	backlight_enable(ctx->bl_dev);
403 
404 	ctx->enabled = true;
405 
406 	return 0;
407 }
408 
409 static int s6e63m0_get_modes(struct drm_panel *panel,
410 			     struct drm_connector *connector)
411 {
412 	struct drm_display_mode *mode;
413 
414 	mode = drm_mode_duplicate(connector->dev, &default_mode);
415 	if (!mode) {
416 		dev_err(panel->dev, "failed to add mode %ux%u@%u\n",
417 			default_mode.hdisplay, default_mode.vdisplay,
418 			drm_mode_vrefresh(&default_mode));
419 		return -ENOMEM;
420 	}
421 
422 	drm_mode_set_name(mode);
423 
424 	mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED;
425 	drm_mode_probed_add(connector, mode);
426 
427 	return 1;
428 }
429 
430 static const struct drm_panel_funcs s6e63m0_drm_funcs = {
431 	.disable	= s6e63m0_disable,
432 	.unprepare	= s6e63m0_unprepare,
433 	.prepare	= s6e63m0_prepare,
434 	.enable		= s6e63m0_enable,
435 	.get_modes	= s6e63m0_get_modes,
436 };
437 
438 static int s6e63m0_set_brightness(struct backlight_device *bd)
439 {
440 	struct s6e63m0 *ctx = bl_get_data(bd);
441 
442 	int brightness = bd->props.brightness;
443 
444 	/* disable and set new gamma */
445 	s6e63m0_dcs_write(ctx, s6e63m0_gamma_22[brightness],
446 			  ARRAY_SIZE(s6e63m0_gamma_22[brightness]));
447 
448 	/* update gamma table. */
449 	s6e63m0_dcs_write_seq_static(ctx, MCS_PGAMMACTL, 0x01);
450 
451 	return s6e63m0_clear_error(ctx);
452 }
453 
454 static const struct backlight_ops s6e63m0_backlight_ops = {
455 	.update_status	= s6e63m0_set_brightness,
456 };
457 
458 static int s6e63m0_backlight_register(struct s6e63m0 *ctx)
459 {
460 	struct backlight_properties props = {
461 		.type		= BACKLIGHT_RAW,
462 		.brightness	= MAX_BRIGHTNESS,
463 		.max_brightness = MAX_BRIGHTNESS
464 	};
465 	struct device *dev = ctx->dev;
466 	int ret = 0;
467 
468 	ctx->bl_dev = devm_backlight_device_register(dev, "panel", dev, ctx,
469 						     &s6e63m0_backlight_ops,
470 						     &props);
471 	if (IS_ERR(ctx->bl_dev)) {
472 		ret = PTR_ERR(ctx->bl_dev);
473 		dev_err(dev, "error registering backlight device (%d)\n", ret);
474 	}
475 
476 	return ret;
477 }
478 
479 int s6e63m0_probe(struct device *dev,
480 		  int (*dcs_read)(struct device *dev, const u8 cmd, u8 *val),
481 		  int (*dcs_write)(struct device *dev, const u8 *data, size_t len),
482 		  bool dsi_mode)
483 {
484 	struct s6e63m0 *ctx;
485 	int ret;
486 
487 	ctx = devm_kzalloc(dev, sizeof(struct s6e63m0), GFP_KERNEL);
488 	if (!ctx)
489 		return -ENOMEM;
490 
491 	ctx->dcs_read = dcs_read;
492 	ctx->dcs_write = dcs_write;
493 	dev_set_drvdata(dev, ctx);
494 
495 	ctx->dev = dev;
496 	ctx->enabled = false;
497 	ctx->prepared = false;
498 
499 	ctx->supplies[0].supply = "vdd3";
500 	ctx->supplies[1].supply = "vci";
501 	ret = devm_regulator_bulk_get(dev, ARRAY_SIZE(ctx->supplies),
502 				      ctx->supplies);
503 	if (ret < 0) {
504 		dev_err(dev, "failed to get regulators: %d\n", ret);
505 		return ret;
506 	}
507 
508 	ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
509 	if (IS_ERR(ctx->reset_gpio)) {
510 		dev_err(dev, "cannot get reset-gpios %ld\n", PTR_ERR(ctx->reset_gpio));
511 		return PTR_ERR(ctx->reset_gpio);
512 	}
513 
514 	drm_panel_init(&ctx->panel, dev, &s6e63m0_drm_funcs,
515 		       dsi_mode ? DRM_MODE_CONNECTOR_DSI :
516 		       DRM_MODE_CONNECTOR_DPI);
517 
518 	ret = s6e63m0_backlight_register(ctx);
519 	if (ret < 0)
520 		return ret;
521 
522 	drm_panel_add(&ctx->panel);
523 
524 	return 0;
525 }
526 EXPORT_SYMBOL_GPL(s6e63m0_probe);
527 
528 int s6e63m0_remove(struct device *dev)
529 {
530 	struct s6e63m0 *ctx = dev_get_drvdata(dev);
531 
532 	drm_panel_remove(&ctx->panel);
533 
534 	return 0;
535 }
536 EXPORT_SYMBOL_GPL(s6e63m0_remove);
537 
538 MODULE_AUTHOR("Paweł Chmiel <pawel.mikolaj.chmiel@gmail.com>");
539 MODULE_DESCRIPTION("s6e63m0 LCD Driver");
540 MODULE_LICENSE("GPL v2");
541