| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Pinctrl based I2C DeMultiplexer |
|---|
| 3 | 4 | * |
|---|
| 4 | 5 | * Copyright (C) 2015-16 by Wolfram Sang, Sang Engineering <wsa@sang-engineering.com> |
|---|
| 5 | 6 | * Copyright (C) 2015-16 by Renesas Electronics Corporation |
|---|
| 6 | | - * |
|---|
| 7 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 8 | | - * under the terms of the GNU General Public License as published by the |
|---|
| 9 | | - * Free Software Foundation; version 2 of the License. |
|---|
| 10 | 7 | * |
|---|
| 11 | 8 | * See the bindings doc for DTS setup and the sysfs doc for usage information. |
|---|
| 12 | 9 | * (look for filenames containing 'i2c-demux-pinctrl' in Documentation/) |
|---|
| .. | .. |
|---|
| 99 | 96 | |
|---|
| 100 | 97 | /* Now fill out current adapter structure. cur_chan must be up to date */ |
|---|
| 101 | 98 | priv->algo.master_xfer = i2c_demux_master_xfer; |
|---|
| 99 | + if (adap->algo->master_xfer_atomic) |
|---|
| 100 | + priv->algo.master_xfer_atomic = i2c_demux_master_xfer; |
|---|
| 102 | 101 | priv->algo.functionality = i2c_demux_functionality; |
|---|
| 103 | 102 | |
|---|
| 104 | 103 | snprintf(priv->cur_adap.name, sizeof(priv->cur_adap.name), |
|---|
| .. | .. |
|---|
| 219 | 218 | return -EINVAL; |
|---|
| 220 | 219 | } |
|---|
| 221 | 220 | |
|---|
| 222 | | - priv = devm_kzalloc(&pdev->dev, sizeof(*priv) |
|---|
| 223 | | - + num_chan * sizeof(struct i2c_demux_pinctrl_chan), GFP_KERNEL); |
|---|
| 221 | + priv = devm_kzalloc(&pdev->dev, struct_size(priv, chan, num_chan), |
|---|
| 222 | + GFP_KERNEL); |
|---|
| 224 | 223 | |
|---|
| 225 | 224 | props = devm_kcalloc(&pdev->dev, num_chan, sizeof(*props), GFP_KERNEL); |
|---|
| 226 | 225 | |
|---|
| .. | .. |
|---|
| 244 | 243 | |
|---|
| 245 | 244 | props[i].name = devm_kstrdup(&pdev->dev, "status", GFP_KERNEL); |
|---|
| 246 | 245 | props[i].value = devm_kstrdup(&pdev->dev, "ok", GFP_KERNEL); |
|---|
| 246 | + if (!props[i].name || !props[i].value) { |
|---|
| 247 | + err = -ENOMEM; |
|---|
| 248 | + goto err_rollback; |
|---|
| 249 | + } |
|---|
| 247 | 250 | props[i].length = 3; |
|---|
| 248 | 251 | |
|---|
| 249 | 252 | of_changeset_init(&priv->chan[i].chgset); |
|---|
| .. | .. |
|---|
| 262 | 265 | |
|---|
| 263 | 266 | err = device_create_file(&pdev->dev, &dev_attr_available_masters); |
|---|
| 264 | 267 | if (err) |
|---|
| 265 | | - goto err_rollback; |
|---|
| 268 | + goto err_rollback_activation; |
|---|
| 266 | 269 | |
|---|
| 267 | 270 | err = device_create_file(&pdev->dev, &dev_attr_current_master); |
|---|
| 268 | 271 | if (err) |
|---|
| .. | .. |
|---|
| 272 | 275 | |
|---|
| 273 | 276 | err_rollback_available: |
|---|
| 274 | 277 | device_remove_file(&pdev->dev, &dev_attr_available_masters); |
|---|
| 275 | | -err_rollback: |
|---|
| 278 | +err_rollback_activation: |
|---|
| 276 | 279 | i2c_demux_deactivate_master(priv); |
|---|
| 280 | +err_rollback: |
|---|
| 277 | 281 | for (j = 0; j < i; j++) { |
|---|
| 278 | 282 | of_node_put(priv->chan[j].parent_np); |
|---|
| 279 | 283 | of_changeset_destroy(&priv->chan[j].chgset); |
|---|