arm: sunxi: add support for DIP detection to CHIP board
[platform/kernel/u-boot.git] / board / sunxi / chip.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * (C) Copyright 2021
4  * Köry Maincent, Bootlin, <kory.maincent@bootlin.com>
5  * Based on initial code from Maxime Ripard
6  */
7
8 #include <common.h>
9 #include <malloc.h>
10 #include <dm.h>
11 #include <w1.h>
12 #include <w1-eeprom.h>
13 #include <dm/device-internal.h>
14
15 #include <asm/arch/gpio.h>
16
17 #include <extension_board.h>
18
19 #define for_each_w1_device(b, d) \
20         for (device_find_first_child(b, d); *d; device_find_next_child(d))
21
22 #define dip_convert(field)                                              \
23         (                                                               \
24                 (sizeof(field) == 1) ? field :                          \
25                 (sizeof(field) == 2) ? be16_to_cpu(field) :             \
26                 (sizeof(field) == 4) ? be32_to_cpu(field) :             \
27                 -1                                                      \
28         )
29
30 #define DIP_MAGIC       0x50494843      /* CHIP */
31
32 struct dip_w1_header {
33         u32     magic;                  /* CHIP */
34         u8      version;                /* spec version */
35         u32     vendor_id;
36         u16     product_id;
37         u8      product_version;
38         char    vendor_name[32];
39         char    product_name[32];
40         u8      rsvd[36];               /* rsvd for future spec versions */
41         u8      data[16];               /* user data, per-dip specific */
42 } __packed;
43
44 int extension_board_scan(struct list_head *extension_list)
45 {
46         struct extension *dip;
47         struct dip_w1_header w1_header;
48         struct udevice *bus, *dev;
49         u32 vid;
50         u16 pid;
51         int ret;
52
53         int num_dip = 0;
54
55         sunxi_gpio_set_pull(SUNXI_GPD(2), SUNXI_GPIO_PULL_UP);
56
57         ret = w1_get_bus(0, &bus);
58         if (ret) {
59                 printf("one wire interface not found\n");
60                 return 0;
61         }
62
63         for_each_w1_device(bus, &dev) {
64                 if (w1_get_device_family(dev) != W1_FAMILY_DS2431)
65                         continue;
66
67                 ret = device_probe(dev);
68                 if (ret) {
69                         printf("Couldn't probe device %s: error %d",
70                                dev->name, ret);
71                         continue;
72                 }
73
74                 w1_eeprom_read_buf(dev, 0, (u8 *)&w1_header, sizeof(w1_header));
75
76                 if (w1_header.magic != DIP_MAGIC)
77                         continue;
78
79                 vid = dip_convert(w1_header.vendor_id);
80                 pid = dip_convert(w1_header.product_id);
81
82                 printf("DIP: %s (0x%x) from %s (0x%x)\n",
83                        w1_header.product_name, pid,
84                        w1_header.vendor_name, vid);
85
86                 dip = calloc(1, sizeof(struct extension));
87                 if (!dip) {
88                         printf("Error in memory allocation\n");
89                         return num_dip;
90                 }
91
92                 snprintf(dip->overlay, sizeof(dip->overlay), "dip-%x-%x.dtbo",
93                          vid, pid);
94                 strncpy(dip->name, w1_header.product_name, 32);
95                 strncpy(dip->owner, w1_header.vendor_name, 32);
96                 list_add_tail(&dip->list, extension_list);
97                 num_dip++;
98         }
99         return num_dip;
100 }