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