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