| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Motorola CPCAP PMIC core driver |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2016 Tony Lindgren <tony@atomide.com> |
|---|
| 5 | | - * |
|---|
| 6 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 7 | | - * it under the terms of the GNU General Public License version 2 as |
|---|
| 8 | | - * published by the Free Software Foundation. |
|---|
| 9 | 6 | */ |
|---|
| 10 | 7 | |
|---|
| 11 | 8 | #include <linux/device.h> |
|---|
| .. | .. |
|---|
| 18 | 15 | #include <linux/regmap.h> |
|---|
| 19 | 16 | #include <linux/sysfs.h> |
|---|
| 20 | 17 | |
|---|
| 18 | +#include <linux/mfd/core.h> |
|---|
| 21 | 19 | #include <linux/mfd/motorola-cpcap.h> |
|---|
| 22 | 20 | #include <linux/spi/spi.h> |
|---|
| 23 | 21 | |
|---|
| .. | .. |
|---|
| 99 | 97 | .ack_base = CPCAP_REG_MI1, |
|---|
| 100 | 98 | .mask_base = CPCAP_REG_MIM1, |
|---|
| 101 | 99 | .use_ack = true, |
|---|
| 102 | | - .ack_invert = true, |
|---|
| 100 | + .clear_ack = true, |
|---|
| 103 | 101 | }, |
|---|
| 104 | 102 | { |
|---|
| 105 | 103 | .name = "cpcap-m2", |
|---|
| .. | .. |
|---|
| 108 | 106 | .ack_base = CPCAP_REG_MI2, |
|---|
| 109 | 107 | .mask_base = CPCAP_REG_MIM2, |
|---|
| 110 | 108 | .use_ack = true, |
|---|
| 111 | | - .ack_invert = true, |
|---|
| 109 | + .clear_ack = true, |
|---|
| 112 | 110 | }, |
|---|
| 113 | 111 | { |
|---|
| 114 | 112 | .name = "cpcap1-4", |
|---|
| .. | .. |
|---|
| 117 | 115 | .ack_base = CPCAP_REG_INT1, |
|---|
| 118 | 116 | .mask_base = CPCAP_REG_INTM1, |
|---|
| 119 | 117 | .use_ack = true, |
|---|
| 120 | | - .ack_invert = true, |
|---|
| 118 | + .clear_ack = true, |
|---|
| 121 | 119 | }, |
|---|
| 122 | 120 | }; |
|---|
| 123 | 121 | |
|---|
| .. | .. |
|---|
| 216 | 214 | .val_format_endian = REGMAP_ENDIAN_LITTLE, |
|---|
| 217 | 215 | }; |
|---|
| 218 | 216 | |
|---|
| 217 | +#ifdef CONFIG_PM_SLEEP |
|---|
| 218 | +static int cpcap_suspend(struct device *dev) |
|---|
| 219 | +{ |
|---|
| 220 | + struct spi_device *spi = to_spi_device(dev); |
|---|
| 221 | + |
|---|
| 222 | + disable_irq(spi->irq); |
|---|
| 223 | + |
|---|
| 224 | + return 0; |
|---|
| 225 | +} |
|---|
| 226 | + |
|---|
| 227 | +static int cpcap_resume(struct device *dev) |
|---|
| 228 | +{ |
|---|
| 229 | + struct spi_device *spi = to_spi_device(dev); |
|---|
| 230 | + |
|---|
| 231 | + enable_irq(spi->irq); |
|---|
| 232 | + |
|---|
| 233 | + return 0; |
|---|
| 234 | +} |
|---|
| 235 | +#endif |
|---|
| 236 | + |
|---|
| 237 | +static SIMPLE_DEV_PM_OPS(cpcap_pm, cpcap_suspend, cpcap_resume); |
|---|
| 238 | + |
|---|
| 239 | +static const struct mfd_cell cpcap_mfd_devices[] = { |
|---|
| 240 | + { |
|---|
| 241 | + .name = "cpcap_adc", |
|---|
| 242 | + .of_compatible = "motorola,mapphone-cpcap-adc", |
|---|
| 243 | + }, { |
|---|
| 244 | + .name = "cpcap_battery", |
|---|
| 245 | + .of_compatible = "motorola,cpcap-battery", |
|---|
| 246 | + }, { |
|---|
| 247 | + .name = "cpcap-charger", |
|---|
| 248 | + .of_compatible = "motorola,mapphone-cpcap-charger", |
|---|
| 249 | + }, { |
|---|
| 250 | + .name = "cpcap-regulator", |
|---|
| 251 | + .of_compatible = "motorola,mapphone-cpcap-regulator", |
|---|
| 252 | + }, { |
|---|
| 253 | + .name = "cpcap-rtc", |
|---|
| 254 | + .of_compatible = "motorola,cpcap-rtc", |
|---|
| 255 | + }, { |
|---|
| 256 | + .name = "cpcap-pwrbutton", |
|---|
| 257 | + .of_compatible = "motorola,cpcap-pwrbutton", |
|---|
| 258 | + }, { |
|---|
| 259 | + .name = "cpcap-usb-phy", |
|---|
| 260 | + .of_compatible = "motorola,mapphone-cpcap-usb-phy", |
|---|
| 261 | + }, { |
|---|
| 262 | + .name = "cpcap-led", |
|---|
| 263 | + .id = 0, |
|---|
| 264 | + .of_compatible = "motorola,cpcap-led-red", |
|---|
| 265 | + }, { |
|---|
| 266 | + .name = "cpcap-led", |
|---|
| 267 | + .id = 1, |
|---|
| 268 | + .of_compatible = "motorola,cpcap-led-green", |
|---|
| 269 | + }, { |
|---|
| 270 | + .name = "cpcap-led", |
|---|
| 271 | + .id = 2, |
|---|
| 272 | + .of_compatible = "motorola,cpcap-led-blue", |
|---|
| 273 | + }, { |
|---|
| 274 | + .name = "cpcap-led", |
|---|
| 275 | + .id = 3, |
|---|
| 276 | + .of_compatible = "motorola,cpcap-led-adl", |
|---|
| 277 | + }, { |
|---|
| 278 | + .name = "cpcap-led", |
|---|
| 279 | + .id = 4, |
|---|
| 280 | + .of_compatible = "motorola,cpcap-led-cp", |
|---|
| 281 | + }, { |
|---|
| 282 | + .name = "cpcap-codec", |
|---|
| 283 | + } |
|---|
| 284 | +}; |
|---|
| 285 | + |
|---|
| 219 | 286 | static int cpcap_probe(struct spi_device *spi) |
|---|
| 220 | 287 | { |
|---|
| 221 | 288 | const struct of_device_id *match; |
|---|
| .. | .. |
|---|
| 260 | 327 | if (ret) |
|---|
| 261 | 328 | return ret; |
|---|
| 262 | 329 | |
|---|
| 263 | | - return devm_of_platform_populate(&cpcap->spi->dev); |
|---|
| 330 | + /* Parent SPI controller uses DMA, CPCAP and child devices do not */ |
|---|
| 331 | + spi->dev.coherent_dma_mask = 0; |
|---|
| 332 | + spi->dev.dma_mask = &spi->dev.coherent_dma_mask; |
|---|
| 333 | + |
|---|
| 334 | + return devm_mfd_add_devices(&spi->dev, 0, cpcap_mfd_devices, |
|---|
| 335 | + ARRAY_SIZE(cpcap_mfd_devices), NULL, 0, NULL); |
|---|
| 264 | 336 | } |
|---|
| 265 | 337 | |
|---|
| 266 | 338 | static struct spi_driver cpcap_driver = { |
|---|
| 267 | 339 | .driver = { |
|---|
| 268 | 340 | .name = "cpcap-core", |
|---|
| 269 | 341 | .of_match_table = cpcap_of_match, |
|---|
| 342 | + .pm = &cpcap_pm, |
|---|
| 270 | 343 | }, |
|---|
| 271 | 344 | .probe = cpcap_probe, |
|---|
| 272 | 345 | }; |
|---|