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