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