18a56736aSDamien Horsley /* 28a56736aSDamien Horsley * Pistachio SoC Reset Controller driver 38a56736aSDamien Horsley * 48a56736aSDamien Horsley * Copyright (C) 2015 Imagination Technologies Ltd. 58a56736aSDamien Horsley * 68a56736aSDamien Horsley * Author: Damien Horsley <Damien.Horsley@imgtec.com> 78a56736aSDamien Horsley * 88a56736aSDamien Horsley * This program is free software; you can redistribute it and/or modify it 98a56736aSDamien Horsley * under the terms and conditions of the GNU General Public License, 108a56736aSDamien Horsley * version 2, as published by the Free Software Foundation. 118a56736aSDamien Horsley */ 128a56736aSDamien Horsley 138a56736aSDamien Horsley #include <linux/module.h> 148a56736aSDamien Horsley #include <linux/of.h> 158a56736aSDamien Horsley #include <linux/platform_device.h> 168a56736aSDamien Horsley #include <linux/regmap.h> 178a56736aSDamien Horsley #include <linux/reset-controller.h> 188a56736aSDamien Horsley #include <linux/slab.h> 198a56736aSDamien Horsley #include <linux/mfd/syscon.h> 208a56736aSDamien Horsley 218a56736aSDamien Horsley #include <dt-bindings/reset/pistachio-resets.h> 228a56736aSDamien Horsley 238a56736aSDamien Horsley #define PISTACHIO_SOFT_RESET 0 248a56736aSDamien Horsley 258a56736aSDamien Horsley struct pistachio_reset_data { 268a56736aSDamien Horsley struct reset_controller_dev rcdev; 278a56736aSDamien Horsley struct regmap *periph_regs; 288a56736aSDamien Horsley }; 298a56736aSDamien Horsley 308a56736aSDamien Horsley static inline int pistachio_reset_shift(unsigned long id) 318a56736aSDamien Horsley { 328a56736aSDamien Horsley switch (id) { 338a56736aSDamien Horsley case PISTACHIO_RESET_I2C0: 348a56736aSDamien Horsley case PISTACHIO_RESET_I2C1: 358a56736aSDamien Horsley case PISTACHIO_RESET_I2C2: 368a56736aSDamien Horsley case PISTACHIO_RESET_I2C3: 378a56736aSDamien Horsley case PISTACHIO_RESET_I2S_IN: 388a56736aSDamien Horsley case PISTACHIO_RESET_PRL_OUT: 398a56736aSDamien Horsley case PISTACHIO_RESET_SPDIF_OUT: 408a56736aSDamien Horsley case PISTACHIO_RESET_SPI: 418a56736aSDamien Horsley case PISTACHIO_RESET_PWM_PDM: 428a56736aSDamien Horsley case PISTACHIO_RESET_UART0: 438a56736aSDamien Horsley case PISTACHIO_RESET_UART1: 448a56736aSDamien Horsley case PISTACHIO_RESET_QSPI: 458a56736aSDamien Horsley case PISTACHIO_RESET_MDC: 468a56736aSDamien Horsley case PISTACHIO_RESET_SDHOST: 478a56736aSDamien Horsley case PISTACHIO_RESET_ETHERNET: 488a56736aSDamien Horsley case PISTACHIO_RESET_IR: 498a56736aSDamien Horsley case PISTACHIO_RESET_HASH: 508a56736aSDamien Horsley case PISTACHIO_RESET_TIMER: 518a56736aSDamien Horsley return id; 528a56736aSDamien Horsley case PISTACHIO_RESET_I2S_OUT: 538a56736aSDamien Horsley case PISTACHIO_RESET_SPDIF_IN: 548a56736aSDamien Horsley case PISTACHIO_RESET_EVT: 558a56736aSDamien Horsley return id + 6; 568a56736aSDamien Horsley case PISTACHIO_RESET_USB_H: 578a56736aSDamien Horsley case PISTACHIO_RESET_USB_PR: 588a56736aSDamien Horsley case PISTACHIO_RESET_USB_PHY_PR: 598a56736aSDamien Horsley case PISTACHIO_RESET_USB_PHY_PON: 608a56736aSDamien Horsley return id + 7; 618a56736aSDamien Horsley default: 628a56736aSDamien Horsley return -EINVAL; 638a56736aSDamien Horsley } 648a56736aSDamien Horsley } 658a56736aSDamien Horsley 668a56736aSDamien Horsley static int pistachio_reset_assert(struct reset_controller_dev *rcdev, 678a56736aSDamien Horsley unsigned long id) 688a56736aSDamien Horsley { 698a56736aSDamien Horsley struct pistachio_reset_data *rd; 708a56736aSDamien Horsley u32 mask; 718a56736aSDamien Horsley int shift; 728a56736aSDamien Horsley 738a56736aSDamien Horsley rd = container_of(rcdev, struct pistachio_reset_data, rcdev); 748a56736aSDamien Horsley shift = pistachio_reset_shift(id); 758a56736aSDamien Horsley if (shift < 0) 768a56736aSDamien Horsley return shift; 778a56736aSDamien Horsley mask = BIT(shift); 788a56736aSDamien Horsley 798a56736aSDamien Horsley return regmap_update_bits(rd->periph_regs, PISTACHIO_SOFT_RESET, 808a56736aSDamien Horsley mask, mask); 818a56736aSDamien Horsley } 828a56736aSDamien Horsley 838a56736aSDamien Horsley static int pistachio_reset_deassert(struct reset_controller_dev *rcdev, 848a56736aSDamien Horsley unsigned long id) 858a56736aSDamien Horsley { 868a56736aSDamien Horsley struct pistachio_reset_data *rd; 878a56736aSDamien Horsley u32 mask; 888a56736aSDamien Horsley int shift; 898a56736aSDamien Horsley 908a56736aSDamien Horsley rd = container_of(rcdev, struct pistachio_reset_data, rcdev); 918a56736aSDamien Horsley shift = pistachio_reset_shift(id); 928a56736aSDamien Horsley if (shift < 0) 938a56736aSDamien Horsley return shift; 948a56736aSDamien Horsley mask = BIT(shift); 958a56736aSDamien Horsley 968a56736aSDamien Horsley return regmap_update_bits(rd->periph_regs, PISTACHIO_SOFT_RESET, 978a56736aSDamien Horsley mask, 0); 988a56736aSDamien Horsley } 998a56736aSDamien Horsley 100*c0cc2609SPhilipp Zabel static const struct reset_control_ops pistachio_reset_ops = { 1018a56736aSDamien Horsley .assert = pistachio_reset_assert, 1028a56736aSDamien Horsley .deassert = pistachio_reset_deassert, 1038a56736aSDamien Horsley }; 1048a56736aSDamien Horsley 1058a56736aSDamien Horsley static int pistachio_reset_probe(struct platform_device *pdev) 1068a56736aSDamien Horsley { 1078a56736aSDamien Horsley struct pistachio_reset_data *rd; 1088a56736aSDamien Horsley struct device *dev = &pdev->dev; 1098a56736aSDamien Horsley struct device_node *np = pdev->dev.of_node; 1108a56736aSDamien Horsley 1118a56736aSDamien Horsley rd = devm_kzalloc(dev, sizeof(*rd), GFP_KERNEL); 1128a56736aSDamien Horsley if (!rd) 1138a56736aSDamien Horsley return -ENOMEM; 1148a56736aSDamien Horsley 1158a56736aSDamien Horsley rd->periph_regs = syscon_node_to_regmap(np->parent); 1168a56736aSDamien Horsley if (IS_ERR(rd->periph_regs)) 1178a56736aSDamien Horsley return PTR_ERR(rd->periph_regs); 1188a56736aSDamien Horsley 1198a56736aSDamien Horsley rd->rcdev.owner = THIS_MODULE; 1208a56736aSDamien Horsley rd->rcdev.nr_resets = PISTACHIO_RESET_MAX + 1; 1218a56736aSDamien Horsley rd->rcdev.ops = &pistachio_reset_ops; 1228a56736aSDamien Horsley rd->rcdev.of_node = np; 1238a56736aSDamien Horsley 1248a56736aSDamien Horsley return reset_controller_register(&rd->rcdev); 1258a56736aSDamien Horsley } 1268a56736aSDamien Horsley 1278a56736aSDamien Horsley static int pistachio_reset_remove(struct platform_device *pdev) 1288a56736aSDamien Horsley { 1298a56736aSDamien Horsley struct pistachio_reset_data *data = platform_get_drvdata(pdev); 1308a56736aSDamien Horsley 1318a56736aSDamien Horsley reset_controller_unregister(&data->rcdev); 1328a56736aSDamien Horsley 1338a56736aSDamien Horsley return 0; 1348a56736aSDamien Horsley } 1358a56736aSDamien Horsley 1368a56736aSDamien Horsley static const struct of_device_id pistachio_reset_dt_ids[] = { 1378a56736aSDamien Horsley { .compatible = "img,pistachio-reset", }, 1388a56736aSDamien Horsley { /* sentinel */ }, 1398a56736aSDamien Horsley }; 1408a56736aSDamien Horsley MODULE_DEVICE_TABLE(of, pistachio_reset_dt_ids); 1418a56736aSDamien Horsley 1428a56736aSDamien Horsley static struct platform_driver pistachio_reset_driver = { 1438a56736aSDamien Horsley .probe = pistachio_reset_probe, 1448a56736aSDamien Horsley .remove = pistachio_reset_remove, 1458a56736aSDamien Horsley .driver = { 1468a56736aSDamien Horsley .name = "pistachio-reset", 1478a56736aSDamien Horsley .of_match_table = pistachio_reset_dt_ids, 1488a56736aSDamien Horsley }, 1498a56736aSDamien Horsley }; 1508a56736aSDamien Horsley module_platform_driver(pistachio_reset_driver); 1518a56736aSDamien Horsley 1528a56736aSDamien Horsley MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); 1538a56736aSDamien Horsley MODULE_DESCRIPTION("Pistacho Reset Controller Driver"); 1548a56736aSDamien Horsley MODULE_LICENSE("GPL v2"); 155