Commit | Line | Data |
---|---|---|
26c7e05a | 1 | // SPDX-License-Identifier: GPL-2.0 |
7cf0a66f | 2 | /* |
26c7e05a | 3 | * Device access for Crystal Cove PMIC |
7cf0a66f | 4 | * |
03f271b0 | 5 | * Copyright (C) 2012-2014, 2022 Intel Corporation. All rights reserved. |
7cf0a66f | 6 | * |
7cf0a66f ZL |
7 | * Author: Yang, Bin <bin.yang@intel.com> |
8 | * Author: Zhu, Lejun <lejun.zhu@linux.intel.com> | |
9 | */ | |
10 | ||
5a30b210 | 11 | #include <linux/i2c.h> |
7cf0a66f | 12 | #include <linux/interrupt.h> |
09c4e702 | 13 | #include <linux/mod_devicetable.h> |
5a30b210 | 14 | #include <linux/module.h> |
51eeee8e | 15 | #include <linux/mfd/core.h> |
7cf0a66f | 16 | #include <linux/mfd/intel_soc_pmic.h> |
5a30b210 AS |
17 | #include <linux/platform_data/x86/soc.h> |
18 | #include <linux/pwm.h> | |
19 | #include <linux/regmap.h> | |
7cf0a66f ZL |
20 | |
21 | #define CRYSTAL_COVE_MAX_REGISTER 0xC6 | |
22 | ||
23 | #define CRYSTAL_COVE_REG_IRQLVL1 0x02 | |
24 | #define CRYSTAL_COVE_REG_MIRQLVL1 0x0E | |
25 | ||
26 | #define CRYSTAL_COVE_IRQ_PWRSRC 0 | |
27 | #define CRYSTAL_COVE_IRQ_THRM 1 | |
28 | #define CRYSTAL_COVE_IRQ_BCU 2 | |
29 | #define CRYSTAL_COVE_IRQ_ADC 3 | |
30 | #define CRYSTAL_COVE_IRQ_CHGR 4 | |
31 | #define CRYSTAL_COVE_IRQ_GPIO 5 | |
32 | #define CRYSTAL_COVE_IRQ_VHDMIOCP 6 | |
33 | ||
bf4cceb6 | 34 | static const struct resource pwrsrc_resources[] = { |
0ce8ea71 | 35 | DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_PWRSRC, "PWRSRC"), |
7cf0a66f ZL |
36 | }; |
37 | ||
bf4cceb6 | 38 | static const struct resource thermal_resources[] = { |
0ce8ea71 | 39 | DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_THRM, "THERMAL"), |
7cf0a66f ZL |
40 | }; |
41 | ||
bf4cceb6 | 42 | static const struct resource bcu_resources[] = { |
0ce8ea71 | 43 | DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_BCU, "BCU"), |
7cf0a66f ZL |
44 | }; |
45 | ||
4946d58d HG |
46 | static const struct resource adc_resources[] = { |
47 | DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_ADC, "ADC"), | |
48 | }; | |
49 | ||
50904e9b HG |
50 | static const struct resource charger_resources[] = { |
51 | DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_CHGR, "CHGR"), | |
52 | }; | |
53 | ||
4946d58d HG |
54 | static const struct resource gpio_resources[] = { |
55 | DEFINE_RES_IRQ_NAMED(CRYSTAL_COVE_IRQ_GPIO, "GPIO"), | |
56 | }; | |
57 | ||
4d9ed62a | 58 | static struct mfd_cell crystal_cove_byt_dev[] = { |
7cf0a66f ZL |
59 | { |
60 | .name = "crystal_cove_pwrsrc", | |
61 | .num_resources = ARRAY_SIZE(pwrsrc_resources), | |
62 | .resources = pwrsrc_resources, | |
63 | }, | |
7cf0a66f ZL |
64 | { |
65 | .name = "crystal_cove_thermal", | |
66 | .num_resources = ARRAY_SIZE(thermal_resources), | |
67 | .resources = thermal_resources, | |
68 | }, | |
69 | { | |
70 | .name = "crystal_cove_bcu", | |
71 | .num_resources = ARRAY_SIZE(bcu_resources), | |
72 | .resources = bcu_resources, | |
73 | }, | |
4946d58d HG |
74 | { |
75 | .name = "crystal_cove_adc", | |
76 | .num_resources = ARRAY_SIZE(adc_resources), | |
77 | .resources = adc_resources, | |
78 | }, | |
50904e9b HG |
79 | { |
80 | .name = "crystal_cove_charger", | |
81 | .num_resources = ARRAY_SIZE(charger_resources), | |
82 | .resources = charger_resources, | |
83 | }, | |
7cf0a66f ZL |
84 | { |
85 | .name = "crystal_cove_gpio", | |
86 | .num_resources = ARRAY_SIZE(gpio_resources), | |
87 | .resources = gpio_resources, | |
88 | }, | |
b1eea857 | 89 | { |
ed852cde | 90 | .name = "byt_crystal_cove_pmic", |
b1eea857 | 91 | }, |
3d5e10ec SK |
92 | { |
93 | .name = "crystal_cove_pwm", | |
94 | }, | |
7cf0a66f ZL |
95 | }; |
96 | ||
4d9ed62a HG |
97 | static struct mfd_cell crystal_cove_cht_dev[] = { |
98 | { | |
99 | .name = "crystal_cove_gpio", | |
100 | .num_resources = ARRAY_SIZE(gpio_resources), | |
101 | .resources = gpio_resources, | |
102 | }, | |
36f1b26b HG |
103 | { |
104 | .name = "cht_crystal_cove_pmic", | |
105 | }, | |
4d9ed62a HG |
106 | { |
107 | .name = "crystal_cove_pwm", | |
108 | }, | |
109 | }; | |
110 | ||
172cb301 | 111 | static const struct regmap_config crystal_cove_regmap_config = { |
7cf0a66f ZL |
112 | .reg_bits = 8, |
113 | .val_bits = 8, | |
114 | ||
115 | .max_register = CRYSTAL_COVE_MAX_REGISTER, | |
116 | .cache_type = REGCACHE_NONE, | |
117 | }; | |
118 | ||
119 | static const struct regmap_irq crystal_cove_irqs[] = { | |
8bd2d03e AS |
120 | REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_PWRSRC, 0, BIT(CRYSTAL_COVE_IRQ_PWRSRC)), |
121 | REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_THRM, 0, BIT(CRYSTAL_COVE_IRQ_THRM)), | |
122 | REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_BCU, 0, BIT(CRYSTAL_COVE_IRQ_BCU)), | |
123 | REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_ADC, 0, BIT(CRYSTAL_COVE_IRQ_ADC)), | |
124 | REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_CHGR, 0, BIT(CRYSTAL_COVE_IRQ_CHGR)), | |
125 | REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_GPIO, 0, BIT(CRYSTAL_COVE_IRQ_GPIO)), | |
126 | REGMAP_IRQ_REG(CRYSTAL_COVE_IRQ_VHDMIOCP, 0, BIT(CRYSTAL_COVE_IRQ_VHDMIOCP)), | |
7cf0a66f ZL |
127 | }; |
128 | ||
7ce7b26f | 129 | static const struct regmap_irq_chip crystal_cove_irq_chip = { |
7cf0a66f ZL |
130 | .name = "Crystal Cove", |
131 | .irqs = crystal_cove_irqs, | |
132 | .num_irqs = ARRAY_SIZE(crystal_cove_irqs), | |
133 | .num_regs = 1, | |
134 | .status_base = CRYSTAL_COVE_REG_IRQLVL1, | |
135 | .mask_base = CRYSTAL_COVE_REG_MIRQLVL1, | |
136 | }; | |
137 | ||
5a30b210 AS |
138 | /* PWM consumed by the Intel GFX */ |
139 | static struct pwm_lookup crc_pwm_lookup[] = { | |
140 | PWM_LOOKUP("crystal_cove_pwm", 0, "0000:00:02.0", "pwm_pmic_backlight", 0, PWM_POLARITY_NORMAL), | |
141 | }; | |
142 | ||
39c8980c | 143 | struct crystal_cove_config { |
5a30b210 AS |
144 | unsigned long irq_flags; |
145 | struct mfd_cell *cell_dev; | |
146 | int n_cell_devs; | |
147 | const struct regmap_config *regmap_config; | |
148 | const struct regmap_irq_chip *irq_chip; | |
149 | }; | |
150 | ||
39c8980c | 151 | static const struct crystal_cove_config crystal_cove_config_byt_crc = { |
4d9ed62a HG |
152 | .irq_flags = IRQF_TRIGGER_RISING, |
153 | .cell_dev = crystal_cove_byt_dev, | |
154 | .n_cell_devs = ARRAY_SIZE(crystal_cove_byt_dev), | |
155 | .regmap_config = &crystal_cove_regmap_config, | |
156 | .irq_chip = &crystal_cove_irq_chip, | |
157 | }; | |
158 | ||
39c8980c | 159 | static const struct crystal_cove_config crystal_cove_config_cht_crc = { |
7cf0a66f | 160 | .irq_flags = IRQF_TRIGGER_RISING, |
4d9ed62a HG |
161 | .cell_dev = crystal_cove_cht_dev, |
162 | .n_cell_devs = ARRAY_SIZE(crystal_cove_cht_dev), | |
7cf0a66f ZL |
163 | .regmap_config = &crystal_cove_regmap_config, |
164 | .irq_chip = &crystal_cove_irq_chip, | |
165 | }; | |
5a30b210 | 166 | |
39c8980c | 167 | static int crystal_cove_i2c_probe(struct i2c_client *i2c) |
5a30b210 | 168 | { |
39c8980c | 169 | const struct crystal_cove_config *config; |
5a30b210 AS |
170 | struct device *dev = &i2c->dev; |
171 | struct intel_soc_pmic *pmic; | |
172 | int ret; | |
173 | ||
174 | if (soc_intel_is_byt()) | |
39c8980c | 175 | config = &crystal_cove_config_byt_crc; |
5a30b210 | 176 | else |
39c8980c | 177 | config = &crystal_cove_config_cht_crc; |
5a30b210 AS |
178 | |
179 | pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); | |
180 | if (!pmic) | |
181 | return -ENOMEM; | |
182 | ||
4b74ec58 | 183 | i2c_set_clientdata(i2c, pmic); |
5a30b210 AS |
184 | |
185 | pmic->regmap = devm_regmap_init_i2c(i2c, config->regmap_config); | |
186 | if (IS_ERR(pmic->regmap)) | |
187 | return PTR_ERR(pmic->regmap); | |
188 | ||
189 | pmic->irq = i2c->irq; | |
190 | ||
cae02b7a AS |
191 | ret = devm_regmap_add_irq_chip(dev, pmic->regmap, pmic->irq, |
192 | config->irq_flags | IRQF_ONESHOT, | |
193 | 0, config->irq_chip, &pmic->irq_chip_data); | |
5a30b210 AS |
194 | if (ret) |
195 | return ret; | |
196 | ||
197 | ret = enable_irq_wake(pmic->irq); | |
198 | if (ret) | |
199 | dev_warn(dev, "Can't enable IRQ as wake source: %d\n", ret); | |
200 | ||
201 | /* Add lookup table for crc-pwm */ | |
202 | pwm_add_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup)); | |
203 | ||
204 | /* To distuingish this domain from the GPIO/charger's irqchip domains */ | |
205 | irq_domain_update_bus_token(regmap_irq_get_domain(pmic->irq_chip_data), | |
206 | DOMAIN_BUS_NEXUS); | |
207 | ||
cae02b7a | 208 | ret = mfd_add_devices(dev, PLATFORM_DEVID_NONE, config->cell_dev, |
5a30b210 AS |
209 | config->n_cell_devs, NULL, 0, |
210 | regmap_irq_get_domain(pmic->irq_chip_data)); | |
211 | if (ret) | |
cae02b7a | 212 | pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup)); |
5a30b210 | 213 | |
5a30b210 AS |
214 | return ret; |
215 | } | |
216 | ||
ae955959 | 217 | static void crystal_cove_i2c_remove(struct i2c_client *i2c) |
5a30b210 | 218 | { |
5a30b210 AS |
219 | /* remove crc-pwm lookup table */ |
220 | pwm_remove_table(crc_pwm_lookup, ARRAY_SIZE(crc_pwm_lookup)); | |
221 | ||
222 | mfd_remove_devices(&i2c->dev); | |
5a30b210 AS |
223 | } |
224 | ||
39c8980c | 225 | static void crystal_cove_shutdown(struct i2c_client *i2c) |
5a30b210 | 226 | { |
4b74ec58 | 227 | struct intel_soc_pmic *pmic = i2c_get_clientdata(i2c); |
5a30b210 AS |
228 | |
229 | disable_irq(pmic->irq); | |
230 | ||
231 | return; | |
232 | } | |
233 | ||
39c8980c | 234 | static int crystal_cove_suspend(struct device *dev) |
5a30b210 AS |
235 | { |
236 | struct intel_soc_pmic *pmic = dev_get_drvdata(dev); | |
237 | ||
238 | disable_irq(pmic->irq); | |
239 | ||
240 | return 0; | |
241 | } | |
242 | ||
39c8980c | 243 | static int crystal_cove_resume(struct device *dev) |
5a30b210 AS |
244 | { |
245 | struct intel_soc_pmic *pmic = dev_get_drvdata(dev); | |
246 | ||
247 | enable_irq(pmic->irq); | |
248 | ||
249 | return 0; | |
250 | } | |
5a30b210 | 251 | |
39c8980c | 252 | static DEFINE_SIMPLE_DEV_PM_OPS(crystal_cove_pm_ops, crystal_cove_suspend, crystal_cove_resume); |
5a30b210 | 253 | |
39c8980c | 254 | static const struct acpi_device_id crystal_cove_acpi_match[] = { |
5a30b210 AS |
255 | { "INT33FD" }, |
256 | { }, | |
257 | }; | |
39c8980c | 258 | MODULE_DEVICE_TABLE(acpi, crystal_cove_acpi_match); |
5a30b210 | 259 | |
39c8980c | 260 | static struct i2c_driver crystal_cove_i2c_driver = { |
5a30b210 | 261 | .driver = { |
39c8980c | 262 | .name = "crystal_cove_i2c", |
e1efbc8e | 263 | .pm = pm_sleep_ptr(&crystal_cove_pm_ops), |
39c8980c | 264 | .acpi_match_table = crystal_cove_acpi_match, |
5a30b210 | 265 | }, |
39c8980c AS |
266 | .probe_new = crystal_cove_i2c_probe, |
267 | .remove = crystal_cove_i2c_remove, | |
268 | .shutdown = crystal_cove_shutdown, | |
5a30b210 AS |
269 | }; |
270 | ||
39c8980c | 271 | module_i2c_driver(crystal_cove_i2c_driver); |
5a30b210 AS |
272 | |
273 | MODULE_DESCRIPTION("I2C driver for Intel SoC PMIC"); | |
274 | MODULE_LICENSE("GPL v2"); | |
275 | MODULE_AUTHOR("Yang, Bin <bin.yang@intel.com>"); | |
276 | MODULE_AUTHOR("Zhu, Lejun <lejun.zhu@linux.intel.com>"); |