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