]>
Commit | Line | Data |
---|---|---|
42595eb7 MW |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Copyright (c) 2021 Michael Walle <[email protected]> | |
4 | */ | |
5 | ||
42595eb7 MW |
6 | #include <dm.h> |
7 | #include <i2c.h> | |
8 | ||
9 | struct sl28cpld_child_plat { | |
10 | uint offset; | |
11 | }; | |
12 | ||
13 | /* | |
14 | * The access methods works either with the first argument being a child | |
15 | * device or with the MFD device itself. | |
16 | */ | |
17 | static int sl28cpld_read_child(struct udevice *dev, uint offset) | |
18 | { | |
19 | struct sl28cpld_child_plat *plat = dev_get_parent_plat(dev); | |
20 | struct udevice *mfd = dev_get_parent(dev); | |
21 | ||
22 | return dm_i2c_reg_read(mfd, offset + plat->offset); | |
23 | } | |
24 | ||
25 | int sl28cpld_read(struct udevice *dev, uint offset) | |
26 | { | |
27 | if (dev->driver == DM_DRIVER_GET(sl28cpld)) | |
28 | return dm_i2c_reg_read(dev, offset); | |
29 | else | |
30 | return sl28cpld_read_child(dev, offset); | |
31 | } | |
32 | ||
33 | static int sl28cpld_write_child(struct udevice *dev, uint offset, | |
34 | uint8_t value) | |
35 | { | |
36 | struct sl28cpld_child_plat *plat = dev_get_parent_plat(dev); | |
37 | struct udevice *mfd = dev_get_parent(dev); | |
38 | ||
39 | return dm_i2c_reg_write(mfd, offset + plat->offset, value); | |
40 | } | |
41 | ||
42 | int sl28cpld_write(struct udevice *dev, uint offset, uint8_t value) | |
43 | { | |
44 | if (dev->driver == DM_DRIVER_GET(sl28cpld)) | |
45 | return dm_i2c_reg_write(dev, offset, value); | |
46 | else | |
47 | return sl28cpld_write_child(dev, offset, value); | |
48 | } | |
49 | ||
50 | int sl28cpld_update(struct udevice *dev, uint offset, uint8_t clear, | |
51 | uint8_t set) | |
52 | { | |
53 | int val; | |
54 | ||
55 | val = sl28cpld_read(dev, offset); | |
56 | if (val < 0) | |
57 | return val; | |
58 | ||
59 | val &= ~clear; | |
60 | val |= set; | |
61 | ||
62 | return sl28cpld_write(dev, offset, val); | |
63 | } | |
64 | ||
65 | static int sl28cpld_probe(struct udevice *dev) | |
66 | { | |
67 | i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS | | |
68 | DM_I2C_CHIP_WR_ADDRESS); | |
69 | ||
70 | return 0; | |
71 | } | |
72 | ||
73 | static int sl28cpld_child_post_bind(struct udevice *dev) | |
74 | { | |
75 | struct sl28cpld_child_plat *plat = dev_get_parent_plat(dev); | |
76 | int offset; | |
77 | ||
78 | if (!dev_has_ofnode(dev)) | |
79 | return 0; | |
80 | ||
81 | offset = dev_read_u32_default(dev, "reg", -1); | |
82 | if (offset == -1) | |
83 | return -EINVAL; | |
84 | ||
85 | plat->offset = offset; | |
86 | ||
87 | return 0; | |
88 | } | |
89 | ||
90 | static const struct udevice_id sl28cpld_ids[] = { | |
91 | { .compatible = "kontron,sl28cpld" }, | |
92 | {} | |
93 | }; | |
94 | ||
95 | U_BOOT_DRIVER(sl28cpld) = { | |
96 | .name = "sl28cpld", | |
97 | .id = UCLASS_NOP, | |
98 | .of_match = sl28cpld_ids, | |
99 | .probe = sl28cpld_probe, | |
100 | .bind = dm_scan_fdt_dev, | |
101 | .flags = DM_FLAG_PRE_RELOC, | |
102 | .per_child_plat_auto = sizeof(struct sl28cpld_child_plat), | |
103 | .child_post_bind = sl28cpld_child_post_bind, | |
104 | }; |