1e5d76075SStephen Gallimore /* 2e5d76075SStephen Gallimore * Copyright (C) 2013 STMicroelectronics Limited 3e5d76075SStephen Gallimore * Author: Stephen Gallimore <stephen.gallimore@st.com> 4e5d76075SStephen Gallimore * 5e5d76075SStephen Gallimore * Inspired by mach-imx/src.c 6e5d76075SStephen Gallimore * 7e5d76075SStephen Gallimore * This program is free software; you can redistribute it and/or modify 8e5d76075SStephen Gallimore * it under the terms of the GNU General Public License as published by 9e5d76075SStephen Gallimore * the Free Software Foundation; either version 2 of the License, or 10e5d76075SStephen Gallimore * (at your option) any later version. 11e5d76075SStephen Gallimore */ 12e5d76075SStephen Gallimore #include <linux/kernel.h> 13e5d76075SStephen Gallimore #include <linux/platform_device.h> 14e5d76075SStephen Gallimore #include <linux/module.h> 15e5d76075SStephen Gallimore #include <linux/err.h> 16e5d76075SStephen Gallimore #include <linux/types.h> 17e5d76075SStephen Gallimore #include <linux/of_device.h> 18e5d76075SStephen Gallimore #include <linux/regmap.h> 19e5d76075SStephen Gallimore #include <linux/mfd/syscon.h> 20e5d76075SStephen Gallimore 21e5d76075SStephen Gallimore #include "reset-syscfg.h" 22e5d76075SStephen Gallimore 23e5d76075SStephen Gallimore /** 24e5d76075SStephen Gallimore * Reset channel regmap configuration 25e5d76075SStephen Gallimore * 26e5d76075SStephen Gallimore * @reset: regmap field for the channel's reset bit. 27e5d76075SStephen Gallimore * @ack: regmap field for the channel's ack bit (optional). 28e5d76075SStephen Gallimore */ 29e5d76075SStephen Gallimore struct syscfg_reset_channel { 30e5d76075SStephen Gallimore struct regmap_field *reset; 31e5d76075SStephen Gallimore struct regmap_field *ack; 32e5d76075SStephen Gallimore }; 33e5d76075SStephen Gallimore 34e5d76075SStephen Gallimore /** 35e5d76075SStephen Gallimore * A reset controller which groups together a set of related reset bits, which 36e5d76075SStephen Gallimore * may be located in different system configuration registers. 37e5d76075SStephen Gallimore * 38e5d76075SStephen Gallimore * @rst: base reset controller structure. 39e5d76075SStephen Gallimore * @active_low: are the resets in this controller active low, i.e. clearing 40e5d76075SStephen Gallimore * the reset bit puts the hardware into reset. 41e5d76075SStephen Gallimore * @channels: An array of reset channels for this controller. 42e5d76075SStephen Gallimore */ 43e5d76075SStephen Gallimore struct syscfg_reset_controller { 44e5d76075SStephen Gallimore struct reset_controller_dev rst; 45e5d76075SStephen Gallimore bool active_low; 46e5d76075SStephen Gallimore struct syscfg_reset_channel *channels; 47e5d76075SStephen Gallimore }; 48e5d76075SStephen Gallimore 49e5d76075SStephen Gallimore #define to_syscfg_reset_controller(_rst) \ 50e5d76075SStephen Gallimore container_of(_rst, struct syscfg_reset_controller, rst) 51e5d76075SStephen Gallimore 52e5d76075SStephen Gallimore static int syscfg_reset_program_hw(struct reset_controller_dev *rcdev, 53e5d76075SStephen Gallimore unsigned long idx, int assert) 54e5d76075SStephen Gallimore { 55e5d76075SStephen Gallimore struct syscfg_reset_controller *rst = to_syscfg_reset_controller(rcdev); 56e5d76075SStephen Gallimore const struct syscfg_reset_channel *ch; 57e5d76075SStephen Gallimore u32 ctrl_val = rst->active_low ? !assert : !!assert; 58e5d76075SStephen Gallimore int err; 59e5d76075SStephen Gallimore 60e5d76075SStephen Gallimore if (idx >= rcdev->nr_resets) 61e5d76075SStephen Gallimore return -EINVAL; 62e5d76075SStephen Gallimore 63e5d76075SStephen Gallimore ch = &rst->channels[idx]; 64e5d76075SStephen Gallimore 65e5d76075SStephen Gallimore err = regmap_field_write(ch->reset, ctrl_val); 66e5d76075SStephen Gallimore if (err) 67e5d76075SStephen Gallimore return err; 68e5d76075SStephen Gallimore 69e5d76075SStephen Gallimore if (ch->ack) { 70e5d76075SStephen Gallimore unsigned long timeout = jiffies + msecs_to_jiffies(1000); 71e5d76075SStephen Gallimore u32 ack_val; 72e5d76075SStephen Gallimore 73e5d76075SStephen Gallimore while (true) { 74e5d76075SStephen Gallimore err = regmap_field_read(ch->ack, &ack_val); 75e5d76075SStephen Gallimore if (err) 76e5d76075SStephen Gallimore return err; 77e5d76075SStephen Gallimore 78e5d76075SStephen Gallimore if (ack_val == ctrl_val) 79e5d76075SStephen Gallimore break; 80e5d76075SStephen Gallimore 81e5d76075SStephen Gallimore if (time_after(jiffies, timeout)) 82e5d76075SStephen Gallimore return -ETIME; 83e5d76075SStephen Gallimore 84e5d76075SStephen Gallimore cpu_relax(); 85e5d76075SStephen Gallimore } 86e5d76075SStephen Gallimore } 87e5d76075SStephen Gallimore 88e5d76075SStephen Gallimore return 0; 89e5d76075SStephen Gallimore } 90e5d76075SStephen Gallimore 91e5d76075SStephen Gallimore static int syscfg_reset_assert(struct reset_controller_dev *rcdev, 92e5d76075SStephen Gallimore unsigned long idx) 93e5d76075SStephen Gallimore { 94e5d76075SStephen Gallimore return syscfg_reset_program_hw(rcdev, idx, true); 95e5d76075SStephen Gallimore } 96e5d76075SStephen Gallimore 97e5d76075SStephen Gallimore static int syscfg_reset_deassert(struct reset_controller_dev *rcdev, 98e5d76075SStephen Gallimore unsigned long idx) 99e5d76075SStephen Gallimore { 100e5d76075SStephen Gallimore return syscfg_reset_program_hw(rcdev, idx, false); 101e5d76075SStephen Gallimore } 102e5d76075SStephen Gallimore 103e5d76075SStephen Gallimore static int syscfg_reset_dev(struct reset_controller_dev *rcdev, 104e5d76075SStephen Gallimore unsigned long idx) 105e5d76075SStephen Gallimore { 106e5d76075SStephen Gallimore int err = syscfg_reset_assert(rcdev, idx); 107e5d76075SStephen Gallimore if (err) 108e5d76075SStephen Gallimore return err; 109e5d76075SStephen Gallimore 110e5d76075SStephen Gallimore return syscfg_reset_deassert(rcdev, idx); 111e5d76075SStephen Gallimore } 112e5d76075SStephen Gallimore 113e5d76075SStephen Gallimore static struct reset_control_ops syscfg_reset_ops = { 114e5d76075SStephen Gallimore .reset = syscfg_reset_dev, 115e5d76075SStephen Gallimore .assert = syscfg_reset_assert, 116e5d76075SStephen Gallimore .deassert = syscfg_reset_deassert, 117e5d76075SStephen Gallimore }; 118e5d76075SStephen Gallimore 119e5d76075SStephen Gallimore static int syscfg_reset_controller_register(struct device *dev, 120e5d76075SStephen Gallimore const struct syscfg_reset_controller_data *data) 121e5d76075SStephen Gallimore { 122e5d76075SStephen Gallimore struct syscfg_reset_controller *rc; 123e5d76075SStephen Gallimore size_t size; 124e5d76075SStephen Gallimore int i, err; 125e5d76075SStephen Gallimore 126e5d76075SStephen Gallimore rc = devm_kzalloc(dev, sizeof(*rc), GFP_KERNEL); 127e5d76075SStephen Gallimore if (!rc) 128e5d76075SStephen Gallimore return -ENOMEM; 129e5d76075SStephen Gallimore 130e5d76075SStephen Gallimore size = sizeof(struct syscfg_reset_channel) * data->nr_channels; 131e5d76075SStephen Gallimore 132e5d76075SStephen Gallimore rc->channels = devm_kzalloc(dev, size, GFP_KERNEL); 133e5d76075SStephen Gallimore if (!rc->channels) 134e5d76075SStephen Gallimore return -ENOMEM; 135e5d76075SStephen Gallimore 136e5d76075SStephen Gallimore rc->rst.ops = &syscfg_reset_ops, 137e5d76075SStephen Gallimore rc->rst.of_node = dev->of_node; 138e5d76075SStephen Gallimore rc->rst.nr_resets = data->nr_channels; 139e5d76075SStephen Gallimore rc->active_low = data->active_low; 140e5d76075SStephen Gallimore 141e5d76075SStephen Gallimore for (i = 0; i < data->nr_channels; i++) { 142e5d76075SStephen Gallimore struct regmap *map; 143e5d76075SStephen Gallimore struct regmap_field *f; 144e5d76075SStephen Gallimore const char *compatible = data->channels[i].compatible; 145e5d76075SStephen Gallimore 146e5d76075SStephen Gallimore map = syscon_regmap_lookup_by_compatible(compatible); 147e5d76075SStephen Gallimore if (IS_ERR(map)) 148e5d76075SStephen Gallimore return PTR_ERR(map); 149e5d76075SStephen Gallimore 150e5d76075SStephen Gallimore f = devm_regmap_field_alloc(dev, map, data->channels[i].reset); 151e5d76075SStephen Gallimore if (IS_ERR(f)) 152e5d76075SStephen Gallimore return PTR_ERR(f); 153e5d76075SStephen Gallimore 154e5d76075SStephen Gallimore rc->channels[i].reset = f; 155e5d76075SStephen Gallimore 156e5d76075SStephen Gallimore if (!data->wait_for_ack) 157e5d76075SStephen Gallimore continue; 158e5d76075SStephen Gallimore 159e5d76075SStephen Gallimore f = devm_regmap_field_alloc(dev, map, data->channels[i].ack); 160e5d76075SStephen Gallimore if (IS_ERR(f)) 161e5d76075SStephen Gallimore return PTR_ERR(f); 162e5d76075SStephen Gallimore 163e5d76075SStephen Gallimore rc->channels[i].ack = f; 164e5d76075SStephen Gallimore } 165e5d76075SStephen Gallimore 166e5d76075SStephen Gallimore err = reset_controller_register(&rc->rst); 167e5d76075SStephen Gallimore if (!err) 168e5d76075SStephen Gallimore dev_info(dev, "registered\n"); 169e5d76075SStephen Gallimore 170e5d76075SStephen Gallimore return err; 171e5d76075SStephen Gallimore } 172e5d76075SStephen Gallimore 173e5d76075SStephen Gallimore int syscfg_reset_probe(struct platform_device *pdev) 174e5d76075SStephen Gallimore { 175e5d76075SStephen Gallimore struct device *dev = pdev ? &pdev->dev : NULL; 176e5d76075SStephen Gallimore const struct of_device_id *match; 177e5d76075SStephen Gallimore 178e5d76075SStephen Gallimore if (!dev || !dev->driver) 179e5d76075SStephen Gallimore return -ENODEV; 180e5d76075SStephen Gallimore 181e5d76075SStephen Gallimore match = of_match_device(dev->driver->of_match_table, dev); 182e5d76075SStephen Gallimore if (!match || !match->data) 183e5d76075SStephen Gallimore return -EINVAL; 184e5d76075SStephen Gallimore 185e5d76075SStephen Gallimore return syscfg_reset_controller_register(dev, match->data); 186e5d76075SStephen Gallimore } 187