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> 14 #include <asm/gpio.h> 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 */ 24 struct gpio_desc gpio_desc[8]; 25 int gpio_count; 26 }; 27 28 /* Crazy little function to draw shapes on the console */ 29 static int shape_hello(struct udevice *dev, int ch) 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 87 static int shape_status(struct udevice *dev, int *status) 88 { 89 struct shape_data *data = dev_get_priv(dev); 90 91 *status = data->num_chars; 92 return 0; 93 } 94 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 136 static const struct demo_ops shape_ops = { 137 .hello = shape_hello, 138 .status = shape_status, 139 .get_light = get_light, 140 .set_light = set_light, 141 }; 142 143 static int shape_ofdata_to_platdata(struct udevice *dev) 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 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 183 static const struct udevice_id demo_shape_id[] = { 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, 194 .probe = dm_shape_probe, 195 .remove = dm_shape_remove, 196 .priv_auto_alloc_size = sizeof(struct shape_data), 197 .platdata_auto_alloc_size = sizeof(struct dm_demo_pdata), 198 }; 199