aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/bcm43xx/bcm43xx_power.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/bcm43xx/bcm43xx_power.c')
-rw-r--r--drivers/net/wireless/bcm43xx/bcm43xx_power.c115
1 files changed, 68 insertions, 47 deletions
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.c b/drivers/net/wireless/bcm43xx/bcm43xx_power.c
index 3c92b62807c5..6569da3a7a39 100644
--- a/drivers/net/wireless/bcm43xx/bcm43xx_power.c
+++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.c
@@ -35,77 +35,101 @@
35#include "bcm43xx_main.h" 35#include "bcm43xx_main.h"
36 36
37 37
38/* Get the Slow Clock Source */
39static int bcm43xx_pctl_get_slowclksrc(struct bcm43xx_private *bcm)
40{
41 u32 tmp;
42 int err;
43
44 assert(bcm->current_core == &bcm->core_chipcommon);
45 if (bcm->current_core->rev < 6) {
46 if (bcm->bustype == BCM43xx_BUSTYPE_PCMCIA ||
47 bcm->bustype == BCM43xx_BUSTYPE_SB)
48 return BCM43xx_PCTL_CLKSRC_XTALOS;
49 if (bcm->bustype == BCM43xx_BUSTYPE_PCI) {
50 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp);
51 assert(!err);
52 if (tmp & 0x10)
53 return BCM43xx_PCTL_CLKSRC_PCI;
54 return BCM43xx_PCTL_CLKSRC_XTALOS;
55 }
56 }
57 if (bcm->current_core->rev < 10) {
58 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
59 tmp &= 0x7;
60 if (tmp == 0)
61 return BCM43xx_PCTL_CLKSRC_LOPWROS;
62 if (tmp == 1)
63 return BCM43xx_PCTL_CLKSRC_XTALOS;
64 if (tmp == 2)
65 return BCM43xx_PCTL_CLKSRC_PCI;
66 }
67
68 return BCM43xx_PCTL_CLKSRC_XTALOS;
69}
70
38/* Get max/min slowclock frequency 71/* Get max/min slowclock frequency
39 * as described in http://bcm-specs.sipsolutions.net/PowerControl 72 * as described in http://bcm-specs.sipsolutions.net/PowerControl
40 */ 73 */
41static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, 74static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm,
42 int get_max) 75 int get_max)
43{ 76{
44 int limit = 0; 77 int limit;
78 int clocksrc;
45 int divisor; 79 int divisor;
46 int selection;
47 int err;
48 u32 tmp; 80 u32 tmp;
49 struct bcm43xx_coreinfo *old_core;
50 81
51 if (!(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL)) 82 assert(bcm->chipcommon_capabilities & BCM43xx_CAPABILITIES_PCTL);
52 goto out; 83 assert(bcm->current_core == &bcm->core_chipcommon);
53 old_core = bcm->current_core;
54 err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);
55 if (err)
56 goto out;
57 84
85 clocksrc = bcm43xx_pctl_get_slowclksrc(bcm);
58 if (bcm->current_core->rev < 6) { 86 if (bcm->current_core->rev < 6) {
59 if ((bcm->bustype == BCM43xx_BUSTYPE_PCMCIA) || 87 switch (clocksrc) {
60 (bcm->bustype == BCM43xx_BUSTYPE_SB)) { 88 case BCM43xx_PCTL_CLKSRC_PCI:
61 selection = 1; 89 divisor = 64;
90 break;
91 case BCM43xx_PCTL_CLKSRC_XTALOS:
62 divisor = 32; 92 divisor = 32;
63 } else { 93 break;
64 err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCTL_OUT, &tmp); 94 default:
65 if (err) { 95 assert(0);
66 printk(KERN_ERR PFX "clockfreqlimit pcicfg read failure\n"); 96 divisor = 1;
67 goto out_switchback;
68 }
69 if (tmp & 0x10) {
70 /* PCI */
71 selection = 2;
72 divisor = 64;
73 } else {
74 /* XTAL */
75 selection = 1;
76 divisor = 32;
77 }
78 } 97 }
79 } else if (bcm->current_core->rev < 10) { 98 } else if (bcm->current_core->rev < 10) {
80 selection = (tmp & 0x07); 99 switch (clocksrc) {
81 if (selection) { 100 case BCM43xx_PCTL_CLKSRC_LOPWROS:
101 divisor = 1;
102 break;
103 case BCM43xx_PCTL_CLKSRC_XTALOS:
104 case BCM43xx_PCTL_CLKSRC_PCI:
82 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL); 105 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SLOWCLKCTL);
83 divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); 106 divisor = ((tmp & 0xFFFF0000) >> 16) + 1;
84 } else 107 divisor *= 4;
108 break;
109 default:
110 assert(0);
85 divisor = 1; 111 divisor = 1;
112 }
86 } else { 113 } else {
87 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL); 114 tmp = bcm43xx_read32(bcm, BCM43xx_CHIPCOMMON_SYSCLKCTL);
88 divisor = 4 * (1 + ((tmp & 0xFFFF0000) >> 16)); 115 divisor = ((tmp & 0xFFFF0000) >> 16) + 1;
89 selection = 1; 116 divisor *= 4;
90 } 117 }
91 118
92 switch (selection) { 119 switch (clocksrc) {
93 case 0: 120 case BCM43xx_PCTL_CLKSRC_LOPWROS:
94 /* LPO */
95 if (get_max) 121 if (get_max)
96 limit = 43000; 122 limit = 43000;
97 else 123 else
98 limit = 25000; 124 limit = 25000;
99 break; 125 break;
100 case 1: 126 case BCM43xx_PCTL_CLKSRC_XTALOS:
101 /* XTAL */
102 if (get_max) 127 if (get_max)
103 limit = 20200000; 128 limit = 20200000;
104 else 129 else
105 limit = 19800000; 130 limit = 19800000;
106 break; 131 break;
107 case 2: 132 case BCM43xx_PCTL_CLKSRC_PCI:
108 /* PCI */
109 if (get_max) 133 if (get_max)
110 limit = 34000000; 134 limit = 34000000;
111 else 135 else
@@ -113,17 +137,14 @@ static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm,
113 break; 137 break;
114 default: 138 default:
115 assert(0); 139 assert(0);
140 limit = 0;
116 } 141 }
117 limit /= divisor; 142 limit /= divisor;
118 143
119out_switchback:
120 err = bcm43xx_switch_core(bcm, old_core);
121 assert(err == 0);
122
123out:
124 return limit; 144 return limit;
125} 145}
126 146
147
127/* init power control 148/* init power control
128 * as described in http://bcm-specs.sipsolutions.net/PowerControl 149 * as described in http://bcm-specs.sipsolutions.net/PowerControl
129 */ 150 */