1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2012 Samsung Electronics Co., Ltd 4 * http://www.samsung.com 5 * Copyright 2025 Linaro Ltd. 6 * 7 * Samsung SxM core driver 8 */ 9 10 #include <linux/device.h> 11 #include <linux/err.h> 12 #include <linux/export.h> 13 #include <linux/interrupt.h> 14 #include <linux/mfd/core.h> 15 #include <linux/mfd/samsung/core.h> 16 #include <linux/mfd/samsung/irq.h> 17 #include <linux/mfd/samsung/s2mps11.h> 18 #include <linux/mfd/samsung/s2mps13.h> 19 #include <linux/module.h> 20 #include <linux/of.h> 21 #include <linux/pm.h> 22 #include <linux/pm_runtime.h> 23 #include <linux/regmap.h> 24 #include "sec-core.h" 25 26 static const struct resource s5m8767_rtc_resources[] = { 27 DEFINE_RES_IRQ_NAMED(S5M8767_IRQ_RTCA1, "alarm"), 28 }; 29 30 static const struct mfd_cell s5m8767_devs[] = { 31 MFD_CELL_NAME("s5m8767-pmic"), 32 MFD_CELL_RES("s5m-rtc", s5m8767_rtc_resources), 33 MFD_CELL_OF("s5m8767-clk", NULL, NULL, 0, 0, "samsung,s5m8767-clk"), 34 }; 35 36 static const struct mfd_cell s2dos05_devs[] = { 37 MFD_CELL_NAME("s2dos05-regulator"), 38 }; 39 40 static const struct resource s2mpg10_rtc_resources[] = { 41 DEFINE_RES_IRQ_NAMED(S2MPG10_IRQ_RTCA0, "alarm"), 42 }; 43 44 static const struct mfd_cell s2mpg10_devs[] = { 45 MFD_CELL_NAME("s2mpg10-meter"), 46 MFD_CELL_NAME("s2mpg10-regulator"), 47 MFD_CELL_RES("s2mpg10-rtc", s2mpg10_rtc_resources), 48 MFD_CELL_OF("s2mpg10-clk", NULL, NULL, 0, 0, "samsung,s2mpg10-clk"), 49 MFD_CELL_OF("s2mpg10-gpio", NULL, NULL, 0, 0, "samsung,s2mpg10-gpio"), 50 }; 51 52 static const struct mfd_cell s2mpg11_devs[] = { 53 MFD_CELL_NAME("s2mpg11-meter"), 54 MFD_CELL_NAME("s2mpg11-regulator"), 55 MFD_CELL_OF("s2mpg11-gpio", NULL, NULL, 0, 0, "samsung,s2mpg11-gpio"), 56 }; 57 58 static const struct resource s2mps11_rtc_resources[] = { 59 DEFINE_RES_IRQ_NAMED(S2MPS11_IRQ_RTCA0, "alarm"), 60 }; 61 62 static const struct mfd_cell s2mps11_devs[] = { 63 MFD_CELL_NAME("s2mps11-regulator"), 64 MFD_CELL_RES("s2mps14-rtc", s2mps11_rtc_resources), 65 MFD_CELL_OF("s2mps11-clk", NULL, NULL, 0, 0, "samsung,s2mps11-clk"), 66 }; 67 68 static const struct resource s2mps14_rtc_resources[] = { 69 DEFINE_RES_IRQ_NAMED(S2MPS14_IRQ_RTCA0, "alarm"), 70 }; 71 72 static const struct mfd_cell s2mps13_devs[] = { 73 MFD_CELL_NAME("s2mps13-regulator"), 74 MFD_CELL_RES("s2mps13-rtc", s2mps14_rtc_resources), 75 MFD_CELL_OF("s2mps13-clk", NULL, NULL, 0, 0, "samsung,s2mps13-clk"), 76 }; 77 78 static const struct mfd_cell s2mps14_devs[] = { 79 MFD_CELL_NAME("s2mps14-regulator"), 80 MFD_CELL_RES("s2mps14-rtc", s2mps14_rtc_resources), 81 MFD_CELL_OF("s2mps14-clk", NULL, NULL, 0, 0, "samsung,s2mps14-clk"), 82 }; 83 84 static const struct mfd_cell s2mps15_devs[] = { 85 MFD_CELL_NAME("s2mps15-regulator"), 86 MFD_CELL_RES("s2mps15-rtc", s2mps14_rtc_resources), 87 MFD_CELL_OF("s2mps13-clk", NULL, NULL, 0, 0, "samsung,s2mps13-clk"), 88 }; 89 90 static const struct mfd_cell s2mpa01_devs[] = { 91 MFD_CELL_NAME("s2mpa01-pmic"), 92 MFD_CELL_RES("s2mps14-rtc", s2mps14_rtc_resources), 93 }; 94 95 static const struct mfd_cell s2mpu02_devs[] = { 96 MFD_CELL_NAME("s2mpu02-regulator"), 97 }; 98 99 static const struct resource s2mpu05_rtc_resources[] = { 100 DEFINE_RES_IRQ_NAMED(S2MPU05_IRQ_RTCA0, "alarm"), 101 }; 102 103 static const struct mfd_cell s2mpu05_devs[] = { 104 MFD_CELL_NAME("s2mpu05-regulator"), 105 MFD_CELL_RES("s2mps15-rtc", s2mpu05_rtc_resources), 106 }; 107 108 static void sec_pmic_dump_rev(struct sec_pmic_dev *sec_pmic) 109 { 110 unsigned int val; 111 112 /* For s2mpg1x, the revision is in a different regmap */ 113 switch (sec_pmic->device_type) { 114 case S2MPG10: 115 case S2MPG11: 116 return; 117 default: 118 break; 119 } 120 121 /* For each device type, the REG_ID is always the first register */ 122 if (!regmap_read(sec_pmic->regmap_pmic, S2MPS11_REG_ID, &val)) 123 dev_dbg(sec_pmic->dev, "Revision: 0x%x\n", val); 124 } 125 126 static void sec_pmic_configure(struct sec_pmic_dev *sec_pmic) 127 { 128 int err; 129 130 if (sec_pmic->device_type != S2MPS13X) 131 return; 132 133 if (sec_pmic->pdata->disable_wrstbi) { 134 /* 135 * If WRSTBI pin is pulled down this feature must be disabled 136 * because each Suspend to RAM will trigger buck voltage reset 137 * to default values. 138 */ 139 err = regmap_update_bits(sec_pmic->regmap_pmic, 140 S2MPS13_REG_WRSTBI, 141 S2MPS13_REG_WRSTBI_MASK, 0x0); 142 if (err) 143 dev_warn(sec_pmic->dev, 144 "Cannot initialize WRSTBI config: %d\n", 145 err); 146 } 147 } 148 149 /* 150 * Only the common platform data elements for s5m8767 are parsed here from the 151 * device tree. Other sub-modules of s5m8767 such as pmic, rtc , charger and 152 * others have to parse their own platform data elements from device tree. 153 * 154 * The s5m8767 platform data structure is instantiated here and the drivers for 155 * the sub-modules need not instantiate another instance while parsing their 156 * platform data. 157 */ 158 static struct sec_platform_data * 159 sec_pmic_parse_dt_pdata(struct device *dev) 160 { 161 struct sec_platform_data *pd; 162 163 pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL); 164 if (!pd) 165 return ERR_PTR(-ENOMEM); 166 167 pd->manual_poweroff = of_property_read_bool(dev->of_node, 168 "samsung,s2mps11-acokb-ground"); 169 pd->disable_wrstbi = of_property_read_bool(dev->of_node, 170 "samsung,s2mps11-wrstbi-ground"); 171 return pd; 172 } 173 174 int sec_pmic_probe(struct device *dev, int device_type, unsigned int irq, 175 struct regmap *regmap, struct i2c_client *client) 176 { 177 struct regmap_irq_chip_data *irq_data; 178 struct sec_platform_data *pdata; 179 const struct mfd_cell *sec_devs; 180 struct sec_pmic_dev *sec_pmic; 181 int ret, num_sec_devs; 182 183 sec_pmic = devm_kzalloc(dev, sizeof(*sec_pmic), GFP_KERNEL); 184 if (!sec_pmic) 185 return -ENOMEM; 186 187 dev_set_drvdata(dev, sec_pmic); 188 sec_pmic->dev = dev; 189 sec_pmic->device_type = device_type; 190 sec_pmic->i2c = client; 191 sec_pmic->irq = irq; 192 sec_pmic->regmap_pmic = regmap; 193 194 pdata = sec_pmic_parse_dt_pdata(sec_pmic->dev); 195 if (IS_ERR(pdata)) { 196 ret = PTR_ERR(pdata); 197 return ret; 198 } 199 200 sec_pmic->pdata = pdata; 201 202 irq_data = sec_irq_init(sec_pmic); 203 if (IS_ERR(irq_data)) 204 return PTR_ERR(irq_data); 205 206 pm_runtime_set_active(sec_pmic->dev); 207 208 switch (sec_pmic->device_type) { 209 case S5M8767X: 210 sec_devs = s5m8767_devs; 211 num_sec_devs = ARRAY_SIZE(s5m8767_devs); 212 break; 213 case S2DOS05: 214 sec_devs = s2dos05_devs; 215 num_sec_devs = ARRAY_SIZE(s2dos05_devs); 216 break; 217 case S2MPA01: 218 sec_devs = s2mpa01_devs; 219 num_sec_devs = ARRAY_SIZE(s2mpa01_devs); 220 break; 221 case S2MPG10: 222 sec_devs = s2mpg10_devs; 223 num_sec_devs = ARRAY_SIZE(s2mpg10_devs); 224 break; 225 case S2MPG11: 226 sec_devs = s2mpg11_devs; 227 num_sec_devs = ARRAY_SIZE(s2mpg11_devs); 228 break; 229 case S2MPS11X: 230 sec_devs = s2mps11_devs; 231 num_sec_devs = ARRAY_SIZE(s2mps11_devs); 232 break; 233 case S2MPS13X: 234 sec_devs = s2mps13_devs; 235 num_sec_devs = ARRAY_SIZE(s2mps13_devs); 236 break; 237 case S2MPS14X: 238 sec_devs = s2mps14_devs; 239 num_sec_devs = ARRAY_SIZE(s2mps14_devs); 240 break; 241 case S2MPS15X: 242 sec_devs = s2mps15_devs; 243 num_sec_devs = ARRAY_SIZE(s2mps15_devs); 244 break; 245 case S2MPU02: 246 sec_devs = s2mpu02_devs; 247 num_sec_devs = ARRAY_SIZE(s2mpu02_devs); 248 break; 249 case S2MPU05: 250 sec_devs = s2mpu05_devs; 251 num_sec_devs = ARRAY_SIZE(s2mpu05_devs); 252 break; 253 default: 254 return dev_err_probe(sec_pmic->dev, -EINVAL, 255 "Unsupported device type %d\n", 256 sec_pmic->device_type); 257 } 258 ret = devm_mfd_add_devices(sec_pmic->dev, -1, sec_devs, num_sec_devs, 259 NULL, 0, regmap_irq_get_domain(irq_data)); 260 if (ret) 261 return ret; 262 263 sec_pmic_configure(sec_pmic); 264 sec_pmic_dump_rev(sec_pmic); 265 266 return ret; 267 } 268 EXPORT_SYMBOL_GPL(sec_pmic_probe); 269 270 void sec_pmic_shutdown(struct device *dev) 271 { 272 struct sec_pmic_dev *sec_pmic = dev_get_drvdata(dev); 273 unsigned int reg, mask; 274 275 if (!sec_pmic->pdata->manual_poweroff) 276 return; 277 278 switch (sec_pmic->device_type) { 279 case S2MPS11X: 280 reg = S2MPS11_REG_CTRL1; 281 mask = S2MPS11_CTRL1_PWRHOLD_MASK; 282 break; 283 default: 284 /* 285 * Currently only one board with S2MPS11 needs this, so just 286 * ignore the rest. 287 */ 288 dev_warn(sec_pmic->dev, 289 "Unsupported device %d for manual power off\n", 290 sec_pmic->device_type); 291 return; 292 } 293 294 regmap_update_bits(sec_pmic->regmap_pmic, reg, mask, 0); 295 } 296 EXPORT_SYMBOL_GPL(sec_pmic_shutdown); 297 298 static int sec_pmic_suspend(struct device *dev) 299 { 300 struct sec_pmic_dev *sec_pmic = dev_get_drvdata(dev); 301 302 if (device_may_wakeup(dev)) 303 enable_irq_wake(sec_pmic->irq); 304 /* 305 * PMIC IRQ must be disabled during suspend for RTC alarm 306 * to work properly. 307 * When device is woken up from suspend, an 308 * interrupt occurs before resuming I2C bus controller. 309 * The interrupt is handled by regmap_irq_thread which tries 310 * to read RTC registers. This read fails (I2C is still 311 * suspended) and RTC Alarm interrupt is disabled. 312 */ 313 disable_irq(sec_pmic->irq); 314 315 return 0; 316 } 317 318 static int sec_pmic_resume(struct device *dev) 319 { 320 struct sec_pmic_dev *sec_pmic = dev_get_drvdata(dev); 321 322 if (device_may_wakeup(dev)) 323 disable_irq_wake(sec_pmic->irq); 324 enable_irq(sec_pmic->irq); 325 326 return 0; 327 } 328 329 DEFINE_SIMPLE_DEV_PM_OPS(sec_pmic_pm_ops, sec_pmic_suspend, sec_pmic_resume); 330 EXPORT_SYMBOL_GPL(sec_pmic_pm_ops); 331 332 MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>"); 333 MODULE_AUTHOR("Krzysztof Kozlowski <krzk@kernel.org>"); 334 MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); 335 MODULE_AUTHOR("André Draszik <andre.draszik@linaro.org>"); 336 MODULE_DESCRIPTION("Core driver for the Samsung S5M"); 337 MODULE_LICENSE("GPL"); 338