diff options
Diffstat (limited to 'drivers/clocksource/sh_mtu2.c')
| -rw-r--r-- | drivers/clocksource/sh_mtu2.c | 490 |
1 files changed, 340 insertions, 150 deletions
diff --git a/drivers/clocksource/sh_mtu2.c b/drivers/clocksource/sh_mtu2.c index e30d76e0a6fa..188d4e092efc 100644 --- a/drivers/clocksource/sh_mtu2.c +++ b/drivers/clocksource/sh_mtu2.c | |||
| @@ -11,37 +11,48 @@ | |||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. | 13 | * GNU General Public License for more details. |
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 18 | */ | 14 | */ |
| 19 | 15 | ||
| 16 | #include <linux/clk.h> | ||
| 17 | #include <linux/clockchips.h> | ||
| 18 | #include <linux/delay.h> | ||
| 19 | #include <linux/err.h> | ||
| 20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
| 21 | #include <linux/platform_device.h> | ||
| 22 | #include <linux/spinlock.h> | ||
| 23 | #include <linux/interrupt.h> | 21 | #include <linux/interrupt.h> |
| 24 | #include <linux/ioport.h> | ||
| 25 | #include <linux/delay.h> | ||
| 26 | #include <linux/io.h> | 22 | #include <linux/io.h> |
| 27 | #include <linux/clk.h> | 23 | #include <linux/ioport.h> |
| 28 | #include <linux/irq.h> | 24 | #include <linux/irq.h> |
| 29 | #include <linux/err.h> | ||
| 30 | #include <linux/clockchips.h> | ||
| 31 | #include <linux/sh_timer.h> | ||
| 32 | #include <linux/slab.h> | ||
| 33 | #include <linux/module.h> | 25 | #include <linux/module.h> |
| 26 | #include <linux/platform_device.h> | ||
| 34 | #include <linux/pm_domain.h> | 27 | #include <linux/pm_domain.h> |
| 35 | #include <linux/pm_runtime.h> | 28 | #include <linux/pm_runtime.h> |
| 29 | #include <linux/sh_timer.h> | ||
| 30 | #include <linux/slab.h> | ||
| 31 | #include <linux/spinlock.h> | ||
| 32 | |||
| 33 | struct sh_mtu2_device; | ||
| 34 | |||
| 35 | struct sh_mtu2_channel { | ||
| 36 | struct sh_mtu2_device *mtu; | ||
| 37 | unsigned int index; | ||
| 38 | |||
| 39 | void __iomem *base; | ||
| 40 | int irq; | ||
| 41 | |||
| 42 | struct clock_event_device ced; | ||
| 43 | }; | ||
| 44 | |||
| 45 | struct sh_mtu2_device { | ||
| 46 | struct platform_device *pdev; | ||
| 36 | 47 | ||
| 37 | struct sh_mtu2_priv { | ||
| 38 | void __iomem *mapbase; | 48 | void __iomem *mapbase; |
| 39 | struct clk *clk; | 49 | struct clk *clk; |
| 40 | struct irqaction irqaction; | 50 | |
| 41 | struct platform_device *pdev; | 51 | struct sh_mtu2_channel *channels; |
| 42 | unsigned long rate; | 52 | unsigned int num_channels; |
| 43 | unsigned long periodic; | 53 | |
| 44 | struct clock_event_device ced; | 54 | bool legacy; |
| 55 | bool has_clockevent; | ||
| 45 | }; | 56 | }; |
| 46 | 57 | ||
| 47 | static DEFINE_RAW_SPINLOCK(sh_mtu2_lock); | 58 | static DEFINE_RAW_SPINLOCK(sh_mtu2_lock); |
| @@ -55,6 +66,88 @@ static DEFINE_RAW_SPINLOCK(sh_mtu2_lock); | |||
| 55 | #define TCNT 5 /* channel register */ | 66 | #define TCNT 5 /* channel register */ |
| 56 | #define TGR 6 /* channel register */ | 67 | #define TGR 6 /* channel register */ |
| 57 | 68 | ||
| 69 | #define TCR_CCLR_NONE (0 << 5) | ||
| 70 | #define TCR_CCLR_TGRA (1 << 5) | ||
| 71 | #define TCR_CCLR_TGRB (2 << 5) | ||
| 72 | #define TCR_CCLR_SYNC (3 << 5) | ||
| 73 | #define TCR_CCLR_TGRC (5 << 5) | ||
| 74 | #define TCR_CCLR_TGRD (6 << 5) | ||
| 75 | #define TCR_CCLR_MASK (7 << 5) | ||
| 76 | #define TCR_CKEG_RISING (0 << 3) | ||
| 77 | #define TCR_CKEG_FALLING (1 << 3) | ||
| 78 | #define TCR_CKEG_BOTH (2 << 3) | ||
| 79 | #define TCR_CKEG_MASK (3 << 3) | ||
| 80 | /* Values 4 to 7 are channel-dependent */ | ||
| 81 | #define TCR_TPSC_P1 (0 << 0) | ||
| 82 | #define TCR_TPSC_P4 (1 << 0) | ||
| 83 | #define TCR_TPSC_P16 (2 << 0) | ||
| 84 | #define TCR_TPSC_P64 (3 << 0) | ||
| 85 | #define TCR_TPSC_CH0_TCLKA (4 << 0) | ||
| 86 | #define TCR_TPSC_CH0_TCLKB (5 << 0) | ||
| 87 | #define TCR_TPSC_CH0_TCLKC (6 << 0) | ||
| 88 | #define TCR_TPSC_CH0_TCLKD (7 << 0) | ||
| 89 | #define TCR_TPSC_CH1_TCLKA (4 << 0) | ||
| 90 | #define TCR_TPSC_CH1_TCLKB (5 << 0) | ||
| 91 | #define TCR_TPSC_CH1_P256 (6 << 0) | ||
| 92 | #define TCR_TPSC_CH1_TCNT2 (7 << 0) | ||
| 93 | #define TCR_TPSC_CH2_TCLKA (4 << 0) | ||
| 94 | #define TCR_TPSC_CH2_TCLKB (5 << 0) | ||
| 95 | #define TCR_TPSC_CH2_TCLKC (6 << 0) | ||
| 96 | #define TCR_TPSC_CH2_P1024 (7 << 0) | ||
| 97 | #define TCR_TPSC_CH34_P256 (4 << 0) | ||
| 98 | #define TCR_TPSC_CH34_P1024 (5 << 0) | ||
| 99 | #define TCR_TPSC_CH34_TCLKA (6 << 0) | ||
| 100 | #define TCR_TPSC_CH34_TCLKB (7 << 0) | ||
| 101 | #define TCR_TPSC_MASK (7 << 0) | ||
| 102 | |||
| 103 | #define TMDR_BFE (1 << 6) | ||
| 104 | #define TMDR_BFB (1 << 5) | ||
| 105 | #define TMDR_BFA (1 << 4) | ||
| 106 | #define TMDR_MD_NORMAL (0 << 0) | ||
| 107 | #define TMDR_MD_PWM_1 (2 << 0) | ||
| 108 | #define TMDR_MD_PWM_2 (3 << 0) | ||
| 109 | #define TMDR_MD_PHASE_1 (4 << 0) | ||
| 110 | #define TMDR_MD_PHASE_2 (5 << 0) | ||
| 111 | #define TMDR_MD_PHASE_3 (6 << 0) | ||
| 112 | #define TMDR_MD_PHASE_4 (7 << 0) | ||
| 113 | #define TMDR_MD_PWM_SYNC (8 << 0) | ||
| 114 | #define TMDR_MD_PWM_COMP_CREST (13 << 0) | ||
| 115 | #define TMDR_MD_PWM_COMP_TROUGH (14 << 0) | ||
| 116 | #define TMDR_MD_PWM_COMP_BOTH (15 << 0) | ||
| 117 | #define TMDR_MD_MASK (15 << 0) | ||
| 118 | |||
| 119 | #define TIOC_IOCH(n) ((n) << 4) | ||
| 120 | #define TIOC_IOCL(n) ((n) << 0) | ||
| 121 | #define TIOR_OC_RETAIN (0 << 0) | ||
| 122 | #define TIOR_OC_0_CLEAR (1 << 0) | ||
| 123 | #define TIOR_OC_0_SET (2 << 0) | ||
| 124 | #define TIOR_OC_0_TOGGLE (3 << 0) | ||
| 125 | #define TIOR_OC_1_CLEAR (5 << 0) | ||
| 126 | #define TIOR_OC_1_SET (6 << 0) | ||
| 127 | #define TIOR_OC_1_TOGGLE (7 << 0) | ||
| 128 | #define TIOR_IC_RISING (8 << 0) | ||
| 129 | #define TIOR_IC_FALLING (9 << 0) | ||
| 130 | #define TIOR_IC_BOTH (10 << 0) | ||
| 131 | #define TIOR_IC_TCNT (12 << 0) | ||
| 132 | #define TIOR_MASK (15 << 0) | ||
| 133 | |||
| 134 | #define TIER_TTGE (1 << 7) | ||
| 135 | #define TIER_TTGE2 (1 << 6) | ||
| 136 | #define TIER_TCIEU (1 << 5) | ||
| 137 | #define TIER_TCIEV (1 << 4) | ||
| 138 | #define TIER_TGIED (1 << 3) | ||
| 139 | #define TIER_TGIEC (1 << 2) | ||
| 140 | #define TIER_TGIEB (1 << 1) | ||
| 141 | #define TIER_TGIEA (1 << 0) | ||
| 142 | |||
| 143 | #define TSR_TCFD (1 << 7) | ||
| 144 | #define TSR_TCFU (1 << 5) | ||
| 145 | #define TSR_TCFV (1 << 4) | ||
| 146 | #define TSR_TGFD (1 << 3) | ||
| 147 | #define TSR_TGFC (1 << 2) | ||
| 148 | #define TSR_TGFB (1 << 1) | ||
| 149 | #define TSR_TGFA (1 << 0) | ||
| 150 | |||
| 58 | static unsigned long mtu2_reg_offs[] = { | 151 | static unsigned long mtu2_reg_offs[] = { |
| 59 | [TCR] = 0, | 152 | [TCR] = 0, |
| 60 | [TMDR] = 1, | 153 | [TMDR] = 1, |
| @@ -65,135 +158,143 @@ static unsigned long mtu2_reg_offs[] = { | |||
| 65 | [TGR] = 8, | 158 | [TGR] = 8, |
| 66 | }; | 159 | }; |
| 67 | 160 | ||
| 68 | static inline unsigned long sh_mtu2_read(struct sh_mtu2_priv *p, int reg_nr) | 161 | static inline unsigned long sh_mtu2_read(struct sh_mtu2_channel *ch, int reg_nr) |
| 69 | { | 162 | { |
| 70 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; | ||
| 71 | void __iomem *base = p->mapbase; | ||
| 72 | unsigned long offs; | 163 | unsigned long offs; |
| 73 | 164 | ||
| 74 | if (reg_nr == TSTR) | 165 | if (reg_nr == TSTR) { |
| 75 | return ioread8(base + cfg->channel_offset); | 166 | if (ch->mtu->legacy) |
| 167 | return ioread8(ch->mtu->mapbase); | ||
| 168 | else | ||
| 169 | return ioread8(ch->mtu->mapbase + 0x280); | ||
| 170 | } | ||
| 76 | 171 | ||
| 77 | offs = mtu2_reg_offs[reg_nr]; | 172 | offs = mtu2_reg_offs[reg_nr]; |
| 78 | 173 | ||
| 79 | if ((reg_nr == TCNT) || (reg_nr == TGR)) | 174 | if ((reg_nr == TCNT) || (reg_nr == TGR)) |
| 80 | return ioread16(base + offs); | 175 | return ioread16(ch->base + offs); |
| 81 | else | 176 | else |
| 82 | return ioread8(base + offs); | 177 | return ioread8(ch->base + offs); |
| 83 | } | 178 | } |
| 84 | 179 | ||
| 85 | static inline void sh_mtu2_write(struct sh_mtu2_priv *p, int reg_nr, | 180 | static inline void sh_mtu2_write(struct sh_mtu2_channel *ch, int reg_nr, |
| 86 | unsigned long value) | 181 | unsigned long value) |
| 87 | { | 182 | { |
| 88 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; | ||
| 89 | void __iomem *base = p->mapbase; | ||
| 90 | unsigned long offs; | 183 | unsigned long offs; |
| 91 | 184 | ||
| 92 | if (reg_nr == TSTR) { | 185 | if (reg_nr == TSTR) { |
| 93 | iowrite8(value, base + cfg->channel_offset); | 186 | if (ch->mtu->legacy) |
| 94 | return; | 187 | return iowrite8(value, ch->mtu->mapbase); |
| 188 | else | ||
| 189 | return iowrite8(value, ch->mtu->mapbase + 0x280); | ||
| 95 | } | 190 | } |
| 96 | 191 | ||
| 97 | offs = mtu2_reg_offs[reg_nr]; | 192 | offs = mtu2_reg_offs[reg_nr]; |
| 98 | 193 | ||
| 99 | if ((reg_nr == TCNT) || (reg_nr == TGR)) | 194 | if ((reg_nr == TCNT) || (reg_nr == TGR)) |
| 100 | iowrite16(value, base + offs); | 195 | iowrite16(value, ch->base + offs); |
| 101 | else | 196 | else |
| 102 | iowrite8(value, base + offs); | 197 | iowrite8(value, ch->base + offs); |
| 103 | } | 198 | } |
| 104 | 199 | ||
| 105 | static void sh_mtu2_start_stop_ch(struct sh_mtu2_priv *p, int start) | 200 | static void sh_mtu2_start_stop_ch(struct sh_mtu2_channel *ch, int start) |
| 106 | { | 201 | { |
| 107 | struct sh_timer_config *cfg = p->pdev->dev.platform_data; | ||
| 108 | unsigned long flags, value; | 202 | unsigned long flags, value; |
| 109 | 203 | ||
| 110 | /* start stop register shared by multiple timer channels */ | 204 | /* start stop register shared by multiple timer channels */ |
| 111 | raw_spin_lock_irqsave(&sh_mtu2_lock, flags); | 205 | raw_spin_lock_irqsave(&sh_mtu2_lock, flags); |
| 112 | value = sh_mtu2_read(p, TSTR); | 206 | value = sh_mtu2_read(ch, TSTR); |
| 113 | 207 | ||
| 114 | if (start) | 208 | if (start) |
| 115 | value |= 1 << cfg->timer_bit; | 209 | value |= 1 << ch->index; |
| 116 | else | 210 | else |
| 117 | value &= ~(1 << cfg->timer_bit); | 211 | value &= ~(1 << ch->index); |
| 118 | 212 | ||
| 119 | sh_mtu2_write(p, TSTR, value); | 213 | sh_mtu2_write(ch, TSTR, value); |
| 120 | raw_spin_unlock_irqrestore(&sh_mtu2_lock, flags); | 214 | raw_spin_unlock_irqrestore(&sh_mtu2_lock, flags); |
| 121 | } | 215 | } |
| 122 | 216 | ||
| 123 | static int sh_mtu2_enable(struct sh_mtu2_priv *p) | 217 | static int sh_mtu2_enable(struct sh_mtu2_channel *ch) |
| 124 | { | 218 | { |
| 219 | unsigned long periodic; | ||
| 220 | unsigned long rate; | ||
| 125 | int ret; | 221 | int ret; |
| 126 | 222 | ||
| 127 | pm_runtime_get_sync(&p->pdev->dev); | 223 | pm_runtime_get_sync(&ch->mtu->pdev->dev); |
| 128 | dev_pm_syscore_device(&p->pdev->dev, true); | 224 | dev_pm_syscore_device(&ch->mtu->pdev->dev, true); |
| 129 | 225 | ||
| 130 | /* enable clock */ | 226 | /* enable clock */ |
| 131 | ret = clk_enable(p->clk); | 227 | ret = clk_enable(ch->mtu->clk); |
| 132 | if (ret) { | 228 | if (ret) { |
| 133 | dev_err(&p->pdev->dev, "cannot enable clock\n"); | 229 | dev_err(&ch->mtu->pdev->dev, "ch%u: cannot enable clock\n", |
| 230 | ch->index); | ||
| 134 | return ret; | 231 | return ret; |
| 135 | } | 232 | } |
| 136 | 233 | ||
| 137 | /* make sure channel is disabled */ | 234 | /* make sure channel is disabled */ |
| 138 | sh_mtu2_start_stop_ch(p, 0); | 235 | sh_mtu2_start_stop_ch(ch, 0); |
| 139 | 236 | ||
| 140 | p->rate = clk_get_rate(p->clk) / 64; | 237 | rate = clk_get_rate(ch->mtu->clk) / 64; |
| 141 | p->periodic = (p->rate + HZ/2) / HZ; | 238 | periodic = (rate + HZ/2) / HZ; |
| 142 | 239 | ||
| 143 | /* "Periodic Counter Operation" */ | 240 | /* |
| 144 | sh_mtu2_write(p, TCR, 0x23); /* TGRA clear, divide clock by 64 */ | 241 | * "Periodic Counter Operation" |
| 145 | sh_mtu2_write(p, TIOR, 0); | 242 | * Clear on TGRA compare match, divide clock by 64. |
| 146 | sh_mtu2_write(p, TGR, p->periodic); | 243 | */ |
| 147 | sh_mtu2_write(p, TCNT, 0); | 244 | sh_mtu2_write(ch, TCR, TCR_CCLR_TGRA | TCR_TPSC_P64); |
| 148 | sh_mtu2_write(p, TMDR, 0); | 245 | sh_mtu2_write(ch, TIOR, TIOC_IOCH(TIOR_OC_0_CLEAR) | |
| 149 | sh_mtu2_write(p, TIER, 0x01); | 246 | TIOC_IOCL(TIOR_OC_0_CLEAR)); |
| 247 | sh_mtu2_write(ch, TGR, periodic); | ||
| 248 | sh_mtu2_write(ch, TCNT, 0); | ||
| 249 | sh_mtu2_write(ch, TMDR, TMDR_MD_NORMAL); | ||
| 250 | sh_mtu2_write(ch, TIER, TIER_TGIEA); | ||
| 150 | 251 | ||
| 151 | /* enable channel */ | 252 | /* enable channel */ |
| 152 | sh_mtu2_start_stop_ch(p, 1); | 253 | sh_mtu2_start_stop_ch(ch, 1); |
| 153 | 254 | ||
| 154 | return 0; | 255 | return 0; |
| 155 | } | 256 | } |
| 156 | 257 | ||
| 157 | static void sh_mtu2_disable(struct sh_mtu2_priv *p) | 258 | static void sh_mtu2_disable(struct sh_mtu2_channel *ch) |
| 158 | { | 259 | { |
| 159 | /* disable channel */ | 260 | /* disable channel */ |
| 160 | sh_mtu2_start_stop_ch(p, 0); | 261 | sh_mtu2_start_stop_ch(ch, 0); |
| 161 | 262 | ||
| 162 | /* stop clock */ | 263 | /* stop clock */ |
| 163 | clk_disable(p->clk); | 264 | clk_disable(ch->mtu->clk); |
| 164 | 265 | ||
| 165 | dev_pm_syscore_device(&p->pdev->dev, false); | 266 | dev_pm_syscore_device(&ch->mtu->pdev->dev, false); |
| 166 | pm_runtime_put(&p->pdev->dev); | 267 | pm_runtime_put(&ch->mtu->pdev->dev); |
| 167 | } | 268 | } |
| 168 | 269 | ||
| 169 | static irqreturn_t sh_mtu2_interrupt(int irq, void *dev_id) | 270 | static irqreturn_t sh_mtu2_interrupt(int irq, void *dev_id) |
| 170 | { | 271 | { |
| 171 | struct sh_mtu2_priv *p = dev_id; | 272 | struct sh_mtu2_channel *ch = dev_id; |
| 172 | 273 | ||
| 173 | /* acknowledge interrupt */ | 274 | /* acknowledge interrupt */ |
| 174 | sh_mtu2_read(p, TSR); | 275 | sh_mtu2_read(ch, TSR); |
| 175 | sh_mtu2_write(p, TSR, 0xfe); | 276 | sh_mtu2_write(ch, TSR, ~TSR_TGFA); |
| 176 | 277 | ||
| 177 | /* notify clockevent layer */ | 278 | /* notify clockevent layer */ |
| 178 | p->ced.event_handler(&p->ced); | 279 | ch->ced.event_handler(&ch->ced); |
| 179 | return IRQ_HANDLED; | 280 | return IRQ_HANDLED; |
| 180 | } | 281 | } |
| 181 | 282 | ||
| 182 | static struct sh_mtu2_priv *ced_to_sh_mtu2(struct clock_event_device *ced) | 283 | static struct sh_mtu2_channel *ced_to_sh_mtu2(struct clock_event_device *ced) |
| 183 | { | 284 | { |
| 184 | return container_of(ced, struct sh_mtu2_priv, ced); | 285 | return container_of(ced, struct sh_mtu2_channel, ced); |
| 185 | } | 286 | } |
| 186 | 287 | ||
| 187 | static void sh_mtu2_clock_event_mode(enum clock_event_mode mode, | 288 | static void sh_mtu2_clock_event_mode(enum clock_event_mode mode, |
| 188 | struct clock_event_device *ced) | 289 | struct clock_event_device *ced) |
| 189 | { | 290 | { |
| 190 | struct sh_mtu2_priv *p = ced_to_sh_mtu2(ced); | 291 | struct sh_mtu2_channel *ch = ced_to_sh_mtu2(ced); |
| 191 | int disabled = 0; | 292 | int disabled = 0; |
| 192 | 293 | ||
| 193 | /* deal with old setting first */ | 294 | /* deal with old setting first */ |
| 194 | switch (ced->mode) { | 295 | switch (ced->mode) { |
| 195 | case CLOCK_EVT_MODE_PERIODIC: | 296 | case CLOCK_EVT_MODE_PERIODIC: |
| 196 | sh_mtu2_disable(p); | 297 | sh_mtu2_disable(ch); |
| 197 | disabled = 1; | 298 | disabled = 1; |
| 198 | break; | 299 | break; |
| 199 | default: | 300 | default: |
| @@ -202,12 +303,13 @@ static void sh_mtu2_clock_event_mode(enum clock_event_mode mode, | |||
| 202 | 303 | ||
| 203 | switch (mode) { | 304 | switch (mode) { |
| 204 | case CLOCK_EVT_MODE_PERIODIC: | 305 | case CLOCK_EVT_MODE_PERIODIC: |
| 205 | dev_info(&p->pdev->dev, "used for periodic clock events\n"); | 306 | dev_info(&ch->mtu->pdev->dev, |
| 206 | sh_mtu2_enable(p); | 307 | "ch%u: used for periodic clock events\n", ch->index); |
| 308 | sh_mtu2_enable(ch); | ||
| 207 | break; | 309 | break; |
| 208 | case CLOCK_EVT_MODE_UNUSED: | 310 | case CLOCK_EVT_MODE_UNUSED: |
| 209 | if (!disabled) | 311 | if (!disabled) |
| 210 | sh_mtu2_disable(p); | 312 | sh_mtu2_disable(ch); |
| 211 | break; | 313 | break; |
| 212 | case CLOCK_EVT_MODE_SHUTDOWN: | 314 | case CLOCK_EVT_MODE_SHUTDOWN: |
| 213 | default: | 315 | default: |
| @@ -217,125 +319,207 @@ static void sh_mtu2_clock_event_mode(enum clock_event_mode mode, | |||
| 217 | 319 | ||
| 218 | static void sh_mtu2_clock_event_suspend(struct clock_event_device *ced) | 320 | static void sh_mtu2_clock_event_suspend(struct clock_event_device *ced) |
| 219 | { | 321 | { |
| 220 | pm_genpd_syscore_poweroff(&ced_to_sh_mtu2(ced)->pdev->dev); | 322 | pm_genpd_syscore_poweroff(&ced_to_sh_mtu2(ced)->mtu->pdev->dev); |
| 221 | } | 323 | } |
| 222 | 324 | ||
| 223 | static void sh_mtu2_clock_event_resume(struct clock_event_device *ced) | 325 | static void sh_mtu2_clock_event_resume(struct clock_event_device *ced) |
| 224 | { | 326 | { |
| 225 | pm_genpd_syscore_poweron(&ced_to_sh_mtu2(ced)->pdev->dev); | 327 | pm_genpd_syscore_poweron(&ced_to_sh_mtu2(ced)->mtu->pdev->dev); |
| 226 | } | 328 | } |
| 227 | 329 | ||
| 228 | static void sh_mtu2_register_clockevent(struct sh_mtu2_priv *p, | 330 | static void sh_mtu2_register_clockevent(struct sh_mtu2_channel *ch, |
| 229 | char *name, unsigned long rating) | 331 | const char *name) |
| 230 | { | 332 | { |
| 231 | struct clock_event_device *ced = &p->ced; | 333 | struct clock_event_device *ced = &ch->ced; |
| 232 | int ret; | 334 | int ret; |
| 233 | 335 | ||
| 234 | memset(ced, 0, sizeof(*ced)); | ||
| 235 | |||
| 236 | ced->name = name; | 336 | ced->name = name; |
| 237 | ced->features = CLOCK_EVT_FEAT_PERIODIC; | 337 | ced->features = CLOCK_EVT_FEAT_PERIODIC; |
| 238 | ced->rating = rating; | 338 | ced->rating = 200; |
| 239 | ced->cpumask = cpumask_of(0); | 339 | ced->cpumask = cpu_possible_mask; |
| 240 | ced->set_mode = sh_mtu2_clock_event_mode; | 340 | ced->set_mode = sh_mtu2_clock_event_mode; |
| 241 | ced->suspend = sh_mtu2_clock_event_suspend; | 341 | ced->suspend = sh_mtu2_clock_event_suspend; |
| 242 | ced->resume = sh_mtu2_clock_event_resume; | 342 | ced->resume = sh_mtu2_clock_event_resume; |
| 243 | 343 | ||
| 244 | dev_info(&p->pdev->dev, "used for clock events\n"); | 344 | dev_info(&ch->mtu->pdev->dev, "ch%u: used for clock events\n", |
| 345 | ch->index); | ||
| 245 | clockevents_register_device(ced); | 346 | clockevents_register_device(ced); |
| 246 | 347 | ||
| 247 | ret = setup_irq(p->irqaction.irq, &p->irqaction); | 348 | ret = request_irq(ch->irq, sh_mtu2_interrupt, |
| 349 | IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING, | ||
| 350 | dev_name(&ch->mtu->pdev->dev), ch); | ||
| 248 | if (ret) { | 351 | if (ret) { |
| 249 | dev_err(&p->pdev->dev, "failed to request irq %d\n", | 352 | dev_err(&ch->mtu->pdev->dev, "ch%u: failed to request irq %d\n", |
| 250 | p->irqaction.irq); | 353 | ch->index, ch->irq); |
| 251 | return; | 354 | return; |
| 252 | } | 355 | } |
| 253 | } | 356 | } |
| 254 | 357 | ||
| 255 | static int sh_mtu2_register(struct sh_mtu2_priv *p, char *name, | 358 | static int sh_mtu2_register(struct sh_mtu2_channel *ch, const char *name, |
| 256 | unsigned long clockevent_rating) | 359 | bool clockevent) |
| 257 | { | 360 | { |
| 258 | if (clockevent_rating) | 361 | if (clockevent) { |
| 259 | sh_mtu2_register_clockevent(p, name, clockevent_rating); | 362 | ch->mtu->has_clockevent = true; |
| 363 | sh_mtu2_register_clockevent(ch, name); | ||
| 364 | } | ||
| 260 | 365 | ||
| 261 | return 0; | 366 | return 0; |
| 262 | } | 367 | } |
| 263 | 368 | ||
| 264 | static int sh_mtu2_setup(struct sh_mtu2_priv *p, struct platform_device *pdev) | 369 | static int sh_mtu2_setup_channel(struct sh_mtu2_channel *ch, unsigned int index, |
| 370 | struct sh_mtu2_device *mtu) | ||
| 265 | { | 371 | { |
| 266 | struct sh_timer_config *cfg = pdev->dev.platform_data; | 372 | static const unsigned int channel_offsets[] = { |
| 267 | struct resource *res; | 373 | 0x300, 0x380, 0x000, |
| 268 | int irq, ret; | 374 | }; |
| 269 | ret = -ENXIO; | 375 | bool clockevent; |
| 376 | |||
| 377 | ch->mtu = mtu; | ||
| 378 | |||
| 379 | if (mtu->legacy) { | ||
| 380 | struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; | ||
| 381 | |||
| 382 | clockevent = cfg->clockevent_rating != 0; | ||
| 270 | 383 | ||
| 271 | memset(p, 0, sizeof(*p)); | 384 | ch->irq = platform_get_irq(mtu->pdev, 0); |
| 272 | p->pdev = pdev; | 385 | ch->base = mtu->mapbase - cfg->channel_offset; |
| 386 | ch->index = cfg->timer_bit; | ||
| 387 | } else { | ||
| 388 | char name[6]; | ||
| 273 | 389 | ||
| 274 | if (!cfg) { | 390 | clockevent = true; |
| 275 | dev_err(&p->pdev->dev, "missing platform data\n"); | 391 | |
| 276 | goto err0; | 392 | sprintf(name, "tgi%ua", index); |
| 393 | ch->irq = platform_get_irq_byname(mtu->pdev, name); | ||
| 394 | ch->base = mtu->mapbase + channel_offsets[index]; | ||
| 395 | ch->index = index; | ||
| 277 | } | 396 | } |
| 278 | 397 | ||
| 279 | platform_set_drvdata(pdev, p); | 398 | if (ch->irq < 0) { |
| 399 | /* Skip channels with no declared interrupt. */ | ||
| 400 | if (!mtu->legacy) | ||
| 401 | return 0; | ||
| 402 | |||
| 403 | dev_err(&mtu->pdev->dev, "ch%u: failed to get irq\n", | ||
| 404 | ch->index); | ||
| 405 | return ch->irq; | ||
| 406 | } | ||
| 407 | |||
| 408 | return sh_mtu2_register(ch, dev_name(&mtu->pdev->dev), clockevent); | ||
| 409 | } | ||
| 280 | 410 | ||
| 281 | res = platform_get_resource(p->pdev, IORESOURCE_MEM, 0); | 411 | static int sh_mtu2_map_memory(struct sh_mtu2_device *mtu) |
| 412 | { | ||
| 413 | struct resource *res; | ||
| 414 | |||
| 415 | res = platform_get_resource(mtu->pdev, IORESOURCE_MEM, 0); | ||
| 282 | if (!res) { | 416 | if (!res) { |
| 283 | dev_err(&p->pdev->dev, "failed to get I/O memory\n"); | 417 | dev_err(&mtu->pdev->dev, "failed to get I/O memory\n"); |
| 284 | goto err0; | 418 | return -ENXIO; |
| 419 | } | ||
| 420 | |||
| 421 | mtu->mapbase = ioremap_nocache(res->start, resource_size(res)); | ||
| 422 | if (mtu->mapbase == NULL) | ||
| 423 | return -ENXIO; | ||
| 424 | |||
| 425 | /* | ||
| 426 | * In legacy platform device configuration (with one device per channel) | ||
| 427 | * the resource points to the channel base address. | ||
| 428 | */ | ||
| 429 | if (mtu->legacy) { | ||
| 430 | struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; | ||
| 431 | mtu->mapbase += cfg->channel_offset; | ||
| 285 | } | 432 | } |
| 286 | 433 | ||
| 287 | irq = platform_get_irq(p->pdev, 0); | 434 | return 0; |
| 288 | if (irq < 0) { | 435 | } |
| 289 | dev_err(&p->pdev->dev, "failed to get irq\n"); | 436 | |
| 290 | goto err0; | 437 | static void sh_mtu2_unmap_memory(struct sh_mtu2_device *mtu) |
| 438 | { | ||
| 439 | if (mtu->legacy) { | ||
| 440 | struct sh_timer_config *cfg = mtu->pdev->dev.platform_data; | ||
| 441 | mtu->mapbase -= cfg->channel_offset; | ||
| 291 | } | 442 | } |
| 292 | 443 | ||
| 293 | /* map memory, let mapbase point to our channel */ | 444 | iounmap(mtu->mapbase); |
| 294 | p->mapbase = ioremap_nocache(res->start, resource_size(res)); | 445 | } |
| 295 | if (p->mapbase == NULL) { | 446 | |
| 296 | dev_err(&p->pdev->dev, "failed to remap I/O memory\n"); | 447 | static int sh_mtu2_setup(struct sh_mtu2_device *mtu, |
| 297 | goto err0; | 448 | struct platform_device *pdev) |
| 449 | { | ||
| 450 | struct sh_timer_config *cfg = pdev->dev.platform_data; | ||
| 451 | const struct platform_device_id *id = pdev->id_entry; | ||
| 452 | unsigned int i; | ||
| 453 | int ret; | ||
| 454 | |||
| 455 | mtu->pdev = pdev; | ||
| 456 | mtu->legacy = id->driver_data; | ||
| 457 | |||
| 458 | if (mtu->legacy && !cfg) { | ||
| 459 | dev_err(&mtu->pdev->dev, "missing platform data\n"); | ||
| 460 | return -ENXIO; | ||
| 298 | } | 461 | } |
| 299 | 462 | ||
| 300 | /* setup data for setup_irq() (too early for request_irq()) */ | 463 | /* Get hold of clock. */ |
| 301 | p->irqaction.name = dev_name(&p->pdev->dev); | 464 | mtu->clk = clk_get(&mtu->pdev->dev, mtu->legacy ? "mtu2_fck" : "fck"); |
| 302 | p->irqaction.handler = sh_mtu2_interrupt; | 465 | if (IS_ERR(mtu->clk)) { |
| 303 | p->irqaction.dev_id = p; | 466 | dev_err(&mtu->pdev->dev, "cannot get clock\n"); |
| 304 | p->irqaction.irq = irq; | 467 | return PTR_ERR(mtu->clk); |
| 305 | p->irqaction.flags = IRQF_TIMER | IRQF_IRQPOLL | IRQF_NOBALANCING; | ||
| 306 | |||
| 307 | /* get hold of clock */ | ||
| 308 | p->clk = clk_get(&p->pdev->dev, "mtu2_fck"); | ||
| 309 | if (IS_ERR(p->clk)) { | ||
| 310 | dev_err(&p->pdev->dev, "cannot get clock\n"); | ||
| 311 | ret = PTR_ERR(p->clk); | ||
| 312 | goto err1; | ||
| 313 | } | 468 | } |
| 314 | 469 | ||
| 315 | ret = clk_prepare(p->clk); | 470 | ret = clk_prepare(mtu->clk); |
| 316 | if (ret < 0) | 471 | if (ret < 0) |
| 317 | goto err2; | 472 | goto err_clk_put; |
| 318 | 473 | ||
| 319 | ret = sh_mtu2_register(p, (char *)dev_name(&p->pdev->dev), | 474 | /* Map the memory resource. */ |
| 320 | cfg->clockevent_rating); | 475 | ret = sh_mtu2_map_memory(mtu); |
| 321 | if (ret < 0) | 476 | if (ret < 0) { |
| 322 | goto err3; | 477 | dev_err(&mtu->pdev->dev, "failed to remap I/O memory\n"); |
| 478 | goto err_clk_unprepare; | ||
| 479 | } | ||
| 480 | |||
| 481 | /* Allocate and setup the channels. */ | ||
| 482 | if (mtu->legacy) | ||
| 483 | mtu->num_channels = 1; | ||
| 484 | else | ||
| 485 | mtu->num_channels = 3; | ||
| 486 | |||
| 487 | mtu->channels = kzalloc(sizeof(*mtu->channels) * mtu->num_channels, | ||
| 488 | GFP_KERNEL); | ||
| 489 | if (mtu->channels == NULL) { | ||
| 490 | ret = -ENOMEM; | ||
| 491 | goto err_unmap; | ||
| 492 | } | ||
| 493 | |||
| 494 | if (mtu->legacy) { | ||
| 495 | ret = sh_mtu2_setup_channel(&mtu->channels[0], 0, mtu); | ||
| 496 | if (ret < 0) | ||
| 497 | goto err_unmap; | ||
| 498 | } else { | ||
| 499 | for (i = 0; i < mtu->num_channels; ++i) { | ||
| 500 | ret = sh_mtu2_setup_channel(&mtu->channels[i], i, mtu); | ||
| 501 | if (ret < 0) | ||
| 502 | goto err_unmap; | ||
| 503 | } | ||
| 504 | } | ||
| 505 | |||
| 506 | platform_set_drvdata(pdev, mtu); | ||
| 323 | 507 | ||
| 324 | return 0; | 508 | return 0; |
| 325 | err3: | 509 | |
| 326 | clk_unprepare(p->clk); | 510 | err_unmap: |
| 327 | err2: | 511 | kfree(mtu->channels); |
| 328 | clk_put(p->clk); | 512 | sh_mtu2_unmap_memory(mtu); |
| 329 | err1: | 513 | err_clk_unprepare: |
| 330 | iounmap(p->mapbase); | 514 | clk_unprepare(mtu->clk); |
| 331 | err0: | 515 | err_clk_put: |
| 516 | clk_put(mtu->clk); | ||
| 332 | return ret; | 517 | return ret; |
| 333 | } | 518 | } |
| 334 | 519 | ||
| 335 | static int sh_mtu2_probe(struct platform_device *pdev) | 520 | static int sh_mtu2_probe(struct platform_device *pdev) |
| 336 | { | 521 | { |
| 337 | struct sh_mtu2_priv *p = platform_get_drvdata(pdev); | 522 | struct sh_mtu2_device *mtu = platform_get_drvdata(pdev); |
| 338 | struct sh_timer_config *cfg = pdev->dev.platform_data; | ||
| 339 | int ret; | 523 | int ret; |
| 340 | 524 | ||
| 341 | if (!is_early_platform_device(pdev)) { | 525 | if (!is_early_platform_device(pdev)) { |
| @@ -343,20 +527,18 @@ static int sh_mtu2_probe(struct platform_device *pdev) | |||
| 343 | pm_runtime_enable(&pdev->dev); | 527 | pm_runtime_enable(&pdev->dev); |
| 344 | } | 528 | } |
| 345 | 529 | ||
| 346 | if (p) { | 530 | if (mtu) { |
| 347 | dev_info(&pdev->dev, "kept as earlytimer\n"); | 531 | dev_info(&pdev->dev, "kept as earlytimer\n"); |
| 348 | goto out; | 532 | goto out; |
| 349 | } | 533 | } |
| 350 | 534 | ||
| 351 | p = kmalloc(sizeof(*p), GFP_KERNEL); | 535 | mtu = kzalloc(sizeof(*mtu), GFP_KERNEL); |
| 352 | if (p == NULL) { | 536 | if (mtu == NULL) |
| 353 | dev_err(&pdev->dev, "failed to allocate driver data\n"); | ||
| 354 | return -ENOMEM; | 537 | return -ENOMEM; |
| 355 | } | ||
| 356 | 538 | ||
| 357 | ret = sh_mtu2_setup(p, pdev); | 539 | ret = sh_mtu2_setup(mtu, pdev); |
| 358 | if (ret) { | 540 | if (ret) { |
| 359 | kfree(p); | 541 | kfree(mtu); |
| 360 | pm_runtime_idle(&pdev->dev); | 542 | pm_runtime_idle(&pdev->dev); |
| 361 | return ret; | 543 | return ret; |
| 362 | } | 544 | } |
| @@ -364,7 +546,7 @@ static int sh_mtu2_probe(struct platform_device *pdev) | |||
| 364 | return 0; | 546 | return 0; |
| 365 | 547 | ||
| 366 | out: | 548 | out: |
| 367 | if (cfg->clockevent_rating) | 549 | if (mtu->has_clockevent) |
| 368 | pm_runtime_irq_safe(&pdev->dev); | 550 | pm_runtime_irq_safe(&pdev->dev); |
| 369 | else | 551 | else |
| 370 | pm_runtime_idle(&pdev->dev); | 552 | pm_runtime_idle(&pdev->dev); |
| @@ -377,12 +559,20 @@ static int sh_mtu2_remove(struct platform_device *pdev) | |||
| 377 | return -EBUSY; /* cannot unregister clockevent */ | 559 | return -EBUSY; /* cannot unregister clockevent */ |
| 378 | } | 560 | } |
| 379 | 561 | ||
| 562 | static const struct platform_device_id sh_mtu2_id_table[] = { | ||
| 563 | { "sh_mtu2", 1 }, | ||
| 564 | { "sh-mtu2", 0 }, | ||
| 565 | { }, | ||
| 566 | }; | ||
| 567 | MODULE_DEVICE_TABLE(platform, sh_mtu2_id_table); | ||
| 568 | |||
| 380 | static struct platform_driver sh_mtu2_device_driver = { | 569 | static struct platform_driver sh_mtu2_device_driver = { |
| 381 | .probe = sh_mtu2_probe, | 570 | .probe = sh_mtu2_probe, |
| 382 | .remove = sh_mtu2_remove, | 571 | .remove = sh_mtu2_remove, |
| 383 | .driver = { | 572 | .driver = { |
| 384 | .name = "sh_mtu2", | 573 | .name = "sh_mtu2", |
| 385 | } | 574 | }, |
| 575 | .id_table = sh_mtu2_id_table, | ||
| 386 | }; | 576 | }; |
| 387 | 577 | ||
| 388 | static int __init sh_mtu2_init(void) | 578 | static int __init sh_mtu2_init(void) |
