1/*
2 *  Atheros AR71XX/AR724X/AR913X Calibration data in NAND flash fixup
3 *
4 *  Copyright (c) 2012 The Linux Foundation. All rights reserved.
5 *
6 *  This program is free software; you can redistribute it and/or modify it
7 *  under the terms of the GNU General Public License version 2 as published
8 *  by the Free Software Foundation.
9 */
10
11#include <linux/types.h>
12#include <linux/ath9k_platform.h>
13#include <linux/mtd/mtd.h>
14
15#include "dev-ap9x-pci.h"
16#include "dev-wmac.h"
17#include "dev-eth.h"
18#include "nand-caldata-fixup.h"
19
20static struct ath79_caldata_fixup *ath79_caldata;
21
22static void mtd_caldata_add(struct mtd_info *mtd)
23{
24	int i, ret;
25	size_t retlen;
26	struct ath9k_platform_data *wmac_pdata;
27	struct ag71xx_platform_data *eth_pdata;
28
29	/* If the device added doesn't match the name of the device containing
30	 * caldata, then we do nothing; just return */
31	if (strcmp(mtd->name, ath79_caldata->name))
32		return;
33
34	/* If the caldata PCIe address provided by the platform is non-null,
35	 * then fetch the data from MTD and fill it into the platform
36	 * structure */
37	for (i = 0;
38	     i < sizeof(ath79_caldata->pcie_caldata_addr) / sizeof(loff_t);
39	     i++) {
40		if (ath79_caldata->pcie_caldata_addr[i] == FIXUP_UNDEFINED)
41			continue;
42
43		wmac_pdata = ap9x_pci_get_wmac_data(i);
44
45		ret =
46		    mtd_read(mtd, ath79_caldata->pcie_caldata_addr[i],
47			     sizeof(wmac_pdata->eeprom_data), &retlen,
48			     (u_char *) wmac_pdata->eeprom_data);
49		if (retlen != sizeof(wmac_pdata->eeprom_data) || ret < 0) {
50			pr_err("%s: Error while reading %dB at offset 0x%08x\n",
51			       mtd->name, sizeof(wmac_pdata->eeprom_data),
52			       (u_int) ath79_caldata->pcie_caldata_addr[i]);
53		}
54	}
55
56	/* Same here for WMAC caldata */
57	if (ath79_caldata->wmac_caldata_addr != FIXUP_UNDEFINED) {
58		wmac_pdata = ath79_get_wmac_data();
59
60		ret =
61		    mtd_read(mtd, ath79_caldata->wmac_caldata_addr,
62			     sizeof(wmac_pdata->eeprom_data), &retlen,
63			     (u_char *) wmac_pdata->eeprom_data);
64		if (retlen != sizeof(wmac_pdata->eeprom_data) || ret < 0) {
65			pr_err("%s: Error while reading %dB at offset 0x%08x\n",
66			       mtd->name, sizeof(wmac_pdata->eeprom_data),
67			       (u_int) ath79_caldata->wmac_caldata_addr);
68		}
69	}
70
71	/* Same here for Ethernet MAC@ */
72	for (i = 0; i < sizeof(ath79_caldata->mac_addr) / sizeof(loff_t); i++) {
73		switch (i) {
74		case 0:
75			eth_pdata = &ath79_eth0_data;
76			break;
77		case 1:
78			eth_pdata = &ath79_eth1_data;
79			break;
80		default:
81			eth_pdata = NULL;
82		}
83
84		if (ath79_caldata->mac_addr[i] == FIXUP_UNDEFINED)
85			continue;
86
87		ret =
88		    mtd_read(mtd, ath79_caldata->mac_addr[i],
89			     sizeof(eth_pdata->mac_addr), &retlen,
90			     (u_char *) eth_pdata->mac_addr);
91		if (retlen != sizeof(eth_pdata->mac_addr) || ret < 0) {
92			pr_err("%s: Error while reading %dB at offset 0x%08x\n",
93			       mtd->name, sizeof(eth_pdata->mac_addr),
94			       (u_int) ath79_caldata->mac_addr[i]);
95		}
96	}
97}
98
99static void mtd_caldata_remove(struct mtd_info *mtd)
100{
101	return;
102}
103
104static void add_mtd_caldata_notifier(void)
105{
106	static struct mtd_notifier not = {
107		.add = mtd_caldata_add,
108		.remove = mtd_caldata_remove,
109	};
110
111	register_mtd_user(&not);
112}
113
114void __init ath79_mtd_caldata_fixup(struct ath79_caldata_fixup
115				    *platform_caldata)
116{
117	ath79_caldata = platform_caldata;
118	add_mtd_caldata_notifier();
119}
120