1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Load Analog Devices SigmaStudio firmware files 4 * 5 * Copyright 2009-2011 Analog Devices Inc. 6 */ 7 8 #include <linux/export.h> 9 #include <linux/i2c.h> 10 #include <linux/module.h> 11 #include <linux/slab.h> 12 #include <asm/unaligned.h> 13 14 #include "sigmadsp.h" 15 16 static int sigmadsp_write_i2c(void *control_data, 17 unsigned int addr, const uint8_t data[], size_t len) 18 { 19 uint8_t *buf; 20 int ret; 21 22 buf = kzalloc(2 + len, GFP_KERNEL | GFP_DMA); 23 if (!buf) 24 return -ENOMEM; 25 26 put_unaligned_be16(addr, buf); 27 memcpy(buf + 2, data, len); 28 29 ret = i2c_master_send(control_data, buf, len + 2); 30 31 kfree(buf); 32 33 if (ret < 0) 34 return ret; 35 36 return 0; 37 } 38 39 static int sigmadsp_read_i2c(void *control_data, 40 unsigned int addr, uint8_t data[], size_t len) 41 { 42 struct i2c_client *client = control_data; 43 struct i2c_msg msgs[2]; 44 uint8_t buf[2]; 45 int ret; 46 47 put_unaligned_be16(addr, buf); 48 49 msgs[0].addr = client->addr; 50 msgs[0].len = sizeof(buf); 51 msgs[0].buf = buf; 52 msgs[0].flags = 0; 53 54 msgs[1].addr = client->addr; 55 msgs[1].len = len; 56 msgs[1].buf = data; 57 msgs[1].flags = I2C_M_RD; 58 59 ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 60 if (ret < 0) 61 return ret; 62 else if (ret != ARRAY_SIZE(msgs)) 63 return -EIO; 64 return 0; 65 } 66 67 /** 68 * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance 69 * @client: The parent I2C device 70 * @ops: The sigmadsp_ops to use for this instance 71 * @firmware_name: Name of the firmware file to load 72 * 73 * Allocates a SigmaDSP instance and loads the specified firmware file. 74 * 75 * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error. 76 */ 77 struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client, 78 const struct sigmadsp_ops *ops, const char *firmware_name) 79 { 80 struct sigmadsp *sigmadsp; 81 82 sigmadsp = devm_sigmadsp_init(&client->dev, ops, firmware_name); 83 if (IS_ERR(sigmadsp)) 84 return sigmadsp; 85 86 sigmadsp->control_data = client; 87 sigmadsp->write = sigmadsp_write_i2c; 88 sigmadsp->read = sigmadsp_read_i2c; 89 90 return sigmadsp; 91 } 92 EXPORT_SYMBOL_GPL(devm_sigmadsp_init_i2c); 93 94 MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); 95 MODULE_DESCRIPTION("SigmaDSP I2C firmware loader"); 96 MODULE_LICENSE("GPL"); 97