diff options
Diffstat (limited to 'drivers/net/wireless/mediatek/mt76/eeprom.c')
-rw-r--r-- | drivers/net/wireless/mediatek/mt76/eeprom.c | 120 |
1 files changed, 120 insertions, 0 deletions
diff --git a/drivers/net/wireless/mediatek/mt76/eeprom.c b/drivers/net/wireless/mediatek/mt76/eeprom.c new file mode 100644 index 000000000..a1529920d --- /dev/null +++ b/drivers/net/wireless/mediatek/mt76/eeprom.c @@ -0,0 +1,120 @@ +/* + * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#include <linux/of.h> +#include <linux/of_net.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <linux/etherdevice.h> +#include "mt76.h" + +static int +mt76_get_of_eeprom(struct mt76_dev *dev, int len) +{ +#if defined(CONFIG_OF) && defined(CONFIG_MTD) + struct device_node *np = dev->dev->of_node; + struct mtd_info *mtd; + const __be32 *list; + const char *part; + phandle phandle; + int offset = 0; + int size; + size_t retlen; + int ret; + + if (!np) + return -ENOENT; + + list = of_get_property(np, "mediatek,mtd-eeprom", &size); + if (!list) + return -ENOENT; + + phandle = be32_to_cpup(list++); + if (!phandle) + return -ENOENT; + + np = of_find_node_by_phandle(phandle); + if (!np) + return -EINVAL; + + part = of_get_property(np, "label", NULL); + if (!part) + part = np->name; + + mtd = get_mtd_device_nm(part); + if (IS_ERR(mtd)) { + ret = PTR_ERR(mtd); + goto out_put_node; + } + + if (size <= sizeof(*list)) { + ret = -EINVAL; + goto out_put_node; + } + + offset = be32_to_cpup(list); + ret = mtd_read(mtd, offset, len, &retlen, dev->eeprom.data); + put_mtd_device(mtd); + if (ret) + goto out_put_node; + + if (retlen < len) { + ret = -EINVAL; + goto out_put_node; + } + +out_put_node: + of_node_put(np); + return ret; +#else + return -ENOENT; +#endif +} + +void +mt76_eeprom_override(struct mt76_dev *dev) +{ +#ifdef CONFIG_OF + struct device_node *np = dev->dev->of_node; + const u8 *mac; + + if (!np) + return; + + mac = of_get_mac_address(np); + if (mac) + memcpy(dev->macaddr, mac, ETH_ALEN); +#endif + + if (!is_valid_ether_addr(dev->macaddr)) { + eth_random_addr(dev->macaddr); + dev_info(dev->dev, + "Invalid MAC address, using random address %pM\n", + dev->macaddr); + } +} +EXPORT_SYMBOL_GPL(mt76_eeprom_override); + +int +mt76_eeprom_init(struct mt76_dev *dev, int len) +{ + dev->eeprom.size = len; + dev->eeprom.data = devm_kzalloc(dev->dev, len, GFP_KERNEL); + if (!dev->eeprom.data) + return -ENOMEM; + + return !mt76_get_of_eeprom(dev, len); +} +EXPORT_SYMBOL_GPL(mt76_eeprom_init); |