1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2019, Linaro Limited
5 #include <linux/gpio/consumer.h>
6 #include <linux/interrupt.h>
7 #include <linux/kernel.h>
8 #include <linux/mfd/core.h>
9 #include <linux/mfd/wcd934x/registers.h>
10 #include <linux/mfd/wcd934x/wcd934x.h>
11 #include <linux/module.h>
13 #include <linux/of_irq.h>
14 #include <linux/platform_device.h>
15 #include <linux/regmap.h>
16 #include <linux/regulator/consumer.h>
17 #include <linux/slimbus.h>
19 #define WCD934X_REGMAP_IRQ_REG(_irq, _off, _mask) \
21 .reg_offset = (_off), \
24 .type_reg_offset = (_off), \
25 .types_supported = IRQ_TYPE_EDGE_BOTH, \
26 .type_reg_mask = (_mask), \
27 .type_level_low_val = (_mask), \
28 .type_level_high_val = (_mask), \
29 .type_falling_val = 0, \
30 .type_rising_val = 0, \
34 static const struct mfd_cell wcd934x_devices
[] = {
36 .name
= "wcd934x-codec",
38 .name
= "wcd934x-gpio",
39 .of_compatible
= "qcom,wcd9340-gpio",
41 .name
= "wcd934x-soundwire",
42 .of_compatible
= "qcom,soundwire-v1.3.0",
46 static const struct regmap_irq wcd934x_irqs
[] = {
47 WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_SLIMBUS
, 0, BIT(0)),
48 WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_HPH_PA_OCPL_FAULT
, 0, BIT(2)),
49 WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_HPH_PA_OCPR_FAULT
, 0, BIT(3)),
50 WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_MBHC_SW_DET
, 1, BIT(0)),
51 WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_MBHC_ELECT_INS_REM_DET
, 1, BIT(1)),
52 WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_MBHC_BUTTON_PRESS_DET
, 1, BIT(2)),
53 WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_MBHC_BUTTON_RELEASE_DET
, 1, BIT(3)),
54 WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_MBHC_ELECT_INS_REM_LEG_DET
, 1, BIT(4)),
55 WCD934X_REGMAP_IRQ_REG(WCD934X_IRQ_SOUNDWIRE
, 2, BIT(4)),
58 static const unsigned int wcd934x_config_regs
[] = {
62 static const struct regmap_irq_chip wcd934x_regmap_irq_chip
= {
63 .name
= "wcd934x_irq",
64 .status_base
= WCD934X_INTR_PIN1_STATUS0
,
65 .mask_base
= WCD934X_INTR_PIN1_MASK0
,
66 .ack_base
= WCD934X_INTR_PIN1_CLEAR0
,
69 .num_irqs
= ARRAY_SIZE(wcd934x_irqs
),
70 .config_base
= wcd934x_config_regs
,
71 .num_config_bases
= ARRAY_SIZE(wcd934x_config_regs
),
73 .set_type_config
= regmap_irq_set_type_config_simple
,
76 static bool wcd934x_is_volatile_register(struct device
*dev
, unsigned int reg
)
79 case WCD934X_INTR_PIN1_STATUS0
...WCD934X_INTR_PIN2_CLEAR3
:
80 case WCD934X_SWR_AHB_BRIDGE_RD_DATA_0
:
81 case WCD934X_SWR_AHB_BRIDGE_RD_DATA_1
:
82 case WCD934X_SWR_AHB_BRIDGE_RD_DATA_2
:
83 case WCD934X_SWR_AHB_BRIDGE_RD_DATA_3
:
84 case WCD934X_SWR_AHB_BRIDGE_ACCESS_STATUS
:
85 case WCD934X_ANA_MBHC_RESULT_3
:
86 case WCD934X_ANA_MBHC_RESULT_2
:
87 case WCD934X_ANA_MBHC_RESULT_1
:
88 case WCD934X_ANA_MBHC_MECH
:
89 case WCD934X_ANA_MBHC_ELECT
:
90 case WCD934X_ANA_MBHC_ZDET
:
91 case WCD934X_ANA_MICB2
:
93 case WCD934X_ANA_BIAS
:
100 static const struct regmap_range_cfg wcd934x_ranges
[] = {
103 .range_max
= WCD934X_MAX_REGISTER
,
104 .selector_reg
= WCD934X_SEL_REGISTER
,
105 .selector_mask
= WCD934X_SEL_MASK
,
106 .selector_shift
= WCD934X_SEL_SHIFT
,
107 .window_start
= WCD934X_WINDOW_START
,
108 .window_len
= WCD934X_WINDOW_LENGTH
,
112 static const struct regmap_config wcd934x_regmap_config
= {
115 .cache_type
= REGCACHE_MAPLE
,
116 .max_register
= 0xffff,
117 .can_multi_write
= true,
118 .ranges
= wcd934x_ranges
,
119 .num_ranges
= ARRAY_SIZE(wcd934x_ranges
),
120 .volatile_reg
= wcd934x_is_volatile_register
,
123 static int wcd934x_bring_up(struct wcd934x_ddata
*ddata
)
125 struct regmap
*regmap
= ddata
->regmap
;
126 u16 id_minor
, id_major
;
129 ret
= regmap_bulk_read(regmap
, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE0
,
130 (u8
*)&id_minor
, sizeof(u16
));
134 ret
= regmap_bulk_read(regmap
, WCD934X_CHIP_TIER_CTRL_CHIP_ID_BYTE2
,
135 (u8
*)&id_major
, sizeof(u16
));
139 dev_info(ddata
->dev
, "WCD934x chip id major 0x%x, minor 0x%x\n",
142 regmap_write(regmap
, WCD934X_CODEC_RPM_RST_CTL
, 0x01);
143 regmap_write(regmap
, WCD934X_SIDO_NEW_VOUT_A_STARTUP
, 0x19);
144 regmap_write(regmap
, WCD934X_SIDO_NEW_VOUT_D_STARTUP
, 0x15);
145 /* Add 1msec delay for VOUT to settle */
146 usleep_range(1000, 1100);
147 regmap_write(regmap
, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL
, 0x5);
148 regmap_write(regmap
, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL
, 0x7);
149 regmap_write(regmap
, WCD934X_CODEC_RPM_RST_CTL
, 0x3);
150 regmap_write(regmap
, WCD934X_CODEC_RPM_RST_CTL
, 0x7);
151 regmap_write(regmap
, WCD934X_CODEC_RPM_PWR_CDC_DIG_HM_CTL
, 0x3);
156 static int wcd934x_slim_status_up(struct slim_device
*sdev
)
158 struct device
*dev
= &sdev
->dev
;
159 struct wcd934x_ddata
*ddata
;
162 ddata
= dev_get_drvdata(dev
);
164 ddata
->regmap
= regmap_init_slimbus(sdev
, &wcd934x_regmap_config
);
165 if (IS_ERR(ddata
->regmap
)) {
166 dev_err(dev
, "Error allocating slim regmap\n");
167 return PTR_ERR(ddata
->regmap
);
170 ret
= wcd934x_bring_up(ddata
);
172 dev_err(dev
, "Failed to bring up WCD934X: err = %d\n", ret
);
176 ret
= devm_regmap_add_irq_chip(dev
, ddata
->regmap
, ddata
->irq
,
177 IRQF_TRIGGER_HIGH
, 0,
178 &wcd934x_regmap_irq_chip
,
181 dev_err(dev
, "Failed to add IRQ chip: err = %d\n", ret
);
185 ret
= mfd_add_devices(dev
, PLATFORM_DEVID_AUTO
, wcd934x_devices
,
186 ARRAY_SIZE(wcd934x_devices
), NULL
, 0, NULL
);
188 dev_err(dev
, "Failed to add child devices: err = %d\n",
196 static int wcd934x_slim_status(struct slim_device
*sdev
,
197 enum slim_device_status status
)
200 case SLIM_DEVICE_STATUS_UP
:
201 return wcd934x_slim_status_up(sdev
);
202 case SLIM_DEVICE_STATUS_DOWN
:
203 mfd_remove_devices(&sdev
->dev
);
212 static int wcd934x_slim_probe(struct slim_device
*sdev
)
214 struct device
*dev
= &sdev
->dev
;
215 struct device_node
*np
= dev
->of_node
;
216 struct wcd934x_ddata
*ddata
;
217 struct gpio_desc
*reset_gpio
;
220 ddata
= devm_kzalloc(dev
, sizeof(*ddata
), GFP_KERNEL
);
224 ddata
->irq
= of_irq_get(np
, 0);
226 return dev_err_probe(ddata
->dev
, ddata
->irq
,
227 "Failed to get IRQ\n");
229 ddata
->extclk
= devm_clk_get(dev
, "extclk");
230 if (IS_ERR(ddata
->extclk
))
231 return dev_err_probe(dev
, PTR_ERR(ddata
->extclk
),
232 "Failed to get extclk");
234 ddata
->supplies
[0].supply
= "vdd-buck";
235 ddata
->supplies
[1].supply
= "vdd-buck-sido";
236 ddata
->supplies
[2].supply
= "vdd-tx";
237 ddata
->supplies
[3].supply
= "vdd-rx";
238 ddata
->supplies
[4].supply
= "vdd-io";
240 ret
= regulator_bulk_get(dev
, WCD934X_MAX_SUPPLY
, ddata
->supplies
);
242 return dev_err_probe(dev
, ret
, "Failed to get supplies\n");
244 ret
= regulator_bulk_enable(WCD934X_MAX_SUPPLY
, ddata
->supplies
);
246 return dev_err_probe(dev
, ret
, "Failed to enable supplies\n");
249 * For WCD934X, it takes about 600us for the Vout_A and
250 * Vout_D to be ready after BUCK_SIDO is powered up.
251 * SYS_RST_N shouldn't be pulled high during this time
253 usleep_range(600, 650);
254 reset_gpio
= devm_gpiod_get_optional(dev
, "reset", GPIOD_OUT_LOW
);
255 if (IS_ERR(reset_gpio
)) {
256 ret
= dev_err_probe(dev
, PTR_ERR(reset_gpio
),
257 "Failed to get reset gpio\n");
258 goto err_disable_regulators
;
261 gpiod_set_value(reset_gpio
, 1);
265 dev_set_drvdata(dev
, ddata
);
269 err_disable_regulators
:
270 regulator_bulk_disable(WCD934X_MAX_SUPPLY
, ddata
->supplies
);
274 static void wcd934x_slim_remove(struct slim_device
*sdev
)
276 struct wcd934x_ddata
*ddata
= dev_get_drvdata(&sdev
->dev
);
278 regulator_bulk_disable(WCD934X_MAX_SUPPLY
, ddata
->supplies
);
279 mfd_remove_devices(&sdev
->dev
);
282 static const struct slim_device_id wcd934x_slim_id
[] = {
283 { SLIM_MANF_ID_QCOM
, SLIM_PROD_CODE_WCD9340
,
284 SLIM_DEV_IDX_WCD9340
, SLIM_DEV_INSTANCE_ID_WCD9340
},
287 MODULE_DEVICE_TABLE(slim
, wcd934x_slim_id
);
289 static struct slim_driver wcd934x_slim_driver
= {
291 .name
= "wcd934x-slim",
293 .probe
= wcd934x_slim_probe
,
294 .remove
= wcd934x_slim_remove
,
295 .device_status
= wcd934x_slim_status
,
296 .id_table
= wcd934x_slim_id
,
299 module_slim_driver(wcd934x_slim_driver
);
300 MODULE_DESCRIPTION("WCD934X slim driver");
301 MODULE_LICENSE("GPL v2");
302 MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@linaro.org>");