190550d19SMattias Nilsson /* 290550d19SMattias Nilsson * Copyright (C) ST-Ericsson SA 2010 390550d19SMattias Nilsson * Author: Mattias Nilsson <[email protected]> for ST Ericsson. 490550d19SMattias Nilsson * License terms: GNU General Public License (GPL) version 2 590550d19SMattias Nilsson */ 690550d19SMattias Nilsson 790550d19SMattias Nilsson #include <linux/err.h> 84e36dd33SPaul Gortmaker #include <linux/module.h> 990550d19SMattias Nilsson #include <linux/platform_device.h> 10*379749c4SLee Jones #include <linux/pm.h> 11*379749c4SLee Jones #include <linux/signal.h> 1290550d19SMattias Nilsson #include <linux/mfd/abx500.h> 13ee66e653SLinus Walleij #include <linux/mfd/abx500/ab8500.h> 14ee66e653SLinus Walleij #include <linux/mfd/abx500/ab8500-sysctrl.h> 1590550d19SMattias Nilsson 1690550d19SMattias Nilsson static struct device *sysctrl_dev; 1790550d19SMattias Nilsson 18*379749c4SLee Jones void ab8500_power_off(void) 19*379749c4SLee Jones { 20*379749c4SLee Jones sigset_t old; 21*379749c4SLee Jones sigset_t all; 22*379749c4SLee Jones 23*379749c4SLee Jones sigfillset(&all); 24*379749c4SLee Jones 25*379749c4SLee Jones if (!sigprocmask(SIG_BLOCK, &all, &old)) { 26*379749c4SLee Jones (void)ab8500_sysctrl_set(AB8500_STW4500CTRL1, 27*379749c4SLee Jones AB8500_STW4500CTRL1_SWOFF | 28*379749c4SLee Jones AB8500_STW4500CTRL1_SWRESET4500N); 29*379749c4SLee Jones (void)sigprocmask(SIG_SETMASK, &old, NULL); 30*379749c4SLee Jones } 31*379749c4SLee Jones } 32*379749c4SLee Jones 3390550d19SMattias Nilsson static inline bool valid_bank(u8 bank) 3490550d19SMattias Nilsson { 3590550d19SMattias Nilsson return ((bank == AB8500_SYS_CTRL1_BLOCK) || 3690550d19SMattias Nilsson (bank == AB8500_SYS_CTRL2_BLOCK)); 3790550d19SMattias Nilsson } 3890550d19SMattias Nilsson 3990550d19SMattias Nilsson int ab8500_sysctrl_read(u16 reg, u8 *value) 4090550d19SMattias Nilsson { 4190550d19SMattias Nilsson u8 bank; 4290550d19SMattias Nilsson 4390550d19SMattias Nilsson if (sysctrl_dev == NULL) 4490550d19SMattias Nilsson return -EAGAIN; 4590550d19SMattias Nilsson 4690550d19SMattias Nilsson bank = (reg >> 8); 4790550d19SMattias Nilsson if (!valid_bank(bank)) 4890550d19SMattias Nilsson return -EINVAL; 4990550d19SMattias Nilsson 5090550d19SMattias Nilsson return abx500_get_register_interruptible(sysctrl_dev, bank, 5190550d19SMattias Nilsson (u8)(reg & 0xFF), value); 5290550d19SMattias Nilsson } 5390550d19SMattias Nilsson 5490550d19SMattias Nilsson int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value) 5590550d19SMattias Nilsson { 5690550d19SMattias Nilsson u8 bank; 5790550d19SMattias Nilsson 5890550d19SMattias Nilsson if (sysctrl_dev == NULL) 5990550d19SMattias Nilsson return -EAGAIN; 6090550d19SMattias Nilsson 6190550d19SMattias Nilsson bank = (reg >> 8); 6290550d19SMattias Nilsson if (!valid_bank(bank)) 6390550d19SMattias Nilsson return -EINVAL; 6490550d19SMattias Nilsson 6590550d19SMattias Nilsson return abx500_mask_and_set_register_interruptible(sysctrl_dev, bank, 6690550d19SMattias Nilsson (u8)(reg & 0xFF), mask, value); 6790550d19SMattias Nilsson } 6890550d19SMattias Nilsson 69f791be49SBill Pemberton static int ab8500_sysctrl_probe(struct platform_device *pdev) 7090550d19SMattias Nilsson { 71*379749c4SLee Jones struct ab8500_platform_data *plat; 72*379749c4SLee Jones 7390550d19SMattias Nilsson sysctrl_dev = &pdev->dev; 74*379749c4SLee Jones plat = dev_get_platdata(pdev->dev.parent); 75*379749c4SLee Jones if (plat->pm_power_off) 76*379749c4SLee Jones pm_power_off = ab8500_power_off; 7790550d19SMattias Nilsson return 0; 7890550d19SMattias Nilsson } 7990550d19SMattias Nilsson 804740f73fSBill Pemberton static int ab8500_sysctrl_remove(struct platform_device *pdev) 8190550d19SMattias Nilsson { 8290550d19SMattias Nilsson sysctrl_dev = NULL; 8390550d19SMattias Nilsson return 0; 8490550d19SMattias Nilsson } 8590550d19SMattias Nilsson 8690550d19SMattias Nilsson static struct platform_driver ab8500_sysctrl_driver = { 8790550d19SMattias Nilsson .driver = { 8890550d19SMattias Nilsson .name = "ab8500-sysctrl", 8990550d19SMattias Nilsson .owner = THIS_MODULE, 9090550d19SMattias Nilsson }, 9190550d19SMattias Nilsson .probe = ab8500_sysctrl_probe, 9284449216SBill Pemberton .remove = ab8500_sysctrl_remove, 9390550d19SMattias Nilsson }; 9490550d19SMattias Nilsson 9590550d19SMattias Nilsson static int __init ab8500_sysctrl_init(void) 9690550d19SMattias Nilsson { 9790550d19SMattias Nilsson return platform_driver_register(&ab8500_sysctrl_driver); 9890550d19SMattias Nilsson } 9990550d19SMattias Nilsson subsys_initcall(ab8500_sysctrl_init); 10090550d19SMattias Nilsson 10190550d19SMattias Nilsson MODULE_AUTHOR("Mattias Nilsson <[email protected]"); 10290550d19SMattias Nilsson MODULE_DESCRIPTION("AB8500 system control driver"); 10390550d19SMattias Nilsson MODULE_LICENSE("GPL v2"); 104