demo: migrate uclass to livetree
[platform/kernel/u-boot.git] / drivers / reboot-mode / reboot-mode-uclass.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c), Vaisala Oyj
4  */
5
6 #include <common.h>
7 #include <dm.h>
8 #include <dm/device_compat.h>
9 #include <dm/devres.h>
10 #include <exports.h>
11 #include <reboot-mode/reboot-mode.h>
12
13 DECLARE_GLOBAL_DATA_PTR;
14
15 int dm_reboot_mode_update(struct udevice *dev)
16 {
17         struct reboot_mode_ops *ops = reboot_mode_get_ops(dev);
18         u32 rebootmode;
19         int ret, i;
20
21         assert(ops);
22
23         if (!ops->get)
24                 return -ENOSYS;
25
26         ret = ops->get(dev, &rebootmode);
27         if (ret < 0) {
28                 dev_err(dev, "Failed to retrieve the reboot mode value\n");
29                 return ret;
30         }
31
32         const struct reboot_mode_uclass_platdata *plat_data =
33                 dev_get_uclass_plat(dev);
34
35         for (i = 0; i < plat_data->count; i++) {
36                 if (plat_data->modes[i].mode_id == rebootmode) {
37                         ret = env_set(plat_data->env_variable,
38                                       plat_data->modes[i].mode_name);
39                         if (ret) {
40                                 dev_err(dev, "Failed to set env: %s\n",
41                                         plat_data->env_variable);
42                                 return ret;
43                         }
44                 }
45         }
46
47         if (ops->set) {
48                 /* Clear the value */
49                 rebootmode = 0;
50                 ret = ops->set(dev, rebootmode);
51                 if (ret) {
52                         dev_err(dev, "Failed to clear the reboot mode\n");
53                         return ret;
54                 }
55         }
56
57         return 0;
58 }
59
60 int dm_reboot_mode_pre_probe(struct udevice *dev)
61 {
62         struct reboot_mode_uclass_platdata *plat_data;
63
64         plat_data = dev_get_uclass_plat(dev);
65         if (!plat_data)
66                 return -EINVAL;
67
68 #if CONFIG_IS_ENABLED(OF_CONTROL)
69         const int node = dev_of_offset(dev);
70         const char *mode_prefix = "mode-";
71         const int mode_prefix_len = strlen(mode_prefix);
72         int property;
73         const u32 *propvalue;
74         const char *propname;
75
76         plat_data->env_variable = fdt_getprop(gd->fdt_blob,
77                                               node,
78                                               "u-boot,env-variable",
79                                               NULL);
80         if (!plat_data->env_variable)
81                 plat_data->env_variable = "reboot-mode";
82
83         plat_data->count = 0;
84
85         fdt_for_each_property_offset(property, gd->fdt_blob, node) {
86                 propvalue = fdt_getprop_by_offset(gd->fdt_blob,
87                                                   property, &propname, NULL);
88                 if (!propvalue) {
89                         dev_err(dev, "Could not get the value for property %s\n",
90                                 propname);
91                         return -EINVAL;
92                 }
93
94                 if (!strncmp(propname, mode_prefix, mode_prefix_len))
95                         plat_data->count++;
96         }
97
98         plat_data->modes = devm_kcalloc(dev, plat_data->count,
99                                         sizeof(struct reboot_mode_mode), 0);
100
101         struct reboot_mode_mode *next = plat_data->modes;
102
103         fdt_for_each_property_offset(property, gd->fdt_blob, node) {
104                 propvalue = fdt_getprop_by_offset(gd->fdt_blob,
105                                                   property, &propname, NULL);
106                 if (!propvalue) {
107                         dev_err(dev, "Could not get the value for property %s\n",
108                                 propname);
109                         return -EINVAL;
110                 }
111
112                 if (!strncmp(propname, mode_prefix, mode_prefix_len)) {
113                         next->mode_name = &propname[mode_prefix_len];
114                         next->mode_id = fdt32_to_cpu(*propvalue);
115
116                         next++;
117                 }
118         }
119 #else
120         if (!plat_data->env_variable)
121                 plat_data->env_variable = "reboot-mode";
122
123 #endif
124
125         return 0;
126 }
127
128 UCLASS_DRIVER(reboot_mode) = {
129         .name   = "reboot-mode",
130         .id     = UCLASS_REBOOT_MODE,
131         .pre_probe      = dm_reboot_mode_pre_probe,
132         .per_device_plat_auto =
133                 sizeof(struct reboot_mode_uclass_platdata),
134 };