diff options
| -rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_power.c | 115 | ||||
| -rw-r--r-- | drivers/net/wireless/bcm43xx/bcm43xx_power.h | 9 |
2 files changed, 77 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 */ | ||
| 39 | static 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 | */ |
| 41 | static int bcm43xx_pctl_clockfreqlimit(struct bcm43xx_private *bcm, | 74 | static 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 | ||
| 119 | out_switchback: | ||
| 120 | err = bcm43xx_switch_core(bcm, old_core); | ||
| 121 | assert(err == 0); | ||
| 122 | |||
| 123 | out: | ||
| 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 | */ |
diff --git a/drivers/net/wireless/bcm43xx/bcm43xx_power.h b/drivers/net/wireless/bcm43xx/bcm43xx_power.h index 5f63640810bd..c966ab3a5a8c 100644 --- a/drivers/net/wireless/bcm43xx/bcm43xx_power.h +++ b/drivers/net/wireless/bcm43xx/bcm43xx_power.h | |||
| @@ -33,6 +33,15 @@ | |||
| 33 | 33 | ||
| 34 | #include <linux/types.h> | 34 | #include <linux/types.h> |
| 35 | 35 | ||
| 36 | /* Clock sources */ | ||
| 37 | enum { | ||
| 38 | /* PCI clock */ | ||
| 39 | BCM43xx_PCTL_CLKSRC_PCI, | ||
| 40 | /* Crystal slow clock oscillator */ | ||
| 41 | BCM43xx_PCTL_CLKSRC_XTALOS, | ||
| 42 | /* Low power oscillator */ | ||
| 43 | BCM43xx_PCTL_CLKSRC_LOPWROS, | ||
| 44 | }; | ||
| 36 | 45 | ||
| 37 | struct bcm43xx_private; | 46 | struct bcm43xx_private; |
| 38 | 47 | ||
