1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (c) 2013 Google, Inc
4 */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <errno.h>
9 #include <fdtdec.h>
10 #include <log.h>
11 #include <malloc.h>
12 #include <dm-demo.h>
13 #include <asm/global_data.h>
14 #include <asm/io.h>
15 #include <asm/gpio.h>
16
17 DECLARE_GLOBAL_DATA_PTR;
18
19 /* Shape size */
20 #define WIDTH 8
21 #define HEIGHT 6
22
23 struct shape_data {
24 int num_chars; /* Number of non-space characters output so far */
25 struct gpio_desc gpio_desc[8];
26 int gpio_count;
27 };
28
29 /* Crazy little function to draw shapes on the console */
shape_hello(struct udevice * dev,int ch)30 static int shape_hello(struct udevice *dev, int ch)
31 {
32 const struct dm_demo_pdata *pdata = dev_get_plat(dev);
33 struct shape_data *data = dev_get_priv(dev);
34 static const struct shape {
35 int start;
36 int end;
37 int dstart;
38 int dend;
39 } shapes[3] = {
40 { 0, 1, 0, 1 },
41 { 0, WIDTH, 0, 0 },
42 { HEIGHT / 2 - 1, WIDTH - HEIGHT / 2 + 1, -1, 1},
43 };
44 struct shape shape;
45 unsigned int index;
46 int line, pos, inside;
47 const char *colour = pdata->colour;
48 int first = 0;
49
50 if (!ch)
51 ch = pdata->default_char;
52 if (!ch)
53 ch = '@';
54
55 index = (pdata->sides / 2) - 1;
56 if (index >= ARRAY_SIZE(shapes))
57 return -EIO;
58 shape = shapes[index];
59
60 for (line = 0; line < HEIGHT; line++) {
61 first = 1;
62 for (pos = 0; pos < WIDTH; pos++) {
63 inside = pos >= shape.start && pos < shape.end;
64 if (inside) {
65 putc(first ? *colour++ : ch);
66 data->num_chars++;
67 first = 0;
68 if (!*colour)
69 colour = pdata->colour;
70 } else {
71 putc(' ');
72 }
73 }
74 putc('\n');
75 shape.start += shape.dstart;
76 shape.end += shape.dend;
77 if (shape.start < 0) {
78 shape.dstart = -shape.dstart;
79 shape.dend = -shape.dend;
80 shape.start += shape.dstart;
81 shape.end += shape.dend;
82 }
83 }
84
85 return 0;
86 }
87
shape_status(struct udevice * dev,int * status)88 static int shape_status(struct udevice *dev, int *status)
89 {
90 struct shape_data *data = dev_get_priv(dev);
91
92 *status = data->num_chars;
93 return 0;
94 }
95
set_light(struct udevice * dev,int light)96 static int set_light(struct udevice *dev, int light)
97 {
98 struct shape_data *priv = dev_get_priv(dev);
99 struct gpio_desc *desc;
100 int ret;
101 int i;
102
103 desc = priv->gpio_desc;
104 for (i = 0; i < priv->gpio_count; i++, desc++) {
105 uint mask = 1 << i;
106
107 ret = dm_gpio_set_value(desc, light & mask);
108 if (ret < 0)
109 return ret;
110 }
111
112 return 0;
113 }
114
get_light(struct udevice * dev)115 static int get_light(struct udevice *dev)
116 {
117 struct shape_data *priv = dev_get_priv(dev);
118 struct gpio_desc *desc;
119 uint value = 0;
120 int ret;
121 int i;
122
123 desc = priv->gpio_desc;
124 for (i = 0; i < priv->gpio_count; i++, desc++) {
125 uint mask = 1 << i;
126
127 ret = dm_gpio_get_value(desc);
128 if (ret < 0)
129 return ret;
130 if (ret)
131 value |= mask;
132 }
133
134 return value;
135 }
136
137 static const struct demo_ops shape_ops = {
138 .hello = shape_hello,
139 .status = shape_status,
140 .get_light = get_light,
141 .set_light = set_light,
142 };
143
shape_of_to_plat(struct udevice * dev)144 static int shape_of_to_plat(struct udevice *dev)
145 {
146 struct dm_demo_pdata *pdata = dev_get_plat(dev);
147 int ret;
148
149 /* Parse the data that is common with all demo devices */
150 ret = demo_parse_dt(dev);
151 if (ret)
152 return ret;
153
154 /* Parse the data that only we need */
155 pdata->default_char = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev),
156 "character", '@');
157
158 return 0;
159 }
160
dm_shape_probe(struct udevice * dev)161 static int dm_shape_probe(struct udevice *dev)
162 {
163 struct shape_data *priv = dev_get_priv(dev);
164 int ret;
165
166 ret = gpio_request_list_by_name(dev, "light-gpios", priv->gpio_desc,
167 ARRAY_SIZE(priv->gpio_desc),
168 GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
169 if (ret < 0)
170 return ret;
171 priv->gpio_count = ret;
172 debug("%s: %d GPIOs\n", __func__, priv->gpio_count);
173
174 return 0;
175 }
176
dm_shape_remove(struct udevice * dev)177 static int dm_shape_remove(struct udevice *dev)
178 {
179 struct shape_data *priv = dev_get_priv(dev);
180
181 return gpio_free_list(dev, priv->gpio_desc, priv->gpio_count);
182 }
183
184 static const struct udevice_id demo_shape_id[] = {
185 { "demo-shape", 0 },
186 { },
187 };
188
189 U_BOOT_DRIVER(demo_shape_drv) = {
190 .name = "demo_shape_drv",
191 .of_match = demo_shape_id,
192 .id = UCLASS_DEMO,
193 .of_to_plat = shape_of_to_plat,
194 .ops = &shape_ops,
195 .probe = dm_shape_probe,
196 .remove = dm_shape_remove,
197 .priv_auto = sizeof(struct shape_data),
198 .plat_auto = sizeof(struct dm_demo_pdata),
199 };
200