blob: 1c61b005af3a71569027e8bd113f1e636e7c5548 [file] [log] [blame]
Michael Walle2184cc62022-02-25 18:06:24 +05301// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2021 Michael Walle <michael@walle.cc>
4 */
5
Michael Walle2184cc62022-02-25 18:06:24 +05306#include <dm.h>
7#include <i2c.h>
8
9struct 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 */
17static 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
25int 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
33static 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
42int 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
50int 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
65static 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
73static 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
90static const struct udevice_id sl28cpld_ids[] = {
91 { .compatible = "kontron,sl28cpld" },
92 {}
93};
94
95U_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};