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