4
4
* Author: Paul Burton <[email protected] >
5
5
*/
6
6
7
- #include <generated/utsrelease.h>
8
7
#include <linux/kernel.h>
9
8
#include <linux/io.h>
10
9
#include <linux/mfd/syscon.h>
14
13
#include <linux/platform_device.h>
15
14
#include <linux/regmap.h>
16
15
#include <linux/slab.h>
17
- #include <linux/sysfs.h>
16
+
17
+ #include "line-display.h"
18
18
19
19
struct img_ascii_lcd_ctx ;
20
20
@@ -27,45 +27,37 @@ struct img_ascii_lcd_ctx;
27
27
struct img_ascii_lcd_config {
28
28
unsigned int num_chars ;
29
29
bool external_regmap ;
30
- void (* update )(struct img_ascii_lcd_ctx * ctx );
30
+ void (* update )(struct linedisp * linedisp );
31
31
};
32
32
33
33
/**
34
34
* struct img_ascii_lcd_ctx - Private data structure
35
- * @pdev: the ASCII LCD platform device
36
35
* @base: the base address of the LCD registers
37
36
* @regmap: the regmap through which LCD registers are accessed
38
37
* @offset: the offset within regmap to the start of the LCD registers
39
38
* @cfg: pointer to the LCD model configuration
40
- * @message: the full message to display or scroll on the LCD
41
- * @message_len: the length of the @message string
42
- * @scroll_pos: index of the first character of @message currently displayed
43
- * @scroll_rate: scroll interval in jiffies
44
- * @timer: timer used to implement scrolling
39
+ * @linedisp: line display structure
45
40
* @curr: the string currently displayed on the LCD
46
41
*/
47
42
struct img_ascii_lcd_ctx {
48
- struct platform_device * pdev ;
49
43
union {
50
44
void __iomem * base ;
51
45
struct regmap * regmap ;
52
46
};
53
47
u32 offset ;
54
48
const struct img_ascii_lcd_config * cfg ;
55
- char * message ;
56
- unsigned int message_len ;
57
- unsigned int scroll_pos ;
58
- unsigned int scroll_rate ;
59
- struct timer_list timer ;
49
+ struct linedisp linedisp ;
60
50
char curr [] __aligned (8 );
61
51
};
62
52
63
53
/*
64
54
* MIPS Boston development board
65
55
*/
66
56
67
- static void boston_update (struct img_ascii_lcd_ctx * ctx )
57
+ static void boston_update (struct linedisp * linedisp )
68
58
{
59
+ struct img_ascii_lcd_ctx * ctx =
60
+ container_of (linedisp , struct img_ascii_lcd_ctx , linedisp );
69
61
ulong val ;
70
62
71
63
#if BITS_PER_LONG == 64
@@ -90,12 +82,14 @@ static struct img_ascii_lcd_config boston_config = {
90
82
* MIPS Malta development board
91
83
*/
92
84
93
- static void malta_update (struct img_ascii_lcd_ctx * ctx )
85
+ static void malta_update (struct linedisp * linedisp )
94
86
{
87
+ struct img_ascii_lcd_ctx * ctx =
88
+ container_of (linedisp , struct img_ascii_lcd_ctx , linedisp );
95
89
unsigned int i ;
96
90
int err = 0 ;
97
91
98
- for (i = 0 ; i < ctx -> cfg -> num_chars ; i ++ ) {
92
+ for (i = 0 ; i < linedisp -> num_chars ; i ++ ) {
99
93
err = regmap_write (ctx -> regmap ,
100
94
ctx -> offset + (i * 8 ), ctx -> curr [i ]);
101
95
if (err )
@@ -173,12 +167,14 @@ static int sead3_wait_lcd_idle(struct img_ascii_lcd_ctx *ctx)
173
167
return 0 ;
174
168
}
175
169
176
- static void sead3_update (struct img_ascii_lcd_ctx * ctx )
170
+ static void sead3_update (struct linedisp * linedisp )
177
171
{
172
+ struct img_ascii_lcd_ctx * ctx =
173
+ container_of (linedisp , struct img_ascii_lcd_ctx , linedisp );
178
174
unsigned int i ;
179
175
int err = 0 ;
180
176
181
- for (i = 0 ; i < ctx -> cfg -> num_chars ; i ++ ) {
177
+ for (i = 0 ; i < linedisp -> num_chars ; i ++ ) {
182
178
err = sead3_wait_lcd_idle (ctx );
183
179
if (err )
184
180
break ;
@@ -218,140 +214,6 @@ static const struct of_device_id img_ascii_lcd_matches[] = {
218
214
};
219
215
MODULE_DEVICE_TABLE (of , img_ascii_lcd_matches );
220
216
221
- /**
222
- * img_ascii_lcd_scroll() - scroll the display by a character
223
- * @t: really a pointer to the private data structure
224
- *
225
- * Scroll the current message along the LCD by one character, rearming the
226
- * timer if required.
227
- */
228
- static void img_ascii_lcd_scroll (struct timer_list * t )
229
- {
230
- struct img_ascii_lcd_ctx * ctx = from_timer (ctx , t , timer );
231
- unsigned int i , ch = ctx -> scroll_pos ;
232
- unsigned int num_chars = ctx -> cfg -> num_chars ;
233
-
234
- /* update the current message string */
235
- for (i = 0 ; i < num_chars ;) {
236
- /* copy as many characters from the string as possible */
237
- for (; i < num_chars && ch < ctx -> message_len ; i ++ , ch ++ )
238
- ctx -> curr [i ] = ctx -> message [ch ];
239
-
240
- /* wrap around to the start of the string */
241
- ch = 0 ;
242
- }
243
-
244
- /* update the LCD */
245
- ctx -> cfg -> update (ctx );
246
-
247
- /* move on to the next character */
248
- ctx -> scroll_pos ++ ;
249
- ctx -> scroll_pos %= ctx -> message_len ;
250
-
251
- /* rearm the timer */
252
- if (ctx -> message_len > ctx -> cfg -> num_chars )
253
- mod_timer (& ctx -> timer , jiffies + ctx -> scroll_rate );
254
- }
255
-
256
- /**
257
- * img_ascii_lcd_display() - set the message to be displayed
258
- * @ctx: pointer to the private data structure
259
- * @msg: the message to display
260
- * @count: length of msg, or -1
261
- *
262
- * Display a new message @msg on the LCD. @msg can be longer than the number of
263
- * characters the LCD can display, in which case it will begin scrolling across
264
- * the LCD display.
265
- *
266
- * Return: 0 on success, -ENOMEM on memory allocation failure
267
- */
268
- static int img_ascii_lcd_display (struct img_ascii_lcd_ctx * ctx ,
269
- const char * msg , ssize_t count )
270
- {
271
- char * new_msg ;
272
-
273
- /* stop the scroll timer */
274
- del_timer_sync (& ctx -> timer );
275
-
276
- if (count == -1 )
277
- count = strlen (msg );
278
-
279
- /* if the string ends with a newline, trim it */
280
- if (msg [count - 1 ] == '\n' )
281
- count -- ;
282
-
283
- if (!count ) {
284
- /* clear the LCD */
285
- devm_kfree (& ctx -> pdev -> dev , ctx -> message );
286
- ctx -> message = NULL ;
287
- ctx -> message_len = 0 ;
288
- memset (ctx -> curr , ' ' , ctx -> cfg -> num_chars );
289
- ctx -> cfg -> update (ctx );
290
- return 0 ;
291
- }
292
-
293
- new_msg = devm_kmalloc (& ctx -> pdev -> dev , count + 1 , GFP_KERNEL );
294
- if (!new_msg )
295
- return - ENOMEM ;
296
-
297
- memcpy (new_msg , msg , count );
298
- new_msg [count ] = 0 ;
299
-
300
- if (ctx -> message )
301
- devm_kfree (& ctx -> pdev -> dev , ctx -> message );
302
-
303
- ctx -> message = new_msg ;
304
- ctx -> message_len = count ;
305
- ctx -> scroll_pos = 0 ;
306
-
307
- /* update the LCD */
308
- img_ascii_lcd_scroll (& ctx -> timer );
309
-
310
- return 0 ;
311
- }
312
-
313
- /**
314
- * message_show() - read message via sysfs
315
- * @dev: the LCD device
316
- * @attr: the LCD message attribute
317
- * @buf: the buffer to read the message into
318
- *
319
- * Read the current message being displayed or scrolled across the LCD display
320
- * into @buf, for reads from sysfs.
321
- *
322
- * Return: the number of characters written to @buf
323
- */
324
- static ssize_t message_show (struct device * dev , struct device_attribute * attr ,
325
- char * buf )
326
- {
327
- struct img_ascii_lcd_ctx * ctx = dev_get_drvdata (dev );
328
-
329
- return sysfs_emit (buf , "%s\n" , ctx -> message );
330
- }
331
-
332
- /**
333
- * message_store() - write a new message via sysfs
334
- * @dev: the LCD device
335
- * @attr: the LCD message attribute
336
- * @buf: the buffer containing the new message
337
- * @count: the size of the message in @buf
338
- *
339
- * Write a new message to display or scroll across the LCD display from sysfs.
340
- *
341
- * Return: the size of the message on success, else -ERRNO
342
- */
343
- static ssize_t message_store (struct device * dev , struct device_attribute * attr ,
344
- const char * buf , size_t count )
345
- {
346
- struct img_ascii_lcd_ctx * ctx = dev_get_drvdata (dev );
347
- int err ;
348
-
349
- err = img_ascii_lcd_display (ctx , buf , count );
350
- return err ?: count ;
351
- }
352
-
353
- static DEVICE_ATTR_RW (message );
354
-
355
217
/**
356
218
* img_ascii_lcd_probe() - probe an LCD display device
357
219
* @pdev: the LCD platform device
@@ -391,29 +253,23 @@ static int img_ascii_lcd_probe(struct platform_device *pdev)
391
253
return PTR_ERR (ctx -> base );
392
254
}
393
255
394
- ctx -> pdev = pdev ;
395
- ctx -> cfg = cfg ;
396
- ctx -> message = NULL ;
397
- ctx -> scroll_pos = 0 ;
398
- ctx -> scroll_rate = HZ / 2 ;
399
-
400
- /* initialise a timer for scrolling the message */
401
- timer_setup (& ctx -> timer , img_ascii_lcd_scroll , 0 );
402
-
403
- platform_set_drvdata (pdev , ctx );
404
-
405
- /* display a default message */
406
- err = img_ascii_lcd_display (ctx , "Linux " UTS_RELEASE " " , -1 );
256
+ err = linedisp_register (& ctx -> linedisp , dev , cfg -> num_chars , ctx -> curr ,
257
+ cfg -> update );
407
258
if (err )
408
- goto out_del_timer ;
259
+ return err ;
409
260
410
- err = device_create_file (dev , & dev_attr_message );
261
+ /* for backwards compatibility */
262
+ err = compat_only_sysfs_link_entry_to_kobj (& dev -> kobj ,
263
+ & ctx -> linedisp .dev .kobj ,
264
+ "message" , NULL );
411
265
if (err )
412
- goto out_del_timer ;
266
+ goto err_unregister ;
413
267
268
+ platform_set_drvdata (pdev , ctx );
414
269
return 0 ;
415
- out_del_timer :
416
- del_timer_sync (& ctx -> timer );
270
+
271
+ err_unregister :
272
+ linedisp_unregister (& ctx -> linedisp );
417
273
return err ;
418
274
}
419
275
@@ -430,8 +286,8 @@ static int img_ascii_lcd_remove(struct platform_device *pdev)
430
286
{
431
287
struct img_ascii_lcd_ctx * ctx = platform_get_drvdata (pdev );
432
288
433
- device_remove_file (& pdev -> dev , & dev_attr_message );
434
- del_timer_sync (& ctx -> timer );
289
+ sysfs_remove_link (& pdev -> dev . kobj , "message" );
290
+ linedisp_unregister (& ctx -> linedisp );
435
291
return 0 ;
436
292
}
437
293
0 commit comments