10e3d6777SRyder Lee // SPDX-License-Identifier: ISC
217f1de56SFelix Fietkau /*
317f1de56SFelix Fietkau * Copyright (C) 2016 Felix Fietkau <nbd@nbd.name>
417f1de56SFelix Fietkau */
517f1de56SFelix Fietkau #include <linux/of.h>
617f1de56SFelix Fietkau #include <linux/of_net.h>
717f1de56SFelix Fietkau #include <linux/mtd/mtd.h>
817f1de56SFelix Fietkau #include <linux/mtd/partitions.h>
95bef3a40SChristian Marangi #include <linux/nvmem-consumer.h>
1017f1de56SFelix Fietkau #include <linux/etherdevice.h>
1117f1de56SFelix Fietkau #include "mt76.h"
1217f1de56SFelix Fietkau
mt76_get_of_eeprom_data(struct mt76_dev * dev,void * eep,int len)137d424a99SChristian Marangi static int mt76_get_of_eeprom_data(struct mt76_dev *dev, void *eep, int len)
1417f1de56SFelix Fietkau {
1517f1de56SFelix Fietkau struct device_node *np = dev->dev->of_node;
16255d3807SDaniel Golle const void *data;
1717f1de56SFelix Fietkau int size;
1817f1de56SFelix Fietkau
19255d3807SDaniel Golle data = of_get_property(np, "mediatek,eeprom-data", &size);
207d424a99SChristian Marangi if (!data)
217d424a99SChristian Marangi return -ENOENT;
227d424a99SChristian Marangi
23255d3807SDaniel Golle if (size > len)
24255d3807SDaniel Golle return -EINVAL;
25255d3807SDaniel Golle
26255d3807SDaniel Golle memcpy(eep, data, size);
27255d3807SDaniel Golle
28255d3807SDaniel Golle return 0;
29255d3807SDaniel Golle }
30255d3807SDaniel Golle
mt76_get_of_epprom_from_mtd(struct mt76_dev * dev,void * eep,int offset,int len)317d424a99SChristian Marangi static int mt76_get_of_epprom_from_mtd(struct mt76_dev *dev, void *eep, int offset, int len)
327d424a99SChristian Marangi {
337d424a99SChristian Marangi #ifdef CONFIG_MTD
347d424a99SChristian Marangi struct device_node *np = dev->dev->of_node;
357d424a99SChristian Marangi struct mtd_info *mtd;
367d424a99SChristian Marangi const __be32 *list;
377d424a99SChristian Marangi const char *part;
387d424a99SChristian Marangi phandle phandle;
397d424a99SChristian Marangi size_t retlen;
407d424a99SChristian Marangi int size;
417d424a99SChristian Marangi int ret;
427d424a99SChristian Marangi
4317f1de56SFelix Fietkau list = of_get_property(np, "mediatek,mtd-eeprom", &size);
4417f1de56SFelix Fietkau if (!list)
4517f1de56SFelix Fietkau return -ENOENT;
4617f1de56SFelix Fietkau
4717f1de56SFelix Fietkau phandle = be32_to_cpup(list++);
4817f1de56SFelix Fietkau if (!phandle)
4917f1de56SFelix Fietkau return -ENOENT;
5017f1de56SFelix Fietkau
5117f1de56SFelix Fietkau np = of_find_node_by_phandle(phandle);
5217f1de56SFelix Fietkau if (!np)
5317f1de56SFelix Fietkau return -EINVAL;
5417f1de56SFelix Fietkau
5517f1de56SFelix Fietkau part = of_get_property(np, "label", NULL);
5617f1de56SFelix Fietkau if (!part)
5717f1de56SFelix Fietkau part = np->name;
5817f1de56SFelix Fietkau
5917f1de56SFelix Fietkau mtd = get_mtd_device_nm(part);
6034e022d8SWen Yang if (IS_ERR(mtd)) {
6134e022d8SWen Yang ret = PTR_ERR(mtd);
6234e022d8SWen Yang goto out_put_node;
6334e022d8SWen Yang }
6417f1de56SFelix Fietkau
6534e022d8SWen Yang if (size <= sizeof(*list)) {
6634e022d8SWen Yang ret = -EINVAL;
6734e022d8SWen Yang goto out_put_node;
6834e022d8SWen Yang }
6917f1de56SFelix Fietkau
70*c30d0fcbSChristian Marangi offset += be32_to_cpup(list);
71495184acSRyder Lee ret = mtd_read(mtd, offset, len, &retlen, eep);
7217f1de56SFelix Fietkau put_mtd_device(mtd);
735b595b66SDaniel Golle if (mtd_is_bitflip(ret))
745b595b66SDaniel Golle ret = 0;
752c4766fdSHauke Mehrtens if (ret) {
762c4766fdSHauke Mehrtens dev_err(dev->dev, "reading EEPROM from mtd %s failed: %i\n",
772c4766fdSHauke Mehrtens part, ret);
7834e022d8SWen Yang goto out_put_node;
792c4766fdSHauke Mehrtens }
8034e022d8SWen Yang
8134e022d8SWen Yang if (retlen < len) {
8234e022d8SWen Yang ret = -EINVAL;
8334e022d8SWen Yang goto out_put_node;
8434e022d8SWen Yang }
8534e022d8SWen Yang
86b3c6d638SLorenzo Bianconi if (of_property_read_bool(dev->dev->of_node, "big-endian")) {
87495184acSRyder Lee u8 *data = (u8 *)eep;
88b3c6d638SLorenzo Bianconi int i;
89b3c6d638SLorenzo Bianconi
90b3c6d638SLorenzo Bianconi /* convert eeprom data in Little Endian */
91b3c6d638SLorenzo Bianconi for (i = 0; i < round_down(len, 2); i += 2)
92b3c6d638SLorenzo Bianconi put_unaligned_le16(get_unaligned_be16(&data[i]),
93b3c6d638SLorenzo Bianconi &data[i]);
94b3c6d638SLorenzo Bianconi }
95b3c6d638SLorenzo Bianconi
96f0efa862SFelix Fietkau #ifdef CONFIG_NL80211_TESTMODE
97e7a6a044SShayne Chen dev->test_mtd.name = devm_kstrdup(dev->dev, part, GFP_KERNEL);
98e7a6a044SShayne Chen dev->test_mtd.offset = offset;
99f0efa862SFelix Fietkau #endif
100f0efa862SFelix Fietkau
10134e022d8SWen Yang out_put_node:
10234e022d8SWen Yang of_node_put(np);
10317f1de56SFelix Fietkau return ret;
10417f1de56SFelix Fietkau #else
10517f1de56SFelix Fietkau return -ENOENT;
10617f1de56SFelix Fietkau #endif
10717f1de56SFelix Fietkau }
1087d424a99SChristian Marangi
mt76_get_of_eeprom_from_nvmem(struct mt76_dev * dev,void * eep,int len)109b9b61d15SChristian Marangi static int mt76_get_of_eeprom_from_nvmem(struct mt76_dev *dev, void *eep, int len)
1105bef3a40SChristian Marangi {
1115bef3a40SChristian Marangi struct device_node *np = dev->dev->of_node;
1125bef3a40SChristian Marangi struct nvmem_cell *cell;
1135bef3a40SChristian Marangi const void *data;
1145bef3a40SChristian Marangi size_t retlen;
1155bef3a40SChristian Marangi int ret = 0;
1165bef3a40SChristian Marangi
1175bef3a40SChristian Marangi cell = of_nvmem_cell_get(np, "eeprom");
1185bef3a40SChristian Marangi if (IS_ERR(cell))
1195bef3a40SChristian Marangi return PTR_ERR(cell);
1205bef3a40SChristian Marangi
1215bef3a40SChristian Marangi data = nvmem_cell_read(cell, &retlen);
1225bef3a40SChristian Marangi nvmem_cell_put(cell);
1235bef3a40SChristian Marangi
1245bef3a40SChristian Marangi if (IS_ERR(data))
1255bef3a40SChristian Marangi return PTR_ERR(data);
1265bef3a40SChristian Marangi
1275bef3a40SChristian Marangi if (retlen < len) {
1285bef3a40SChristian Marangi ret = -EINVAL;
1295bef3a40SChristian Marangi goto exit;
1305bef3a40SChristian Marangi }
1315bef3a40SChristian Marangi
1325bef3a40SChristian Marangi memcpy(eep, data, len);
1335bef3a40SChristian Marangi
1345bef3a40SChristian Marangi exit:
1355bef3a40SChristian Marangi kfree(data);
1365bef3a40SChristian Marangi
1375bef3a40SChristian Marangi return ret;
1385bef3a40SChristian Marangi }
1395bef3a40SChristian Marangi
mt76_get_of_eeprom(struct mt76_dev * dev,void * eep,int offset,int len)1407d424a99SChristian Marangi int mt76_get_of_eeprom(struct mt76_dev *dev, void *eep, int offset, int len)
1417d424a99SChristian Marangi {
1427d424a99SChristian Marangi struct device_node *np = dev->dev->of_node;
1437d424a99SChristian Marangi int ret;
1447d424a99SChristian Marangi
1457d424a99SChristian Marangi if (!np)
1467d424a99SChristian Marangi return -ENOENT;
1477d424a99SChristian Marangi
1487d424a99SChristian Marangi ret = mt76_get_of_eeprom_data(dev, eep, len);
1497d424a99SChristian Marangi if (!ret)
1507d424a99SChristian Marangi return 0;
1517d424a99SChristian Marangi
1525bef3a40SChristian Marangi ret = mt76_get_of_epprom_from_mtd(dev, eep, offset, len);
1535bef3a40SChristian Marangi if (!ret)
1545bef3a40SChristian Marangi return 0;
1555bef3a40SChristian Marangi
156b9b61d15SChristian Marangi return mt76_get_of_eeprom_from_nvmem(dev, eep, len);
1577d424a99SChristian Marangi }
158495184acSRyder Lee EXPORT_SYMBOL_GPL(mt76_get_of_eeprom);
15917f1de56SFelix Fietkau
16017f1de56SFelix Fietkau void
mt76_eeprom_override(struct mt76_phy * phy)16198df2baeSLorenzo Bianconi mt76_eeprom_override(struct mt76_phy *phy)
16217f1de56SFelix Fietkau {
16398df2baeSLorenzo Bianconi struct mt76_dev *dev = phy->dev;
16417f1de56SFelix Fietkau struct device_node *np = dev->dev->of_node;
16517f1de56SFelix Fietkau
16683216e39SMichael Walle of_get_mac_address(np, phy->macaddr);
16717f1de56SFelix Fietkau
16898df2baeSLorenzo Bianconi if (!is_valid_ether_addr(phy->macaddr)) {
16998df2baeSLorenzo Bianconi eth_random_addr(phy->macaddr);
17017f1de56SFelix Fietkau dev_info(dev->dev,
17117f1de56SFelix Fietkau "Invalid MAC address, using random address %pM\n",
17298df2baeSLorenzo Bianconi phy->macaddr);
17317f1de56SFelix Fietkau }
17417f1de56SFelix Fietkau }
17517f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_eeprom_override);
17617f1de56SFelix Fietkau
mt76_string_prop_find(struct property * prop,const char * str)17722b980baSFelix Fietkau static bool mt76_string_prop_find(struct property *prop, const char *str)
17822b980baSFelix Fietkau {
17922b980baSFelix Fietkau const char *cp = NULL;
18022b980baSFelix Fietkau
18122b980baSFelix Fietkau if (!prop || !str || !str[0])
18222b980baSFelix Fietkau return false;
18322b980baSFelix Fietkau
18422b980baSFelix Fietkau while ((cp = of_prop_next_string(prop, cp)) != NULL)
18522b980baSFelix Fietkau if (!strcasecmp(cp, str))
18622b980baSFelix Fietkau return true;
18722b980baSFelix Fietkau
18822b980baSFelix Fietkau return false;
18922b980baSFelix Fietkau }
19022b980baSFelix Fietkau
19122b980baSFelix Fietkau static struct device_node *
mt76_find_power_limits_node(struct mt76_dev * dev)19222b980baSFelix Fietkau mt76_find_power_limits_node(struct mt76_dev *dev)
19322b980baSFelix Fietkau {
19422b980baSFelix Fietkau struct device_node *np = dev->dev->of_node;
19522b980baSFelix Fietkau const char *const region_names[] = {
196518c5d77SDeren Wu [NL80211_DFS_UNSET] = "ww",
19722b980baSFelix Fietkau [NL80211_DFS_ETSI] = "etsi",
19822b980baSFelix Fietkau [NL80211_DFS_FCC] = "fcc",
19922b980baSFelix Fietkau [NL80211_DFS_JP] = "jp",
20022b980baSFelix Fietkau };
20122b980baSFelix Fietkau struct device_node *cur, *fallback = NULL;
20222b980baSFelix Fietkau const char *region_name = NULL;
20322b980baSFelix Fietkau
20422b980baSFelix Fietkau if (dev->region < ARRAY_SIZE(region_names))
20522b980baSFelix Fietkau region_name = region_names[dev->region];
20622b980baSFelix Fietkau
20722b980baSFelix Fietkau np = of_get_child_by_name(np, "power-limits");
20822b980baSFelix Fietkau if (!np)
20922b980baSFelix Fietkau return NULL;
21022b980baSFelix Fietkau
21122b980baSFelix Fietkau for_each_child_of_node(np, cur) {
21222b980baSFelix Fietkau struct property *country = of_find_property(cur, "country", NULL);
21322b980baSFelix Fietkau struct property *regd = of_find_property(cur, "regdomain", NULL);
21422b980baSFelix Fietkau
21522b980baSFelix Fietkau if (!country && !regd) {
21622b980baSFelix Fietkau fallback = cur;
21722b980baSFelix Fietkau continue;
21822b980baSFelix Fietkau }
21922b980baSFelix Fietkau
22022b980baSFelix Fietkau if (mt76_string_prop_find(country, dev->alpha2) ||
2213bd53ea0SLiang He mt76_string_prop_find(regd, region_name)) {
2223bd53ea0SLiang He of_node_put(np);
22322b980baSFelix Fietkau return cur;
22422b980baSFelix Fietkau }
2253bd53ea0SLiang He }
22622b980baSFelix Fietkau
2273bd53ea0SLiang He of_node_put(np);
22822b980baSFelix Fietkau return fallback;
22922b980baSFelix Fietkau }
23022b980baSFelix Fietkau
23122b980baSFelix Fietkau static const __be32 *
mt76_get_of_array(struct device_node * np,char * name,size_t * len,int min)23222b980baSFelix Fietkau mt76_get_of_array(struct device_node *np, char *name, size_t *len, int min)
23322b980baSFelix Fietkau {
23422b980baSFelix Fietkau struct property *prop = of_find_property(np, name, NULL);
23522b980baSFelix Fietkau
23622b980baSFelix Fietkau if (!prop || !prop->value || prop->length < min * 4)
23722b980baSFelix Fietkau return NULL;
23822b980baSFelix Fietkau
23922b980baSFelix Fietkau *len = prop->length;
24022b980baSFelix Fietkau
24122b980baSFelix Fietkau return prop->value;
24222b980baSFelix Fietkau }
24322b980baSFelix Fietkau
24422b980baSFelix Fietkau static struct device_node *
mt76_find_channel_node(struct device_node * np,struct ieee80211_channel * chan)24522b980baSFelix Fietkau mt76_find_channel_node(struct device_node *np, struct ieee80211_channel *chan)
24622b980baSFelix Fietkau {
24722b980baSFelix Fietkau struct device_node *cur;
24822b980baSFelix Fietkau const __be32 *val;
24922b980baSFelix Fietkau size_t len;
25022b980baSFelix Fietkau
25122b980baSFelix Fietkau for_each_child_of_node(np, cur) {
25222b980baSFelix Fietkau val = mt76_get_of_array(cur, "channels", &len, 2);
25322b980baSFelix Fietkau if (!val)
25422b980baSFelix Fietkau continue;
25522b980baSFelix Fietkau
25622b980baSFelix Fietkau while (len >= 2 * sizeof(*val)) {
25722b980baSFelix Fietkau if (chan->hw_value >= be32_to_cpu(val[0]) &&
25822b980baSFelix Fietkau chan->hw_value <= be32_to_cpu(val[1]))
25922b980baSFelix Fietkau return cur;
26022b980baSFelix Fietkau
26122b980baSFelix Fietkau val += 2;
26222b980baSFelix Fietkau len -= 2 * sizeof(*val);
26322b980baSFelix Fietkau }
26422b980baSFelix Fietkau }
26522b980baSFelix Fietkau
26622b980baSFelix Fietkau return NULL;
26722b980baSFelix Fietkau }
26822b980baSFelix Fietkau
26922b980baSFelix Fietkau static s8
mt76_get_txs_delta(struct device_node * np,u8 nss)27022b980baSFelix Fietkau mt76_get_txs_delta(struct device_node *np, u8 nss)
27122b980baSFelix Fietkau {
27222b980baSFelix Fietkau const __be32 *val;
27322b980baSFelix Fietkau size_t len;
27422b980baSFelix Fietkau
27522b980baSFelix Fietkau val = mt76_get_of_array(np, "txs-delta", &len, nss);
27622b980baSFelix Fietkau if (!val)
27722b980baSFelix Fietkau return 0;
27822b980baSFelix Fietkau
27922b980baSFelix Fietkau return be32_to_cpu(val[nss - 1]);
28022b980baSFelix Fietkau }
28122b980baSFelix Fietkau
28222b980baSFelix Fietkau static void
mt76_apply_array_limit(s8 * pwr,size_t pwr_len,const __be32 * data,s8 target_power,s8 nss_delta,s8 * max_power)28322b980baSFelix Fietkau mt76_apply_array_limit(s8 *pwr, size_t pwr_len, const __be32 *data,
28422b980baSFelix Fietkau s8 target_power, s8 nss_delta, s8 *max_power)
28522b980baSFelix Fietkau {
28622b980baSFelix Fietkau int i;
28722b980baSFelix Fietkau
28822b980baSFelix Fietkau if (!data)
28922b980baSFelix Fietkau return;
29022b980baSFelix Fietkau
29122b980baSFelix Fietkau for (i = 0; i < pwr_len; i++) {
29222b980baSFelix Fietkau pwr[i] = min_t(s8, target_power,
29322b980baSFelix Fietkau be32_to_cpu(data[i]) + nss_delta);
29422b980baSFelix Fietkau *max_power = max(*max_power, pwr[i]);
29522b980baSFelix Fietkau }
29622b980baSFelix Fietkau }
29722b980baSFelix Fietkau
298a9627d99SShayne Chen static void
mt76_apply_multi_array_limit(s8 * pwr,size_t pwr_len,s8 pwr_num,const __be32 * data,size_t len,s8 target_power,s8 nss_delta,s8 * max_power)299a9627d99SShayne Chen mt76_apply_multi_array_limit(s8 *pwr, size_t pwr_len, s8 pwr_num,
300a9627d99SShayne Chen const __be32 *data, size_t len, s8 target_power,
301a9627d99SShayne Chen s8 nss_delta, s8 *max_power)
302a9627d99SShayne Chen {
303a9627d99SShayne Chen int i, cur;
304a9627d99SShayne Chen
305a9627d99SShayne Chen if (!data)
306a9627d99SShayne Chen return;
307a9627d99SShayne Chen
308a9627d99SShayne Chen len /= 4;
309a9627d99SShayne Chen cur = be32_to_cpu(data[0]);
310a9627d99SShayne Chen for (i = 0; i < pwr_num; i++) {
311a9627d99SShayne Chen if (len < pwr_len + 1)
312a9627d99SShayne Chen break;
313a9627d99SShayne Chen
314a9627d99SShayne Chen mt76_apply_array_limit(pwr + pwr_len * i, pwr_len, data + 1,
315a9627d99SShayne Chen target_power, nss_delta, max_power);
316a9627d99SShayne Chen if (--cur > 0)
317a9627d99SShayne Chen continue;
318a9627d99SShayne Chen
319a9627d99SShayne Chen data += pwr_len + 1;
320a9627d99SShayne Chen len -= pwr_len + 1;
321a9627d99SShayne Chen if (!len)
322a9627d99SShayne Chen break;
323a9627d99SShayne Chen
324a9627d99SShayne Chen cur = be32_to_cpu(data[0]);
325a9627d99SShayne Chen }
326a9627d99SShayne Chen }
327a9627d99SShayne Chen
mt76_get_rate_power_limits(struct mt76_phy * phy,struct ieee80211_channel * chan,struct mt76_power_limits * dest,s8 target_power)32822b980baSFelix Fietkau s8 mt76_get_rate_power_limits(struct mt76_phy *phy,
32922b980baSFelix Fietkau struct ieee80211_channel *chan,
33022b980baSFelix Fietkau struct mt76_power_limits *dest,
33122b980baSFelix Fietkau s8 target_power)
33222b980baSFelix Fietkau {
33322b980baSFelix Fietkau struct mt76_dev *dev = phy->dev;
33422b980baSFelix Fietkau struct device_node *np;
33522b980baSFelix Fietkau const __be32 *val;
33622b980baSFelix Fietkau char name[16];
33722b980baSFelix Fietkau u32 mcs_rates = dev->drv->mcs_rates;
338a9627d99SShayne Chen u32 ru_rates = ARRAY_SIZE(dest->ru[0]);
33922b980baSFelix Fietkau char band;
34022b980baSFelix Fietkau size_t len;
34122b980baSFelix Fietkau s8 max_power = 0;
34222b980baSFelix Fietkau s8 txs_delta;
34322b980baSFelix Fietkau
34422b980baSFelix Fietkau if (!mcs_rates)
34522b980baSFelix Fietkau mcs_rates = 10;
34622b980baSFelix Fietkau
34722b980baSFelix Fietkau memset(dest, target_power, sizeof(*dest));
34822b980baSFelix Fietkau
34922b980baSFelix Fietkau if (!IS_ENABLED(CONFIG_OF))
35022b980baSFelix Fietkau return target_power;
35122b980baSFelix Fietkau
35222b980baSFelix Fietkau np = mt76_find_power_limits_node(dev);
35322b980baSFelix Fietkau if (!np)
35422b980baSFelix Fietkau return target_power;
35522b980baSFelix Fietkau
35622b980baSFelix Fietkau switch (chan->band) {
35722b980baSFelix Fietkau case NL80211_BAND_2GHZ:
35822b980baSFelix Fietkau band = '2';
35922b980baSFelix Fietkau break;
36022b980baSFelix Fietkau case NL80211_BAND_5GHZ:
36122b980baSFelix Fietkau band = '5';
36222b980baSFelix Fietkau break;
3639b2ea8eeSLorenzo Bianconi case NL80211_BAND_6GHZ:
3649b2ea8eeSLorenzo Bianconi band = '6';
3659b2ea8eeSLorenzo Bianconi break;
36622b980baSFelix Fietkau default:
36722b980baSFelix Fietkau return target_power;
36822b980baSFelix Fietkau }
36922b980baSFelix Fietkau
37022b980baSFelix Fietkau snprintf(name, sizeof(name), "txpower-%cg", band);
37122b980baSFelix Fietkau np = of_get_child_by_name(np, name);
37222b980baSFelix Fietkau if (!np)
37322b980baSFelix Fietkau return target_power;
37422b980baSFelix Fietkau
37522b980baSFelix Fietkau np = mt76_find_channel_node(np, chan);
37622b980baSFelix Fietkau if (!np)
37722b980baSFelix Fietkau return target_power;
37822b980baSFelix Fietkau
37922b980baSFelix Fietkau txs_delta = mt76_get_txs_delta(np, hweight8(phy->antenna_mask));
38022b980baSFelix Fietkau
38122b980baSFelix Fietkau val = mt76_get_of_array(np, "rates-cck", &len, ARRAY_SIZE(dest->cck));
38222b980baSFelix Fietkau mt76_apply_array_limit(dest->cck, ARRAY_SIZE(dest->cck), val,
38322b980baSFelix Fietkau target_power, txs_delta, &max_power);
38422b980baSFelix Fietkau
38522b980baSFelix Fietkau val = mt76_get_of_array(np, "rates-ofdm",
38622b980baSFelix Fietkau &len, ARRAY_SIZE(dest->ofdm));
38722b980baSFelix Fietkau mt76_apply_array_limit(dest->ofdm, ARRAY_SIZE(dest->ofdm), val,
38822b980baSFelix Fietkau target_power, txs_delta, &max_power);
38922b980baSFelix Fietkau
39022b980baSFelix Fietkau val = mt76_get_of_array(np, "rates-mcs", &len, mcs_rates + 1);
391a9627d99SShayne Chen mt76_apply_multi_array_limit(dest->mcs[0], ARRAY_SIZE(dest->mcs[0]),
392a9627d99SShayne Chen ARRAY_SIZE(dest->mcs), val, len,
393a9627d99SShayne Chen target_power, txs_delta, &max_power);
39422b980baSFelix Fietkau
395a9627d99SShayne Chen val = mt76_get_of_array(np, "rates-ru", &len, ru_rates + 1);
396a9627d99SShayne Chen mt76_apply_multi_array_limit(dest->ru[0], ARRAY_SIZE(dest->ru[0]),
397a9627d99SShayne Chen ARRAY_SIZE(dest->ru), val, len,
398a9627d99SShayne Chen target_power, txs_delta, &max_power);
39922b980baSFelix Fietkau
40022b980baSFelix Fietkau return max_power;
40122b980baSFelix Fietkau }
40222b980baSFelix Fietkau EXPORT_SYMBOL_GPL(mt76_get_rate_power_limits);
40322b980baSFelix Fietkau
40417f1de56SFelix Fietkau int
mt76_eeprom_init(struct mt76_dev * dev,int len)40517f1de56SFelix Fietkau mt76_eeprom_init(struct mt76_dev *dev, int len)
40617f1de56SFelix Fietkau {
40717f1de56SFelix Fietkau dev->eeprom.size = len;
40817f1de56SFelix Fietkau dev->eeprom.data = devm_kzalloc(dev->dev, len, GFP_KERNEL);
40917f1de56SFelix Fietkau if (!dev->eeprom.data)
41017f1de56SFelix Fietkau return -ENOMEM;
41117f1de56SFelix Fietkau
412495184acSRyder Lee return !mt76_get_of_eeprom(dev, dev->eeprom.data, 0, len);
41317f1de56SFelix Fietkau }
41417f1de56SFelix Fietkau EXPORT_SYMBOL_GPL(mt76_eeprom_init);
415