aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd')
-rw-r--r--drivers/mfd/Kconfig10
-rw-r--r--drivers/mfd/Makefile11
-rw-r--r--drivers/mfd/asic3.c40
-rw-r--r--drivers/mfd/mc13783-core.c4
-rw-r--r--drivers/mfd/t7l66xb.c55
-rw-r--r--drivers/mfd/tc6387xb.c119
-rw-r--r--drivers/mfd/tc6393xb.c56
-rw-r--r--drivers/mfd/timberdale.c727
-rw-r--r--drivers/mfd/timberdale.h130
-rw-r--r--drivers/mfd/tmio_core.c52
-rw-r--r--drivers/mfd/wm8350-core.c3
-rw-r--r--drivers/mfd/wm8350-irq.c4
12 files changed, 1134 insertions, 77 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 87829789243e..413576a2f313 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -348,6 +348,16 @@ config AB4500_CORE
348 read/write functions for the devices to get access to this chip. 348 read/write functions for the devices to get access to this chip.
349 This chip embeds various other multimedia funtionalities as well. 349 This chip embeds various other multimedia funtionalities as well.
350 350
351config MFD_TIMBERDALE
352 tristate "Support for the Timberdale FPGA"
353 select MFD_CORE
354 depends on PCI && GPIOLIB
355 ---help---
356 This is the core driver for the timberdale FPGA. This device is a
357 multifunction device which exposes numerous platform devices.
358
359 The timberdale FPGA can be found on the Intel Atom development board
360 for in-vehicle infontainment, called Russellville.
351endmenu 361endmenu
352 362
353menu "Multimedia Capabilities Port drivers" 363menu "Multimedia Capabilities Port drivers"
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index ca2f2c4ff05e..78295d6a75f7 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -3,7 +3,7 @@
3# 3#
4 4
5obj-$(CONFIG_MFD_SM501) += sm501.o 5obj-$(CONFIG_MFD_SM501) += sm501.o
6obj-$(CONFIG_MFD_ASIC3) += asic3.o 6obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
7obj-$(CONFIG_MFD_SH_MOBILE_SDHI) += sh_mobile_sdhi.o 7obj-$(CONFIG_MFD_SH_MOBILE_SDHI) += sh_mobile_sdhi.o
8 8
9obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o 9obj-$(CONFIG_HTC_EGPIO) += htc-egpio.o
@@ -11,9 +11,9 @@ obj-$(CONFIG_HTC_PASIC3) += htc-pasic3.o
11 11
12obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o 12obj-$(CONFIG_MFD_DM355EVM_MSP) += dm355evm_msp.o
13 13
14obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o 14obj-$(CONFIG_MFD_T7L66XB) += t7l66xb.o tmio_core.o
15obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o 15obj-$(CONFIG_MFD_TC6387XB) += tc6387xb.o tmio_core.o
16obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o 16obj-$(CONFIG_MFD_TC6393XB) += tc6393xb.o tmio_core.o
17 17
18obj-$(CONFIG_MFD_WM8400) += wm8400-core.o 18obj-$(CONFIG_MFD_WM8400) += wm8400-core.o
19wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o 19wm831x-objs := wm831x-core.o wm831x-irq.o wm831x-otp.o
@@ -54,5 +54,6 @@ obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o
54obj-$(CONFIG_AB3100_CORE) += ab3100-core.o 54obj-$(CONFIG_AB3100_CORE) += ab3100-core.o
55obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o 55obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o
56obj-$(CONFIG_AB4500_CORE) += ab4500-core.o 56obj-$(CONFIG_AB4500_CORE) += ab4500-core.o
57obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
57obj-$(CONFIG_MFD_88PM8607) += 88pm8607.o 58obj-$(CONFIG_MFD_88PM8607) += 88pm8607.o
58obj-$(CONFIG_PMIC_ADP5520) += adp5520.o \ No newline at end of file 59obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
diff --git a/drivers/mfd/asic3.c b/drivers/mfd/asic3.c
index e22128c3e9a8..95c1e6bd1729 100644
--- a/drivers/mfd/asic3.c
+++ b/drivers/mfd/asic3.c
@@ -80,6 +80,7 @@ struct asic3 {
80 u16 irq_bothedge[4]; 80 u16 irq_bothedge[4];
81 struct gpio_chip gpio; 81 struct gpio_chip gpio;
82 struct device *dev; 82 struct device *dev;
83 void __iomem *tmio_cnf;
83 84
84 struct asic3_clk clocks[ARRAY_SIZE(asic3_clk_init)]; 85 struct asic3_clk clocks[ARRAY_SIZE(asic3_clk_init)];
85}; 86};
@@ -685,8 +686,24 @@ static struct mfd_cell asic3_cell_ds1wm = {
685 .resources = ds1wm_resources, 686 .resources = ds1wm_resources,
686}; 687};
687 688
689static void asic3_mmc_pwr(struct platform_device *pdev, int state)
690{
691 struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
692
693 tmio_core_mmc_pwr(asic->tmio_cnf, 1 - asic->bus_shift, state);
694}
695
696static void asic3_mmc_clk_div(struct platform_device *pdev, int state)
697{
698 struct asic3 *asic = dev_get_drvdata(pdev->dev.parent);
699
700 tmio_core_mmc_clk_div(asic->tmio_cnf, 1 - asic->bus_shift, state);
701}
702
688static struct tmio_mmc_data asic3_mmc_data = { 703static struct tmio_mmc_data asic3_mmc_data = {
689 .hclk = 24576000, 704 .hclk = 24576000,
705 .set_pwr = asic3_mmc_pwr,
706 .set_clk_div = asic3_mmc_clk_div,
690}; 707};
691 708
692static struct resource asic3_mmc_resources[] = { 709static struct resource asic3_mmc_resources[] = {
@@ -696,11 +713,6 @@ static struct resource asic3_mmc_resources[] = {
696 .flags = IORESOURCE_MEM, 713 .flags = IORESOURCE_MEM,
697 }, 714 },
698 { 715 {
699 .start = ASIC3_SD_CONFIG_BASE,
700 .end = ASIC3_SD_CONFIG_BASE + 0x1ff,
701 .flags = IORESOURCE_MEM,
702 },
703 {
704 .start = 0, 716 .start = 0,
705 .end = 0, 717 .end = 0,
706 .flags = IORESOURCE_IRQ, 718 .flags = IORESOURCE_IRQ,
@@ -743,6 +755,10 @@ static int asic3_mmc_enable(struct platform_device *pdev)
743 asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF), 755 asic3_set_register(asic, ASIC3_OFFSET(SDHWCTRL, SDCONF),
744 ASIC3_SDHWCTRL_SDPWR, 1); 756 ASIC3_SDHWCTRL_SDPWR, 1);
745 757
758 /* ASIC3_SD_CTRL_BASE assumes 32-bit addressing, TMIO is 16-bit */
759 tmio_core_mmc_enable(asic->tmio_cnf, 1 - asic->bus_shift,
760 ASIC3_SD_CTRL_BASE >> 1);
761
746 return 0; 762 return 0;
747} 763}
748 764
@@ -797,10 +813,15 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
797 asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm); 813 asic3_cell_ds1wm.data_size = sizeof(asic3_cell_ds1wm);
798 814
799 /* MMC */ 815 /* MMC */
816 asic->tmio_cnf = ioremap((ASIC3_SD_CONFIG_BASE >> asic->bus_shift) +
817 mem_sdio->start, 0x400 >> asic->bus_shift);
818 if (!asic->tmio_cnf) {
819 ret = -ENOMEM;
820 dev_dbg(asic->dev, "Couldn't ioremap SD_CONFIG\n");
821 goto out;
822 }
800 asic3_mmc_resources[0].start >>= asic->bus_shift; 823 asic3_mmc_resources[0].start >>= asic->bus_shift;
801 asic3_mmc_resources[0].end >>= asic->bus_shift; 824 asic3_mmc_resources[0].end >>= asic->bus_shift;
802 asic3_mmc_resources[1].start >>= asic->bus_shift;
803 asic3_mmc_resources[1].end >>= asic->bus_shift;
804 825
805 asic3_cell_mmc.platform_data = &asic3_cell_mmc; 826 asic3_cell_mmc.platform_data = &asic3_cell_mmc;
806 asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc); 827 asic3_cell_mmc.data_size = sizeof(asic3_cell_mmc);
@@ -820,7 +841,10 @@ static int __init asic3_mfd_probe(struct platform_device *pdev,
820 841
821static void asic3_mfd_remove(struct platform_device *pdev) 842static void asic3_mfd_remove(struct platform_device *pdev)
822{ 843{
844 struct asic3 *asic = platform_get_drvdata(pdev);
845
823 mfd_remove_devices(&pdev->dev); 846 mfd_remove_devices(&pdev->dev);
847 iounmap(asic->tmio_cnf);
824} 848}
825 849
826/* Core */ 850/* Core */
diff --git a/drivers/mfd/mc13783-core.c b/drivers/mfd/mc13783-core.c
index a1ade2324ea9..735c8a4d164f 100644
--- a/drivers/mfd/mc13783-core.c
+++ b/drivers/mfd/mc13783-core.c
@@ -619,6 +619,8 @@ err_revision:
619 } 619 }
620 /* This should go away (END) */ 620 /* This should go away (END) */
621 621
622 mc13783_unlock(mc13783);
623
622 if (pdata->flags & MC13783_USE_ADC) 624 if (pdata->flags & MC13783_USE_ADC)
623 mc13783_add_subdevice(mc13783, "mc13783-adc"); 625 mc13783_add_subdevice(mc13783, "mc13783-adc");
624 626
@@ -641,8 +643,6 @@ err_revision:
641 if (pdata->flags & MC13783_USE_TOUCHSCREEN) 643 if (pdata->flags & MC13783_USE_TOUCHSCREEN)
642 mc13783_add_subdevice(mc13783, "mc13783-ts"); 644 mc13783_add_subdevice(mc13783, "mc13783-ts");
643 645
644 mc13783_unlock(mc13783);
645
646 return 0; 646 return 0;
647} 647}
648 648
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 0a255c1f1ce7..bcf4687d4af5 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -38,6 +38,19 @@ enum {
38 T7L66XB_CELL_MMC, 38 T7L66XB_CELL_MMC,
39}; 39};
40 40
41static const struct resource t7l66xb_mmc_resources[] = {
42 {
43 .start = 0x800,
44 .end = 0x9ff,
45 .flags = IORESOURCE_MEM,
46 },
47 {
48 .start = IRQ_T7L66XB_MMC,
49 .end = IRQ_T7L66XB_MMC,
50 .flags = IORESOURCE_IRQ,
51 },
52};
53
41#define SCR_REVID 0x08 /* b Revision ID */ 54#define SCR_REVID 0x08 /* b Revision ID */
42#define SCR_IMR 0x42 /* b Interrupt Mask */ 55#define SCR_IMR 0x42 /* b Interrupt Mask */
43#define SCR_DEV_CTL 0xe0 /* b Device control */ 56#define SCR_DEV_CTL 0xe0 /* b Device control */
@@ -83,6 +96,9 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc)
83 96
84 spin_unlock_irqrestore(&t7l66xb->lock, flags); 97 spin_unlock_irqrestore(&t7l66xb->lock, flags);
85 98
99 tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
100 t7l66xb_mmc_resources[0].start & 0xfffe);
101
86 return 0; 102 return 0;
87} 103}
88 104
@@ -106,28 +122,28 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc)
106 return 0; 122 return 0;
107} 123}
108 124
125static void t7l66xb_mmc_pwr(struct platform_device *mmc, int state)
126{
127 struct platform_device *dev = to_platform_device(mmc->dev.parent);
128 struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
129
130 tmio_core_mmc_pwr(t7l66xb->scr + 0x200, 0, state);
131}
132
133static void t7l66xb_mmc_clk_div(struct platform_device *mmc, int state)
134{
135 struct platform_device *dev = to_platform_device(mmc->dev.parent);
136 struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
137
138 tmio_core_mmc_clk_div(t7l66xb->scr + 0x200, 0, state);
139}
140
109/*--------------------------------------------------------------------------*/ 141/*--------------------------------------------------------------------------*/
110 142
111static struct tmio_mmc_data t7166xb_mmc_data = { 143static struct tmio_mmc_data t7166xb_mmc_data = {
112 .hclk = 24000000, 144 .hclk = 24000000,
113}; 145 .set_pwr = t7l66xb_mmc_pwr,
114 146 .set_clk_div = t7l66xb_mmc_clk_div,
115static const struct resource t7l66xb_mmc_resources[] = {
116 {
117 .start = 0x800,
118 .end = 0x9ff,
119 .flags = IORESOURCE_MEM,
120 },
121 {
122 .start = 0x200,
123 .end = 0x2ff,
124 .flags = IORESOURCE_MEM,
125 },
126 {
127 .start = IRQ_T7L66XB_MMC,
128 .end = IRQ_T7L66XB_MMC,
129 .flags = IORESOURCE_IRQ,
130 },
131}; 147};
132 148
133static const struct resource t7l66xb_nand_resources[] = { 149static const struct resource t7l66xb_nand_resources[] = {
@@ -282,6 +298,9 @@ static int t7l66xb_resume(struct platform_device *dev)
282 if (pdata && pdata->resume) 298 if (pdata && pdata->resume)
283 pdata->resume(dev); 299 pdata->resume(dev);
284 300
301 tmio_core_mmc_enable(t7l66xb->scr + 0x200, 0,
302 t7l66xb_mmc_resources[0].start & 0xfffe);
303
285 return 0; 304 return 0;
286} 305}
287#else 306#else
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c
index 3280ab33f88a..5c7f04343d5c 100644
--- a/drivers/mfd/tc6387xb.c
+++ b/drivers/mfd/tc6387xb.c
@@ -22,28 +22,52 @@ enum {
22 TC6387XB_CELL_MMC, 22 TC6387XB_CELL_MMC,
23}; 23};
24 24
25struct tc6387xb {
26 void __iomem *scr;
27 struct clk *clk32k;
28 struct resource rscr;
29};
30
31static struct resource tc6387xb_mmc_resources[] = {
32 {
33 .start = 0x800,
34 .end = 0x9ff,
35 .flags = IORESOURCE_MEM,
36 },
37 {
38 .start = 0,
39 .end = 0,
40 .flags = IORESOURCE_IRQ,
41 },
42};
43
44/*--------------------------------------------------------------------------*/
45
25#ifdef CONFIG_PM 46#ifdef CONFIG_PM
26static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state) 47static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state)
27{ 48{
28 struct clk *clk32k = platform_get_drvdata(dev); 49 struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
29 struct tc6387xb_platform_data *pdata = dev->dev.platform_data; 50 struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
30 51
31 if (pdata && pdata->suspend) 52 if (pdata && pdata->suspend)
32 pdata->suspend(dev); 53 pdata->suspend(dev);
33 clk_disable(clk32k); 54 clk_disable(tc6387xb->clk32k);
34 55
35 return 0; 56 return 0;
36} 57}
37 58
38static int tc6387xb_resume(struct platform_device *dev) 59static int tc6387xb_resume(struct platform_device *dev)
39{ 60{
40 struct clk *clk32k = platform_get_drvdata(dev); 61 struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
41 struct tc6387xb_platform_data *pdata = dev->dev.platform_data; 62 struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
42 63
43 clk_enable(clk32k); 64 clk_enable(tc6387xb->clk32k);
44 if (pdata && pdata->resume) 65 if (pdata && pdata->resume)
45 pdata->resume(dev); 66 pdata->resume(dev);
46 67
68 tmio_core_mmc_resume(tc6387xb->scr + 0x200, 0,
69 tc6387xb_mmc_resources[0].start & 0xfffe);
70
47 return 0; 71 return 0;
48} 72}
49#else 73#else
@@ -53,12 +77,32 @@ static int tc6387xb_resume(struct platform_device *dev)
53 77
54/*--------------------------------------------------------------------------*/ 78/*--------------------------------------------------------------------------*/
55 79
80static void tc6387xb_mmc_pwr(struct platform_device *mmc, int state)
81{
82 struct platform_device *dev = to_platform_device(mmc->dev.parent);
83 struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
84
85 tmio_core_mmc_pwr(tc6387xb->scr + 0x200, 0, state);
86}
87
88static void tc6387xb_mmc_clk_div(struct platform_device *mmc, int state)
89{
90 struct platform_device *dev = to_platform_device(mmc->dev.parent);
91 struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
92
93 tmio_core_mmc_clk_div(tc6387xb->scr + 0x200, 0, state);
94}
95
96
56static int tc6387xb_mmc_enable(struct platform_device *mmc) 97static int tc6387xb_mmc_enable(struct platform_device *mmc)
57{ 98{
58 struct platform_device *dev = to_platform_device(mmc->dev.parent); 99 struct platform_device *dev = to_platform_device(mmc->dev.parent);
59 struct clk *clk32k = platform_get_drvdata(dev); 100 struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
60 101
61 clk_enable(clk32k); 102 clk_enable(tc6387xb->clk32k);
103
104 tmio_core_mmc_enable(tc6387xb->scr + 0x200, 0,
105 tc6387xb_mmc_resources[0].start & 0xfffe);
62 106
63 return 0; 107 return 0;
64} 108}
@@ -66,36 +110,20 @@ static int tc6387xb_mmc_enable(struct platform_device *mmc)
66static int tc6387xb_mmc_disable(struct platform_device *mmc) 110static int tc6387xb_mmc_disable(struct platform_device *mmc)
67{ 111{
68 struct platform_device *dev = to_platform_device(mmc->dev.parent); 112 struct platform_device *dev = to_platform_device(mmc->dev.parent);
69 struct clk *clk32k = platform_get_drvdata(dev); 113 struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
70 114
71 clk_disable(clk32k); 115 clk_disable(tc6387xb->clk32k);
72 116
73 return 0; 117 return 0;
74} 118}
75 119
76/*--------------------------------------------------------------------------*/
77
78static struct tmio_mmc_data tc6387xb_mmc_data = { 120static struct tmio_mmc_data tc6387xb_mmc_data = {
79 .hclk = 24000000, 121 .hclk = 24000000,
122 .set_pwr = tc6387xb_mmc_pwr,
123 .set_clk_div = tc6387xb_mmc_clk_div,
80}; 124};
81 125
82static struct resource tc6387xb_mmc_resources[] = { 126/*--------------------------------------------------------------------------*/
83 {
84 .start = 0x800,
85 .end = 0x9ff,
86 .flags = IORESOURCE_MEM,
87 },
88 {
89 .start = 0x200,
90 .end = 0x2ff,
91 .flags = IORESOURCE_MEM,
92 },
93 {
94 .start = 0,
95 .end = 0,
96 .flags = IORESOURCE_IRQ,
97 },
98};
99 127
100static struct mfd_cell tc6387xb_cells[] = { 128static struct mfd_cell tc6387xb_cells[] = {
101 [TC6387XB_CELL_MMC] = { 129 [TC6387XB_CELL_MMC] = {
@@ -111,8 +139,9 @@ static struct mfd_cell tc6387xb_cells[] = {
111static int tc6387xb_probe(struct platform_device *dev) 139static int tc6387xb_probe(struct platform_device *dev)
112{ 140{
113 struct tc6387xb_platform_data *pdata = dev->dev.platform_data; 141 struct tc6387xb_platform_data *pdata = dev->dev.platform_data;
114 struct resource *iomem; 142 struct resource *iomem, *rscr;
115 struct clk *clk32k; 143 struct clk *clk32k;
144 struct tc6387xb *tc6387xb;
116 int irq, ret; 145 int irq, ret;
117 146
118 iomem = platform_get_resource(dev, IORESOURCE_MEM, 0); 147 iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
@@ -120,18 +149,40 @@ static int tc6387xb_probe(struct platform_device *dev)
120 return -EINVAL; 149 return -EINVAL;
121 } 150 }
122 151
152 tc6387xb = kzalloc(sizeof *tc6387xb, GFP_KERNEL);
153 if (!tc6387xb)
154 return -ENOMEM;
155
123 ret = platform_get_irq(dev, 0); 156 ret = platform_get_irq(dev, 0);
124 if (ret >= 0) 157 if (ret >= 0)
125 irq = ret; 158 irq = ret;
126 else 159 else
127 goto err_resource; 160 goto err_no_irq;
128 161
129 clk32k = clk_get(&dev->dev, "CLK_CK32K"); 162 clk32k = clk_get(&dev->dev, "CLK_CK32K");
130 if (IS_ERR(clk32k)) { 163 if (IS_ERR(clk32k)) {
131 ret = PTR_ERR(clk32k); 164 ret = PTR_ERR(clk32k);
165 goto err_no_clk;
166 }
167
168 rscr = &tc6387xb->rscr;
169 rscr->name = "tc6387xb-core";
170 rscr->start = iomem->start;
171 rscr->end = iomem->start + 0xff;
172 rscr->flags = IORESOURCE_MEM;
173
174 ret = request_resource(iomem, rscr);
175 if (ret)
132 goto err_resource; 176 goto err_resource;
177
178 tc6387xb->scr = ioremap(rscr->start, rscr->end - rscr->start + 1);
179 if (!tc6387xb->scr) {
180 ret = -ENOMEM;
181 goto err_ioremap;
133 } 182 }
134 platform_set_drvdata(dev, clk32k); 183
184 tc6387xb->clk32k = clk32k;
185 platform_set_drvdata(dev, tc6387xb);
135 186
136 if (pdata && pdata->enable) 187 if (pdata && pdata->enable)
137 pdata->enable(dev); 188 pdata->enable(dev);
@@ -149,8 +200,13 @@ static int tc6387xb_probe(struct platform_device *dev)
149 if (!ret) 200 if (!ret)
150 return 0; 201 return 0;
151 202
152 clk_put(clk32k); 203err_ioremap:
204 release_resource(&tc6387xb->rscr);
153err_resource: 205err_resource:
206 clk_put(clk32k);
207err_no_clk:
208err_no_irq:
209 kfree(tc6387xb);
154 return ret; 210 return ret;
155} 211}
156 212
@@ -195,3 +251,4 @@ MODULE_DESCRIPTION("Toshiba TC6387XB core driver");
195MODULE_LICENSE("GPL v2"); 251MODULE_LICENSE("GPL v2");
196MODULE_AUTHOR("Ian Molton"); 252MODULE_AUTHOR("Ian Molton");
197MODULE_ALIAS("platform:tc6387xb"); 253MODULE_ALIAS("platform:tc6387xb");
254
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index 1429a7341a9a..4bc5a08a2b09 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -136,10 +136,6 @@ static int tc6393xb_nand_enable(struct platform_device *nand)
136 return 0; 136 return 0;
137} 137}
138 138
139static struct tmio_mmc_data tc6393xb_mmc_data = {
140 .hclk = 24000000,
141};
142
143static struct resource __devinitdata tc6393xb_nand_resources[] = { 139static struct resource __devinitdata tc6393xb_nand_resources[] = {
144 { 140 {
145 .start = 0x1000, 141 .start = 0x1000,
@@ -165,11 +161,6 @@ static struct resource __devinitdata tc6393xb_mmc_resources[] = {
165 .flags = IORESOURCE_MEM, 161 .flags = IORESOURCE_MEM,
166 }, 162 },
167 { 163 {
168 .start = 0x200,
169 .end = 0x2ff,
170 .flags = IORESOURCE_MEM,
171 },
172 {
173 .start = IRQ_TC6393_MMC, 164 .start = IRQ_TC6393_MMC,
174 .end = IRQ_TC6393_MMC, 165 .end = IRQ_TC6393_MMC,
175 .flags = IORESOURCE_IRQ, 166 .flags = IORESOURCE_IRQ,
@@ -346,6 +337,50 @@ int tc6393xb_lcd_mode(struct platform_device *fb,
346} 337}
347EXPORT_SYMBOL(tc6393xb_lcd_mode); 338EXPORT_SYMBOL(tc6393xb_lcd_mode);
348 339
340static int tc6393xb_mmc_enable(struct platform_device *mmc)
341{
342 struct platform_device *dev = to_platform_device(mmc->dev.parent);
343 struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
344
345 tmio_core_mmc_enable(tc6393xb->scr + 0x200, 0,
346 tc6393xb_mmc_resources[0].start & 0xfffe);
347
348 return 0;
349}
350
351static int tc6393xb_mmc_resume(struct platform_device *mmc)
352{
353 struct platform_device *dev = to_platform_device(mmc->dev.parent);
354 struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
355
356 tmio_core_mmc_resume(tc6393xb->scr + 0x200, 0,
357 tc6393xb_mmc_resources[0].start & 0xfffe);
358
359 return 0;
360}
361
362static void tc6393xb_mmc_pwr(struct platform_device *mmc, int state)
363{
364 struct platform_device *dev = to_platform_device(mmc->dev.parent);
365 struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
366
367 tmio_core_mmc_pwr(tc6393xb->scr + 0x200, 0, state);
368}
369
370static void tc6393xb_mmc_clk_div(struct platform_device *mmc, int state)
371{
372 struct platform_device *dev = to_platform_device(mmc->dev.parent);
373 struct tc6393xb *tc6393xb = platform_get_drvdata(dev);
374
375 tmio_core_mmc_clk_div(tc6393xb->scr + 0x200, 0, state);
376}
377
378static struct tmio_mmc_data tc6393xb_mmc_data = {
379 .hclk = 24000000,
380 .set_pwr = tc6393xb_mmc_pwr,
381 .set_clk_div = tc6393xb_mmc_clk_div,
382};
383
349static struct mfd_cell __devinitdata tc6393xb_cells[] = { 384static struct mfd_cell __devinitdata tc6393xb_cells[] = {
350 [TC6393XB_CELL_NAND] = { 385 [TC6393XB_CELL_NAND] = {
351 .name = "tmio-nand", 386 .name = "tmio-nand",
@@ -355,6 +390,8 @@ static struct mfd_cell __devinitdata tc6393xb_cells[] = {
355 }, 390 },
356 [TC6393XB_CELL_MMC] = { 391 [TC6393XB_CELL_MMC] = {
357 .name = "tmio-mmc", 392 .name = "tmio-mmc",
393 .enable = tc6393xb_mmc_enable,
394 .resume = tc6393xb_mmc_resume,
358 .driver_data = &tc6393xb_mmc_data, 395 .driver_data = &tc6393xb_mmc_data,
359 .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources), 396 .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
360 .resources = tc6393xb_mmc_resources, 397 .resources = tc6393xb_mmc_resources,
@@ -836,3 +873,4 @@ MODULE_LICENSE("GPL v2");
836MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer"); 873MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer");
837MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller"); 874MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller");
838MODULE_ALIAS("platform:tc6393xb"); 875MODULE_ALIAS("platform:tc6393xb");
876
diff --git a/drivers/mfd/timberdale.c b/drivers/mfd/timberdale.c
new file mode 100644
index 000000000000..1ed44d283803
--- /dev/null
+++ b/drivers/mfd/timberdale.c
@@ -0,0 +1,727 @@
1/*
2 * timberdale.c timberdale FPGA MFD driver
3 * Copyright (c) 2009 Intel Corporation
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19/* Supports:
20 * Timberdale FPGA
21 */
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/pci.h>
26#include <linux/msi.h>
27#include <linux/mfd/core.h>
28
29#include <linux/timb_gpio.h>
30
31#include <linux/i2c.h>
32#include <linux/i2c-ocores.h>
33#include <linux/i2c/tsc2007.h>
34
35#include <linux/spi/spi.h>
36#include <linux/spi/xilinx_spi.h>
37#include <linux/spi/max7301.h>
38#include <linux/spi/mc33880.h>
39
40#include <media/timb_radio.h>
41
42#include "timberdale.h"
43
44#define DRIVER_NAME "timberdale"
45
46struct timberdale_device {
47 resource_size_t ctl_mapbase;
48 unsigned char __iomem *ctl_membase;
49 struct {
50 u32 major;
51 u32 minor;
52 u32 config;
53 } fw;
54};
55
56/*--------------------------------------------------------------------------*/
57
58static struct tsc2007_platform_data timberdale_tsc2007_platform_data = {
59 .model = 2003,
60 .x_plate_ohms = 100
61};
62
63static struct i2c_board_info timberdale_i2c_board_info[] = {
64 {
65 I2C_BOARD_INFO("tsc2007", 0x48),
66 .platform_data = &timberdale_tsc2007_platform_data,
67 .irq = IRQ_TIMBERDALE_TSC_INT
68 },
69};
70
71static __devinitdata struct ocores_i2c_platform_data
72timberdale_ocores_platform_data = {
73 .regstep = 4,
74 .clock_khz = 62500,
75 .devices = timberdale_i2c_board_info,
76 .num_devices = ARRAY_SIZE(timberdale_i2c_board_info)
77};
78
79const static __devinitconst struct resource timberdale_ocores_resources[] = {
80 {
81 .start = OCORESOFFSET,
82 .end = OCORESEND,
83 .flags = IORESOURCE_MEM,
84 },
85 {
86 .start = IRQ_TIMBERDALE_I2C,
87 .end = IRQ_TIMBERDALE_I2C,
88 .flags = IORESOURCE_IRQ,
89 },
90};
91
92const struct max7301_platform_data timberdale_max7301_platform_data = {
93 .base = 200
94};
95
96const struct mc33880_platform_data timberdale_mc33880_platform_data = {
97 .base = 100
98};
99
100static struct spi_board_info timberdale_spi_16bit_board_info[] = {
101 {
102 .modalias = "max7301",
103 .max_speed_hz = 26000,
104 .chip_select = 2,
105 .mode = SPI_MODE_0,
106 .platform_data = &timberdale_max7301_platform_data
107 },
108};
109
110static struct spi_board_info timberdale_spi_8bit_board_info[] = {
111 {
112 .modalias = "mc33880",
113 .max_speed_hz = 4000,
114 .chip_select = 1,
115 .mode = SPI_MODE_1,
116 .platform_data = &timberdale_mc33880_platform_data
117 },
118};
119
120static __devinitdata struct xspi_platform_data timberdale_xspi_platform_data = {
121 .num_chipselect = 3,
122 .little_endian = true,
123 /* bits per word and devices will be filled in runtime depending
124 * on the HW config
125 */
126};
127
128const static __devinitconst struct resource timberdale_spi_resources[] = {
129 {
130 .start = SPIOFFSET,
131 .end = SPIEND,
132 .flags = IORESOURCE_MEM,
133 },
134 {
135 .start = IRQ_TIMBERDALE_SPI,
136 .end = IRQ_TIMBERDALE_SPI,
137 .flags = IORESOURCE_IRQ,
138 },
139};
140
141const static __devinitconst struct resource timberdale_eth_resources[] = {
142 {
143 .start = ETHOFFSET,
144 .end = ETHEND,
145 .flags = IORESOURCE_MEM,
146 },
147 {
148 .start = IRQ_TIMBERDALE_ETHSW_IF,
149 .end = IRQ_TIMBERDALE_ETHSW_IF,
150 .flags = IORESOURCE_IRQ,
151 },
152};
153
154static __devinitdata struct timbgpio_platform_data
155 timberdale_gpio_platform_data = {
156 .gpio_base = 0,
157 .nr_pins = GPIO_NR_PINS,
158 .irq_base = 200,
159};
160
161const static __devinitconst struct resource timberdale_gpio_resources[] = {
162 {
163 .start = GPIOOFFSET,
164 .end = GPIOEND,
165 .flags = IORESOURCE_MEM,
166 },
167 {
168 .start = IRQ_TIMBERDALE_GPIO,
169 .end = IRQ_TIMBERDALE_GPIO,
170 .flags = IORESOURCE_IRQ,
171 },
172};
173
174const static __devinitconst struct resource timberdale_mlogicore_resources[] = {
175 {
176 .start = MLCOREOFFSET,
177 .end = MLCOREEND,
178 .flags = IORESOURCE_MEM,
179 },
180 {
181 .start = IRQ_TIMBERDALE_MLCORE,
182 .end = IRQ_TIMBERDALE_MLCORE,
183 .flags = IORESOURCE_IRQ,
184 },
185 {
186 .start = IRQ_TIMBERDALE_MLCORE_BUF,
187 .end = IRQ_TIMBERDALE_MLCORE_BUF,
188 .flags = IORESOURCE_IRQ,
189 },
190};
191
192const static __devinitconst struct resource timberdale_uart_resources[] = {
193 {
194 .start = UARTOFFSET,
195 .end = UARTEND,
196 .flags = IORESOURCE_MEM,
197 },
198 {
199 .start = IRQ_TIMBERDALE_UART,
200 .end = IRQ_TIMBERDALE_UART,
201 .flags = IORESOURCE_IRQ,
202 },
203};
204
205const static __devinitconst struct resource timberdale_uartlite_resources[] = {
206 {
207 .start = UARTLITEOFFSET,
208 .end = UARTLITEEND,
209 .flags = IORESOURCE_MEM,
210 },
211 {
212 .start = IRQ_TIMBERDALE_UARTLITE,
213 .end = IRQ_TIMBERDALE_UARTLITE,
214 .flags = IORESOURCE_IRQ,
215 },
216};
217
218const static __devinitconst struct resource timberdale_radio_resources[] = {
219 {
220 .start = RDSOFFSET,
221 .end = RDSEND,
222 .flags = IORESOURCE_MEM,
223 },
224 {
225 .start = IRQ_TIMBERDALE_RDS,
226 .end = IRQ_TIMBERDALE_RDS,
227 .flags = IORESOURCE_IRQ,
228 },
229};
230
231static __devinitdata struct i2c_board_info timberdale_tef6868_i2c_board_info = {
232 I2C_BOARD_INFO("tef6862", 0x60)
233};
234
235static __devinitdata struct i2c_board_info timberdale_saa7706_i2c_board_info = {
236 I2C_BOARD_INFO("saa7706h", 0x1C)
237};
238
239static __devinitdata struct timb_radio_platform_data
240 timberdale_radio_platform_data = {
241 .i2c_adapter = 0,
242 .tuner = {
243 .module_name = "tef6862",
244 .info = &timberdale_tef6868_i2c_board_info
245 },
246 .dsp = {
247 .module_name = "saa7706h",
248 .info = &timberdale_saa7706_i2c_board_info
249 }
250};
251
252const static __devinitconst struct resource timberdale_dma_resources[] = {
253 {
254 .start = DMAOFFSET,
255 .end = DMAEND,
256 .flags = IORESOURCE_MEM,
257 },
258 {
259 .start = IRQ_TIMBERDALE_DMA,
260 .end = IRQ_TIMBERDALE_DMA,
261 .flags = IORESOURCE_IRQ,
262 },
263};
264
265static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg0[] = {
266 {
267 .name = "timb-uart",
268 .num_resources = ARRAY_SIZE(timberdale_uart_resources),
269 .resources = timberdale_uart_resources,
270 },
271 {
272 .name = "timb-gpio",
273 .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
274 .resources = timberdale_gpio_resources,
275 .platform_data = &timberdale_gpio_platform_data,
276 .data_size = sizeof(timberdale_gpio_platform_data),
277 },
278 {
279 .name = "timb-radio",
280 .num_resources = ARRAY_SIZE(timberdale_radio_resources),
281 .resources = timberdale_radio_resources,
282 .platform_data = &timberdale_radio_platform_data,
283 .data_size = sizeof(timberdale_radio_platform_data),
284 },
285 {
286 .name = "xilinx_spi",
287 .num_resources = ARRAY_SIZE(timberdale_spi_resources),
288 .resources = timberdale_spi_resources,
289 .platform_data = &timberdale_xspi_platform_data,
290 .data_size = sizeof(timberdale_xspi_platform_data),
291 },
292 {
293 .name = "ks8842",
294 .num_resources = ARRAY_SIZE(timberdale_eth_resources),
295 .resources = timberdale_eth_resources,
296 },
297 {
298 .name = "timb-dma",
299 .num_resources = ARRAY_SIZE(timberdale_dma_resources),
300 .resources = timberdale_dma_resources,
301 },
302};
303
304static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg1[] = {
305 {
306 .name = "timb-uart",
307 .num_resources = ARRAY_SIZE(timberdale_uart_resources),
308 .resources = timberdale_uart_resources,
309 },
310 {
311 .name = "uartlite",
312 .num_resources = ARRAY_SIZE(timberdale_uartlite_resources),
313 .resources = timberdale_uartlite_resources,
314 },
315 {
316 .name = "timb-gpio",
317 .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
318 .resources = timberdale_gpio_resources,
319 .platform_data = &timberdale_gpio_platform_data,
320 .data_size = sizeof(timberdale_gpio_platform_data),
321 },
322 {
323 .name = "timb-mlogicore",
324 .num_resources = ARRAY_SIZE(timberdale_mlogicore_resources),
325 .resources = timberdale_mlogicore_resources,
326 },
327 {
328 .name = "timb-radio",
329 .num_resources = ARRAY_SIZE(timberdale_radio_resources),
330 .resources = timberdale_radio_resources,
331 .platform_data = &timberdale_radio_platform_data,
332 .data_size = sizeof(timberdale_radio_platform_data),
333 },
334 {
335 .name = "xilinx_spi",
336 .num_resources = ARRAY_SIZE(timberdale_spi_resources),
337 .resources = timberdale_spi_resources,
338 .platform_data = &timberdale_xspi_platform_data,
339 .data_size = sizeof(timberdale_xspi_platform_data),
340 },
341 {
342 .name = "ks8842",
343 .num_resources = ARRAY_SIZE(timberdale_eth_resources),
344 .resources = timberdale_eth_resources,
345 },
346 {
347 .name = "timb-dma",
348 .num_resources = ARRAY_SIZE(timberdale_dma_resources),
349 .resources = timberdale_dma_resources,
350 },
351};
352
353static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg2[] = {
354 {
355 .name = "timb-uart",
356 .num_resources = ARRAY_SIZE(timberdale_uart_resources),
357 .resources = timberdale_uart_resources,
358 },
359 {
360 .name = "timb-gpio",
361 .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
362 .resources = timberdale_gpio_resources,
363 .platform_data = &timberdale_gpio_platform_data,
364 .data_size = sizeof(timberdale_gpio_platform_data),
365 },
366 {
367 .name = "timb-radio",
368 .num_resources = ARRAY_SIZE(timberdale_radio_resources),
369 .resources = timberdale_radio_resources,
370 .platform_data = &timberdale_radio_platform_data,
371 .data_size = sizeof(timberdale_radio_platform_data),
372 },
373 {
374 .name = "xilinx_spi",
375 .num_resources = ARRAY_SIZE(timberdale_spi_resources),
376 .resources = timberdale_spi_resources,
377 .platform_data = &timberdale_xspi_platform_data,
378 .data_size = sizeof(timberdale_xspi_platform_data),
379 },
380 {
381 .name = "timb-dma",
382 .num_resources = ARRAY_SIZE(timberdale_dma_resources),
383 .resources = timberdale_dma_resources,
384 },
385};
386
387static __devinitdata struct mfd_cell timberdale_cells_bar0_cfg3[] = {
388 {
389 .name = "timb-uart",
390 .num_resources = ARRAY_SIZE(timberdale_uart_resources),
391 .resources = timberdale_uart_resources,
392 },
393 {
394 .name = "ocores-i2c",
395 .num_resources = ARRAY_SIZE(timberdale_ocores_resources),
396 .resources = timberdale_ocores_resources,
397 .platform_data = &timberdale_ocores_platform_data,
398 .data_size = sizeof(timberdale_ocores_platform_data),
399 },
400 {
401 .name = "timb-gpio",
402 .num_resources = ARRAY_SIZE(timberdale_gpio_resources),
403 .resources = timberdale_gpio_resources,
404 .platform_data = &timberdale_gpio_platform_data,
405 .data_size = sizeof(timberdale_gpio_platform_data),
406 },
407 {
408 .name = "timb-radio",
409 .num_resources = ARRAY_SIZE(timberdale_radio_resources),
410 .resources = timberdale_radio_resources,
411 .platform_data = &timberdale_radio_platform_data,
412 .data_size = sizeof(timberdale_radio_platform_data),
413 },
414 {
415 .name = "xilinx_spi",
416 .num_resources = ARRAY_SIZE(timberdale_spi_resources),
417 .resources = timberdale_spi_resources,
418 .platform_data = &timberdale_xspi_platform_data,
419 .data_size = sizeof(timberdale_xspi_platform_data),
420 },
421 {
422 .name = "ks8842",
423 .num_resources = ARRAY_SIZE(timberdale_eth_resources),
424 .resources = timberdale_eth_resources,
425 },
426 {
427 .name = "timb-dma",
428 .num_resources = ARRAY_SIZE(timberdale_dma_resources),
429 .resources = timberdale_dma_resources,
430 },
431};
432
433static const __devinitconst struct resource timberdale_sdhc_resources[] = {
434 /* located in bar 1 and bar 2 */
435 {
436 .start = SDHC0OFFSET,
437 .end = SDHC0END,
438 .flags = IORESOURCE_MEM,
439 },
440 {
441 .start = IRQ_TIMBERDALE_SDHC,
442 .end = IRQ_TIMBERDALE_SDHC,
443 .flags = IORESOURCE_IRQ,
444 },
445};
446
447static __devinitdata struct mfd_cell timberdale_cells_bar1[] = {
448 {
449 .name = "sdhci",
450 .num_resources = ARRAY_SIZE(timberdale_sdhc_resources),
451 .resources = timberdale_sdhc_resources,
452 },
453};
454
455static __devinitdata struct mfd_cell timberdale_cells_bar2[] = {
456 {
457 .name = "sdhci",
458 .num_resources = ARRAY_SIZE(timberdale_sdhc_resources),
459 .resources = timberdale_sdhc_resources,
460 },
461};
462
463static ssize_t show_fw_ver(struct device *dev, struct device_attribute *attr,
464 char *buf)
465{
466 struct pci_dev *pdev = to_pci_dev(dev);
467 struct timberdale_device *priv = pci_get_drvdata(pdev);
468
469 return sprintf(buf, "%d.%d.%d\n", priv->fw.major, priv->fw.minor,
470 priv->fw.config);
471}
472
473static DEVICE_ATTR(fw_ver, S_IRUGO, show_fw_ver, NULL);
474
475/*--------------------------------------------------------------------------*/
476
477static int __devinit timb_probe(struct pci_dev *dev,
478 const struct pci_device_id *id)
479{
480 struct timberdale_device *priv;
481 int err, i;
482 resource_size_t mapbase;
483 struct msix_entry *msix_entries = NULL;
484 u8 ip_setup;
485
486 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
487 if (!priv)
488 return -ENOMEM;
489
490 pci_set_drvdata(dev, priv);
491
492 err = pci_enable_device(dev);
493 if (err)
494 goto err_enable;
495
496 mapbase = pci_resource_start(dev, 0);
497 if (!mapbase) {
498 dev_err(&dev->dev, "No resource\n");
499 goto err_start;
500 }
501
502 /* create a resource for the PCI master register */
503 priv->ctl_mapbase = mapbase + CHIPCTLOFFSET;
504 if (!request_mem_region(priv->ctl_mapbase, CHIPCTLSIZE, "timb-ctl")) {
505 dev_err(&dev->dev, "Failed to request ctl mem\n");
506 goto err_request;
507 }
508
509 priv->ctl_membase = ioremap(priv->ctl_mapbase, CHIPCTLSIZE);
510 if (!priv->ctl_membase) {
511 dev_err(&dev->dev, "ioremap failed for ctl mem\n");
512 goto err_ioremap;
513 }
514
515 /* read the HW config */
516 priv->fw.major = ioread32(priv->ctl_membase + TIMB_REV_MAJOR);
517 priv->fw.minor = ioread32(priv->ctl_membase + TIMB_REV_MINOR);
518 priv->fw.config = ioread32(priv->ctl_membase + TIMB_HW_CONFIG);
519
520 if (priv->fw.major > TIMB_SUPPORTED_MAJOR) {
521 dev_err(&dev->dev, "The driver supports an older "
522 "version of the FPGA, please update the driver to "
523 "support %d.%d\n", priv->fw.major, priv->fw.minor);
524 goto err_ioremap;
525 }
526 if (priv->fw.major < TIMB_SUPPORTED_MAJOR ||
527 priv->fw.minor < TIMB_REQUIRED_MINOR) {
528 dev_err(&dev->dev, "The FPGA image is too old (%d.%d), "
529 "please upgrade the FPGA to at least: %d.%d\n",
530 priv->fw.major, priv->fw.minor,
531 TIMB_SUPPORTED_MAJOR, TIMB_REQUIRED_MINOR);
532 goto err_ioremap;
533 }
534
535 msix_entries = kzalloc(TIMBERDALE_NR_IRQS * sizeof(*msix_entries),
536 GFP_KERNEL);
537 if (!msix_entries)
538 goto err_ioremap;
539
540 for (i = 0; i < TIMBERDALE_NR_IRQS; i++)
541 msix_entries[i].entry = i;
542
543 err = pci_enable_msix(dev, msix_entries, TIMBERDALE_NR_IRQS);
544 if (err) {
545 dev_err(&dev->dev,
546 "MSI-X init failed: %d, expected entries: %d\n",
547 err, TIMBERDALE_NR_IRQS);
548 goto err_msix;
549 }
550
551 err = device_create_file(&dev->dev, &dev_attr_fw_ver);
552 if (err)
553 goto err_create_file;
554
555 /* Reset all FPGA PLB peripherals */
556 iowrite32(0x1, priv->ctl_membase + TIMB_SW_RST);
557
558 /* update IRQ offsets in I2C board info */
559 for (i = 0; i < ARRAY_SIZE(timberdale_i2c_board_info); i++)
560 timberdale_i2c_board_info[i].irq =
561 msix_entries[timberdale_i2c_board_info[i].irq].vector;
562
563 /* Update the SPI configuration depending on the HW (8 or 16 bit) */
564 if (priv->fw.config & TIMB_HW_CONFIG_SPI_8BIT) {
565 timberdale_xspi_platform_data.bits_per_word = 8;
566 timberdale_xspi_platform_data.devices =
567 timberdale_spi_8bit_board_info;
568 timberdale_xspi_platform_data.num_devices =
569 ARRAY_SIZE(timberdale_spi_8bit_board_info);
570 } else {
571 timberdale_xspi_platform_data.bits_per_word = 16;
572 timberdale_xspi_platform_data.devices =
573 timberdale_spi_16bit_board_info;
574 timberdale_xspi_platform_data.num_devices =
575 ARRAY_SIZE(timberdale_spi_16bit_board_info);
576 }
577
578 ip_setup = priv->fw.config & TIMB_HW_VER_MASK;
579 switch (ip_setup) {
580 case TIMB_HW_VER0:
581 err = mfd_add_devices(&dev->dev, -1,
582 timberdale_cells_bar0_cfg0,
583 ARRAY_SIZE(timberdale_cells_bar0_cfg0),
584 &dev->resource[0], msix_entries[0].vector);
585 break;
586 case TIMB_HW_VER1:
587 err = mfd_add_devices(&dev->dev, -1,
588 timberdale_cells_bar0_cfg1,
589 ARRAY_SIZE(timberdale_cells_bar0_cfg1),
590 &dev->resource[0], msix_entries[0].vector);
591 break;
592 case TIMB_HW_VER2:
593 err = mfd_add_devices(&dev->dev, -1,
594 timberdale_cells_bar0_cfg2,
595 ARRAY_SIZE(timberdale_cells_bar0_cfg2),
596 &dev->resource[0], msix_entries[0].vector);
597 break;
598 case TIMB_HW_VER3:
599 err = mfd_add_devices(&dev->dev, -1,
600 timberdale_cells_bar0_cfg3,
601 ARRAY_SIZE(timberdale_cells_bar0_cfg3),
602 &dev->resource[0], msix_entries[0].vector);
603 break;
604 default:
605 dev_err(&dev->dev, "Uknown IP setup: %d.%d.%d\n",
606 priv->fw.major, priv->fw.minor, ip_setup);
607 err = -ENODEV;
608 goto err_mfd;
609 break;
610 }
611
612 if (err) {
613 dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
614 goto err_mfd;
615 }
616
617 err = mfd_add_devices(&dev->dev, 0,
618 timberdale_cells_bar1, ARRAY_SIZE(timberdale_cells_bar1),
619 &dev->resource[1], msix_entries[0].vector);
620 if (err) {
621 dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
622 goto err_mfd2;
623 }
624
625 /* only version 0 and 3 have the iNand routed to SDHCI */
626 if (((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER0) ||
627 ((priv->fw.config & TIMB_HW_VER_MASK) == TIMB_HW_VER3)) {
628 err = mfd_add_devices(&dev->dev, 1, timberdale_cells_bar2,
629 ARRAY_SIZE(timberdale_cells_bar2),
630 &dev->resource[2], msix_entries[0].vector);
631 if (err) {
632 dev_err(&dev->dev, "mfd_add_devices failed: %d\n", err);
633 goto err_mfd2;
634 }
635 }
636
637 kfree(msix_entries);
638
639 dev_info(&dev->dev,
640 "Found Timberdale Card. Rev: %d.%d, HW config: 0x%02x\n",
641 priv->fw.major, priv->fw.minor, priv->fw.config);
642
643 return 0;
644
645err_mfd2:
646 mfd_remove_devices(&dev->dev);
647err_mfd:
648 device_remove_file(&dev->dev, &dev_attr_fw_ver);
649err_create_file:
650 pci_disable_msix(dev);
651err_msix:
652 iounmap(priv->ctl_membase);
653err_ioremap:
654 release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE);
655err_request:
656 pci_set_drvdata(dev, NULL);
657err_start:
658 pci_disable_device(dev);
659err_enable:
660 kfree(msix_entries);
661 kfree(priv);
662 pci_set_drvdata(dev, NULL);
663 return -ENODEV;
664}
665
666static void __devexit timb_remove(struct pci_dev *dev)
667{
668 struct timberdale_device *priv = pci_get_drvdata(dev);
669
670 mfd_remove_devices(&dev->dev);
671
672 device_remove_file(&dev->dev, &dev_attr_fw_ver);
673
674 iounmap(priv->ctl_membase);
675 release_mem_region(priv->ctl_mapbase, CHIPCTLSIZE);
676
677 pci_disable_msix(dev);
678 pci_disable_device(dev);
679 pci_set_drvdata(dev, NULL);
680 kfree(priv);
681}
682
683static struct pci_device_id timberdale_pci_tbl[] = {
684 { PCI_DEVICE(PCI_VENDOR_ID_TIMB, PCI_DEVICE_ID_TIMB) },
685 { 0 }
686};
687MODULE_DEVICE_TABLE(pci, timberdale_pci_tbl);
688
689static struct pci_driver timberdale_pci_driver = {
690 .name = DRIVER_NAME,
691 .id_table = timberdale_pci_tbl,
692 .probe = timb_probe,
693 .remove = __devexit_p(timb_remove),
694};
695
696static int __init timberdale_init(void)
697{
698 int err;
699
700 err = pci_register_driver(&timberdale_pci_driver);
701 if (err < 0) {
702 printk(KERN_ERR
703 "Failed to register PCI driver for %s device.\n",
704 timberdale_pci_driver.name);
705 return -ENODEV;
706 }
707
708 printk(KERN_INFO "Driver for %s has been successfully registered.\n",
709 timberdale_pci_driver.name);
710
711 return 0;
712}
713
714static void __exit timberdale_exit(void)
715{
716 pci_unregister_driver(&timberdale_pci_driver);
717
718 printk(KERN_INFO "Driver for %s has been successfully unregistered.\n",
719 timberdale_pci_driver.name);
720}
721
722module_init(timberdale_init);
723module_exit(timberdale_exit);
724
725MODULE_AUTHOR("Mocean Laboratories <info@mocean-labs.com>");
726MODULE_VERSION(DRV_VERSION);
727MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/timberdale.h b/drivers/mfd/timberdale.h
new file mode 100644
index 000000000000..8d27ffabc25d
--- /dev/null
+++ b/drivers/mfd/timberdale.h
@@ -0,0 +1,130 @@
1/*
2 * timberdale.h timberdale FPGA MFD driver defines
3 * Copyright (c) 2009 Intel Corporation
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19/* Supports:
20 * Timberdale FPGA
21 */
22
23#ifndef MFD_TIMBERDALE_H
24#define MFD_TIMBERDALE_H
25
26#define DRV_VERSION "0.1"
27
28/* This driver only support versions >= 3.8 and < 4.0 */
29#define TIMB_SUPPORTED_MAJOR 3
30
31/* This driver only support minor >= 8 */
32#define TIMB_REQUIRED_MINOR 8
33
34/* Registers of the control area */
35#define TIMB_REV_MAJOR 0x00
36#define TIMB_REV_MINOR 0x04
37#define TIMB_HW_CONFIG 0x08
38#define TIMB_SW_RST 0x40
39
40/* bits in the TIMB_HW_CONFIG register */
41#define TIMB_HW_CONFIG_SPI_8BIT 0x80
42
43#define TIMB_HW_VER_MASK 0x0f
44#define TIMB_HW_VER0 0x00
45#define TIMB_HW_VER1 0x01
46#define TIMB_HW_VER2 0x02
47#define TIMB_HW_VER3 0x03
48
49#define OCORESOFFSET 0x0
50#define OCORESEND 0x1f
51
52#define SPIOFFSET 0x80
53#define SPIEND 0xff
54
55#define UARTLITEOFFSET 0x100
56#define UARTLITEEND 0x10f
57
58#define RDSOFFSET 0x180
59#define RDSEND 0x183
60
61#define ETHOFFSET 0x300
62#define ETHEND 0x3ff
63
64#define GPIOOFFSET 0x400
65#define GPIOEND 0x7ff
66
67#define CHIPCTLOFFSET 0x800
68#define CHIPCTLEND 0x8ff
69#define CHIPCTLSIZE (CHIPCTLEND - CHIPCTLOFFSET)
70
71#define INTCOFFSET 0xc00
72#define INTCEND 0xfff
73#define INTCSIZE (INTCEND - INTCOFFSET)
74
75#define MOSTOFFSET 0x1000
76#define MOSTEND 0x13ff
77
78#define UARTOFFSET 0x1400
79#define UARTEND 0x17ff
80
81#define XIICOFFSET 0x1800
82#define XIICEND 0x19ff
83
84#define I2SOFFSET 0x1C00
85#define I2SEND 0x1fff
86
87#define LOGIWOFFSET 0x30000
88#define LOGIWEND 0x37fff
89
90#define MLCOREOFFSET 0x40000
91#define MLCOREEND 0x43fff
92
93#define DMAOFFSET 0x01000000
94#define DMAEND 0x013fffff
95
96/* SDHC0 is placed in PCI bar 1 */
97#define SDHC0OFFSET 0x00
98#define SDHC0END 0xff
99
100/* SDHC1 is placed in PCI bar 2 */
101#define SDHC1OFFSET 0x00
102#define SDHC1END 0xff
103
104#define PCI_VENDOR_ID_TIMB 0x10ee
105#define PCI_DEVICE_ID_TIMB 0xa123
106
107#define IRQ_TIMBERDALE_INIC 0
108#define IRQ_TIMBERDALE_MLB 1
109#define IRQ_TIMBERDALE_GPIO 2
110#define IRQ_TIMBERDALE_I2C 3
111#define IRQ_TIMBERDALE_UART 4
112#define IRQ_TIMBERDALE_DMA 5
113#define IRQ_TIMBERDALE_I2S 6
114#define IRQ_TIMBERDALE_TSC_INT 7
115#define IRQ_TIMBERDALE_SDHC 8
116#define IRQ_TIMBERDALE_ADV7180 9
117#define IRQ_TIMBERDALE_ETHSW_IF 10
118#define IRQ_TIMBERDALE_SPI 11
119#define IRQ_TIMBERDALE_UARTLITE 12
120#define IRQ_TIMBERDALE_MLCORE 13
121#define IRQ_TIMBERDALE_MLCORE_BUF 14
122#define IRQ_TIMBERDALE_RDS 15
123#define TIMBERDALE_NR_IRQS 16
124
125#define GPIO_PIN_ASCB 8
126#define GPIO_PIN_INIC_RST 14
127#define GPIO_PIN_BT_RST 15
128#define GPIO_NR_PINS 16
129
130#endif
diff --git a/drivers/mfd/tmio_core.c b/drivers/mfd/tmio_core.c
new file mode 100644
index 000000000000..eddc19ae464b
--- /dev/null
+++ b/drivers/mfd/tmio_core.c
@@ -0,0 +1,52 @@
1/*
2 * Copyright(c) 2009 Ian Molton <spyro@f2s.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include <linux/mfd/tmio.h>
10
11int tmio_core_mmc_enable(void __iomem *cnf, int shift, unsigned long base)
12{
13 /* Enable the MMC/SD Control registers */
14 sd_config_write16(cnf, shift, CNF_CMD, SDCREN);
15 sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe);
16
17 /* Disable SD power during suspend */
18 sd_config_write8(cnf, shift, CNF_PWR_CTL_3, 0x01);
19
20 /* The below is required but why? FIXME */
21 sd_config_write8(cnf, shift, CNF_STOP_CLK_CTL, 0x1f);
22
23 /* Power down SD bus */
24 sd_config_write8(cnf, shift, CNF_PWR_CTL_2, 0x00);
25
26 return 0;
27}
28EXPORT_SYMBOL(tmio_core_mmc_enable);
29
30int tmio_core_mmc_resume(void __iomem *cnf, int shift, unsigned long base)
31{
32
33 /* Enable the MMC/SD Control registers */
34 sd_config_write16(cnf, shift, CNF_CMD, SDCREN);
35 sd_config_write32(cnf, shift, CNF_CTL_BASE, base & 0xfffe);
36
37 return 0;
38}
39EXPORT_SYMBOL(tmio_core_mmc_resume);
40
41void tmio_core_mmc_pwr(void __iomem *cnf, int shift, int state)
42{
43 sd_config_write8(cnf, shift, CNF_PWR_CTL_2, state ? 0x02 : 0x00);
44}
45EXPORT_SYMBOL(tmio_core_mmc_pwr);
46
47void tmio_core_mmc_clk_div(void __iomem *cnf, int shift, int state)
48{
49 sd_config_write8(cnf, shift, CNF_SD_CLK_MODE, state ? 1 : 0);
50}
51EXPORT_SYMBOL(tmio_core_mmc_clk_div);
52
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
index 8485a7018060..9a970bd68775 100644
--- a/drivers/mfd/wm8350-core.c
+++ b/drivers/mfd/wm8350-core.c
@@ -134,8 +134,7 @@ static inline int is_reg_locked(struct wm8350 *wm8350, u8 reg)
134 wm8350->reg_cache[WM8350_SECURITY] == WM8350_UNLOCK_KEY) 134 wm8350->reg_cache[WM8350_SECURITY] == WM8350_UNLOCK_KEY)
135 return 0; 135 return 0;
136 136
137 if ((reg == WM8350_GPIO_CONFIGURATION_I_O) || 137 if ((reg >= WM8350_GPIO_FUNCTION_SELECT_1 &&
138 (reg >= WM8350_GPIO_FUNCTION_SELECT_1 &&
139 reg <= WM8350_GPIO_FUNCTION_SELECT_4) || 138 reg <= WM8350_GPIO_FUNCTION_SELECT_4) ||
140 (reg >= WM8350_BATTERY_CHARGER_CONTROL_1 && 139 (reg >= WM8350_BATTERY_CHARGER_CONTROL_1 &&
141 reg <= WM8350_BATTERY_CHARGER_CONTROL_3)) 140 reg <= WM8350_BATTERY_CHARGER_CONTROL_3))
diff --git a/drivers/mfd/wm8350-irq.c b/drivers/mfd/wm8350-irq.c
index c8df547c4747..9025f29e2707 100644
--- a/drivers/mfd/wm8350-irq.c
+++ b/drivers/mfd/wm8350-irq.c
@@ -434,7 +434,7 @@ int wm8350_register_irq(struct wm8350 *wm8350, int irq,
434 irq_handler_t handler, unsigned long flags, 434 irq_handler_t handler, unsigned long flags,
435 const char *name, void *data) 435 const char *name, void *data)
436{ 436{
437 if (irq < 0 || irq > WM8350_NUM_IRQ || !handler) 437 if (irq < 0 || irq >= WM8350_NUM_IRQ || !handler)
438 return -EINVAL; 438 return -EINVAL;
439 439
440 if (wm8350->irq[irq].handler) 440 if (wm8350->irq[irq].handler)
@@ -453,7 +453,7 @@ EXPORT_SYMBOL_GPL(wm8350_register_irq);
453 453
454int wm8350_free_irq(struct wm8350 *wm8350, int irq) 454int wm8350_free_irq(struct wm8350 *wm8350, int irq)
455{ 455{
456 if (irq < 0 || irq > WM8350_NUM_IRQ) 456 if (irq < 0 || irq >= WM8350_NUM_IRQ)
457 return -EINVAL; 457 return -EINVAL;
458 458
459 wm8350_mask_irq(wm8350, irq); 459 wm8350_mask_irq(wm8350, irq);