GNU Linux-libre 4.19.286-gnu1
[releases.git] / drivers / net / wireless / mediatek / mt76 / eeprom.c
1 /*
2  * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
3  *
4  * Permission to use, copy, modify, and/or distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 #include <linux/of.h>
17 #include <linux/of_net.h>
18 #include <linux/mtd/mtd.h>
19 #include <linux/mtd/partitions.h>
20 #include <linux/etherdevice.h>
21 #include "mt76.h"
22
23 static int
24 mt76_get_of_eeprom(struct mt76_dev *dev, int len)
25 {
26 #if defined(CONFIG_OF) && defined(CONFIG_MTD)
27         struct device_node *np = dev->dev->of_node;
28         struct mtd_info *mtd;
29         const __be32 *list;
30         const char *part;
31         phandle phandle;
32         int offset = 0;
33         int size;
34         size_t retlen;
35         int ret;
36
37         if (!np)
38                 return -ENOENT;
39
40         list = of_get_property(np, "mediatek,mtd-eeprom", &size);
41         if (!list)
42                 return -ENOENT;
43
44         phandle = be32_to_cpup(list++);
45         if (!phandle)
46                 return -ENOENT;
47
48         np = of_find_node_by_phandle(phandle);
49         if (!np)
50                 return -EINVAL;
51
52         part = of_get_property(np, "label", NULL);
53         if (!part)
54                 part = np->name;
55
56         mtd = get_mtd_device_nm(part);
57         if (IS_ERR(mtd)) {
58                 ret =  PTR_ERR(mtd);
59                 goto out_put_node;
60         }
61
62         if (size <= sizeof(*list)) {
63                 ret = -EINVAL;
64                 goto out_put_node;
65         }
66
67         offset = be32_to_cpup(list);
68         ret = mtd_read(mtd, offset, len, &retlen, dev->eeprom.data);
69         put_mtd_device(mtd);
70         if (ret)
71                 goto out_put_node;
72
73         if (retlen < len) {
74                 ret = -EINVAL;
75                 goto out_put_node;
76         }
77
78 out_put_node:
79         of_node_put(np);
80         return ret;
81 #else
82         return -ENOENT;
83 #endif
84 }
85
86 void
87 mt76_eeprom_override(struct mt76_dev *dev)
88 {
89 #ifdef CONFIG_OF
90         struct device_node *np = dev->dev->of_node;
91         const u8 *mac;
92
93         if (!np)
94                 return;
95
96         mac = of_get_mac_address(np);
97         if (mac)
98                 memcpy(dev->macaddr, mac, ETH_ALEN);
99 #endif
100
101         if (!is_valid_ether_addr(dev->macaddr)) {
102                 eth_random_addr(dev->macaddr);
103                 dev_info(dev->dev,
104                          "Invalid MAC address, using random address %pM\n",
105                          dev->macaddr);
106         }
107 }
108 EXPORT_SYMBOL_GPL(mt76_eeprom_override);
109
110 int
111 mt76_eeprom_init(struct mt76_dev *dev, int len)
112 {
113         dev->eeprom.size = len;
114         dev->eeprom.data = devm_kzalloc(dev->dev, len, GFP_KERNEL);
115         if (!dev->eeprom.data)
116                 return -ENOMEM;
117
118         return !mt76_get_of_eeprom(dev, len);
119 }
120 EXPORT_SYMBOL_GPL(mt76_eeprom_init);