1*8a56736aSDamien Horsley /* 2*8a56736aSDamien Horsley * Pistachio SoC Reset Controller driver 3*8a56736aSDamien Horsley * 4*8a56736aSDamien Horsley * Copyright (C) 2015 Imagination Technologies Ltd. 5*8a56736aSDamien Horsley * 6*8a56736aSDamien Horsley * Author: Damien Horsley <Damien.Horsley@imgtec.com> 7*8a56736aSDamien Horsley * 8*8a56736aSDamien Horsley * This program is free software; you can redistribute it and/or modify it 9*8a56736aSDamien Horsley * under the terms and conditions of the GNU General Public License, 10*8a56736aSDamien Horsley * version 2, as published by the Free Software Foundation. 11*8a56736aSDamien Horsley */ 12*8a56736aSDamien Horsley 13*8a56736aSDamien Horsley #include <linux/module.h> 14*8a56736aSDamien Horsley #include <linux/of.h> 15*8a56736aSDamien Horsley #include <linux/platform_device.h> 16*8a56736aSDamien Horsley #include <linux/regmap.h> 17*8a56736aSDamien Horsley #include <linux/reset-controller.h> 18*8a56736aSDamien Horsley #include <linux/slab.h> 19*8a56736aSDamien Horsley #include <linux/mfd/syscon.h> 20*8a56736aSDamien Horsley 21*8a56736aSDamien Horsley #include <dt-bindings/reset/pistachio-resets.h> 22*8a56736aSDamien Horsley 23*8a56736aSDamien Horsley #define PISTACHIO_SOFT_RESET 0 24*8a56736aSDamien Horsley 25*8a56736aSDamien Horsley struct pistachio_reset_data { 26*8a56736aSDamien Horsley struct reset_controller_dev rcdev; 27*8a56736aSDamien Horsley struct regmap *periph_regs; 28*8a56736aSDamien Horsley }; 29*8a56736aSDamien Horsley 30*8a56736aSDamien Horsley static inline int pistachio_reset_shift(unsigned long id) 31*8a56736aSDamien Horsley { 32*8a56736aSDamien Horsley switch (id) { 33*8a56736aSDamien Horsley case PISTACHIO_RESET_I2C0: 34*8a56736aSDamien Horsley case PISTACHIO_RESET_I2C1: 35*8a56736aSDamien Horsley case PISTACHIO_RESET_I2C2: 36*8a56736aSDamien Horsley case PISTACHIO_RESET_I2C3: 37*8a56736aSDamien Horsley case PISTACHIO_RESET_I2S_IN: 38*8a56736aSDamien Horsley case PISTACHIO_RESET_PRL_OUT: 39*8a56736aSDamien Horsley case PISTACHIO_RESET_SPDIF_OUT: 40*8a56736aSDamien Horsley case PISTACHIO_RESET_SPI: 41*8a56736aSDamien Horsley case PISTACHIO_RESET_PWM_PDM: 42*8a56736aSDamien Horsley case PISTACHIO_RESET_UART0: 43*8a56736aSDamien Horsley case PISTACHIO_RESET_UART1: 44*8a56736aSDamien Horsley case PISTACHIO_RESET_QSPI: 45*8a56736aSDamien Horsley case PISTACHIO_RESET_MDC: 46*8a56736aSDamien Horsley case PISTACHIO_RESET_SDHOST: 47*8a56736aSDamien Horsley case PISTACHIO_RESET_ETHERNET: 48*8a56736aSDamien Horsley case PISTACHIO_RESET_IR: 49*8a56736aSDamien Horsley case PISTACHIO_RESET_HASH: 50*8a56736aSDamien Horsley case PISTACHIO_RESET_TIMER: 51*8a56736aSDamien Horsley return id; 52*8a56736aSDamien Horsley case PISTACHIO_RESET_I2S_OUT: 53*8a56736aSDamien Horsley case PISTACHIO_RESET_SPDIF_IN: 54*8a56736aSDamien Horsley case PISTACHIO_RESET_EVT: 55*8a56736aSDamien Horsley return id + 6; 56*8a56736aSDamien Horsley case PISTACHIO_RESET_USB_H: 57*8a56736aSDamien Horsley case PISTACHIO_RESET_USB_PR: 58*8a56736aSDamien Horsley case PISTACHIO_RESET_USB_PHY_PR: 59*8a56736aSDamien Horsley case PISTACHIO_RESET_USB_PHY_PON: 60*8a56736aSDamien Horsley return id + 7; 61*8a56736aSDamien Horsley default: 62*8a56736aSDamien Horsley return -EINVAL; 63*8a56736aSDamien Horsley } 64*8a56736aSDamien Horsley } 65*8a56736aSDamien Horsley 66*8a56736aSDamien Horsley static int pistachio_reset_assert(struct reset_controller_dev *rcdev, 67*8a56736aSDamien Horsley unsigned long id) 68*8a56736aSDamien Horsley { 69*8a56736aSDamien Horsley struct pistachio_reset_data *rd; 70*8a56736aSDamien Horsley u32 mask; 71*8a56736aSDamien Horsley int shift; 72*8a56736aSDamien Horsley 73*8a56736aSDamien Horsley rd = container_of(rcdev, struct pistachio_reset_data, rcdev); 74*8a56736aSDamien Horsley shift = pistachio_reset_shift(id); 75*8a56736aSDamien Horsley if (shift < 0) 76*8a56736aSDamien Horsley return shift; 77*8a56736aSDamien Horsley mask = BIT(shift); 78*8a56736aSDamien Horsley 79*8a56736aSDamien Horsley return regmap_update_bits(rd->periph_regs, PISTACHIO_SOFT_RESET, 80*8a56736aSDamien Horsley mask, mask); 81*8a56736aSDamien Horsley } 82*8a56736aSDamien Horsley 83*8a56736aSDamien Horsley static int pistachio_reset_deassert(struct reset_controller_dev *rcdev, 84*8a56736aSDamien Horsley unsigned long id) 85*8a56736aSDamien Horsley { 86*8a56736aSDamien Horsley struct pistachio_reset_data *rd; 87*8a56736aSDamien Horsley u32 mask; 88*8a56736aSDamien Horsley int shift; 89*8a56736aSDamien Horsley 90*8a56736aSDamien Horsley rd = container_of(rcdev, struct pistachio_reset_data, rcdev); 91*8a56736aSDamien Horsley shift = pistachio_reset_shift(id); 92*8a56736aSDamien Horsley if (shift < 0) 93*8a56736aSDamien Horsley return shift; 94*8a56736aSDamien Horsley mask = BIT(shift); 95*8a56736aSDamien Horsley 96*8a56736aSDamien Horsley return regmap_update_bits(rd->periph_regs, PISTACHIO_SOFT_RESET, 97*8a56736aSDamien Horsley mask, 0); 98*8a56736aSDamien Horsley } 99*8a56736aSDamien Horsley 100*8a56736aSDamien Horsley static struct reset_control_ops pistachio_reset_ops = { 101*8a56736aSDamien Horsley .assert = pistachio_reset_assert, 102*8a56736aSDamien Horsley .deassert = pistachio_reset_deassert, 103*8a56736aSDamien Horsley }; 104*8a56736aSDamien Horsley 105*8a56736aSDamien Horsley static int pistachio_reset_probe(struct platform_device *pdev) 106*8a56736aSDamien Horsley { 107*8a56736aSDamien Horsley struct pistachio_reset_data *rd; 108*8a56736aSDamien Horsley struct device *dev = &pdev->dev; 109*8a56736aSDamien Horsley struct device_node *np = pdev->dev.of_node; 110*8a56736aSDamien Horsley 111*8a56736aSDamien Horsley rd = devm_kzalloc(dev, sizeof(*rd), GFP_KERNEL); 112*8a56736aSDamien Horsley if (!rd) 113*8a56736aSDamien Horsley return -ENOMEM; 114*8a56736aSDamien Horsley 115*8a56736aSDamien Horsley rd->periph_regs = syscon_node_to_regmap(np->parent); 116*8a56736aSDamien Horsley if (IS_ERR(rd->periph_regs)) 117*8a56736aSDamien Horsley return PTR_ERR(rd->periph_regs); 118*8a56736aSDamien Horsley 119*8a56736aSDamien Horsley rd->rcdev.owner = THIS_MODULE; 120*8a56736aSDamien Horsley rd->rcdev.nr_resets = PISTACHIO_RESET_MAX + 1; 121*8a56736aSDamien Horsley rd->rcdev.ops = &pistachio_reset_ops; 122*8a56736aSDamien Horsley rd->rcdev.of_node = np; 123*8a56736aSDamien Horsley 124*8a56736aSDamien Horsley return reset_controller_register(&rd->rcdev); 125*8a56736aSDamien Horsley } 126*8a56736aSDamien Horsley 127*8a56736aSDamien Horsley static int pistachio_reset_remove(struct platform_device *pdev) 128*8a56736aSDamien Horsley { 129*8a56736aSDamien Horsley struct pistachio_reset_data *data = platform_get_drvdata(pdev); 130*8a56736aSDamien Horsley 131*8a56736aSDamien Horsley reset_controller_unregister(&data->rcdev); 132*8a56736aSDamien Horsley 133*8a56736aSDamien Horsley return 0; 134*8a56736aSDamien Horsley } 135*8a56736aSDamien Horsley 136*8a56736aSDamien Horsley static const struct of_device_id pistachio_reset_dt_ids[] = { 137*8a56736aSDamien Horsley { .compatible = "img,pistachio-reset", }, 138*8a56736aSDamien Horsley { /* sentinel */ }, 139*8a56736aSDamien Horsley }; 140*8a56736aSDamien Horsley MODULE_DEVICE_TABLE(of, pistachio_reset_dt_ids); 141*8a56736aSDamien Horsley 142*8a56736aSDamien Horsley static struct platform_driver pistachio_reset_driver = { 143*8a56736aSDamien Horsley .probe = pistachio_reset_probe, 144*8a56736aSDamien Horsley .remove = pistachio_reset_remove, 145*8a56736aSDamien Horsley .driver = { 146*8a56736aSDamien Horsley .name = "pistachio-reset", 147*8a56736aSDamien Horsley .of_match_table = pistachio_reset_dt_ids, 148*8a56736aSDamien Horsley }, 149*8a56736aSDamien Horsley }; 150*8a56736aSDamien Horsley module_platform_driver(pistachio_reset_driver); 151*8a56736aSDamien Horsley 152*8a56736aSDamien Horsley MODULE_AUTHOR("Damien Horsley <Damien.Horsley@imgtec.com>"); 153*8a56736aSDamien Horsley MODULE_DESCRIPTION("Pistacho Reset Controller Driver"); 154*8a56736aSDamien Horsley MODULE_LICENSE("GPL v2"); 155