blob: 913ed88d45f79079a6e41fb45f31abcceaa23d61 [file] [log] [blame]
Matti Vaittinen9d4ce302019-05-07 10:45:55 +03001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) 2019 ROHM Semiconductors
4 *
5 * ROHM BD71837 regulator driver
6 */
7
Tom Riniabb9a042024-05-18 20:20:43 -06008#include <common.h>
Matti Vaittinen9d4ce302019-05-07 10:45:55 +03009#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060010#include <log.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060011#include <linux/bitops.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060012#include <linux/printk.h>
Matti Vaittinen9d4ce302019-05-07 10:45:55 +030013#include <power/bd71837.h>
14#include <power/pmic.h>
15#include <power/regulator.h>
16
17#define HW_STATE_CONTROL 0
18#define DEBUG
19
20/**
21 * struct bd71837_vrange - describe linear range of voltages
22 *
23 * @min_volt: smallest voltage in range
24 * @step: how much voltage changes at each selector step
25 * @min_sel: smallest selector in the range
26 * @max_sel: maximum selector in the range
27 * @rangeval: register value used to select this range if selectible
28 * ranges are supported
29 */
30struct bd71837_vrange {
31 unsigned int min_volt;
32 unsigned int step;
33 u8 min_sel;
34 u8 max_sel;
35 u8 rangeval;
36};
37
38/**
Simon Glassb75b15b2020-12-03 16:55:23 -070039 * struct bd71837_plat - describe regulator control registers
Matti Vaittinen9d4ce302019-05-07 10:45:55 +030040 *
41 * @name: name of the regulator. Used for matching the dt-entry
42 * @enable_reg: register address used to enable/disable regulator
43 * @enablemask: register mask used to enable/disable regulator
44 * @volt_reg: register address used to configure regulator voltage
45 * @volt_mask: register mask used to configure regulator voltage
46 * @ranges: pointer to ranges of regulator voltages and matching register
47 * values
48 * @numranges: number of voltage ranges pointed by ranges
49 * @rangemask: mask for selecting used ranges if multiple ranges are supported
50 * @sel_mask: bit to toggle in order to transfer the register control to SW
51 * @dvs: whether the voltage can be changed when regulator is enabled
52 */
Simon Glassb75b15b2020-12-03 16:55:23 -070053struct bd71837_plat {
Matti Vaittinen9d4ce302019-05-07 10:45:55 +030054 const char *name;
55 u8 enable_reg;
56 u8 enablemask;
57 u8 volt_reg;
58 u8 volt_mask;
59 struct bd71837_vrange *ranges;
60 unsigned int numranges;
61 u8 rangemask;
62 u8 sel_mask;
63 bool dvs;
64};
65
66#define BD_RANGE(_min, _vstep, _sel_low, _sel_hi, _range_sel) \
67{ \
68 .min_volt = (_min), .step = (_vstep), .min_sel = (_sel_low), \
69 .max_sel = (_sel_hi), .rangeval = (_range_sel) \
70}
71
72#define BD_DATA(_name, enreg, enmask, vreg, vmask, _range, rmask, _dvs, sel) \
73{ \
74 .name = (_name), .enable_reg = (enreg), .enablemask = (enmask), \
75 .volt_reg = (vreg), .volt_mask = (vmask), .ranges = (_range), \
76 .numranges = ARRAY_SIZE(_range), .rangemask = (rmask), .dvs = (_dvs), \
77 .sel_mask = (sel) \
78}
79
80static struct bd71837_vrange dvs_buck_vranges[] = {
81 BD_RANGE(700000, 10000, 0, 0x3c, 0),
82 BD_RANGE(1300000, 0, 0x3d, 0x3f, 0),
83};
84
85static struct bd71837_vrange bd71847_buck3_vranges[] = {
86 BD_RANGE(700000, 100000, 0x00, 0x03, 0),
87 BD_RANGE(1050000, 50000, 0x04, 0x05, 0),
88 BD_RANGE(1200000, 150000, 0x06, 0x07, 0),
89 BD_RANGE(550000, 50000, 0x0, 0x7, 0x40),
90 BD_RANGE(675000, 100000, 0x0, 0x3, 0x80),
91 BD_RANGE(1025000, 50000, 0x4, 0x5, 0x80),
92 BD_RANGE(1175000, 150000, 0x6, 0x7, 0x80),
93};
94
95static struct bd71837_vrange bd71847_buck4_vranges[] = {
96 BD_RANGE(3000000, 100000, 0x00, 0x03, 0),
97 BD_RANGE(2600000, 100000, 0x00, 0x03, 40),
98};
99
100static struct bd71837_vrange bd71837_buck5_vranges[] = {
101 BD_RANGE(700000, 100000, 0, 0x3, 0),
102 BD_RANGE(1050000, 50000, 0x04, 0x05, 0),
103 BD_RANGE(1200000, 150000, 0x06, 0x07, 0),
104 BD_RANGE(675000, 100000, 0x0, 0x3, 0x80),
105 BD_RANGE(1025000, 50000, 0x04, 0x05, 0x80),
106 BD_RANGE(1175000, 150000, 0x06, 0x07, 0x80),
107};
108
109static struct bd71837_vrange bd71837_buck6_vranges[] = {
110 BD_RANGE(3000000, 100000, 0x00, 0x03, 0),
111};
112
113static struct bd71837_vrange nodvs_buck3_vranges[] = {
114 BD_RANGE(1605000, 90000, 0, 1, 0),
115 BD_RANGE(1755000, 45000, 2, 4, 0),
116 BD_RANGE(1905000, 45000, 5, 7, 0),
117};
118
119static struct bd71837_vrange nodvs_buck4_vranges[] = {
120 BD_RANGE(800000, 10000, 0x00, 0x3C, 0),
121};
122
123static struct bd71837_vrange ldo1_vranges[] = {
124 BD_RANGE(3000000, 100000, 0x00, 0x03, 0),
125 BD_RANGE(1600000, 100000, 0x00, 0x03, 0x20),
126};
127
128static struct bd71837_vrange ldo2_vranges[] = {
129 BD_RANGE(900000, 0, 0, 0, 0),
130 BD_RANGE(800000, 0, 1, 1, 0),
131};
132
133static struct bd71837_vrange ldo3_vranges[] = {
134 BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
135};
136
137static struct bd71837_vrange ldo4_vranges[] = {
138 BD_RANGE(900000, 100000, 0x00, 0x09, 0),
139};
140
141static struct bd71837_vrange bd71837_ldo5_vranges[] = {
142 BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
143};
144
145static struct bd71837_vrange bd71847_ldo5_vranges[] = {
146 BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
147 BD_RANGE(800000, 100000, 0x00, 0x0f, 0x20),
148};
149
150static struct bd71837_vrange ldo6_vranges[] = {
151 BD_RANGE(900000, 100000, 0x00, 0x09, 0),
152};
153
154static struct bd71837_vrange ldo7_vranges[] = {
155 BD_RANGE(1800000, 100000, 0x00, 0x0f, 0),
156};
157
158/*
159 * We use enable mask 'HW_STATE_CONTROL' to indicate that this regulator
160 * must not be enabled or disabled by SW. The typical use-case for BD71837
161 * is powering NXP i.MX8. In this use-case we (for now) only allow control
162 * for BUCK3 and BUCK4 which are not boot critical.
163 */
Simon Glassb75b15b2020-12-03 16:55:23 -0700164static struct bd71837_plat bd71837_reg_data[] = {
Matti Vaittinen9d4ce302019-05-07 10:45:55 +0300165/* Bucks 1-4 which support dynamic voltage scaling */
166 BD_DATA("BUCK1", BD718XX_BUCK1_CTRL, HW_STATE_CONTROL,
167 BD718XX_BUCK1_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
168 true, BD718XX_BUCK_SEL),
169 BD_DATA("BUCK2", BD718XX_BUCK2_CTRL, HW_STATE_CONTROL,
170 BD718XX_BUCK2_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
171 true, BD718XX_BUCK_SEL),
172 BD_DATA("BUCK3", BD71837_BUCK3_CTRL, BD718XX_BUCK_EN,
173 BD71837_BUCK3_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
174 true, BD718XX_BUCK_SEL),
175 BD_DATA("BUCK4", BD71837_BUCK4_CTRL, BD718XX_BUCK_EN,
176 BD71837_BUCK4_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
177 true, BD718XX_BUCK_SEL),
178/* Bucks 5-8 which do not support dynamic voltage scaling */
179 BD_DATA("BUCK5", BD718XX_1ST_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
180 BD718XX_1ST_NODVS_BUCK_VOLT, BD718XX_1ST_NODVS_BUCK_MASK,
181 bd71837_buck5_vranges, 0x80, false, BD718XX_BUCK_SEL),
182 BD_DATA("BUCK6", BD718XX_2ND_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
183 BD718XX_2ND_NODVS_BUCK_VOLT, BD71837_BUCK6_MASK,
184 bd71837_buck6_vranges, 0, false, BD718XX_BUCK_SEL),
185 BD_DATA("BUCK7", BD718XX_3RD_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
186 BD718XX_3RD_NODVS_BUCK_VOLT, BD718XX_3RD_NODVS_BUCK_MASK,
187 nodvs_buck3_vranges, 0, false, BD718XX_BUCK_SEL),
188 BD_DATA("BUCK8", BD718XX_4TH_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
189 BD718XX_4TH_NODVS_BUCK_VOLT, BD718XX_4TH_NODVS_BUCK_MASK,
190 nodvs_buck4_vranges, 0, false, BD718XX_BUCK_SEL),
191/* LDOs */
192 BD_DATA("LDO1", BD718XX_LDO1_VOLT, HW_STATE_CONTROL, BD718XX_LDO1_VOLT,
193 BD718XX_LDO1_MASK, ldo1_vranges, 0x20, false, BD718XX_LDO_SEL),
194 BD_DATA("LDO2", BD718XX_LDO2_VOLT, HW_STATE_CONTROL, BD718XX_LDO2_VOLT,
195 BD718XX_LDO2_MASK, ldo2_vranges, 0, false, BD718XX_LDO_SEL),
196 BD_DATA("LDO3", BD718XX_LDO3_VOLT, HW_STATE_CONTROL, BD718XX_LDO3_VOLT,
197 BD718XX_LDO3_MASK, ldo3_vranges, 0, false, BD718XX_LDO_SEL),
198 BD_DATA("LDO4", BD718XX_LDO4_VOLT, HW_STATE_CONTROL, BD718XX_LDO4_VOLT,
199 BD718XX_LDO4_MASK, ldo4_vranges, 0, false, BD718XX_LDO_SEL),
200 BD_DATA("LDO5", BD718XX_LDO5_VOLT, HW_STATE_CONTROL, BD718XX_LDO5_VOLT,
201 BD71837_LDO5_MASK, bd71837_ldo5_vranges, 0, false,
202 BD718XX_LDO_SEL),
203 BD_DATA("LDO6", BD718XX_LDO6_VOLT, HW_STATE_CONTROL, BD718XX_LDO6_VOLT,
204 BD718XX_LDO6_MASK, ldo6_vranges, 0, false, BD718XX_LDO_SEL),
205 BD_DATA("LDO7", BD71837_LDO7_VOLT, HW_STATE_CONTROL, BD71837_LDO7_VOLT,
206 BD71837_LDO7_MASK, ldo7_vranges, 0, false, BD718XX_LDO_SEL),
207};
208
Simon Glassb75b15b2020-12-03 16:55:23 -0700209static struct bd71837_plat bd71847_reg_data[] = {
Matti Vaittinen9d4ce302019-05-07 10:45:55 +0300210/* Bucks 1 and 2 which support dynamic voltage scaling */
211 BD_DATA("BUCK1", BD718XX_BUCK1_CTRL, HW_STATE_CONTROL,
212 BD718XX_BUCK1_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
213 true, BD718XX_BUCK_SEL),
214 BD_DATA("BUCK2", BD718XX_BUCK2_CTRL, HW_STATE_CONTROL,
215 BD718XX_BUCK2_VOLT_RUN, DVS_BUCK_RUN_MASK, dvs_buck_vranges, 0,
216 true, BD718XX_BUCK_SEL),
217/* Bucks 3-6 which do not support dynamic voltage scaling */
218 BD_DATA("BUCK3", BD718XX_1ST_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
219 BD718XX_1ST_NODVS_BUCK_VOLT, BD718XX_1ST_NODVS_BUCK_MASK,
220 bd71847_buck3_vranges, 0xc0, false, BD718XX_BUCK_SEL),
221 BD_DATA("BUCK4", BD718XX_2ND_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
222 BD718XX_2ND_NODVS_BUCK_VOLT, BD71837_BUCK6_MASK,
223 bd71847_buck4_vranges, 0x40, false, BD718XX_BUCK_SEL),
224 BD_DATA("BUCK5", BD718XX_3RD_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
225 BD718XX_3RD_NODVS_BUCK_VOLT, BD718XX_3RD_NODVS_BUCK_MASK,
226 nodvs_buck3_vranges, 0, false, BD718XX_BUCK_SEL),
227 BD_DATA("BUCK6", BD718XX_4TH_NODVS_BUCK_CTRL, HW_STATE_CONTROL,
228 BD718XX_4TH_NODVS_BUCK_VOLT, BD718XX_4TH_NODVS_BUCK_MASK,
229 nodvs_buck4_vranges, 0, false, BD718XX_BUCK_SEL),
230/* LDOs */
231 BD_DATA("LDO1", BD718XX_LDO1_VOLT, HW_STATE_CONTROL, BD718XX_LDO1_VOLT,
232 BD718XX_LDO1_MASK, ldo1_vranges, 0x20, false, BD718XX_LDO_SEL),
233 BD_DATA("LDO2", BD718XX_LDO2_VOLT, HW_STATE_CONTROL, BD718XX_LDO2_VOLT,
234 BD718XX_LDO2_MASK, ldo2_vranges, 0, false, BD718XX_LDO_SEL),
235 BD_DATA("LDO3", BD718XX_LDO3_VOLT, HW_STATE_CONTROL, BD718XX_LDO3_VOLT,
236 BD718XX_LDO3_MASK, ldo3_vranges, 0, false, BD718XX_LDO_SEL),
237 BD_DATA("LDO4", BD718XX_LDO4_VOLT, HW_STATE_CONTROL, BD718XX_LDO4_VOLT,
238 BD718XX_LDO4_MASK, ldo4_vranges, 0, false, BD718XX_LDO_SEL),
239 BD_DATA("LDO5", BD718XX_LDO5_VOLT, HW_STATE_CONTROL, BD718XX_LDO5_VOLT,
240 BD71847_LDO5_MASK, bd71847_ldo5_vranges, 0x20, false,
241 BD718XX_LDO_SEL),
242 BD_DATA("LDO6", BD718XX_LDO6_VOLT, HW_STATE_CONTROL, BD718XX_LDO6_VOLT,
243 BD718XX_LDO6_MASK, ldo6_vranges, 0, false, BD718XX_LDO_SEL),
244};
245
246static int vrange_find_value(struct bd71837_vrange *r, unsigned int sel,
247 unsigned int *val)
248{
249 if (!val || sel < r->min_sel || sel > r->max_sel)
250 return -EINVAL;
251
252 *val = r->min_volt + r->step * (sel - r->min_sel);
253 return 0;
254}
255
256static int vrange_find_selector(struct bd71837_vrange *r, int val,
257 unsigned int *sel)
258{
259 int ret = -EINVAL;
260 int num_vals = r->max_sel - r->min_sel + 1;
261
262 if (val >= r->min_volt &&
263 val <= r->min_volt + r->step * (num_vals - 1)) {
264 if (r->step) {
265 *sel = r->min_sel + ((val - r->min_volt) / r->step);
266 ret = 0;
267 } else {
268 *sel = r->min_sel;
269 ret = 0;
270 }
271 }
272 return ret;
273}
274
275static int bd71837_get_enable(struct udevice *dev)
276{
277 int val;
Simon Glassb75b15b2020-12-03 16:55:23 -0700278 struct bd71837_plat *plat = dev_get_plat(dev);
Matti Vaittinen9d4ce302019-05-07 10:45:55 +0300279
280 /*
281 * boot critical regulators on bd71837 must not be controlled by sw
282 * due to the 'feature' which leaves power rails down if bd71837 is
283 * reseted to snvs state. hence we can't get the state here.
284 *
285 * if we are alive it means we probably are on run state and
286 * if the regulator can't be controlled we can assume it is
287 * enabled.
288 */
289 if (plat->enablemask == HW_STATE_CONTROL)
290 return 1;
291
292 val = pmic_reg_read(dev->parent, plat->enable_reg);
293 if (val < 0)
294 return val;
295
296 return (val & plat->enablemask);
297}
298
299static int bd71837_set_enable(struct udevice *dev, bool enable)
300{
301 int val = 0;
Simon Glassb75b15b2020-12-03 16:55:23 -0700302 struct bd71837_plat *plat = dev_get_plat(dev);
Matti Vaittinen9d4ce302019-05-07 10:45:55 +0300303
304 /*
305 * boot critical regulators on bd71837 must not be controlled by sw
306 * due to the 'feature' which leaves power rails down if bd71837 is
307 * reseted to snvs state. Hence we can't set the state here.
308 */
309 if (plat->enablemask == HW_STATE_CONTROL)
Marek Vasutf54598a2022-01-25 03:46:52 +0100310 return enable ? 0 : -EINVAL;
Matti Vaittinen9d4ce302019-05-07 10:45:55 +0300311
312 if (enable)
313 val = plat->enablemask;
314
315 return pmic_clrsetbits(dev->parent, plat->enable_reg, plat->enablemask,
316 val);
317}
318
Marek Vasutf54598a2022-01-25 03:46:52 +0100319static int bd71837_get_value(struct udevice *dev)
320{
321 unsigned int reg, range;
322 unsigned int tmp;
323 struct bd71837_plat *plat = dev_get_plat(dev);
324 int i;
325
326 reg = pmic_reg_read(dev->parent, plat->volt_reg);
327 if (((int)reg) < 0)
328 return reg;
329
330 range = reg & plat->rangemask;
331
332 reg &= plat->volt_mask;
333 reg >>= ffs(plat->volt_mask) - 1;
334
335 for (i = 0; i < plat->numranges; i++) {
336 struct bd71837_vrange *r = &plat->ranges[i];
337
338 if (plat->rangemask && ((plat->rangemask & range) !=
339 r->rangeval))
340 continue;
341
342 if (!vrange_find_value(r, reg, &tmp))
343 return tmp;
344 }
345
346 pr_err("Unknown voltage value read from pmic\n");
347
348 return -EINVAL;
349}
350
Matti Vaittinen9d4ce302019-05-07 10:45:55 +0300351static int bd71837_set_value(struct udevice *dev, int uvolt)
352{
353 unsigned int sel;
354 unsigned int range;
355 int i;
356 int found = 0;
Simon Glassb75b15b2020-12-03 16:55:23 -0700357 struct bd71837_plat *plat = dev_get_plat(dev);
Matti Vaittinen9d4ce302019-05-07 10:45:55 +0300358
359 /*
360 * An under/overshooting may occur if voltage is changed for other
361 * regulators but buck 1,2,3 or 4 when regulator is enabled. Prevent
362 * change to protect the HW
363 */
364 if (!plat->dvs)
365 if (bd71837_get_enable(dev)) {
Marek Vasutf54598a2022-01-25 03:46:52 +0100366 /* If the value is already set, skip the warning. */
367 if (bd71837_get_value(dev) == uvolt)
368 return 0;
Matti Vaittinen9d4ce302019-05-07 10:45:55 +0300369 pr_err("Only DVS bucks can be changed when enabled\n");
370 return -EINVAL;
371 }
372
373 for (i = 0; i < plat->numranges; i++) {
374 struct bd71837_vrange *r = &plat->ranges[i];
375
376 found = !vrange_find_selector(r, uvolt, &sel);
377 if (found) {
378 unsigned int tmp;
379
380 /*
381 * We require exactly the requested value to be
382 * supported - this can be changed later if needed
383 */
384 range = r->rangeval;
385 found = !vrange_find_value(r, sel, &tmp);
386 if (found && tmp == uvolt)
387 break;
388 found = 0;
389 }
390 }
391
392 if (!found)
393 return -EINVAL;
394
395 sel <<= ffs(plat->volt_mask) - 1;
396
397 if (plat->rangemask)
398 sel |= range;
399
400 return pmic_clrsetbits(dev->parent, plat->volt_reg, plat->volt_mask |
401 plat->rangemask, sel);
402}
403
Matti Vaittinen9d4ce302019-05-07 10:45:55 +0300404static int bd71837_regulator_probe(struct udevice *dev)
405{
Simon Glassb75b15b2020-12-03 16:55:23 -0700406 struct bd71837_plat *plat = dev_get_plat(dev);
Matti Vaittinen9d4ce302019-05-07 10:45:55 +0300407 int i, ret;
Simon Glass71fa5b42020-12-03 16:55:18 -0700408 struct dm_regulator_uclass_plat *uc_pdata;
Matti Vaittinen9d4ce302019-05-07 10:45:55 +0300409 int type;
Simon Glassb75b15b2020-12-03 16:55:23 -0700410 struct bd71837_plat *init_data;
Matti Vaittinen9d4ce302019-05-07 10:45:55 +0300411 int data_amnt;
412
413 type = dev_get_driver_data(dev_get_parent(dev));
414
415 switch (type) {
416 case ROHM_CHIP_TYPE_BD71837:
417 init_data = bd71837_reg_data;
418 data_amnt = ARRAY_SIZE(bd71837_reg_data);
419 break;
420 case ROHM_CHIP_TYPE_BD71847:
421 init_data = bd71847_reg_data;
422 data_amnt = ARRAY_SIZE(bd71847_reg_data);
423 break;
424 default:
425 debug("Unknown PMIC type\n");
426 init_data = NULL;
427 data_amnt = 0;
428 break;
429 }
430
431 for (i = 0; i < data_amnt; i++) {
432 if (!strcmp(dev->name, init_data[i].name)) {
433 *plat = init_data[i];
434 if (plat->enablemask != HW_STATE_CONTROL) {
435 /*
436 * Take the regulator under SW control. Ensure
437 * the initial state matches dt flags and then
438 * write the SEL bit
439 */
Simon Glass71fa5b42020-12-03 16:55:18 -0700440 uc_pdata = dev_get_uclass_plat(dev);
Matti Vaittinen9d4ce302019-05-07 10:45:55 +0300441 ret = bd71837_set_enable(dev,
442 !!(uc_pdata->boot_on ||
443 uc_pdata->always_on));
444 if (ret)
445 return ret;
446
447 return pmic_clrsetbits(dev->parent,
448 plat->enable_reg,
449 plat->sel_mask,
450 plat->sel_mask);
451 }
452 return 0;
453 }
454 }
455
456 pr_err("Unknown regulator '%s'\n", dev->name);
457
458 return -ENOENT;
459}
460
461static const struct dm_regulator_ops bd71837_regulator_ops = {
462 .get_value = bd71837_get_value,
463 .set_value = bd71837_set_value,
464 .get_enable = bd71837_get_enable,
465 .set_enable = bd71837_set_enable,
466};
467
468U_BOOT_DRIVER(bd71837_regulator) = {
469 .name = BD718XX_REGULATOR_DRIVER,
470 .id = UCLASS_REGULATOR,
471 .ops = &bd71837_regulator_ops,
472 .probe = bd71837_regulator_probe,
Simon Glassb75b15b2020-12-03 16:55:23 -0700473 .plat_auto = sizeof(struct bd71837_plat),
Matti Vaittinen9d4ce302019-05-07 10:45:55 +0300474};