1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // Copyright(c) 2020 Intel Corporation. |
3 | |
4 | #include <linux/device.h> |
5 | #include <linux/errno.h> |
6 | #include <linux/module.h> |
7 | #include <linux/regmap.h> |
8 | #include <linux/soundwire/sdw.h> |
9 | #include <linux/soundwire/sdw_registers.h> |
10 | #include "internal.h" |
11 | |
12 | static int regmap_sdw_mbq_write(void *context, unsigned int reg, unsigned int val) |
13 | { |
14 | struct device *dev = context; |
15 | struct sdw_slave *slave = dev_to_sdw_dev(dev); |
16 | int ret; |
17 | |
18 | ret = sdw_write_no_pm(slave, SDW_SDCA_MBQ_CTL(reg), value: (val >> 8) & 0xff); |
19 | if (ret < 0) |
20 | return ret; |
21 | |
22 | return sdw_write_no_pm(slave, addr: reg, value: val & 0xff); |
23 | } |
24 | |
25 | static int regmap_sdw_mbq_read(void *context, unsigned int reg, unsigned int *val) |
26 | { |
27 | struct device *dev = context; |
28 | struct sdw_slave *slave = dev_to_sdw_dev(dev); |
29 | int read0; |
30 | int read1; |
31 | |
32 | read0 = sdw_read_no_pm(slave, addr: reg); |
33 | if (read0 < 0) |
34 | return read0; |
35 | |
36 | read1 = sdw_read_no_pm(slave, SDW_SDCA_MBQ_CTL(reg)); |
37 | if (read1 < 0) |
38 | return read1; |
39 | |
40 | *val = (read1 << 8) | read0; |
41 | |
42 | return 0; |
43 | } |
44 | |
45 | static const struct regmap_bus regmap_sdw_mbq = { |
46 | .reg_read = regmap_sdw_mbq_read, |
47 | .reg_write = regmap_sdw_mbq_write, |
48 | .reg_format_endian_default = REGMAP_ENDIAN_LITTLE, |
49 | .val_format_endian_default = REGMAP_ENDIAN_LITTLE, |
50 | }; |
51 | |
52 | static int regmap_sdw_mbq_config_check(const struct regmap_config *config) |
53 | { |
54 | /* MBQ-based controls are only 16-bits for now */ |
55 | if (config->val_bits != 16) |
56 | return -ENOTSUPP; |
57 | |
58 | /* Registers are 32 bits wide */ |
59 | if (config->reg_bits != 32) |
60 | return -ENOTSUPP; |
61 | |
62 | if (config->pad_bits != 0) |
63 | return -ENOTSUPP; |
64 | |
65 | return 0; |
66 | } |
67 | |
68 | struct regmap *__regmap_init_sdw_mbq(struct sdw_slave *sdw, |
69 | const struct regmap_config *config, |
70 | struct lock_class_key *lock_key, |
71 | const char *lock_name) |
72 | { |
73 | int ret; |
74 | |
75 | ret = regmap_sdw_mbq_config_check(config); |
76 | if (ret) |
77 | return ERR_PTR(error: ret); |
78 | |
79 | return __regmap_init(dev: &sdw->dev, bus: ®map_sdw_mbq, |
80 | bus_context: &sdw->dev, config, lock_key, lock_name); |
81 | } |
82 | EXPORT_SYMBOL_GPL(__regmap_init_sdw_mbq); |
83 | |
84 | struct regmap *__devm_regmap_init_sdw_mbq(struct sdw_slave *sdw, |
85 | const struct regmap_config *config, |
86 | struct lock_class_key *lock_key, |
87 | const char *lock_name) |
88 | { |
89 | int ret; |
90 | |
91 | ret = regmap_sdw_mbq_config_check(config); |
92 | if (ret) |
93 | return ERR_PTR(error: ret); |
94 | |
95 | return __devm_regmap_init(dev: &sdw->dev, bus: ®map_sdw_mbq, |
96 | bus_context: &sdw->dev, config, lock_key, lock_name); |
97 | } |
98 | EXPORT_SYMBOL_GPL(__devm_regmap_init_sdw_mbq); |
99 | |
100 | MODULE_DESCRIPTION("Regmap SoundWire MBQ Module" ); |
101 | MODULE_LICENSE("GPL" ); |
102 | |