diff options
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/gpio/gpio-stp-xway.c | 2 | ||||
| -rw-r--r-- | drivers/net/ethernet/broadcom/bcm63xx_enet.h | 30 | ||||
| -rw-r--r-- | drivers/net/ethernet/octeon/octeon_mgmt.c | 550 | ||||
| -rw-r--r-- | drivers/pinctrl/Kconfig | 16 | ||||
| -rw-r--r-- | drivers/pinctrl/Makefile | 3 | ||||
| -rw-r--r-- | drivers/pinctrl/pinctrl-falcon.c | 468 | ||||
| -rw-r--r-- | drivers/pinctrl/pinctrl-lantiq.c | 342 | ||||
| -rw-r--r-- | drivers/pinctrl/pinctrl-lantiq.h | 194 | ||||
| -rw-r--r-- | drivers/pinctrl/pinctrl-xway.c | 781 | ||||
| -rw-r--r-- | drivers/spi/Kconfig | 7 | ||||
| -rw-r--r-- | drivers/spi/Makefile | 1 | ||||
| -rw-r--r-- | drivers/spi/spi-octeon.c | 362 |
12 files changed, 2621 insertions, 135 deletions
diff --git a/drivers/gpio/gpio-stp-xway.c b/drivers/gpio/gpio-stp-xway.c index e35096bf3cfb..8bead0bb6459 100644 --- a/drivers/gpio/gpio-stp-xway.c +++ b/drivers/gpio/gpio-stp-xway.c | |||
| @@ -82,7 +82,7 @@ struct xway_stp { | |||
| 82 | struct gpio_chip gc; | 82 | struct gpio_chip gc; |
| 83 | void __iomem *virt; | 83 | void __iomem *virt; |
| 84 | u32 edge; /* rising or falling edge triggered shift register */ | 84 | u32 edge; /* rising or falling edge triggered shift register */ |
| 85 | u16 shadow; /* shadow the shift registers state */ | 85 | u32 shadow; /* shadow the shift registers state */ |
| 86 | u8 groups; /* we can drive 1-3 groups of 8bit each */ | 86 | u8 groups; /* we can drive 1-3 groups of 8bit each */ |
| 87 | u8 dsl; /* the 2 LSBs can be driven by the dsl core */ | 87 | u8 dsl; /* the 2 LSBs can be driven by the dsl core */ |
| 88 | u8 phy1; /* 3 bits can be driven by phy1 */ | 88 | u8 phy1; /* 3 bits can be driven by phy1 */ |
diff --git a/drivers/net/ethernet/broadcom/bcm63xx_enet.h b/drivers/net/ethernet/broadcom/bcm63xx_enet.h index 0e3048b788c2..133d5857b9e2 100644 --- a/drivers/net/ethernet/broadcom/bcm63xx_enet.h +++ b/drivers/net/ethernet/broadcom/bcm63xx_enet.h | |||
| @@ -10,6 +10,7 @@ | |||
| 10 | #include <bcm63xx_regs.h> | 10 | #include <bcm63xx_regs.h> |
| 11 | #include <bcm63xx_irq.h> | 11 | #include <bcm63xx_irq.h> |
| 12 | #include <bcm63xx_io.h> | 12 | #include <bcm63xx_io.h> |
| 13 | #include <bcm63xx_iudma.h> | ||
| 13 | 14 | ||
| 14 | /* default number of descriptor */ | 15 | /* default number of descriptor */ |
| 15 | #define BCMENET_DEF_RX_DESC 64 | 16 | #define BCMENET_DEF_RX_DESC 64 |
| @@ -31,35 +32,6 @@ | |||
| 31 | #define BCMENET_MAX_MTU 2046 | 32 | #define BCMENET_MAX_MTU 2046 |
| 32 | 33 | ||
| 33 | /* | 34 | /* |
| 34 | * rx/tx dma descriptor | ||
| 35 | */ | ||
| 36 | struct bcm_enet_desc { | ||
| 37 | u32 len_stat; | ||
| 38 | u32 address; | ||
| 39 | }; | ||
| 40 | |||
| 41 | #define DMADESC_LENGTH_SHIFT 16 | ||
| 42 | #define DMADESC_LENGTH_MASK (0xfff << DMADESC_LENGTH_SHIFT) | ||
| 43 | #define DMADESC_OWNER_MASK (1 << 15) | ||
| 44 | #define DMADESC_EOP_MASK (1 << 14) | ||
| 45 | #define DMADESC_SOP_MASK (1 << 13) | ||
| 46 | #define DMADESC_ESOP_MASK (DMADESC_EOP_MASK | DMADESC_SOP_MASK) | ||
| 47 | #define DMADESC_WRAP_MASK (1 << 12) | ||
| 48 | |||
| 49 | #define DMADESC_UNDER_MASK (1 << 9) | ||
| 50 | #define DMADESC_APPEND_CRC (1 << 8) | ||
| 51 | #define DMADESC_OVSIZE_MASK (1 << 4) | ||
| 52 | #define DMADESC_RXER_MASK (1 << 2) | ||
| 53 | #define DMADESC_CRC_MASK (1 << 1) | ||
| 54 | #define DMADESC_OV_MASK (1 << 0) | ||
| 55 | #define DMADESC_ERR_MASK (DMADESC_UNDER_MASK | \ | ||
| 56 | DMADESC_OVSIZE_MASK | \ | ||
| 57 | DMADESC_RXER_MASK | \ | ||
| 58 | DMADESC_CRC_MASK | \ | ||
| 59 | DMADESC_OV_MASK) | ||
| 60 | |||
| 61 | |||
| 62 | /* | ||
| 63 | * MIB Counters register definitions | 35 | * MIB Counters register definitions |
| 64 | */ | 36 | */ |
| 65 | #define ETH_MIB_TX_GD_OCTETS 0 | 37 | #define ETH_MIB_TX_GD_OCTETS 0 |
diff --git a/drivers/net/ethernet/octeon/octeon_mgmt.c b/drivers/net/ethernet/octeon/octeon_mgmt.c index a688a2ddcfd6..f97719c48516 100644 --- a/drivers/net/ethernet/octeon/octeon_mgmt.c +++ b/drivers/net/ethernet/octeon/octeon_mgmt.c | |||
| @@ -3,13 +3,14 @@ | |||
| 3 | * License. See the file "COPYING" in the main directory of this archive | 3 | * License. See the file "COPYING" in the main directory of this archive |
| 4 | * for more details. | 4 | * for more details. |
| 5 | * | 5 | * |
| 6 | * Copyright (C) 2009 Cavium Networks | 6 | * Copyright (C) 2009-2012 Cavium, Inc |
| 7 | */ | 7 | */ |
| 8 | 8 | ||
| 9 | #include <linux/platform_device.h> | 9 | #include <linux/platform_device.h> |
| 10 | #include <linux/dma-mapping.h> | 10 | #include <linux/dma-mapping.h> |
| 11 | #include <linux/etherdevice.h> | 11 | #include <linux/etherdevice.h> |
| 12 | #include <linux/capability.h> | 12 | #include <linux/capability.h> |
| 13 | #include <linux/net_tstamp.h> | ||
| 13 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
| 14 | #include <linux/netdevice.h> | 15 | #include <linux/netdevice.h> |
| 15 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
| @@ -33,8 +34,7 @@ | |||
| 33 | 34 | ||
| 34 | #define OCTEON_MGMT_NAPI_WEIGHT 16 | 35 | #define OCTEON_MGMT_NAPI_WEIGHT 16 |
| 35 | 36 | ||
| 36 | /* | 37 | /* Ring sizes that are powers of two allow for more efficient modulo |
| 37 | * Ring sizes that are powers of two allow for more efficient modulo | ||
| 38 | * opertions. | 38 | * opertions. |
| 39 | */ | 39 | */ |
| 40 | #define OCTEON_MGMT_RX_RING_SIZE 512 | 40 | #define OCTEON_MGMT_RX_RING_SIZE 512 |
| @@ -93,6 +93,7 @@ union mgmt_port_ring_entry { | |||
| 93 | #define AGL_GMX_RX_ADR_CAM4 0x1a0 | 93 | #define AGL_GMX_RX_ADR_CAM4 0x1a0 |
| 94 | #define AGL_GMX_RX_ADR_CAM5 0x1a8 | 94 | #define AGL_GMX_RX_ADR_CAM5 0x1a8 |
| 95 | 95 | ||
| 96 | #define AGL_GMX_TX_CLK 0x208 | ||
| 96 | #define AGL_GMX_TX_STATS_CTL 0x268 | 97 | #define AGL_GMX_TX_STATS_CTL 0x268 |
| 97 | #define AGL_GMX_TX_CTL 0x270 | 98 | #define AGL_GMX_TX_CTL 0x270 |
| 98 | #define AGL_GMX_TX_STAT0 0x280 | 99 | #define AGL_GMX_TX_STAT0 0x280 |
| @@ -110,8 +111,10 @@ struct octeon_mgmt { | |||
| 110 | struct net_device *netdev; | 111 | struct net_device *netdev; |
| 111 | u64 mix; | 112 | u64 mix; |
| 112 | u64 agl; | 113 | u64 agl; |
| 114 | u64 agl_prt_ctl; | ||
| 113 | int port; | 115 | int port; |
| 114 | int irq; | 116 | int irq; |
| 117 | bool has_rx_tstamp; | ||
| 115 | u64 *tx_ring; | 118 | u64 *tx_ring; |
| 116 | dma_addr_t tx_ring_handle; | 119 | dma_addr_t tx_ring_handle; |
| 117 | unsigned int tx_next; | 120 | unsigned int tx_next; |
| @@ -131,6 +134,7 @@ struct octeon_mgmt { | |||
| 131 | spinlock_t lock; | 134 | spinlock_t lock; |
| 132 | unsigned int last_duplex; | 135 | unsigned int last_duplex; |
| 133 | unsigned int last_link; | 136 | unsigned int last_link; |
| 137 | unsigned int last_speed; | ||
| 134 | struct device *dev; | 138 | struct device *dev; |
| 135 | struct napi_struct napi; | 139 | struct napi_struct napi; |
| 136 | struct tasklet_struct tx_clean_tasklet; | 140 | struct tasklet_struct tx_clean_tasklet; |
| @@ -140,6 +144,8 @@ struct octeon_mgmt { | |||
| 140 | resource_size_t mix_size; | 144 | resource_size_t mix_size; |
| 141 | resource_size_t agl_phys; | 145 | resource_size_t agl_phys; |
| 142 | resource_size_t agl_size; | 146 | resource_size_t agl_size; |
| 147 | resource_size_t agl_prt_ctl_phys; | ||
| 148 | resource_size_t agl_prt_ctl_size; | ||
| 143 | }; | 149 | }; |
| 144 | 150 | ||
| 145 | static void octeon_mgmt_set_rx_irq(struct octeon_mgmt *p, int enable) | 151 | static void octeon_mgmt_set_rx_irq(struct octeon_mgmt *p, int enable) |
| @@ -166,22 +172,22 @@ static void octeon_mgmt_set_tx_irq(struct octeon_mgmt *p, int enable) | |||
| 166 | spin_unlock_irqrestore(&p->lock, flags); | 172 | spin_unlock_irqrestore(&p->lock, flags); |
| 167 | } | 173 | } |
| 168 | 174 | ||
| 169 | static inline void octeon_mgmt_enable_rx_irq(struct octeon_mgmt *p) | 175 | static void octeon_mgmt_enable_rx_irq(struct octeon_mgmt *p) |
| 170 | { | 176 | { |
| 171 | octeon_mgmt_set_rx_irq(p, 1); | 177 | octeon_mgmt_set_rx_irq(p, 1); |
| 172 | } | 178 | } |
| 173 | 179 | ||
| 174 | static inline void octeon_mgmt_disable_rx_irq(struct octeon_mgmt *p) | 180 | static void octeon_mgmt_disable_rx_irq(struct octeon_mgmt *p) |
| 175 | { | 181 | { |
| 176 | octeon_mgmt_set_rx_irq(p, 0); | 182 | octeon_mgmt_set_rx_irq(p, 0); |
| 177 | } | 183 | } |
| 178 | 184 | ||
| 179 | static inline void octeon_mgmt_enable_tx_irq(struct octeon_mgmt *p) | 185 | static void octeon_mgmt_enable_tx_irq(struct octeon_mgmt *p) |
| 180 | { | 186 | { |
| 181 | octeon_mgmt_set_tx_irq(p, 1); | 187 | octeon_mgmt_set_tx_irq(p, 1); |
| 182 | } | 188 | } |
| 183 | 189 | ||
| 184 | static inline void octeon_mgmt_disable_tx_irq(struct octeon_mgmt *p) | 190 | static void octeon_mgmt_disable_tx_irq(struct octeon_mgmt *p) |
| 185 | { | 191 | { |
| 186 | octeon_mgmt_set_tx_irq(p, 0); | 192 | octeon_mgmt_set_tx_irq(p, 0); |
| 187 | } | 193 | } |
| @@ -233,6 +239,28 @@ static void octeon_mgmt_rx_fill_ring(struct net_device *netdev) | |||
| 233 | } | 239 | } |
| 234 | } | 240 | } |
| 235 | 241 | ||
| 242 | static ktime_t ptp_to_ktime(u64 ptptime) | ||
| 243 | { | ||
| 244 | ktime_t ktimebase; | ||
| 245 | u64 ptpbase; | ||
| 246 | unsigned long flags; | ||
| 247 | |||
| 248 | local_irq_save(flags); | ||
| 249 | /* Fill the icache with the code */ | ||
| 250 | ktime_get_real(); | ||
| 251 | /* Flush all pending operations */ | ||
| 252 | mb(); | ||
| 253 | /* Read the time and PTP clock as close together as | ||
| 254 | * possible. It is important that this sequence take the same | ||
| 255 | * amount of time to reduce jitter | ||
| 256 | */ | ||
| 257 | ktimebase = ktime_get_real(); | ||
| 258 | ptpbase = cvmx_read_csr(CVMX_MIO_PTP_CLOCK_HI); | ||
| 259 | local_irq_restore(flags); | ||
| 260 | |||
| 261 | return ktime_sub_ns(ktimebase, ptpbase - ptptime); | ||
| 262 | } | ||
| 263 | |||
| 236 | static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p) | 264 | static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p) |
| 237 | { | 265 | { |
| 238 | union cvmx_mixx_orcnt mix_orcnt; | 266 | union cvmx_mixx_orcnt mix_orcnt; |
| @@ -272,6 +300,20 @@ static void octeon_mgmt_clean_tx_buffers(struct octeon_mgmt *p) | |||
| 272 | 300 | ||
| 273 | dma_unmap_single(p->dev, re.s.addr, re.s.len, | 301 | dma_unmap_single(p->dev, re.s.addr, re.s.len, |
| 274 | DMA_TO_DEVICE); | 302 | DMA_TO_DEVICE); |
| 303 | |||
| 304 | /* Read the hardware TX timestamp if one was recorded */ | ||
| 305 | if (unlikely(re.s.tstamp)) { | ||
| 306 | struct skb_shared_hwtstamps ts; | ||
| 307 | /* Read the timestamp */ | ||
| 308 | u64 ns = cvmx_read_csr(CVMX_MIXX_TSTAMP(p->port)); | ||
| 309 | /* Remove the timestamp from the FIFO */ | ||
| 310 | cvmx_write_csr(CVMX_MIXX_TSCTL(p->port), 0); | ||
| 311 | /* Tell the kernel about the timestamp */ | ||
| 312 | ts.syststamp = ptp_to_ktime(ns); | ||
| 313 | ts.hwtstamp = ns_to_ktime(ns); | ||
| 314 | skb_tstamp_tx(skb, &ts); | ||
| 315 | } | ||
| 316 | |||
| 275 | dev_kfree_skb_any(skb); | 317 | dev_kfree_skb_any(skb); |
| 276 | cleaned++; | 318 | cleaned++; |
| 277 | 319 | ||
| @@ -372,14 +414,23 @@ static int octeon_mgmt_receive_one(struct octeon_mgmt *p) | |||
| 372 | /* A good packet, send it up. */ | 414 | /* A good packet, send it up. */ |
| 373 | skb_put(skb, re.s.len); | 415 | skb_put(skb, re.s.len); |
| 374 | good: | 416 | good: |
| 417 | /* Process the RX timestamp if it was recorded */ | ||
| 418 | if (p->has_rx_tstamp) { | ||
| 419 | /* The first 8 bytes are the timestamp */ | ||
| 420 | u64 ns = *(u64 *)skb->data; | ||
| 421 | struct skb_shared_hwtstamps *ts; | ||
| 422 | ts = skb_hwtstamps(skb); | ||
| 423 | ts->hwtstamp = ns_to_ktime(ns); | ||
| 424 | ts->syststamp = ptp_to_ktime(ns); | ||
| 425 | __skb_pull(skb, 8); | ||
| 426 | } | ||
| 375 | skb->protocol = eth_type_trans(skb, netdev); | 427 | skb->protocol = eth_type_trans(skb, netdev); |
| 376 | netdev->stats.rx_packets++; | 428 | netdev->stats.rx_packets++; |
| 377 | netdev->stats.rx_bytes += skb->len; | 429 | netdev->stats.rx_bytes += skb->len; |
| 378 | netif_receive_skb(skb); | 430 | netif_receive_skb(skb); |
| 379 | rc = 0; | 431 | rc = 0; |
| 380 | } else if (re.s.code == RING_ENTRY_CODE_MORE) { | 432 | } else if (re.s.code == RING_ENTRY_CODE_MORE) { |
| 381 | /* | 433 | /* Packet split across skbs. This can happen if we |
| 382 | * Packet split across skbs. This can happen if we | ||
| 383 | * increase the MTU. Buffers that are already in the | 434 | * increase the MTU. Buffers that are already in the |
| 384 | * rx ring can then end up being too small. As the rx | 435 | * rx ring can then end up being too small. As the rx |
| 385 | * ring is refilled, buffers sized for the new MTU | 436 | * ring is refilled, buffers sized for the new MTU |
| @@ -409,8 +460,7 @@ good: | |||
| 409 | } else { | 460 | } else { |
| 410 | /* Some other error, discard it. */ | 461 | /* Some other error, discard it. */ |
| 411 | dev_kfree_skb_any(skb); | 462 | dev_kfree_skb_any(skb); |
| 412 | /* | 463 | /* Error statistics are accumulated in |
| 413 | * Error statistics are accumulated in | ||
| 414 | * octeon_mgmt_update_rx_stats. | 464 | * octeon_mgmt_update_rx_stats. |
| 415 | */ | 465 | */ |
| 416 | } | 466 | } |
| @@ -488,7 +538,7 @@ static void octeon_mgmt_reset_hw(struct octeon_mgmt *p) | |||
| 488 | mix_ctl.s.reset = 1; | 538 | mix_ctl.s.reset = 1; |
| 489 | cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64); | 539 | cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64); |
| 490 | cvmx_read_csr(p->mix + MIX_CTL); | 540 | cvmx_read_csr(p->mix + MIX_CTL); |
| 491 | cvmx_wait(64); | 541 | octeon_io_clk_delay(64); |
| 492 | 542 | ||
| 493 | mix_bist.u64 = cvmx_read_csr(p->mix + MIX_BIST); | 543 | mix_bist.u64 = cvmx_read_csr(p->mix + MIX_BIST); |
| 494 | if (mix_bist.u64) | 544 | if (mix_bist.u64) |
| @@ -537,8 +587,7 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev) | |||
| 537 | cam_mode = 0; | 587 | cam_mode = 0; |
| 538 | available_cam_entries = 8; | 588 | available_cam_entries = 8; |
| 539 | } else { | 589 | } else { |
| 540 | /* | 590 | /* One CAM entry for the primary address, leaves seven |
| 541 | * One CAM entry for the primary address, leaves seven | ||
| 542 | * for the secondary addresses. | 591 | * for the secondary addresses. |
| 543 | */ | 592 | */ |
| 544 | available_cam_entries = 7 - netdev->uc.count; | 593 | available_cam_entries = 7 - netdev->uc.count; |
| @@ -595,12 +644,10 @@ static void octeon_mgmt_set_rx_filtering(struct net_device *netdev) | |||
| 595 | 644 | ||
| 596 | static int octeon_mgmt_set_mac_address(struct net_device *netdev, void *addr) | 645 | static int octeon_mgmt_set_mac_address(struct net_device *netdev, void *addr) |
| 597 | { | 646 | { |
| 598 | struct sockaddr *sa = addr; | 647 | int r = eth_mac_addr(netdev, addr); |
| 599 | 648 | ||
| 600 | if (!is_valid_ether_addr(sa->sa_data)) | 649 | if (r) |
| 601 | return -EADDRNOTAVAIL; | 650 | return r; |
| 602 | |||
| 603 | memcpy(netdev->dev_addr, sa->sa_data, ETH_ALEN); | ||
| 604 | 651 | ||
| 605 | octeon_mgmt_set_rx_filtering(netdev); | 652 | octeon_mgmt_set_rx_filtering(netdev); |
| 606 | 653 | ||
| @@ -612,8 +659,7 @@ static int octeon_mgmt_change_mtu(struct net_device *netdev, int new_mtu) | |||
| 612 | struct octeon_mgmt *p = netdev_priv(netdev); | 659 | struct octeon_mgmt *p = netdev_priv(netdev); |
| 613 | int size_without_fcs = new_mtu + OCTEON_MGMT_RX_HEADROOM; | 660 | int size_without_fcs = new_mtu + OCTEON_MGMT_RX_HEADROOM; |
| 614 | 661 | ||
| 615 | /* | 662 | /* Limit the MTU to make sure the ethernet packets are between |
| 616 | * Limit the MTU to make sure the ethernet packets are between | ||
| 617 | * 64 bytes and 16383 bytes. | 663 | * 64 bytes and 16383 bytes. |
| 618 | */ | 664 | */ |
| 619 | if (size_without_fcs < 64 || size_without_fcs > 16383) { | 665 | if (size_without_fcs < 64 || size_without_fcs > 16383) { |
| @@ -656,53 +702,258 @@ static irqreturn_t octeon_mgmt_interrupt(int cpl, void *dev_id) | |||
| 656 | return IRQ_HANDLED; | 702 | return IRQ_HANDLED; |
| 657 | } | 703 | } |
| 658 | 704 | ||
| 705 | static int octeon_mgmt_ioctl_hwtstamp(struct net_device *netdev, | ||
| 706 | struct ifreq *rq, int cmd) | ||
| 707 | { | ||
| 708 | struct octeon_mgmt *p = netdev_priv(netdev); | ||
| 709 | struct hwtstamp_config config; | ||
| 710 | union cvmx_mio_ptp_clock_cfg ptp; | ||
| 711 | union cvmx_agl_gmx_rxx_frm_ctl rxx_frm_ctl; | ||
| 712 | bool have_hw_timestamps = false; | ||
| 713 | |||
| 714 | if (copy_from_user(&config, rq->ifr_data, sizeof(config))) | ||
| 715 | return -EFAULT; | ||
| 716 | |||
| 717 | if (config.flags) /* reserved for future extensions */ | ||
| 718 | return -EINVAL; | ||
| 719 | |||
| 720 | /* Check the status of hardware for tiemstamps */ | ||
| 721 | if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { | ||
| 722 | /* Get the current state of the PTP clock */ | ||
| 723 | ptp.u64 = cvmx_read_csr(CVMX_MIO_PTP_CLOCK_CFG); | ||
| 724 | if (!ptp.s.ext_clk_en) { | ||
| 725 | /* The clock has not been configured to use an | ||
| 726 | * external source. Program it to use the main clock | ||
| 727 | * reference. | ||
| 728 | */ | ||
| 729 | u64 clock_comp = (NSEC_PER_SEC << 32) / octeon_get_io_clock_rate(); | ||
| 730 | if (!ptp.s.ptp_en) | ||
| 731 | cvmx_write_csr(CVMX_MIO_PTP_CLOCK_COMP, clock_comp); | ||
| 732 | pr_info("PTP Clock: Using sclk reference at %lld Hz\n", | ||
| 733 | (NSEC_PER_SEC << 32) / clock_comp); | ||
| 734 | } else { | ||
| 735 | /* The clock is already programmed to use a GPIO */ | ||
| 736 | u64 clock_comp = cvmx_read_csr(CVMX_MIO_PTP_CLOCK_COMP); | ||
| 737 | pr_info("PTP Clock: Using GPIO %d at %lld Hz\n", | ||
| 738 | ptp.s.ext_clk_in, | ||
| 739 | (NSEC_PER_SEC << 32) / clock_comp); | ||
| 740 | } | ||
| 741 | |||
| 742 | /* Enable the clock if it wasn't done already */ | ||
| 743 | if (!ptp.s.ptp_en) { | ||
| 744 | ptp.s.ptp_en = 1; | ||
| 745 | cvmx_write_csr(CVMX_MIO_PTP_CLOCK_CFG, ptp.u64); | ||
| 746 | } | ||
| 747 | have_hw_timestamps = true; | ||
| 748 | } | ||
| 749 | |||
| 750 | if (!have_hw_timestamps) | ||
| 751 | return -EINVAL; | ||
| 752 | |||
| 753 | switch (config.tx_type) { | ||
| 754 | case HWTSTAMP_TX_OFF: | ||
| 755 | case HWTSTAMP_TX_ON: | ||
| 756 | break; | ||
| 757 | default: | ||
| 758 | return -ERANGE; | ||
| 759 | } | ||
| 760 | |||
| 761 | switch (config.rx_filter) { | ||
| 762 | case HWTSTAMP_FILTER_NONE: | ||
| 763 | p->has_rx_tstamp = false; | ||
| 764 | rxx_frm_ctl.u64 = cvmx_read_csr(p->agl + AGL_GMX_RX_FRM_CTL); | ||
| 765 | rxx_frm_ctl.s.ptp_mode = 0; | ||
| 766 | cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_CTL, rxx_frm_ctl.u64); | ||
| 767 | break; | ||
| 768 | case HWTSTAMP_FILTER_ALL: | ||
| 769 | case HWTSTAMP_FILTER_SOME: | ||
| 770 | case HWTSTAMP_FILTER_PTP_V1_L4_EVENT: | ||
| 771 | case HWTSTAMP_FILTER_PTP_V1_L4_SYNC: | ||
| 772 | case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ: | ||
| 773 | case HWTSTAMP_FILTER_PTP_V2_L4_EVENT: | ||
| 774 | case HWTSTAMP_FILTER_PTP_V2_L4_SYNC: | ||
| 775 | case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ: | ||
| 776 | case HWTSTAMP_FILTER_PTP_V2_L2_EVENT: | ||
| 777 | case HWTSTAMP_FILTER_PTP_V2_L2_SYNC: | ||
| 778 | case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ: | ||
| 779 | case HWTSTAMP_FILTER_PTP_V2_EVENT: | ||
| 780 | case HWTSTAMP_FILTER_PTP_V2_SYNC: | ||
| 781 | case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ: | ||
| 782 | p->has_rx_tstamp = have_hw_timestamps; | ||
| 783 | config.rx_filter = HWTSTAMP_FILTER_ALL; | ||
| 784 | if (p->has_rx_tstamp) { | ||
| 785 | rxx_frm_ctl.u64 = cvmx_read_csr(p->agl + AGL_GMX_RX_FRM_CTL); | ||
| 786 | rxx_frm_ctl.s.ptp_mode = 1; | ||
| 787 | cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_CTL, rxx_frm_ctl.u64); | ||
| 788 | } | ||
| 789 | break; | ||
| 790 | default: | ||
| 791 | return -ERANGE; | ||
| 792 | } | ||
| 793 | |||
| 794 | if (copy_to_user(rq->ifr_data, &config, sizeof(config))) | ||
| 795 | return -EFAULT; | ||
| 796 | |||
| 797 | return 0; | ||
| 798 | } | ||
| 799 | |||
| 659 | static int octeon_mgmt_ioctl(struct net_device *netdev, | 800 | static int octeon_mgmt_ioctl(struct net_device *netdev, |
| 660 | struct ifreq *rq, int cmd) | 801 | struct ifreq *rq, int cmd) |
| 661 | { | 802 | { |
| 662 | struct octeon_mgmt *p = netdev_priv(netdev); | 803 | struct octeon_mgmt *p = netdev_priv(netdev); |
| 663 | 804 | ||
| 664 | if (!netif_running(netdev)) | 805 | switch (cmd) { |
| 806 | case SIOCSHWTSTAMP: | ||
| 807 | return octeon_mgmt_ioctl_hwtstamp(netdev, rq, cmd); | ||
| 808 | default: | ||
| 809 | if (p->phydev) | ||
| 810 | return phy_mii_ioctl(p->phydev, rq, cmd); | ||
| 665 | return -EINVAL; | 811 | return -EINVAL; |
| 812 | } | ||
| 813 | } | ||
| 666 | 814 | ||
| 667 | if (!p->phydev) | 815 | static void octeon_mgmt_disable_link(struct octeon_mgmt *p) |
| 668 | return -EINVAL; | 816 | { |
| 817 | union cvmx_agl_gmx_prtx_cfg prtx_cfg; | ||
| 669 | 818 | ||
| 670 | return phy_mii_ioctl(p->phydev, rq, cmd); | 819 | /* Disable GMX before we make any changes. */ |
| 820 | prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); | ||
| 821 | prtx_cfg.s.en = 0; | ||
| 822 | prtx_cfg.s.tx_en = 0; | ||
| 823 | prtx_cfg.s.rx_en = 0; | ||
| 824 | cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64); | ||
| 825 | |||
| 826 | if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { | ||
| 827 | int i; | ||
| 828 | for (i = 0; i < 10; i++) { | ||
| 829 | prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); | ||
| 830 | if (prtx_cfg.s.tx_idle == 1 || prtx_cfg.s.rx_idle == 1) | ||
| 831 | break; | ||
| 832 | mdelay(1); | ||
| 833 | i++; | ||
| 834 | } | ||
| 835 | } | ||
| 836 | } | ||
| 837 | |||
| 838 | static void octeon_mgmt_enable_link(struct octeon_mgmt *p) | ||
| 839 | { | ||
| 840 | union cvmx_agl_gmx_prtx_cfg prtx_cfg; | ||
| 841 | |||
| 842 | /* Restore the GMX enable state only if link is set */ | ||
| 843 | prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); | ||
| 844 | prtx_cfg.s.tx_en = 1; | ||
| 845 | prtx_cfg.s.rx_en = 1; | ||
| 846 | prtx_cfg.s.en = 1; | ||
| 847 | cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64); | ||
| 848 | } | ||
| 849 | |||
| 850 | static void octeon_mgmt_update_link(struct octeon_mgmt *p) | ||
| 851 | { | ||
| 852 | union cvmx_agl_gmx_prtx_cfg prtx_cfg; | ||
| 853 | |||
| 854 | prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); | ||
| 855 | |||
| 856 | if (!p->phydev->link) | ||
| 857 | prtx_cfg.s.duplex = 1; | ||
| 858 | else | ||
| 859 | prtx_cfg.s.duplex = p->phydev->duplex; | ||
| 860 | |||
| 861 | switch (p->phydev->speed) { | ||
| 862 | case 10: | ||
| 863 | prtx_cfg.s.speed = 0; | ||
| 864 | prtx_cfg.s.slottime = 0; | ||
| 865 | |||
| 866 | if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { | ||
| 867 | prtx_cfg.s.burst = 1; | ||
| 868 | prtx_cfg.s.speed_msb = 1; | ||
| 869 | } | ||
| 870 | break; | ||
| 871 | case 100: | ||
| 872 | prtx_cfg.s.speed = 0; | ||
| 873 | prtx_cfg.s.slottime = 0; | ||
| 874 | |||
| 875 | if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { | ||
| 876 | prtx_cfg.s.burst = 1; | ||
| 877 | prtx_cfg.s.speed_msb = 0; | ||
| 878 | } | ||
| 879 | break; | ||
| 880 | case 1000: | ||
| 881 | /* 1000 MBits is only supported on 6XXX chips */ | ||
| 882 | if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { | ||
| 883 | prtx_cfg.s.speed = 1; | ||
| 884 | prtx_cfg.s.speed_msb = 0; | ||
| 885 | /* Only matters for half-duplex */ | ||
| 886 | prtx_cfg.s.slottime = 1; | ||
| 887 | prtx_cfg.s.burst = p->phydev->duplex; | ||
| 888 | } | ||
| 889 | break; | ||
| 890 | case 0: /* No link */ | ||
| 891 | default: | ||
| 892 | break; | ||
| 893 | } | ||
| 894 | |||
| 895 | /* Write the new GMX setting with the port still disabled. */ | ||
| 896 | cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64); | ||
| 897 | |||
| 898 | /* Read GMX CFG again to make sure the config is completed. */ | ||
| 899 | prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); | ||
| 900 | |||
| 901 | if (OCTEON_IS_MODEL(OCTEON_CN6XXX)) { | ||
| 902 | union cvmx_agl_gmx_txx_clk agl_clk; | ||
| 903 | union cvmx_agl_prtx_ctl prtx_ctl; | ||
| 904 | |||
| 905 | prtx_ctl.u64 = cvmx_read_csr(p->agl_prt_ctl); | ||
| 906 | agl_clk.u64 = cvmx_read_csr(p->agl + AGL_GMX_TX_CLK); | ||
| 907 | /* MII (both speeds) and RGMII 1000 speed. */ | ||
| 908 | agl_clk.s.clk_cnt = 1; | ||
| 909 | if (prtx_ctl.s.mode == 0) { /* RGMII mode */ | ||
| 910 | if (p->phydev->speed == 10) | ||
| 911 | agl_clk.s.clk_cnt = 50; | ||
| 912 | else if (p->phydev->speed == 100) | ||
| 913 | agl_clk.s.clk_cnt = 5; | ||
| 914 | } | ||
| 915 | cvmx_write_csr(p->agl + AGL_GMX_TX_CLK, agl_clk.u64); | ||
| 916 | } | ||
| 671 | } | 917 | } |
| 672 | 918 | ||
| 673 | static void octeon_mgmt_adjust_link(struct net_device *netdev) | 919 | static void octeon_mgmt_adjust_link(struct net_device *netdev) |
| 674 | { | 920 | { |
| 675 | struct octeon_mgmt *p = netdev_priv(netdev); | 921 | struct octeon_mgmt *p = netdev_priv(netdev); |
| 676 | union cvmx_agl_gmx_prtx_cfg prtx_cfg; | ||
| 677 | unsigned long flags; | 922 | unsigned long flags; |
| 678 | int link_changed = 0; | 923 | int link_changed = 0; |
| 679 | 924 | ||
| 925 | if (!p->phydev) | ||
| 926 | return; | ||
| 927 | |||
| 680 | spin_lock_irqsave(&p->lock, flags); | 928 | spin_lock_irqsave(&p->lock, flags); |
| 681 | if (p->phydev->link) { | 929 | |
| 682 | if (!p->last_link) | 930 | |
| 683 | link_changed = 1; | 931 | if (!p->phydev->link && p->last_link) |
| 684 | if (p->last_duplex != p->phydev->duplex) { | 932 | link_changed = -1; |
| 685 | p->last_duplex = p->phydev->duplex; | 933 | |
| 686 | prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); | 934 | if (p->phydev->link |
| 687 | prtx_cfg.s.duplex = p->phydev->duplex; | 935 | && (p->last_duplex != p->phydev->duplex |
| 688 | cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64); | 936 | || p->last_link != p->phydev->link |
| 689 | } | 937 | || p->last_speed != p->phydev->speed)) { |
| 690 | } else { | 938 | octeon_mgmt_disable_link(p); |
| 691 | if (p->last_link) | 939 | link_changed = 1; |
| 692 | link_changed = -1; | 940 | octeon_mgmt_update_link(p); |
| 941 | octeon_mgmt_enable_link(p); | ||
| 693 | } | 942 | } |
| 943 | |||
| 694 | p->last_link = p->phydev->link; | 944 | p->last_link = p->phydev->link; |
| 945 | p->last_speed = p->phydev->speed; | ||
| 946 | p->last_duplex = p->phydev->duplex; | ||
| 947 | |||
| 695 | spin_unlock_irqrestore(&p->lock, flags); | 948 | spin_unlock_irqrestore(&p->lock, flags); |
| 696 | 949 | ||
| 697 | if (link_changed != 0) { | 950 | if (link_changed != 0) { |
| 698 | if (link_changed > 0) { | 951 | if (link_changed > 0) { |
| 699 | netif_carrier_on(netdev); | ||
| 700 | pr_info("%s: Link is up - %d/%s\n", netdev->name, | 952 | pr_info("%s: Link is up - %d/%s\n", netdev->name, |
| 701 | p->phydev->speed, | 953 | p->phydev->speed, |
| 702 | DUPLEX_FULL == p->phydev->duplex ? | 954 | DUPLEX_FULL == p->phydev->duplex ? |
| 703 | "Full" : "Half"); | 955 | "Full" : "Half"); |
| 704 | } else { | 956 | } else { |
| 705 | netif_carrier_off(netdev); | ||
| 706 | pr_info("%s: Link is down\n", netdev->name); | 957 | pr_info("%s: Link is down\n", netdev->name); |
| 707 | } | 958 | } |
| 708 | } | 959 | } |
| @@ -723,9 +974,7 @@ static int octeon_mgmt_init_phy(struct net_device *netdev) | |||
| 723 | PHY_INTERFACE_MODE_MII); | 974 | PHY_INTERFACE_MODE_MII); |
| 724 | 975 | ||
| 725 | if (!p->phydev) | 976 | if (!p->phydev) |
| 726 | return -1; | 977 | return -ENODEV; |
| 727 | |||
| 728 | phy_start_aneg(p->phydev); | ||
| 729 | 978 | ||
| 730 | return 0; | 979 | return 0; |
| 731 | } | 980 | } |
| @@ -733,12 +982,10 @@ static int octeon_mgmt_init_phy(struct net_device *netdev) | |||
| 733 | static int octeon_mgmt_open(struct net_device *netdev) | 982 | static int octeon_mgmt_open(struct net_device *netdev) |
| 734 | { | 983 | { |
| 735 | struct octeon_mgmt *p = netdev_priv(netdev); | 984 | struct octeon_mgmt *p = netdev_priv(netdev); |
| 736 | int port = p->port; | ||
| 737 | union cvmx_mixx_ctl mix_ctl; | 985 | union cvmx_mixx_ctl mix_ctl; |
| 738 | union cvmx_agl_gmx_inf_mode agl_gmx_inf_mode; | 986 | union cvmx_agl_gmx_inf_mode agl_gmx_inf_mode; |
| 739 | union cvmx_mixx_oring1 oring1; | 987 | union cvmx_mixx_oring1 oring1; |
| 740 | union cvmx_mixx_iring1 iring1; | 988 | union cvmx_mixx_iring1 iring1; |
| 741 | union cvmx_agl_gmx_prtx_cfg prtx_cfg; | ||
| 742 | union cvmx_agl_gmx_rxx_frm_ctl rxx_frm_ctl; | 989 | union cvmx_agl_gmx_rxx_frm_ctl rxx_frm_ctl; |
| 743 | union cvmx_mixx_irhwm mix_irhwm; | 990 | union cvmx_mixx_irhwm mix_irhwm; |
| 744 | union cvmx_mixx_orhwm mix_orhwm; | 991 | union cvmx_mixx_orhwm mix_orhwm; |
| @@ -785,9 +1032,30 @@ static int octeon_mgmt_open(struct net_device *netdev) | |||
| 785 | } while (mix_ctl.s.reset); | 1032 | } while (mix_ctl.s.reset); |
| 786 | } | 1033 | } |
| 787 | 1034 | ||
| 788 | agl_gmx_inf_mode.u64 = 0; | 1035 | if (OCTEON_IS_MODEL(OCTEON_CN5XXX)) { |
| 789 | agl_gmx_inf_mode.s.en = 1; | 1036 | agl_gmx_inf_mode.u64 = 0; |
| 790 | cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64); | 1037 | agl_gmx_inf_mode.s.en = 1; |
| 1038 | cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64); | ||
| 1039 | } | ||
| 1040 | if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) | ||
| 1041 | || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { | ||
| 1042 | /* Force compensation values, as they are not | ||
| 1043 | * determined properly by HW | ||
| 1044 | */ | ||
| 1045 | union cvmx_agl_gmx_drv_ctl drv_ctl; | ||
| 1046 | |||
| 1047 | drv_ctl.u64 = cvmx_read_csr(CVMX_AGL_GMX_DRV_CTL); | ||
| 1048 | if (p->port) { | ||
| 1049 | drv_ctl.s.byp_en1 = 1; | ||
| 1050 | drv_ctl.s.nctl1 = 6; | ||
| 1051 | drv_ctl.s.pctl1 = 6; | ||
| 1052 | } else { | ||
| 1053 | drv_ctl.s.byp_en = 1; | ||
| 1054 | drv_ctl.s.nctl = 6; | ||
| 1055 | drv_ctl.s.pctl = 6; | ||
| 1056 | } | ||
| 1057 | cvmx_write_csr(CVMX_AGL_GMX_DRV_CTL, drv_ctl.u64); | ||
| 1058 | } | ||
| 791 | 1059 | ||
| 792 | oring1.u64 = 0; | 1060 | oring1.u64 = 0; |
| 793 | oring1.s.obase = p->tx_ring_handle >> 3; | 1061 | oring1.s.obase = p->tx_ring_handle >> 3; |
| @@ -799,18 +1067,12 @@ static int octeon_mgmt_open(struct net_device *netdev) | |||
| 799 | iring1.s.isize = OCTEON_MGMT_RX_RING_SIZE; | 1067 | iring1.s.isize = OCTEON_MGMT_RX_RING_SIZE; |
| 800 | cvmx_write_csr(p->mix + MIX_IRING1, iring1.u64); | 1068 | cvmx_write_csr(p->mix + MIX_IRING1, iring1.u64); |
| 801 | 1069 | ||
| 802 | /* Disable packet I/O. */ | ||
| 803 | prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); | ||
| 804 | prtx_cfg.s.en = 0; | ||
| 805 | cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64); | ||
| 806 | |||
| 807 | memcpy(sa.sa_data, netdev->dev_addr, ETH_ALEN); | 1070 | memcpy(sa.sa_data, netdev->dev_addr, ETH_ALEN); |
| 808 | octeon_mgmt_set_mac_address(netdev, &sa); | 1071 | octeon_mgmt_set_mac_address(netdev, &sa); |
| 809 | 1072 | ||
| 810 | octeon_mgmt_change_mtu(netdev, netdev->mtu); | 1073 | octeon_mgmt_change_mtu(netdev, netdev->mtu); |
| 811 | 1074 | ||
| 812 | /* | 1075 | /* Enable the port HW. Packets are not allowed until |
| 813 | * Enable the port HW. Packets are not allowed until | ||
| 814 | * cvmx_mgmt_port_enable() is called. | 1076 | * cvmx_mgmt_port_enable() is called. |
| 815 | */ | 1077 | */ |
| 816 | mix_ctl.u64 = 0; | 1078 | mix_ctl.u64 = 0; |
| @@ -819,27 +1081,70 @@ static int octeon_mgmt_open(struct net_device *netdev) | |||
| 819 | mix_ctl.s.nbtarb = 0; /* Arbitration mode */ | 1081 | mix_ctl.s.nbtarb = 0; /* Arbitration mode */ |
| 820 | /* MII CB-request FIFO programmable high watermark */ | 1082 | /* MII CB-request FIFO programmable high watermark */ |
| 821 | mix_ctl.s.mrq_hwm = 1; | 1083 | mix_ctl.s.mrq_hwm = 1; |
| 1084 | #ifdef __LITTLE_ENDIAN | ||
| 1085 | mix_ctl.s.lendian = 1; | ||
| 1086 | #endif | ||
| 822 | cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64); | 1087 | cvmx_write_csr(p->mix + MIX_CTL, mix_ctl.u64); |
| 823 | 1088 | ||
| 824 | if (OCTEON_IS_MODEL(OCTEON_CN56XX_PASS1_X) | 1089 | /* Read the PHY to find the mode of the interface. */ |
| 825 | || OCTEON_IS_MODEL(OCTEON_CN52XX_PASS1_X)) { | 1090 | if (octeon_mgmt_init_phy(netdev)) { |
| 826 | /* | 1091 | dev_err(p->dev, "Cannot initialize PHY on MIX%d.\n", p->port); |
| 827 | * Force compensation values, as they are not | 1092 | goto err_noirq; |
| 828 | * determined properly by HW | 1093 | } |
| 829 | */ | ||
| 830 | union cvmx_agl_gmx_drv_ctl drv_ctl; | ||
| 831 | 1094 | ||
| 832 | drv_ctl.u64 = cvmx_read_csr(CVMX_AGL_GMX_DRV_CTL); | 1095 | /* Set the mode of the interface, RGMII/MII. */ |
| 833 | if (port) { | 1096 | if (OCTEON_IS_MODEL(OCTEON_CN6XXX) && p->phydev) { |
| 834 | drv_ctl.s.byp_en1 = 1; | 1097 | union cvmx_agl_prtx_ctl agl_prtx_ctl; |
| 835 | drv_ctl.s.nctl1 = 6; | 1098 | int rgmii_mode = (p->phydev->supported & |
| 836 | drv_ctl.s.pctl1 = 6; | 1099 | (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)) != 0; |
| 837 | } else { | 1100 | |
| 838 | drv_ctl.s.byp_en = 1; | 1101 | agl_prtx_ctl.u64 = cvmx_read_csr(p->agl_prt_ctl); |
| 839 | drv_ctl.s.nctl = 6; | 1102 | agl_prtx_ctl.s.mode = rgmii_mode ? 0 : 1; |
| 840 | drv_ctl.s.pctl = 6; | 1103 | cvmx_write_csr(p->agl_prt_ctl, agl_prtx_ctl.u64); |
| 1104 | |||
| 1105 | /* MII clocks counts are based on the 125Mhz | ||
| 1106 | * reference, which has an 8nS period. So our delays | ||
| 1107 | * need to be multiplied by this factor. | ||
| 1108 | */ | ||
| 1109 | #define NS_PER_PHY_CLK 8 | ||
| 1110 | |||
| 1111 | /* Take the DLL and clock tree out of reset */ | ||
| 1112 | agl_prtx_ctl.u64 = cvmx_read_csr(p->agl_prt_ctl); | ||
| 1113 | agl_prtx_ctl.s.clkrst = 0; | ||
| 1114 | if (rgmii_mode) { | ||
| 1115 | agl_prtx_ctl.s.dllrst = 0; | ||
| 1116 | agl_prtx_ctl.s.clktx_byp = 0; | ||
| 841 | } | 1117 | } |
| 842 | cvmx_write_csr(CVMX_AGL_GMX_DRV_CTL, drv_ctl.u64); | 1118 | cvmx_write_csr(p->agl_prt_ctl, agl_prtx_ctl.u64); |
| 1119 | cvmx_read_csr(p->agl_prt_ctl); /* Force write out before wait */ | ||
| 1120 | |||
| 1121 | /* Wait for the DLL to lock. External 125 MHz | ||
| 1122 | * reference clock must be stable at this point. | ||
| 1123 | */ | ||
| 1124 | ndelay(256 * NS_PER_PHY_CLK); | ||
| 1125 | |||
| 1126 | /* Enable the interface */ | ||
| 1127 | agl_prtx_ctl.u64 = cvmx_read_csr(p->agl_prt_ctl); | ||
| 1128 | agl_prtx_ctl.s.enable = 1; | ||
| 1129 | cvmx_write_csr(p->agl_prt_ctl, agl_prtx_ctl.u64); | ||
| 1130 | |||
| 1131 | /* Read the value back to force the previous write */ | ||
| 1132 | agl_prtx_ctl.u64 = cvmx_read_csr(p->agl_prt_ctl); | ||
| 1133 | |||
| 1134 | /* Enable the compensation controller */ | ||
| 1135 | agl_prtx_ctl.s.comp = 1; | ||
| 1136 | agl_prtx_ctl.s.drv_byp = 0; | ||
| 1137 | cvmx_write_csr(p->agl_prt_ctl, agl_prtx_ctl.u64); | ||
| 1138 | /* Force write out before wait. */ | ||
| 1139 | cvmx_read_csr(p->agl_prt_ctl); | ||
| 1140 | |||
| 1141 | /* For compensation state to lock. */ | ||
| 1142 | ndelay(1040 * NS_PER_PHY_CLK); | ||
| 1143 | |||
| 1144 | /* Some Ethernet switches cannot handle standard | ||
| 1145 | * Interframe Gap, increase to 16 bytes. | ||
| 1146 | */ | ||
| 1147 | cvmx_write_csr(CVMX_AGL_GMX_TX_IFG, 0x88); | ||
| 843 | } | 1148 | } |
| 844 | 1149 | ||
| 845 | octeon_mgmt_rx_fill_ring(netdev); | 1150 | octeon_mgmt_rx_fill_ring(netdev); |
| @@ -870,7 +1175,7 @@ static int octeon_mgmt_open(struct net_device *netdev) | |||
| 870 | 1175 | ||
| 871 | /* Interrupt when we have 1 or more packets to clean. */ | 1176 | /* Interrupt when we have 1 or more packets to clean. */ |
| 872 | mix_orhwm.u64 = 0; | 1177 | mix_orhwm.u64 = 0; |
| 873 | mix_orhwm.s.orhwm = 1; | 1178 | mix_orhwm.s.orhwm = 0; |
| 874 | cvmx_write_csr(p->mix + MIX_ORHWM, mix_orhwm.u64); | 1179 | cvmx_write_csr(p->mix + MIX_ORHWM, mix_orhwm.u64); |
| 875 | 1180 | ||
| 876 | /* Enable receive and transmit interrupts */ | 1181 | /* Enable receive and transmit interrupts */ |
| @@ -879,13 +1184,12 @@ static int octeon_mgmt_open(struct net_device *netdev) | |||
| 879 | mix_intena.s.othena = 1; | 1184 | mix_intena.s.othena = 1; |
| 880 | cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64); | 1185 | cvmx_write_csr(p->mix + MIX_INTENA, mix_intena.u64); |
| 881 | 1186 | ||
| 882 | |||
| 883 | /* Enable packet I/O. */ | 1187 | /* Enable packet I/O. */ |
| 884 | 1188 | ||
| 885 | rxx_frm_ctl.u64 = 0; | 1189 | rxx_frm_ctl.u64 = 0; |
| 1190 | rxx_frm_ctl.s.ptp_mode = p->has_rx_tstamp ? 1 : 0; | ||
| 886 | rxx_frm_ctl.s.pre_align = 1; | 1191 | rxx_frm_ctl.s.pre_align = 1; |
| 887 | /* | 1192 | /* When set, disables the length check for non-min sized pkts |
| 888 | * When set, disables the length check for non-min sized pkts | ||
| 889 | * with padding in the client data. | 1193 | * with padding in the client data. |
| 890 | */ | 1194 | */ |
| 891 | rxx_frm_ctl.s.pad_len = 1; | 1195 | rxx_frm_ctl.s.pad_len = 1; |
| @@ -903,33 +1207,26 @@ static int octeon_mgmt_open(struct net_device *netdev) | |||
| 903 | rxx_frm_ctl.s.ctl_drp = 1; | 1207 | rxx_frm_ctl.s.ctl_drp = 1; |
| 904 | /* Strip off the preamble */ | 1208 | /* Strip off the preamble */ |
| 905 | rxx_frm_ctl.s.pre_strp = 1; | 1209 | rxx_frm_ctl.s.pre_strp = 1; |
| 906 | /* | 1210 | /* This port is configured to send PREAMBLE+SFD to begin every |
| 907 | * This port is configured to send PREAMBLE+SFD to begin every | ||
| 908 | * frame. GMX checks that the PREAMBLE is sent correctly. | 1211 | * frame. GMX checks that the PREAMBLE is sent correctly. |
| 909 | */ | 1212 | */ |
| 910 | rxx_frm_ctl.s.pre_chk = 1; | 1213 | rxx_frm_ctl.s.pre_chk = 1; |
| 911 | cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_CTL, rxx_frm_ctl.u64); | 1214 | cvmx_write_csr(p->agl + AGL_GMX_RX_FRM_CTL, rxx_frm_ctl.u64); |
| 912 | 1215 | ||
| 913 | /* Enable the AGL block */ | 1216 | /* Configure the port duplex, speed and enables */ |
| 914 | agl_gmx_inf_mode.u64 = 0; | 1217 | octeon_mgmt_disable_link(p); |
| 915 | agl_gmx_inf_mode.s.en = 1; | 1218 | if (p->phydev) |
| 916 | cvmx_write_csr(CVMX_AGL_GMX_INF_MODE, agl_gmx_inf_mode.u64); | 1219 | octeon_mgmt_update_link(p); |
| 917 | 1220 | octeon_mgmt_enable_link(p); | |
| 918 | /* Configure the port duplex and enables */ | ||
| 919 | prtx_cfg.u64 = cvmx_read_csr(p->agl + AGL_GMX_PRT_CFG); | ||
| 920 | prtx_cfg.s.tx_en = 1; | ||
| 921 | prtx_cfg.s.rx_en = 1; | ||
| 922 | prtx_cfg.s.en = 1; | ||
| 923 | p->last_duplex = 1; | ||
| 924 | prtx_cfg.s.duplex = p->last_duplex; | ||
| 925 | cvmx_write_csr(p->agl + AGL_GMX_PRT_CFG, prtx_cfg.u64); | ||
| 926 | 1221 | ||
| 927 | p->last_link = 0; | 1222 | p->last_link = 0; |
| 928 | netif_carrier_off(netdev); | 1223 | p->last_speed = 0; |
| 929 | 1224 | /* PHY is not present in simulator. The carrier is enabled | |
| 930 | if (octeon_mgmt_init_phy(netdev)) { | 1225 | * while initializing the phy for simulator, leave it enabled. |
| 931 | dev_err(p->dev, "Cannot initialize PHY.\n"); | 1226 | */ |
| 932 | goto err_noirq; | 1227 | if (p->phydev) { |
| 1228 | netif_carrier_off(netdev); | ||
| 1229 | phy_start_aneg(p->phydev); | ||
| 933 | } | 1230 | } |
| 934 | 1231 | ||
| 935 | netif_wake_queue(netdev); | 1232 | netif_wake_queue(netdev); |
| @@ -959,6 +1256,7 @@ static int octeon_mgmt_stop(struct net_device *netdev) | |||
| 959 | 1256 | ||
| 960 | if (p->phydev) | 1257 | if (p->phydev) |
| 961 | phy_disconnect(p->phydev); | 1258 | phy_disconnect(p->phydev); |
| 1259 | p->phydev = NULL; | ||
| 962 | 1260 | ||
| 963 | netif_carrier_off(netdev); | 1261 | netif_carrier_off(netdev); |
| 964 | 1262 | ||
| @@ -991,6 +1289,7 @@ static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
| 991 | int rv = NETDEV_TX_BUSY; | 1289 | int rv = NETDEV_TX_BUSY; |
| 992 | 1290 | ||
| 993 | re.d64 = 0; | 1291 | re.d64 = 0; |
| 1292 | re.s.tstamp = ((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) != 0); | ||
| 994 | re.s.len = skb->len; | 1293 | re.s.len = skb->len; |
| 995 | re.s.addr = dma_map_single(p->dev, skb->data, | 1294 | re.s.addr = dma_map_single(p->dev, skb->data, |
| 996 | skb->len, | 1295 | skb->len, |
| @@ -1031,6 +1330,7 @@ static int octeon_mgmt_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
| 1031 | /* Ring the bell. */ | 1330 | /* Ring the bell. */ |
| 1032 | cvmx_write_csr(p->mix + MIX_ORING2, 1); | 1331 | cvmx_write_csr(p->mix + MIX_ORING2, 1); |
| 1033 | 1332 | ||
| 1333 | netdev->trans_start = jiffies; | ||
| 1034 | rv = NETDEV_TX_OK; | 1334 | rv = NETDEV_TX_OK; |
| 1035 | out: | 1335 | out: |
| 1036 | octeon_mgmt_update_tx_stats(netdev); | 1336 | octeon_mgmt_update_tx_stats(netdev); |
| @@ -1068,7 +1368,7 @@ static int octeon_mgmt_get_settings(struct net_device *netdev, | |||
| 1068 | if (p->phydev) | 1368 | if (p->phydev) |
| 1069 | return phy_ethtool_gset(p->phydev, cmd); | 1369 | return phy_ethtool_gset(p->phydev, cmd); |
| 1070 | 1370 | ||
| 1071 | return -EINVAL; | 1371 | return -EOPNOTSUPP; |
| 1072 | } | 1372 | } |
| 1073 | 1373 | ||
| 1074 | static int octeon_mgmt_set_settings(struct net_device *netdev, | 1374 | static int octeon_mgmt_set_settings(struct net_device *netdev, |
| @@ -1082,23 +1382,37 @@ static int octeon_mgmt_set_settings(struct net_device *netdev, | |||
| 1082 | if (p->phydev) | 1382 | if (p->phydev) |
| 1083 | return phy_ethtool_sset(p->phydev, cmd); | 1383 | return phy_ethtool_sset(p->phydev, cmd); |
| 1084 | 1384 | ||
| 1085 | return -EINVAL; | 1385 | return -EOPNOTSUPP; |
| 1386 | } | ||
| 1387 | |||
| 1388 | static int octeon_mgmt_nway_reset(struct net_device *dev) | ||
| 1389 | { | ||
| 1390 | struct octeon_mgmt *p = netdev_priv(dev); | ||
| 1391 | |||
| 1392 | if (!capable(CAP_NET_ADMIN)) | ||
| 1393 | return -EPERM; | ||
| 1394 | |||
| 1395 | if (p->phydev) | ||
| 1396 | return phy_start_aneg(p->phydev); | ||
| 1397 | |||
| 1398 | return -EOPNOTSUPP; | ||
| 1086 | } | 1399 | } |
| 1087 | 1400 | ||
| 1088 | static const struct ethtool_ops octeon_mgmt_ethtool_ops = { | 1401 | static const struct ethtool_ops octeon_mgmt_ethtool_ops = { |
| 1089 | .get_drvinfo = octeon_mgmt_get_drvinfo, | 1402 | .get_drvinfo = octeon_mgmt_get_drvinfo, |
| 1090 | .get_link = ethtool_op_get_link, | ||
| 1091 | .get_settings = octeon_mgmt_get_settings, | 1403 | .get_settings = octeon_mgmt_get_settings, |
| 1092 | .set_settings = octeon_mgmt_set_settings | 1404 | .set_settings = octeon_mgmt_set_settings, |
| 1405 | .nway_reset = octeon_mgmt_nway_reset, | ||
| 1406 | .get_link = ethtool_op_get_link, | ||
| 1093 | }; | 1407 | }; |
| 1094 | 1408 | ||
| 1095 | static const struct net_device_ops octeon_mgmt_ops = { | 1409 | static const struct net_device_ops octeon_mgmt_ops = { |
| 1096 | .ndo_open = octeon_mgmt_open, | 1410 | .ndo_open = octeon_mgmt_open, |
| 1097 | .ndo_stop = octeon_mgmt_stop, | 1411 | .ndo_stop = octeon_mgmt_stop, |
| 1098 | .ndo_start_xmit = octeon_mgmt_xmit, | 1412 | .ndo_start_xmit = octeon_mgmt_xmit, |
| 1099 | .ndo_set_rx_mode = octeon_mgmt_set_rx_filtering, | 1413 | .ndo_set_rx_mode = octeon_mgmt_set_rx_filtering, |
| 1100 | .ndo_set_mac_address = octeon_mgmt_set_mac_address, | 1414 | .ndo_set_mac_address = octeon_mgmt_set_mac_address, |
| 1101 | .ndo_do_ioctl = octeon_mgmt_ioctl, | 1415 | .ndo_do_ioctl = octeon_mgmt_ioctl, |
| 1102 | .ndo_change_mtu = octeon_mgmt_change_mtu, | 1416 | .ndo_change_mtu = octeon_mgmt_change_mtu, |
| 1103 | #ifdef CONFIG_NET_POLL_CONTROLLER | 1417 | #ifdef CONFIG_NET_POLL_CONTROLLER |
| 1104 | .ndo_poll_controller = octeon_mgmt_poll_controller, | 1418 | .ndo_poll_controller = octeon_mgmt_poll_controller, |
| @@ -1113,6 +1427,7 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev) | |||
| 1113 | const u8 *mac; | 1427 | const u8 *mac; |
| 1114 | struct resource *res_mix; | 1428 | struct resource *res_mix; |
| 1115 | struct resource *res_agl; | 1429 | struct resource *res_agl; |
| 1430 | struct resource *res_agl_prt_ctl; | ||
| 1116 | int len; | 1431 | int len; |
| 1117 | int result; | 1432 | int result; |
| 1118 | 1433 | ||
| @@ -1120,6 +1435,8 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev) | |||
| 1120 | if (netdev == NULL) | 1435 | if (netdev == NULL) |
| 1121 | return -ENOMEM; | 1436 | return -ENOMEM; |
| 1122 | 1437 | ||
| 1438 | SET_NETDEV_DEV(netdev, &pdev->dev); | ||
| 1439 | |||
| 1123 | dev_set_drvdata(&pdev->dev, netdev); | 1440 | dev_set_drvdata(&pdev->dev, netdev); |
| 1124 | p = netdev_priv(netdev); | 1441 | p = netdev_priv(netdev); |
| 1125 | netif_napi_add(netdev, &p->napi, octeon_mgmt_napi_poll, | 1442 | netif_napi_add(netdev, &p->napi, octeon_mgmt_napi_poll, |
| @@ -1127,6 +1444,7 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev) | |||
| 1127 | 1444 | ||
| 1128 | p->netdev = netdev; | 1445 | p->netdev = netdev; |
| 1129 | p->dev = &pdev->dev; | 1446 | p->dev = &pdev->dev; |
| 1447 | p->has_rx_tstamp = false; | ||
| 1130 | 1448 | ||
| 1131 | data = of_get_property(pdev->dev.of_node, "cell-index", &len); | 1449 | data = of_get_property(pdev->dev.of_node, "cell-index", &len); |
| 1132 | if (data && len == sizeof(*data)) { | 1450 | if (data && len == sizeof(*data)) { |
| @@ -1159,10 +1477,19 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev) | |||
| 1159 | goto err; | 1477 | goto err; |
| 1160 | } | 1478 | } |
| 1161 | 1479 | ||
| 1480 | res_agl_prt_ctl = platform_get_resource(pdev, IORESOURCE_MEM, 3); | ||
| 1481 | if (res_agl_prt_ctl == NULL) { | ||
| 1482 | dev_err(&pdev->dev, "no 'reg' resource\n"); | ||
| 1483 | result = -ENXIO; | ||
| 1484 | goto err; | ||
| 1485 | } | ||
| 1486 | |||
| 1162 | p->mix_phys = res_mix->start; | 1487 | p->mix_phys = res_mix->start; |
| 1163 | p->mix_size = resource_size(res_mix); | 1488 | p->mix_size = resource_size(res_mix); |
| 1164 | p->agl_phys = res_agl->start; | 1489 | p->agl_phys = res_agl->start; |
| 1165 | p->agl_size = resource_size(res_agl); | 1490 | p->agl_size = resource_size(res_agl); |
| 1491 | p->agl_prt_ctl_phys = res_agl_prt_ctl->start; | ||
| 1492 | p->agl_prt_ctl_size = resource_size(res_agl_prt_ctl); | ||
| 1166 | 1493 | ||
| 1167 | 1494 | ||
| 1168 | if (!devm_request_mem_region(&pdev->dev, p->mix_phys, p->mix_size, | 1495 | if (!devm_request_mem_region(&pdev->dev, p->mix_phys, p->mix_size, |
| @@ -1181,10 +1508,18 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev) | |||
| 1181 | goto err; | 1508 | goto err; |
| 1182 | } | 1509 | } |
| 1183 | 1510 | ||
| 1511 | if (!devm_request_mem_region(&pdev->dev, p->agl_prt_ctl_phys, | ||
| 1512 | p->agl_prt_ctl_size, res_agl_prt_ctl->name)) { | ||
| 1513 | result = -ENXIO; | ||
| 1514 | dev_err(&pdev->dev, "request_mem_region (%s) failed\n", | ||
| 1515 | res_agl_prt_ctl->name); | ||
| 1516 | goto err; | ||
| 1517 | } | ||
| 1184 | 1518 | ||
| 1185 | p->mix = (u64)devm_ioremap(&pdev->dev, p->mix_phys, p->mix_size); | 1519 | p->mix = (u64)devm_ioremap(&pdev->dev, p->mix_phys, p->mix_size); |
| 1186 | p->agl = (u64)devm_ioremap(&pdev->dev, p->agl_phys, p->agl_size); | 1520 | p->agl = (u64)devm_ioremap(&pdev->dev, p->agl_phys, p->agl_size); |
| 1187 | 1521 | p->agl_prt_ctl = (u64)devm_ioremap(&pdev->dev, p->agl_prt_ctl_phys, | |
| 1522 | p->agl_prt_ctl_size); | ||
| 1188 | spin_lock_init(&p->lock); | 1523 | spin_lock_init(&p->lock); |
| 1189 | 1524 | ||
| 1190 | skb_queue_head_init(&p->tx_list); | 1525 | skb_queue_head_init(&p->tx_list); |
| @@ -1199,14 +1534,19 @@ static int __devinit octeon_mgmt_probe(struct platform_device *pdev) | |||
| 1199 | 1534 | ||
| 1200 | mac = of_get_mac_address(pdev->dev.of_node); | 1535 | mac = of_get_mac_address(pdev->dev.of_node); |
| 1201 | 1536 | ||
| 1202 | if (mac) | 1537 | if (mac && is_valid_ether_addr(mac)) { |
| 1203 | memcpy(netdev->dev_addr, mac, 6); | 1538 | memcpy(netdev->dev_addr, mac, ETH_ALEN); |
| 1539 | netdev->addr_assign_type &= ~NET_ADDR_RANDOM; | ||
| 1540 | } else { | ||
| 1541 | eth_hw_addr_random(netdev); | ||
| 1542 | } | ||
| 1204 | 1543 | ||
| 1205 | p->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); | 1544 | p->phy_np = of_parse_phandle(pdev->dev.of_node, "phy-handle", 0); |
| 1206 | 1545 | ||
| 1207 | pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64); | 1546 | pdev->dev.coherent_dma_mask = DMA_BIT_MASK(64); |
| 1208 | pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; | 1547 | pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; |
| 1209 | 1548 | ||
| 1549 | netif_carrier_off(netdev); | ||
| 1210 | result = register_netdev(netdev); | 1550 | result = register_netdev(netdev); |
| 1211 | if (result) | 1551 | if (result) |
| 1212 | goto err; | 1552 | goto err; |
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 33e3df9e39ca..7bf914df6e91 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig | |||
| @@ -68,10 +68,21 @@ config PINCTRL_IMX6Q | |||
| 68 | help | 68 | help |
| 69 | Say Y here to enable the imx6q pinctrl driver | 69 | Say Y here to enable the imx6q pinctrl driver |
| 70 | 70 | ||
| 71 | config PINCTRL_LANTIQ | ||
| 72 | bool | ||
| 73 | depends on LANTIQ | ||
| 74 | select PINMUX | ||
| 75 | select PINCONF | ||
| 76 | |||
| 71 | config PINCTRL_PXA3xx | 77 | config PINCTRL_PXA3xx |
| 72 | bool | 78 | bool |
| 73 | select PINMUX | 79 | select PINMUX |
| 74 | 80 | ||
| 81 | config PINCTRL_FALCON | ||
| 82 | bool | ||
| 83 | depends on SOC_FALCON | ||
| 84 | depends on PINCTRL_LANTIQ | ||
| 85 | |||
| 75 | config PINCTRL_MMP2 | 86 | config PINCTRL_MMP2 |
| 76 | bool "MMP2 pin controller driver" | 87 | bool "MMP2 pin controller driver" |
| 77 | depends on ARCH_MMP | 88 | depends on ARCH_MMP |
| @@ -199,6 +210,11 @@ config PINCTRL_ARMADA_XP | |||
| 199 | 210 | ||
| 200 | source "drivers/pinctrl/spear/Kconfig" | 211 | source "drivers/pinctrl/spear/Kconfig" |
| 201 | 212 | ||
| 213 | config PINCTRL_XWAY | ||
| 214 | bool | ||
| 215 | depends on SOC_TYPE_XWAY | ||
| 216 | depends on PINCTRL_LANTIQ | ||
| 217 | |||
| 202 | endmenu | 218 | endmenu |
| 203 | 219 | ||
| 204 | endif | 220 | endif |
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index f162e0196300..f395ba5cec25 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile | |||
| @@ -16,6 +16,7 @@ obj-$(CONFIG_PINCTRL_IMX51) += pinctrl-imx51.o | |||
| 16 | obj-$(CONFIG_PINCTRL_IMX53) += pinctrl-imx53.o | 16 | obj-$(CONFIG_PINCTRL_IMX53) += pinctrl-imx53.o |
| 17 | obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6q.o | 17 | obj-$(CONFIG_PINCTRL_IMX6Q) += pinctrl-imx6q.o |
| 18 | obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o | 18 | obj-$(CONFIG_PINCTRL_PXA3xx) += pinctrl-pxa3xx.o |
| 19 | obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o | ||
| 19 | obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o | 20 | obj-$(CONFIG_PINCTRL_MMP2) += pinctrl-mmp2.o |
| 20 | obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o | 21 | obj-$(CONFIG_PINCTRL_MXS) += pinctrl-mxs.o |
| 21 | obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o | 22 | obj-$(CONFIG_PINCTRL_IMX23) += pinctrl-imx23.o |
| @@ -40,5 +41,7 @@ obj-$(CONFIG_PINCTRL_DOVE) += pinctrl-dove.o | |||
| 40 | obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o | 41 | obj-$(CONFIG_PINCTRL_KIRKWOOD) += pinctrl-kirkwood.o |
| 41 | obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o | 42 | obj-$(CONFIG_PINCTRL_ARMADA_370) += pinctrl-armada-370.o |
| 42 | obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o | 43 | obj-$(CONFIG_PINCTRL_ARMADA_XP) += pinctrl-armada-xp.o |
| 44 | obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o | ||
| 45 | obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o | ||
| 43 | 46 | ||
| 44 | obj-$(CONFIG_PLAT_SPEAR) += spear/ | 47 | obj-$(CONFIG_PLAT_SPEAR) += spear/ |
diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c new file mode 100644 index 000000000000..ee7305903470 --- /dev/null +++ b/drivers/pinctrl/pinctrl-falcon.c | |||
| @@ -0,0 +1,468 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/pinctrl/pinmux-falcon.c | ||
| 3 | * based on linux/drivers/pinctrl/pinmux-pxa910.c | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or modify it | ||
| 6 | * under the terms of the GNU General Public License version 2 as published | ||
| 7 | * by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * Copyright (C) 2012 Thomas Langer <thomas.langer@lantiq.com> | ||
| 10 | * Copyright (C) 2012 John Crispin <blogic@openwrt.org> | ||
| 11 | */ | ||
| 12 | |||
| 13 | #include <linux/gpio.h> | ||
| 14 | #include <linux/interrupt.h> | ||
| 15 | #include <linux/slab.h> | ||
| 16 | #include <linux/export.h> | ||
| 17 | #include <linux/err.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/of.h> | ||
| 20 | #include <linux/of_platform.h> | ||
| 21 | #include <linux/of_address.h> | ||
| 22 | #include <linux/of_gpio.h> | ||
| 23 | #include <linux/platform_device.h> | ||
| 24 | |||
| 25 | #include "pinctrl-lantiq.h" | ||
| 26 | |||
| 27 | #include <lantiq_soc.h> | ||
| 28 | |||
| 29 | /* Multiplexer Control Register */ | ||
| 30 | #define LTQ_PADC_MUX(x) (x * 0x4) | ||
| 31 | /* Pull Up Enable Register */ | ||
| 32 | #define LTQ_PADC_PUEN 0x80 | ||
| 33 | /* Pull Down Enable Register */ | ||
| 34 | #define LTQ_PADC_PDEN 0x84 | ||
| 35 | /* Slew Rate Control Register */ | ||
| 36 | #define LTQ_PADC_SRC 0x88 | ||
| 37 | /* Drive Current Control Register */ | ||
| 38 | #define LTQ_PADC_DCC 0x8C | ||
| 39 | /* Pad Control Availability Register */ | ||
| 40 | #define LTQ_PADC_AVAIL 0xF0 | ||
| 41 | |||
| 42 | #define pad_r32(p, reg) ltq_r32(p + reg) | ||
| 43 | #define pad_w32(p, val, reg) ltq_w32(val, p + reg) | ||
| 44 | #define pad_w32_mask(c, clear, set, reg) \ | ||
| 45 | pad_w32(c, (pad_r32(c, reg) & ~(clear)) | (set), reg) | ||
| 46 | |||
| 47 | #define pad_getbit(m, r, p) (!!(ltq_r32(m + r) & (1 << p))) | ||
| 48 | |||
| 49 | #define PORTS 5 | ||
| 50 | #define PINS 32 | ||
| 51 | #define PORT(x) (x / PINS) | ||
| 52 | #define PORT_PIN(x) (x % PINS) | ||
| 53 | |||
| 54 | #define MFP_FALCON(a, f0, f1, f2, f3) \ | ||
| 55 | { \ | ||
| 56 | .name = #a, \ | ||
| 57 | .pin = a, \ | ||
| 58 | .func = { \ | ||
| 59 | FALCON_MUX_##f0, \ | ||
| 60 | FALCON_MUX_##f1, \ | ||
| 61 | FALCON_MUX_##f2, \ | ||
| 62 | FALCON_MUX_##f3, \ | ||
| 63 | }, \ | ||
| 64 | } | ||
| 65 | |||
| 66 | #define GRP_MUX(a, m, p) \ | ||
| 67 | { \ | ||
| 68 | .name = a, \ | ||
| 69 | .mux = FALCON_MUX_##m, \ | ||
| 70 | .pins = p, \ | ||
| 71 | .npins = ARRAY_SIZE(p), \ | ||
| 72 | } | ||
| 73 | |||
| 74 | enum falcon_mux { | ||
| 75 | FALCON_MUX_GPIO = 0, | ||
| 76 | FALCON_MUX_RST, | ||
| 77 | FALCON_MUX_NTR, | ||
| 78 | FALCON_MUX_MDIO, | ||
| 79 | FALCON_MUX_LED, | ||
| 80 | FALCON_MUX_SPI, | ||
| 81 | FALCON_MUX_ASC, | ||
| 82 | FALCON_MUX_I2C, | ||
| 83 | FALCON_MUX_HOSTIF, | ||
| 84 | FALCON_MUX_SLIC, | ||
| 85 | FALCON_MUX_JTAG, | ||
| 86 | FALCON_MUX_PCM, | ||
| 87 | FALCON_MUX_MII, | ||
| 88 | FALCON_MUX_PHY, | ||
| 89 | FALCON_MUX_NONE = 0xffff, | ||
| 90 | }; | ||
| 91 | |||
| 92 | static struct pinctrl_pin_desc falcon_pads[PORTS * PINS]; | ||
| 93 | static int pad_count[PORTS]; | ||
| 94 | |||
| 95 | static void lantiq_load_pin_desc(struct pinctrl_pin_desc *d, int bank, int len) | ||
| 96 | { | ||
| 97 | int base = bank * PINS; | ||
| 98 | int i; | ||
| 99 | |||
| 100 | for (i = 0; i < len; i++) { | ||
| 101 | /* strlen("ioXYZ") + 1 = 6 */ | ||
| 102 | char *name = kzalloc(6, GFP_KERNEL); | ||
| 103 | snprintf(name, 6, "io%d", base + i); | ||
| 104 | d[i].number = base + i; | ||
| 105 | d[i].name = name; | ||
| 106 | } | ||
| 107 | pad_count[bank] = len; | ||
| 108 | } | ||
| 109 | |||
| 110 | static struct ltq_mfp_pin falcon_mfp[] = { | ||
| 111 | /* pin f0 f1 f2 f3 */ | ||
| 112 | MFP_FALCON(GPIO0, RST, GPIO, NONE, NONE), | ||
| 113 | MFP_FALCON(GPIO1, GPIO, GPIO, NONE, NONE), | ||
| 114 | MFP_FALCON(GPIO2, GPIO, GPIO, NONE, NONE), | ||
| 115 | MFP_FALCON(GPIO3, GPIO, GPIO, NONE, NONE), | ||
| 116 | MFP_FALCON(GPIO4, NTR, GPIO, NONE, NONE), | ||
| 117 | MFP_FALCON(GPIO5, NTR, GPIO, NONE, NONE), | ||
| 118 | MFP_FALCON(GPIO6, RST, GPIO, NONE, NONE), | ||
| 119 | MFP_FALCON(GPIO7, MDIO, GPIO, NONE, NONE), | ||
| 120 | MFP_FALCON(GPIO8, MDIO, GPIO, NONE, NONE), | ||
| 121 | MFP_FALCON(GPIO9, LED, GPIO, NONE, NONE), | ||
| 122 | MFP_FALCON(GPIO10, LED, GPIO, NONE, NONE), | ||
| 123 | MFP_FALCON(GPIO11, LED, GPIO, NONE, NONE), | ||
| 124 | MFP_FALCON(GPIO12, LED, GPIO, NONE, NONE), | ||
| 125 | MFP_FALCON(GPIO13, LED, GPIO, NONE, NONE), | ||
| 126 | MFP_FALCON(GPIO14, LED, GPIO, NONE, NONE), | ||
| 127 | MFP_FALCON(GPIO32, ASC, GPIO, NONE, NONE), | ||
| 128 | MFP_FALCON(GPIO33, ASC, GPIO, NONE, NONE), | ||
| 129 | MFP_FALCON(GPIO34, SPI, GPIO, NONE, NONE), | ||
| 130 | MFP_FALCON(GPIO35, SPI, GPIO, NONE, NONE), | ||
| 131 | MFP_FALCON(GPIO36, SPI, GPIO, NONE, NONE), | ||
| 132 | MFP_FALCON(GPIO37, SPI, GPIO, NONE, NONE), | ||
| 133 | MFP_FALCON(GPIO38, SPI, GPIO, NONE, NONE), | ||
| 134 | MFP_FALCON(GPIO39, I2C, GPIO, NONE, NONE), | ||
| 135 | MFP_FALCON(GPIO40, I2C, GPIO, NONE, NONE), | ||
| 136 | MFP_FALCON(GPIO41, HOSTIF, GPIO, HOSTIF, JTAG), | ||
| 137 | MFP_FALCON(GPIO42, HOSTIF, GPIO, HOSTIF, NONE), | ||
| 138 | MFP_FALCON(GPIO43, SLIC, GPIO, NONE, NONE), | ||
| 139 | MFP_FALCON(GPIO44, SLIC, GPIO, PCM, ASC), | ||
| 140 | MFP_FALCON(GPIO45, SLIC, GPIO, PCM, ASC), | ||
| 141 | MFP_FALCON(GPIO64, MII, GPIO, NONE, NONE), | ||
| 142 | MFP_FALCON(GPIO65, MII, GPIO, NONE, NONE), | ||
| 143 | MFP_FALCON(GPIO66, MII, GPIO, NONE, NONE), | ||
| 144 | MFP_FALCON(GPIO67, MII, GPIO, NONE, NONE), | ||
| 145 | MFP_FALCON(GPIO68, MII, GPIO, NONE, NONE), | ||
| 146 | MFP_FALCON(GPIO69, MII, GPIO, NONE, NONE), | ||
| 147 | MFP_FALCON(GPIO70, MII, GPIO, NONE, NONE), | ||
| 148 | MFP_FALCON(GPIO71, MII, GPIO, NONE, NONE), | ||
| 149 | MFP_FALCON(GPIO72, MII, GPIO, NONE, NONE), | ||
| 150 | MFP_FALCON(GPIO73, MII, GPIO, NONE, NONE), | ||
| 151 | MFP_FALCON(GPIO74, MII, GPIO, NONE, NONE), | ||
| 152 | MFP_FALCON(GPIO75, MII, GPIO, NONE, NONE), | ||
| 153 | MFP_FALCON(GPIO76, MII, GPIO, NONE, NONE), | ||
| 154 | MFP_FALCON(GPIO77, MII, GPIO, NONE, NONE), | ||
| 155 | MFP_FALCON(GPIO78, MII, GPIO, NONE, NONE), | ||
| 156 | MFP_FALCON(GPIO79, MII, GPIO, NONE, NONE), | ||
| 157 | MFP_FALCON(GPIO80, MII, GPIO, NONE, NONE), | ||
| 158 | MFP_FALCON(GPIO81, MII, GPIO, NONE, NONE), | ||
| 159 | MFP_FALCON(GPIO82, MII, GPIO, NONE, NONE), | ||
| 160 | MFP_FALCON(GPIO83, MII, GPIO, NONE, NONE), | ||
| 161 | MFP_FALCON(GPIO84, MII, GPIO, NONE, NONE), | ||
| 162 | MFP_FALCON(GPIO85, MII, GPIO, NONE, NONE), | ||
| 163 | MFP_FALCON(GPIO86, MII, GPIO, NONE, NONE), | ||
| 164 | MFP_FALCON(GPIO87, MII, GPIO, NONE, NONE), | ||
| 165 | MFP_FALCON(GPIO88, PHY, GPIO, NONE, NONE), | ||
| 166 | }; | ||
| 167 | |||
| 168 | static const unsigned pins_por[] = {GPIO0}; | ||
| 169 | static const unsigned pins_ntr[] = {GPIO4}; | ||
| 170 | static const unsigned pins_ntr8k[] = {GPIO5}; | ||
| 171 | static const unsigned pins_hrst[] = {GPIO6}; | ||
| 172 | static const unsigned pins_mdio[] = {GPIO7, GPIO8}; | ||
| 173 | static const unsigned pins_bled[] = {GPIO7, GPIO10, GPIO11, | ||
| 174 | GPIO12, GPIO13, GPIO14}; | ||
| 175 | static const unsigned pins_asc0[] = {GPIO32, GPIO33}; | ||
| 176 | static const unsigned pins_spi[] = {GPIO34, GPIO35, GPIO36}; | ||
| 177 | static const unsigned pins_spi_cs0[] = {GPIO37}; | ||
| 178 | static const unsigned pins_spi_cs1[] = {GPIO38}; | ||
| 179 | static const unsigned pins_i2c[] = {GPIO39, GPIO40}; | ||
| 180 | static const unsigned pins_jtag[] = {GPIO41}; | ||
| 181 | static const unsigned pins_slic[] = {GPIO43, GPIO44, GPIO45}; | ||
| 182 | static const unsigned pins_pcm[] = {GPIO44, GPIO45}; | ||
| 183 | static const unsigned pins_asc1[] = {GPIO44, GPIO45}; | ||
| 184 | |||
| 185 | static struct ltq_pin_group falcon_grps[] = { | ||
| 186 | GRP_MUX("por", RST, pins_por), | ||
| 187 | GRP_MUX("ntr", NTR, pins_ntr), | ||
| 188 | GRP_MUX("ntr8k", NTR, pins_ntr8k), | ||
| 189 | GRP_MUX("hrst", RST, pins_hrst), | ||
| 190 | GRP_MUX("mdio", MDIO, pins_mdio), | ||
| 191 | GRP_MUX("bootled", LED, pins_bled), | ||
| 192 | GRP_MUX("asc0", ASC, pins_asc0), | ||
| 193 | GRP_MUX("spi", SPI, pins_spi), | ||
| 194 | GRP_MUX("spi cs0", SPI, pins_spi_cs0), | ||
| 195 | GRP_MUX("spi cs1", SPI, pins_spi_cs1), | ||
| 196 | GRP_MUX("i2c", I2C, pins_i2c), | ||
| 197 | GRP_MUX("jtag", JTAG, pins_jtag), | ||
| 198 | GRP_MUX("slic", SLIC, pins_slic), | ||
| 199 | GRP_MUX("pcm", PCM, pins_pcm), | ||
| 200 | GRP_MUX("asc1", ASC, pins_asc1), | ||
| 201 | }; | ||
| 202 | |||
| 203 | static const char * const ltq_rst_grps[] = {"por", "hrst"}; | ||
| 204 | static const char * const ltq_ntr_grps[] = {"ntr", "ntr8k"}; | ||
| 205 | static const char * const ltq_mdio_grps[] = {"mdio"}; | ||
| 206 | static const char * const ltq_bled_grps[] = {"bootled"}; | ||
| 207 | static const char * const ltq_asc_grps[] = {"asc0", "asc1"}; | ||
| 208 | static const char * const ltq_spi_grps[] = {"spi", "spi cs0", "spi cs1"}; | ||
| 209 | static const char * const ltq_i2c_grps[] = {"i2c"}; | ||
| 210 | static const char * const ltq_jtag_grps[] = {"jtag"}; | ||
| 211 | static const char * const ltq_slic_grps[] = {"slic"}; | ||
| 212 | static const char * const ltq_pcm_grps[] = {"pcm"}; | ||
| 213 | |||
| 214 | static struct ltq_pmx_func falcon_funcs[] = { | ||
| 215 | {"rst", ARRAY_AND_SIZE(ltq_rst_grps)}, | ||
| 216 | {"ntr", ARRAY_AND_SIZE(ltq_ntr_grps)}, | ||
| 217 | {"mdio", ARRAY_AND_SIZE(ltq_mdio_grps)}, | ||
| 218 | {"led", ARRAY_AND_SIZE(ltq_bled_grps)}, | ||
| 219 | {"asc", ARRAY_AND_SIZE(ltq_asc_grps)}, | ||
| 220 | {"spi", ARRAY_AND_SIZE(ltq_spi_grps)}, | ||
| 221 | {"i2c", ARRAY_AND_SIZE(ltq_i2c_grps)}, | ||
| 222 | {"jtag", ARRAY_AND_SIZE(ltq_jtag_grps)}, | ||
| 223 | {"slic", ARRAY_AND_SIZE(ltq_slic_grps)}, | ||
| 224 | {"pcm", ARRAY_AND_SIZE(ltq_pcm_grps)}, | ||
| 225 | }; | ||
| 226 | |||
| 227 | |||
| 228 | |||
| 229 | |||
| 230 | /* --------- pinconf related code --------- */ | ||
| 231 | static int falcon_pinconf_group_get(struct pinctrl_dev *pctrldev, | ||
| 232 | unsigned group, unsigned long *config) | ||
| 233 | { | ||
| 234 | return -ENOTSUPP; | ||
| 235 | } | ||
| 236 | |||
| 237 | static int falcon_pinconf_group_set(struct pinctrl_dev *pctrldev, | ||
| 238 | unsigned group, unsigned long config) | ||
| 239 | { | ||
| 240 | return -ENOTSUPP; | ||
| 241 | } | ||
| 242 | |||
| 243 | static int falcon_pinconf_get(struct pinctrl_dev *pctrldev, | ||
| 244 | unsigned pin, unsigned long *config) | ||
| 245 | { | ||
| 246 | struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); | ||
| 247 | enum ltq_pinconf_param param = LTQ_PINCONF_UNPACK_PARAM(*config); | ||
| 248 | void __iomem *mem = info->membase[PORT(pin)]; | ||
| 249 | |||
| 250 | switch (param) { | ||
| 251 | case LTQ_PINCONF_PARAM_DRIVE_CURRENT: | ||
| 252 | *config = LTQ_PINCONF_PACK(param, | ||
| 253 | !!pad_getbit(mem, LTQ_PADC_DCC, PORT_PIN(pin))); | ||
| 254 | break; | ||
| 255 | |||
| 256 | case LTQ_PINCONF_PARAM_SLEW_RATE: | ||
| 257 | *config = LTQ_PINCONF_PACK(param, | ||
| 258 | !!pad_getbit(mem, LTQ_PADC_SRC, PORT_PIN(pin))); | ||
| 259 | break; | ||
| 260 | |||
| 261 | case LTQ_PINCONF_PARAM_PULL: | ||
| 262 | if (pad_getbit(mem, LTQ_PADC_PDEN, PORT_PIN(pin))) | ||
| 263 | *config = LTQ_PINCONF_PACK(param, 1); | ||
| 264 | else if (pad_getbit(mem, LTQ_PADC_PUEN, PORT_PIN(pin))) | ||
| 265 | *config = LTQ_PINCONF_PACK(param, 2); | ||
| 266 | else | ||
| 267 | *config = LTQ_PINCONF_PACK(param, 0); | ||
| 268 | |||
| 269 | break; | ||
| 270 | |||
| 271 | default: | ||
| 272 | return -ENOTSUPP; | ||
| 273 | } | ||
| 274 | |||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | |||
| 278 | static int falcon_pinconf_set(struct pinctrl_dev *pctrldev, | ||
| 279 | unsigned pin, unsigned long config) | ||
| 280 | { | ||
| 281 | enum ltq_pinconf_param param = LTQ_PINCONF_UNPACK_PARAM(config); | ||
| 282 | int arg = LTQ_PINCONF_UNPACK_ARG(config); | ||
| 283 | struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); | ||
| 284 | void __iomem *mem = info->membase[PORT(pin)]; | ||
| 285 | u32 reg; | ||
| 286 | |||
| 287 | switch (param) { | ||
| 288 | case LTQ_PINCONF_PARAM_DRIVE_CURRENT: | ||
| 289 | reg = LTQ_PADC_DCC; | ||
| 290 | break; | ||
| 291 | |||
| 292 | case LTQ_PINCONF_PARAM_SLEW_RATE: | ||
| 293 | reg = LTQ_PADC_SRC; | ||
| 294 | break; | ||
| 295 | |||
| 296 | case LTQ_PINCONF_PARAM_PULL: | ||
| 297 | if (arg == 1) | ||
| 298 | reg = LTQ_PADC_PDEN; | ||
| 299 | else | ||
| 300 | reg = LTQ_PADC_PUEN; | ||
| 301 | break; | ||
| 302 | |||
| 303 | default: | ||
| 304 | pr_err("%s: Invalid config param %04x\n", | ||
| 305 | pinctrl_dev_get_name(pctrldev), param); | ||
| 306 | return -ENOTSUPP; | ||
| 307 | } | ||
| 308 | |||
| 309 | pad_w32(mem, BIT(PORT_PIN(pin)), reg); | ||
| 310 | if (!(pad_r32(mem, reg) & BIT(PORT_PIN(pin)))) | ||
| 311 | return -ENOTSUPP; | ||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | |||
| 315 | static void falcon_pinconf_dbg_show(struct pinctrl_dev *pctrldev, | ||
| 316 | struct seq_file *s, unsigned offset) | ||
| 317 | { | ||
| 318 | } | ||
| 319 | |||
| 320 | static void falcon_pinconf_group_dbg_show(struct pinctrl_dev *pctrldev, | ||
| 321 | struct seq_file *s, unsigned selector) | ||
| 322 | { | ||
| 323 | } | ||
| 324 | |||
| 325 | struct pinconf_ops falcon_pinconf_ops = { | ||
| 326 | .pin_config_get = falcon_pinconf_get, | ||
| 327 | .pin_config_set = falcon_pinconf_set, | ||
| 328 | .pin_config_group_get = falcon_pinconf_group_get, | ||
| 329 | .pin_config_group_set = falcon_pinconf_group_set, | ||
| 330 | .pin_config_dbg_show = falcon_pinconf_dbg_show, | ||
| 331 | .pin_config_group_dbg_show = falcon_pinconf_group_dbg_show, | ||
| 332 | }; | ||
| 333 | |||
| 334 | static struct pinctrl_desc falcon_pctrl_desc = { | ||
| 335 | .owner = THIS_MODULE, | ||
| 336 | .pins = falcon_pads, | ||
| 337 | .confops = &falcon_pinconf_ops, | ||
| 338 | }; | ||
| 339 | |||
| 340 | static inline int falcon_mux_apply(struct pinctrl_dev *pctrldev, | ||
| 341 | int mfp, int mux) | ||
| 342 | { | ||
| 343 | struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); | ||
| 344 | int port = PORT(info->mfp[mfp].pin); | ||
| 345 | |||
| 346 | if ((port >= PORTS) || (!info->membase[port])) | ||
| 347 | return -ENODEV; | ||
| 348 | |||
| 349 | pad_w32(info->membase[port], mux, | ||
| 350 | LTQ_PADC_MUX(PORT_PIN(info->mfp[mfp].pin))); | ||
| 351 | return 0; | ||
| 352 | } | ||
| 353 | |||
| 354 | static const struct ltq_cfg_param falcon_cfg_params[] = { | ||
| 355 | {"lantiq,pull", LTQ_PINCONF_PARAM_PULL}, | ||
| 356 | {"lantiq,drive-current", LTQ_PINCONF_PARAM_DRIVE_CURRENT}, | ||
| 357 | {"lantiq,slew-rate", LTQ_PINCONF_PARAM_SLEW_RATE}, | ||
| 358 | }; | ||
| 359 | |||
| 360 | static struct ltq_pinmux_info falcon_info = { | ||
| 361 | .desc = &falcon_pctrl_desc, | ||
| 362 | .apply_mux = falcon_mux_apply, | ||
| 363 | }; | ||
| 364 | |||
| 365 | |||
| 366 | |||
| 367 | |||
| 368 | /* --------- register the pinctrl layer --------- */ | ||
| 369 | |||
| 370 | int pinctrl_falcon_get_range_size(int id) | ||
| 371 | { | ||
| 372 | u32 avail; | ||
| 373 | |||
| 374 | if ((id >= PORTS) || (!falcon_info.membase[id])) | ||
| 375 | return -EINVAL; | ||
| 376 | |||
| 377 | avail = pad_r32(falcon_info.membase[id], LTQ_PADC_AVAIL); | ||
| 378 | |||
| 379 | return fls(avail); | ||
| 380 | } | ||
| 381 | |||
| 382 | void pinctrl_falcon_add_gpio_range(struct pinctrl_gpio_range *range) | ||
| 383 | { | ||
| 384 | pinctrl_add_gpio_range(falcon_info.pctrl, range); | ||
| 385 | } | ||
| 386 | |||
| 387 | static int pinctrl_falcon_probe(struct platform_device *pdev) | ||
| 388 | { | ||
| 389 | struct device_node *np; | ||
| 390 | int pad_count = 0; | ||
| 391 | int ret = 0; | ||
| 392 | |||
| 393 | /* load and remap the pad resources of the different banks */ | ||
| 394 | for_each_compatible_node(np, NULL, "lantiq,pad-falcon") { | ||
| 395 | struct platform_device *ppdev = of_find_device_by_node(np); | ||
| 396 | const __be32 *bank = of_get_property(np, "lantiq,bank", NULL); | ||
| 397 | struct resource res; | ||
| 398 | u32 avail; | ||
| 399 | int pins; | ||
| 400 | |||
| 401 | if (!ppdev) { | ||
| 402 | dev_err(&pdev->dev, "failed to find pad pdev\n"); | ||
| 403 | continue; | ||
| 404 | } | ||
| 405 | if (!bank || *bank >= PORTS) | ||
| 406 | continue; | ||
| 407 | if (of_address_to_resource(np, 0, &res)) | ||
| 408 | continue; | ||
| 409 | falcon_info.clk[*bank] = clk_get(&ppdev->dev, NULL); | ||
| 410 | if (IS_ERR(falcon_info.clk[*bank])) { | ||
| 411 | dev_err(&ppdev->dev, "failed to get clock\n"); | ||
| 412 | return PTR_ERR(falcon_info.clk[*bank]); | ||
| 413 | } | ||
| 414 | falcon_info.membase[*bank] = | ||
| 415 | devm_request_and_ioremap(&pdev->dev, &res); | ||
| 416 | if (!falcon_info.membase[*bank]) { | ||
| 417 | dev_err(&pdev->dev, | ||
| 418 | "Failed to remap memory for bank %d\n", | ||
| 419 | *bank); | ||
| 420 | return -ENOMEM; | ||
| 421 | } | ||
| 422 | avail = pad_r32(falcon_info.membase[*bank], | ||
| 423 | LTQ_PADC_AVAIL); | ||
| 424 | pins = fls(avail); | ||
| 425 | lantiq_load_pin_desc(&falcon_pads[pad_count], *bank, pins); | ||
| 426 | pad_count += pins; | ||
| 427 | clk_enable(falcon_info.clk[*bank]); | ||
| 428 | dev_dbg(&pdev->dev, "found %s with %d pads\n", | ||
| 429 | res.name, pins); | ||
| 430 | } | ||
| 431 | dev_dbg(&pdev->dev, "found a total of %d pads\n", pad_count); | ||
| 432 | falcon_pctrl_desc.name = dev_name(&pdev->dev); | ||
| 433 | falcon_pctrl_desc.npins = pad_count; | ||
| 434 | |||
| 435 | falcon_info.mfp = falcon_mfp; | ||
| 436 | falcon_info.num_mfp = ARRAY_SIZE(falcon_mfp); | ||
| 437 | falcon_info.grps = falcon_grps; | ||
| 438 | falcon_info.num_grps = ARRAY_SIZE(falcon_grps); | ||
| 439 | falcon_info.funcs = falcon_funcs; | ||
| 440 | falcon_info.num_funcs = ARRAY_SIZE(falcon_funcs); | ||
| 441 | |||
| 442 | ret = ltq_pinctrl_register(pdev, &falcon_info); | ||
| 443 | if (!ret) | ||
| 444 | dev_info(&pdev->dev, "Init done\n"); | ||
| 445 | return ret; | ||
| 446 | } | ||
| 447 | |||
| 448 | static const struct of_device_id falcon_match[] = { | ||
| 449 | { .compatible = "lantiq,pinctrl-falcon" }, | ||
| 450 | {}, | ||
| 451 | }; | ||
| 452 | MODULE_DEVICE_TABLE(of, falcon_match); | ||
| 453 | |||
| 454 | static struct platform_driver pinctrl_falcon_driver = { | ||
| 455 | .probe = pinctrl_falcon_probe, | ||
| 456 | .driver = { | ||
| 457 | .name = "pinctrl-falcon", | ||
| 458 | .owner = THIS_MODULE, | ||
| 459 | .of_match_table = falcon_match, | ||
| 460 | }, | ||
| 461 | }; | ||
| 462 | |||
| 463 | int __init pinctrl_falcon_init(void) | ||
| 464 | { | ||
| 465 | return platform_driver_register(&pinctrl_falcon_driver); | ||
| 466 | } | ||
| 467 | |||
| 468 | core_initcall_sync(pinctrl_falcon_init); | ||
diff --git a/drivers/pinctrl/pinctrl-lantiq.c b/drivers/pinctrl/pinctrl-lantiq.c new file mode 100644 index 000000000000..07ba7682cf22 --- /dev/null +++ b/drivers/pinctrl/pinctrl-lantiq.c | |||
| @@ -0,0 +1,342 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/pinctrl/pinctrl-lantiq.c | ||
| 3 | * based on linux/drivers/pinctrl/pinctrl-pxa3xx.c | ||
| 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 | * publishhed by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * Copyright (C) 2012 John Crispin <blogic@openwrt.org> | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/device.h> | ||
| 14 | #include <linux/io.h> | ||
| 15 | #include <linux/platform_device.h> | ||
| 16 | #include <linux/slab.h> | ||
| 17 | #include <linux/of.h> | ||
| 18 | |||
| 19 | #include "pinctrl-lantiq.h" | ||
| 20 | |||
| 21 | static int ltq_get_group_count(struct pinctrl_dev *pctrldev) | ||
| 22 | { | ||
| 23 | struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); | ||
| 24 | return info->num_grps; | ||
| 25 | } | ||
| 26 | |||
| 27 | static const char *ltq_get_group_name(struct pinctrl_dev *pctrldev, | ||
| 28 | unsigned selector) | ||
| 29 | { | ||
| 30 | struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); | ||
| 31 | if (selector >= info->num_grps) | ||
| 32 | return NULL; | ||
| 33 | return info->grps[selector].name; | ||
| 34 | } | ||
| 35 | |||
| 36 | static int ltq_get_group_pins(struct pinctrl_dev *pctrldev, | ||
| 37 | unsigned selector, | ||
| 38 | const unsigned **pins, | ||
| 39 | unsigned *num_pins) | ||
| 40 | { | ||
| 41 | struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); | ||
| 42 | if (selector >= info->num_grps) | ||
| 43 | return -EINVAL; | ||
| 44 | *pins = info->grps[selector].pins; | ||
| 45 | *num_pins = info->grps[selector].npins; | ||
| 46 | return 0; | ||
| 47 | } | ||
| 48 | |||
| 49 | void ltq_pinctrl_dt_free_map(struct pinctrl_dev *pctldev, | ||
| 50 | struct pinctrl_map *map, unsigned num_maps) | ||
| 51 | { | ||
| 52 | int i; | ||
| 53 | |||
| 54 | for (i = 0; i < num_maps; i++) | ||
| 55 | if (map[i].type == PIN_MAP_TYPE_CONFIGS_PIN) | ||
| 56 | kfree(map[i].data.configs.configs); | ||
| 57 | kfree(map); | ||
| 58 | } | ||
| 59 | |||
| 60 | static void ltq_pinctrl_pin_dbg_show(struct pinctrl_dev *pctldev, | ||
| 61 | struct seq_file *s, | ||
| 62 | unsigned offset) | ||
| 63 | { | ||
| 64 | seq_printf(s, " %s", dev_name(pctldev->dev)); | ||
| 65 | } | ||
| 66 | |||
| 67 | static int ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, | ||
| 68 | struct device_node *np, | ||
| 69 | struct pinctrl_map **map) | ||
| 70 | { | ||
| 71 | struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev); | ||
| 72 | unsigned long configs[3]; | ||
| 73 | unsigned num_configs = 0; | ||
| 74 | struct property *prop; | ||
| 75 | const char *group, *pin; | ||
| 76 | const char *function; | ||
| 77 | int ret, i; | ||
| 78 | |||
| 79 | ret = of_property_read_string(np, "lantiq,function", &function); | ||
| 80 | if (!ret) { | ||
| 81 | of_property_for_each_string(np, "lantiq,groups", prop, group) { | ||
| 82 | (*map)->type = PIN_MAP_TYPE_MUX_GROUP; | ||
| 83 | (*map)->name = function; | ||
| 84 | (*map)->data.mux.group = group; | ||
| 85 | (*map)->data.mux.function = function; | ||
| 86 | (*map)++; | ||
| 87 | } | ||
| 88 | if (of_find_property(np, "lantiq,pins", NULL)) | ||
| 89 | dev_err(pctldev->dev, | ||
| 90 | "%s mixes pins and groups settings\n", | ||
| 91 | np->name); | ||
| 92 | return 0; | ||
| 93 | } | ||
| 94 | |||
| 95 | for (i = 0; i < info->num_params; i++) { | ||
| 96 | u32 val; | ||
| 97 | int ret = of_property_read_u32(np, | ||
| 98 | info->params[i].property, &val); | ||
| 99 | if (!ret) | ||
| 100 | configs[num_configs++] = | ||
| 101 | LTQ_PINCONF_PACK(info->params[i].param, | ||
| 102 | val); | ||
| 103 | } | ||
| 104 | |||
| 105 | if (!num_configs) | ||
| 106 | return -EINVAL; | ||
| 107 | |||
| 108 | of_property_for_each_string(np, "lantiq,pins", prop, pin) { | ||
| 109 | (*map)->data.configs.configs = kmemdup(configs, | ||
| 110 | num_configs * sizeof(unsigned long), | ||
| 111 | GFP_KERNEL); | ||
| 112 | (*map)->type = PIN_MAP_TYPE_CONFIGS_PIN; | ||
| 113 | (*map)->name = pin; | ||
| 114 | (*map)->data.configs.group_or_pin = pin; | ||
| 115 | (*map)->data.configs.num_configs = num_configs; | ||
| 116 | (*map)++; | ||
| 117 | } | ||
| 118 | return 0; | ||
| 119 | } | ||
| 120 | |||
| 121 | static int ltq_pinctrl_dt_subnode_size(struct device_node *np) | ||
| 122 | { | ||
| 123 | int ret; | ||
| 124 | |||
| 125 | ret = of_property_count_strings(np, "lantiq,groups"); | ||
| 126 | if (ret < 0) | ||
| 127 | ret = of_property_count_strings(np, "lantiq,pins"); | ||
| 128 | return ret; | ||
| 129 | } | ||
| 130 | |||
| 131 | int ltq_pinctrl_dt_node_to_map(struct pinctrl_dev *pctldev, | ||
| 132 | struct device_node *np_config, | ||
| 133 | struct pinctrl_map **map, | ||
| 134 | unsigned *num_maps) | ||
| 135 | { | ||
| 136 | struct pinctrl_map *tmp; | ||
| 137 | struct device_node *np; | ||
| 138 | int ret; | ||
| 139 | |||
| 140 | *num_maps = 0; | ||
| 141 | for_each_child_of_node(np_config, np) | ||
| 142 | *num_maps += ltq_pinctrl_dt_subnode_size(np); | ||
| 143 | *map = kzalloc(*num_maps * sizeof(struct pinctrl_map), GFP_KERNEL); | ||
| 144 | if (!*map) | ||
| 145 | return -ENOMEM; | ||
| 146 | tmp = *map; | ||
| 147 | |||
| 148 | for_each_child_of_node(np_config, np) { | ||
| 149 | ret = ltq_pinctrl_dt_subnode_to_map(pctldev, np, &tmp); | ||
| 150 | if (ret < 0) { | ||
| 151 | ltq_pinctrl_dt_free_map(pctldev, *map, *num_maps); | ||
| 152 | return ret; | ||
| 153 | } | ||
| 154 | } | ||
| 155 | return 0; | ||
| 156 | } | ||
| 157 | |||
| 158 | static struct pinctrl_ops ltq_pctrl_ops = { | ||
| 159 | .get_groups_count = ltq_get_group_count, | ||
| 160 | .get_group_name = ltq_get_group_name, | ||
| 161 | .get_group_pins = ltq_get_group_pins, | ||
| 162 | .pin_dbg_show = ltq_pinctrl_pin_dbg_show, | ||
| 163 | .dt_node_to_map = ltq_pinctrl_dt_node_to_map, | ||
| 164 | .dt_free_map = ltq_pinctrl_dt_free_map, | ||
| 165 | }; | ||
| 166 | |||
| 167 | static int ltq_pmx_func_count(struct pinctrl_dev *pctrldev) | ||
| 168 | { | ||
| 169 | struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); | ||
| 170 | |||
| 171 | return info->num_funcs; | ||
| 172 | } | ||
| 173 | |||
| 174 | static const char *ltq_pmx_func_name(struct pinctrl_dev *pctrldev, | ||
| 175 | unsigned selector) | ||
| 176 | { | ||
| 177 | struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); | ||
| 178 | |||
| 179 | if (selector >= info->num_funcs) | ||
| 180 | return NULL; | ||
| 181 | |||
| 182 | return info->funcs[selector].name; | ||
| 183 | } | ||
| 184 | |||
| 185 | static int ltq_pmx_get_groups(struct pinctrl_dev *pctrldev, | ||
| 186 | unsigned func, | ||
| 187 | const char * const **groups, | ||
| 188 | unsigned * const num_groups) | ||
| 189 | { | ||
| 190 | struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); | ||
| 191 | |||
| 192 | *groups = info->funcs[func].groups; | ||
| 193 | *num_groups = info->funcs[func].num_groups; | ||
| 194 | |||
| 195 | return 0; | ||
| 196 | } | ||
| 197 | |||
| 198 | /* Return function number. If failure, return negative value. */ | ||
| 199 | static int match_mux(const struct ltq_mfp_pin *mfp, unsigned mux) | ||
| 200 | { | ||
| 201 | int i; | ||
| 202 | for (i = 0; i < LTQ_MAX_MUX; i++) { | ||
| 203 | if (mfp->func[i] == mux) | ||
| 204 | break; | ||
| 205 | } | ||
| 206 | if (i >= LTQ_MAX_MUX) | ||
| 207 | return -EINVAL; | ||
| 208 | return i; | ||
| 209 | } | ||
| 210 | |||
| 211 | /* dont assume .mfp is linearly mapped. find the mfp with the correct .pin */ | ||
| 212 | static int match_mfp(const struct ltq_pinmux_info *info, int pin) | ||
| 213 | { | ||
| 214 | int i; | ||
| 215 | for (i = 0; i < info->num_mfp; i++) { | ||
| 216 | if (info->mfp[i].pin == pin) | ||
| 217 | return i; | ||
| 218 | } | ||
| 219 | return -1; | ||
| 220 | } | ||
| 221 | |||
| 222 | /* check whether current pin configuration is valid. Negative for failure */ | ||
| 223 | static int match_group_mux(const struct ltq_pin_group *grp, | ||
| 224 | const struct ltq_pinmux_info *info, | ||
| 225 | unsigned mux) | ||
| 226 | { | ||
| 227 | int i, pin, ret = 0; | ||
| 228 | for (i = 0; i < grp->npins; i++) { | ||
| 229 | pin = match_mfp(info, grp->pins[i]); | ||
| 230 | if (pin < 0) { | ||
| 231 | dev_err(info->dev, "could not find mfp for pin %d\n", | ||
| 232 | grp->pins[i]); | ||
| 233 | return -EINVAL; | ||
| 234 | } | ||
| 235 | ret = match_mux(&info->mfp[pin], mux); | ||
| 236 | if (ret < 0) { | ||
| 237 | dev_err(info->dev, "Can't find mux %d on pin%d\n", | ||
| 238 | mux, pin); | ||
| 239 | break; | ||
| 240 | } | ||
| 241 | } | ||
| 242 | return ret; | ||
| 243 | } | ||
| 244 | |||
| 245 | static int ltq_pmx_enable(struct pinctrl_dev *pctrldev, | ||
| 246 | unsigned func, | ||
| 247 | unsigned group) | ||
| 248 | { | ||
| 249 | struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); | ||
| 250 | const struct ltq_pin_group *pin_grp = &info->grps[group]; | ||
| 251 | int i, pin, pin_func, ret; | ||
| 252 | |||
| 253 | if (!pin_grp->npins || | ||
| 254 | (match_group_mux(pin_grp, info, pin_grp->mux) < 0)) { | ||
| 255 | dev_err(info->dev, "Failed to set the pin group: %s\n", | ||
| 256 | info->grps[group].name); | ||
| 257 | return -EINVAL; | ||
| 258 | } | ||
| 259 | for (i = 0; i < pin_grp->npins; i++) { | ||
| 260 | pin = match_mfp(info, pin_grp->pins[i]); | ||
| 261 | if (pin < 0) { | ||
| 262 | dev_err(info->dev, "could not find mfp for pin %d\n", | ||
| 263 | pin_grp->pins[i]); | ||
| 264 | return -EINVAL; | ||
| 265 | } | ||
| 266 | pin_func = match_mux(&info->mfp[pin], pin_grp->mux); | ||
| 267 | ret = info->apply_mux(pctrldev, pin, pin_func); | ||
| 268 | if (ret) { | ||
| 269 | dev_err(info->dev, | ||
| 270 | "failed to apply mux %d for pin %d\n", | ||
| 271 | pin_func, pin); | ||
| 272 | return ret; | ||
| 273 | } | ||
| 274 | } | ||
| 275 | return 0; | ||
| 276 | } | ||
| 277 | |||
| 278 | static void ltq_pmx_disable(struct pinctrl_dev *pctrldev, | ||
| 279 | unsigned func, | ||
| 280 | unsigned group) | ||
| 281 | { | ||
| 282 | /* | ||
| 283 | * Nothing to do here. However, pinconf_check_ops() requires this | ||
| 284 | * callback to be defined. | ||
| 285 | */ | ||
| 286 | } | ||
| 287 | |||
| 288 | static int ltq_pmx_gpio_request_enable(struct pinctrl_dev *pctrldev, | ||
| 289 | struct pinctrl_gpio_range *range, | ||
| 290 | unsigned pin) | ||
| 291 | { | ||
| 292 | struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); | ||
| 293 | int mfp = match_mfp(info, pin + (range->id * 32)); | ||
| 294 | int pin_func; | ||
| 295 | |||
| 296 | if (mfp < 0) { | ||
| 297 | dev_err(info->dev, "could not find mfp for pin %d\n", pin); | ||
| 298 | return -EINVAL; | ||
| 299 | } | ||
| 300 | |||
| 301 | pin_func = match_mux(&info->mfp[mfp], 0); | ||
| 302 | if (pin_func < 0) { | ||
| 303 | dev_err(info->dev, "No GPIO function on pin%d\n", mfp); | ||
| 304 | return -EINVAL; | ||
| 305 | } | ||
| 306 | |||
| 307 | return info->apply_mux(pctrldev, mfp, pin_func); | ||
| 308 | } | ||
| 309 | |||
| 310 | static struct pinmux_ops ltq_pmx_ops = { | ||
| 311 | .get_functions_count = ltq_pmx_func_count, | ||
| 312 | .get_function_name = ltq_pmx_func_name, | ||
| 313 | .get_function_groups = ltq_pmx_get_groups, | ||
| 314 | .enable = ltq_pmx_enable, | ||
| 315 | .disable = ltq_pmx_disable, | ||
| 316 | .gpio_request_enable = ltq_pmx_gpio_request_enable, | ||
| 317 | }; | ||
| 318 | |||
| 319 | /* | ||
| 320 | * allow different socs to register with the generic part of the lanti | ||
| 321 | * pinctrl code | ||
| 322 | */ | ||
| 323 | int ltq_pinctrl_register(struct platform_device *pdev, | ||
| 324 | struct ltq_pinmux_info *info) | ||
| 325 | { | ||
| 326 | struct pinctrl_desc *desc; | ||
| 327 | |||
| 328 | if (!info) | ||
| 329 | return -EINVAL; | ||
| 330 | desc = info->desc; | ||
| 331 | desc->pctlops = <q_pctrl_ops; | ||
| 332 | desc->pmxops = <q_pmx_ops; | ||
| 333 | info->dev = &pdev->dev; | ||
| 334 | |||
| 335 | info->pctrl = pinctrl_register(desc, &pdev->dev, info); | ||
| 336 | if (!info->pctrl) { | ||
| 337 | dev_err(&pdev->dev, "failed to register LTQ pinmux driver\n"); | ||
| 338 | return -EINVAL; | ||
| 339 | } | ||
| 340 | platform_set_drvdata(pdev, info); | ||
| 341 | return 0; | ||
| 342 | } | ||
diff --git a/drivers/pinctrl/pinctrl-lantiq.h b/drivers/pinctrl/pinctrl-lantiq.h new file mode 100644 index 000000000000..4419d32a0ade --- /dev/null +++ b/drivers/pinctrl/pinctrl-lantiq.h | |||
| @@ -0,0 +1,194 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/pinctrl/pinctrl-lantiq.h | ||
| 3 | * based on linux/drivers/pinctrl/pinctrl-pxa3xx.h | ||
| 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 | * publishhed by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * Copyright (C) 2012 John Crispin <blogic@openwrt.org> | ||
| 10 | */ | ||
| 11 | |||
| 12 | #ifndef __PINCTRL_LANTIQ_H | ||
| 13 | |||
| 14 | #include <linux/clkdev.h> | ||
| 15 | #include <linux/pinctrl/pinctrl.h> | ||
| 16 | #include <linux/pinctrl/pinconf.h> | ||
| 17 | #include <linux/pinctrl/pinmux.h> | ||
| 18 | #include <linux/pinctrl/consumer.h> | ||
| 19 | #include <linux/pinctrl/machine.h> | ||
| 20 | |||
| 21 | #include "core.h" | ||
| 22 | |||
| 23 | #define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x) | ||
| 24 | |||
| 25 | #define LTQ_MAX_MUX 4 | ||
| 26 | #define MFPR_FUNC_MASK 0x3 | ||
| 27 | |||
| 28 | #define LTQ_PINCONF_PACK(param, arg) ((param) << 16 | (arg)) | ||
| 29 | #define LTQ_PINCONF_UNPACK_PARAM(conf) ((conf) >> 16) | ||
| 30 | #define LTQ_PINCONF_UNPACK_ARG(conf) ((conf) & 0xffff) | ||
| 31 | |||
| 32 | enum ltq_pinconf_param { | ||
| 33 | LTQ_PINCONF_PARAM_PULL, | ||
| 34 | LTQ_PINCONF_PARAM_OPEN_DRAIN, | ||
| 35 | LTQ_PINCONF_PARAM_DRIVE_CURRENT, | ||
| 36 | LTQ_PINCONF_PARAM_SLEW_RATE, | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct ltq_cfg_param { | ||
| 40 | const char *property; | ||
| 41 | enum ltq_pinconf_param param; | ||
| 42 | }; | ||
| 43 | |||
| 44 | struct ltq_mfp_pin { | ||
| 45 | const char *name; | ||
| 46 | const unsigned int pin; | ||
| 47 | const unsigned short func[LTQ_MAX_MUX]; | ||
| 48 | }; | ||
| 49 | |||
| 50 | struct ltq_pin_group { | ||
| 51 | const char *name; | ||
| 52 | const unsigned mux; | ||
| 53 | const unsigned *pins; | ||
| 54 | const unsigned npins; | ||
| 55 | }; | ||
| 56 | |||
| 57 | struct ltq_pmx_func { | ||
| 58 | const char *name; | ||
| 59 | const char * const *groups; | ||
| 60 | const unsigned num_groups; | ||
| 61 | }; | ||
| 62 | |||
| 63 | struct ltq_pinmux_info { | ||
| 64 | struct device *dev; | ||
| 65 | struct pinctrl_dev *pctrl; | ||
| 66 | |||
| 67 | /* we need to manage up to 5 pad controllers */ | ||
| 68 | void __iomem *membase[5]; | ||
| 69 | |||
| 70 | /* the descriptor for the subsystem */ | ||
| 71 | struct pinctrl_desc *desc; | ||
| 72 | |||
| 73 | /* we expose our pads to the subsystem */ | ||
| 74 | struct pinctrl_pin_desc *pads; | ||
| 75 | |||
| 76 | /* the number of pads. this varies between socs */ | ||
| 77 | unsigned int num_pads; | ||
| 78 | |||
| 79 | /* these are our multifunction pins */ | ||
| 80 | const struct ltq_mfp_pin *mfp; | ||
| 81 | unsigned int num_mfp; | ||
| 82 | |||
| 83 | /* a number of multifunction pins can be grouped together */ | ||
| 84 | const struct ltq_pin_group *grps; | ||
| 85 | unsigned int num_grps; | ||
| 86 | |||
| 87 | /* a mapping between function string and id */ | ||
| 88 | const struct ltq_pmx_func *funcs; | ||
| 89 | unsigned int num_funcs; | ||
| 90 | |||
| 91 | /* the pinconf options that we are able to read from the DT */ | ||
| 92 | const struct ltq_cfg_param *params; | ||
| 93 | unsigned int num_params; | ||
| 94 | |||
| 95 | /* the pad controller can have a irq mapping */ | ||
| 96 | const unsigned *exin; | ||
| 97 | unsigned int num_exin; | ||
| 98 | |||
| 99 | /* we need 5 clocks max */ | ||
| 100 | struct clk *clk[5]; | ||
| 101 | |||
| 102 | /* soc specific callback used to apply muxing */ | ||
| 103 | int (*apply_mux)(struct pinctrl_dev *pctrldev, int pin, int mux); | ||
| 104 | }; | ||
| 105 | |||
| 106 | enum ltq_pin { | ||
| 107 | GPIO0 = 0, | ||
| 108 | GPIO1, | ||
| 109 | GPIO2, | ||
| 110 | GPIO3, | ||
| 111 | GPIO4, | ||
| 112 | GPIO5, | ||
| 113 | GPIO6, | ||
| 114 | GPIO7, | ||
| 115 | GPIO8, | ||
| 116 | GPIO9, | ||
| 117 | GPIO10, /* 10 */ | ||
| 118 | GPIO11, | ||
| 119 | GPIO12, | ||
| 120 | GPIO13, | ||
| 121 | GPIO14, | ||
| 122 | GPIO15, | ||
| 123 | GPIO16, | ||
| 124 | GPIO17, | ||
| 125 | GPIO18, | ||
| 126 | GPIO19, | ||
| 127 | GPIO20, /* 20 */ | ||
| 128 | GPIO21, | ||
| 129 | GPIO22, | ||
| 130 | GPIO23, | ||
| 131 | GPIO24, | ||
| 132 | GPIO25, | ||
| 133 | GPIO26, | ||
| 134 | GPIO27, | ||
| 135 | GPIO28, | ||
| 136 | GPIO29, | ||
| 137 | GPIO30, /* 30 */ | ||
| 138 | GPIO31, | ||
| 139 | GPIO32, | ||
| 140 | GPIO33, | ||
| 141 | GPIO34, | ||
| 142 | GPIO35, | ||
| 143 | GPIO36, | ||
| 144 | GPIO37, | ||
| 145 | GPIO38, | ||
| 146 | GPIO39, | ||
| 147 | GPIO40, /* 40 */ | ||
| 148 | GPIO41, | ||
| 149 | GPIO42, | ||
| 150 | GPIO43, | ||
| 151 | GPIO44, | ||
| 152 | GPIO45, | ||
| 153 | GPIO46, | ||
| 154 | GPIO47, | ||
| 155 | GPIO48, | ||
| 156 | GPIO49, | ||
| 157 | GPIO50, /* 50 */ | ||
| 158 | GPIO51, | ||
| 159 | GPIO52, | ||
| 160 | GPIO53, | ||
| 161 | GPIO54, | ||
| 162 | GPIO55, | ||
| 163 | |||
| 164 | GPIO64, | ||
| 165 | GPIO65, | ||
| 166 | GPIO66, | ||
| 167 | GPIO67, | ||
| 168 | GPIO68, | ||
| 169 | GPIO69, | ||
| 170 | GPIO70, | ||
| 171 | GPIO71, | ||
| 172 | GPIO72, | ||
| 173 | GPIO73, | ||
| 174 | GPIO74, | ||
| 175 | GPIO75, | ||
| 176 | GPIO76, | ||
| 177 | GPIO77, | ||
| 178 | GPIO78, | ||
| 179 | GPIO79, | ||
| 180 | GPIO80, | ||
| 181 | GPIO81, | ||
| 182 | GPIO82, | ||
| 183 | GPIO83, | ||
| 184 | GPIO84, | ||
| 185 | GPIO85, | ||
| 186 | GPIO86, | ||
| 187 | GPIO87, | ||
| 188 | GPIO88, | ||
| 189 | }; | ||
| 190 | |||
| 191 | extern int ltq_pinctrl_register(struct platform_device *pdev, | ||
| 192 | struct ltq_pinmux_info *info); | ||
| 193 | extern int ltq_pinctrl_unregister(struct platform_device *pdev); | ||
| 194 | #endif /* __PINCTRL_PXA3XX_H */ | ||
diff --git a/drivers/pinctrl/pinctrl-xway.c b/drivers/pinctrl/pinctrl-xway.c new file mode 100644 index 000000000000..f8d917d40c92 --- /dev/null +++ b/drivers/pinctrl/pinctrl-xway.c | |||
| @@ -0,0 +1,781 @@ | |||
| 1 | /* | ||
| 2 | * linux/drivers/pinctrl/pinmux-xway.c | ||
| 3 | * based on linux/drivers/pinctrl/pinmux-pxa910.c | ||
| 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 | * publishhed by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * Copyright (C) 2012 John Crispin <blogic@openwrt.org> | ||
| 10 | */ | ||
| 11 | |||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/module.h> | ||
| 14 | #include <linux/of_platform.h> | ||
| 15 | #include <linux/of_address.h> | ||
| 16 | #include <linux/of_gpio.h> | ||
| 17 | #include <linux/ioport.h> | ||
| 18 | #include <linux/io.h> | ||
| 19 | #include <linux/device.h> | ||
| 20 | #include <linux/module.h> | ||
| 21 | #include <linux/io.h> | ||
| 22 | #include <linux/platform_device.h> | ||
| 23 | |||
| 24 | #include "pinctrl-lantiq.h" | ||
| 25 | |||
| 26 | #include <lantiq_soc.h> | ||
| 27 | |||
| 28 | /* we have 3 1/2 banks of 16 bit each */ | ||
| 29 | #define PINS 16 | ||
| 30 | #define PORT3 3 | ||
| 31 | #define PORT(x) (x / PINS) | ||
| 32 | #define PORT_PIN(x) (x % PINS) | ||
| 33 | |||
| 34 | /* we have 2 mux bits that can be set for each pin */ | ||
| 35 | #define MUX_ALT0 0x1 | ||
| 36 | #define MUX_ALT1 0x2 | ||
| 37 | |||
| 38 | /* | ||
| 39 | * each bank has this offset apart from the 1/2 bank that is mixed into the | ||
| 40 | * other 3 ranges | ||
| 41 | */ | ||
| 42 | #define REG_OFF 0x30 | ||
| 43 | |||
| 44 | /* these are the offsets to our registers */ | ||
| 45 | #define GPIO_BASE(p) (REG_OFF * PORT(p)) | ||
| 46 | #define GPIO_OUT(p) GPIO_BASE(p) | ||
| 47 | #define GPIO_IN(p) (GPIO_BASE(p) + 0x04) | ||
| 48 | #define GPIO_DIR(p) (GPIO_BASE(p) + 0x08) | ||
| 49 | #define GPIO_ALT0(p) (GPIO_BASE(p) + 0x0C) | ||
| 50 | #define GPIO_ALT1(p) (GPIO_BASE(p) + 0x10) | ||
| 51 | #define GPIO_OD(p) (GPIO_BASE(p) + 0x14) | ||
| 52 | #define GPIO_PUDSEL(p) (GPIO_BASE(p) + 0x1c) | ||
| 53 | #define GPIO_PUDEN(p) (GPIO_BASE(p) + 0x20) | ||
| 54 | |||
| 55 | /* the 1/2 port needs special offsets for some registers */ | ||
| 56 | #define GPIO3_OD (GPIO_BASE(0) + 0x24) | ||
| 57 | #define GPIO3_PUDSEL (GPIO_BASE(0) + 0x28) | ||
| 58 | #define GPIO3_PUDEN (GPIO_BASE(0) + 0x2C) | ||
| 59 | #define GPIO3_ALT1 (GPIO_BASE(PINS) + 0x24) | ||
| 60 | |||
| 61 | /* macros to help us access the registers */ | ||
| 62 | #define gpio_getbit(m, r, p) (!!(ltq_r32(m + r) & BIT(p))) | ||
| 63 | #define gpio_setbit(m, r, p) ltq_w32_mask(0, BIT(p), m + r) | ||
| 64 | #define gpio_clearbit(m, r, p) ltq_w32_mask(BIT(p), 0, m + r) | ||
| 65 | |||
| 66 | #define MFP_XWAY(a, f0, f1, f2, f3) \ | ||
| 67 | { \ | ||
| 68 | .name = #a, \ | ||
| 69 | .pin = a, \ | ||
| 70 | .func = { \ | ||
| 71 | XWAY_MUX_##f0, \ | ||
| 72 | XWAY_MUX_##f1, \ | ||
| 73 | XWAY_MUX_##f2, \ | ||
| 74 | XWAY_MUX_##f3, \ | ||
| 75 | }, \ | ||
| 76 | } | ||
| 77 | |||
| 78 | #define GRP_MUX(a, m, p) \ | ||
| 79 | { .name = a, .mux = XWAY_MUX_##m, .pins = p, .npins = ARRAY_SIZE(p), } | ||
| 80 | |||
| 81 | #define FUNC_MUX(f, m) \ | ||
| 82 | { .func = f, .mux = XWAY_MUX_##m, } | ||
| 83 | |||
| 84 | #define XWAY_MAX_PIN 32 | ||
| 85 | #define XR9_MAX_PIN 56 | ||
| 86 | |||
| 87 | enum xway_mux { | ||
| 88 | XWAY_MUX_GPIO = 0, | ||
| 89 | XWAY_MUX_SPI, | ||
| 90 | XWAY_MUX_ASC, | ||
| 91 | XWAY_MUX_PCI, | ||
| 92 | XWAY_MUX_CGU, | ||
| 93 | XWAY_MUX_EBU, | ||
| 94 | XWAY_MUX_JTAG, | ||
| 95 | XWAY_MUX_EXIN, | ||
| 96 | XWAY_MUX_TDM, | ||
| 97 | XWAY_MUX_STP, | ||
| 98 | XWAY_MUX_SIN, | ||
| 99 | XWAY_MUX_GPT, | ||
| 100 | XWAY_MUX_NMI, | ||
| 101 | XWAY_MUX_MDIO, | ||
| 102 | XWAY_MUX_MII, | ||
| 103 | XWAY_MUX_EPHY, | ||
| 104 | XWAY_MUX_DFE, | ||
| 105 | XWAY_MUX_SDIO, | ||
| 106 | XWAY_MUX_NONE = 0xffff, | ||
| 107 | }; | ||
| 108 | |||
| 109 | static const struct ltq_mfp_pin xway_mfp[] = { | ||
| 110 | /* pin f0 f1 f2 f3 */ | ||
| 111 | MFP_XWAY(GPIO0, GPIO, EXIN, NONE, TDM), | ||
| 112 | MFP_XWAY(GPIO1, GPIO, EXIN, NONE, NONE), | ||
| 113 | MFP_XWAY(GPIO2, GPIO, CGU, EXIN, NONE), | ||
| 114 | MFP_XWAY(GPIO3, GPIO, CGU, NONE, PCI), | ||
| 115 | MFP_XWAY(GPIO4, GPIO, STP, NONE, ASC), | ||
| 116 | MFP_XWAY(GPIO5, GPIO, STP, NONE, NONE), | ||
| 117 | MFP_XWAY(GPIO6, GPIO, STP, GPT, ASC), | ||
| 118 | MFP_XWAY(GPIO7, GPIO, CGU, PCI, NONE), | ||
| 119 | MFP_XWAY(GPIO8, GPIO, CGU, NMI, NONE), | ||
| 120 | MFP_XWAY(GPIO9, GPIO, ASC, SPI, EXIN), | ||
| 121 | MFP_XWAY(GPIO10, GPIO, ASC, SPI, NONE), | ||
| 122 | MFP_XWAY(GPIO11, GPIO, ASC, PCI, SPI), | ||
| 123 | MFP_XWAY(GPIO12, GPIO, ASC, NONE, NONE), | ||
| 124 | MFP_XWAY(GPIO13, GPIO, EBU, SPI, NONE), | ||
| 125 | MFP_XWAY(GPIO14, GPIO, CGU, PCI, NONE), | ||
| 126 | MFP_XWAY(GPIO15, GPIO, SPI, JTAG, NONE), | ||
| 127 | MFP_XWAY(GPIO16, GPIO, SPI, NONE, JTAG), | ||
| 128 | MFP_XWAY(GPIO17, GPIO, SPI, NONE, JTAG), | ||
| 129 | MFP_XWAY(GPIO18, GPIO, SPI, NONE, JTAG), | ||
| 130 | MFP_XWAY(GPIO19, GPIO, PCI, NONE, NONE), | ||
| 131 | MFP_XWAY(GPIO20, GPIO, JTAG, NONE, NONE), | ||
| 132 | MFP_XWAY(GPIO21, GPIO, PCI, EBU, GPT), | ||
| 133 | MFP_XWAY(GPIO22, GPIO, SPI, NONE, NONE), | ||
| 134 | MFP_XWAY(GPIO23, GPIO, EBU, PCI, STP), | ||
| 135 | MFP_XWAY(GPIO24, GPIO, EBU, TDM, PCI), | ||
| 136 | MFP_XWAY(GPIO25, GPIO, TDM, NONE, ASC), | ||
| 137 | MFP_XWAY(GPIO26, GPIO, EBU, NONE, TDM), | ||
| 138 | MFP_XWAY(GPIO27, GPIO, TDM, NONE, ASC), | ||
| 139 | MFP_XWAY(GPIO28, GPIO, GPT, NONE, NONE), | ||
| 140 | MFP_XWAY(GPIO29, GPIO, PCI, NONE, NONE), | ||
| 141 | MFP_XWAY(GPIO30, GPIO, PCI, NONE, NONE), | ||
| 142 | MFP_XWAY(GPIO31, GPIO, EBU, PCI, NONE), | ||
| 143 | MFP_XWAY(GPIO32, GPIO, NONE, NONE, EBU), | ||
| 144 | MFP_XWAY(GPIO33, GPIO, NONE, NONE, EBU), | ||
| 145 | MFP_XWAY(GPIO34, GPIO, NONE, NONE, EBU), | ||
| 146 | MFP_XWAY(GPIO35, GPIO, NONE, NONE, EBU), | ||
| 147 | MFP_XWAY(GPIO36, GPIO, SIN, NONE, EBU), | ||
| 148 | MFP_XWAY(GPIO37, GPIO, PCI, NONE, NONE), | ||
| 149 | MFP_XWAY(GPIO38, GPIO, PCI, NONE, NONE), | ||
| 150 | MFP_XWAY(GPIO39, GPIO, EXIN, NONE, NONE), | ||
| 151 | MFP_XWAY(GPIO40, GPIO, NONE, NONE, NONE), | ||
| 152 | MFP_XWAY(GPIO41, GPIO, NONE, NONE, NONE), | ||
| 153 | MFP_XWAY(GPIO42, GPIO, MDIO, NONE, NONE), | ||
| 154 | MFP_XWAY(GPIO43, GPIO, MDIO, NONE, NONE), | ||
| 155 | MFP_XWAY(GPIO44, GPIO, NONE, NONE, SIN), | ||
| 156 | MFP_XWAY(GPIO45, GPIO, NONE, NONE, SIN), | ||
| 157 | MFP_XWAY(GPIO46, GPIO, NONE, NONE, EXIN), | ||
| 158 | MFP_XWAY(GPIO47, GPIO, NONE, NONE, SIN), | ||
| 159 | MFP_XWAY(GPIO48, GPIO, EBU, NONE, NONE), | ||
| 160 | MFP_XWAY(GPIO49, GPIO, EBU, NONE, NONE), | ||
| 161 | MFP_XWAY(GPIO50, GPIO, NONE, NONE, NONE), | ||
| 162 | MFP_XWAY(GPIO51, GPIO, NONE, NONE, NONE), | ||
| 163 | MFP_XWAY(GPIO52, GPIO, NONE, NONE, NONE), | ||
| 164 | MFP_XWAY(GPIO53, GPIO, NONE, NONE, NONE), | ||
| 165 | MFP_XWAY(GPIO54, GPIO, NONE, NONE, NONE), | ||
| 166 | MFP_XWAY(GPIO55, GPIO, NONE, NONE, NONE), | ||
| 167 | }; | ||
| 168 | |||
| 169 | static const struct ltq_mfp_pin ase_mfp[] = { | ||
| 170 | /* pin f0 f1 f2 f3 */ | ||
| 171 | MFP_XWAY(GPIO0, GPIO, EXIN, MII, TDM), | ||
| 172 | MFP_XWAY(GPIO1, GPIO, STP, DFE, EBU), | ||
| 173 | MFP_XWAY(GPIO2, GPIO, STP, DFE, EPHY), | ||
| 174 | MFP_XWAY(GPIO3, GPIO, STP, EPHY, EBU), | ||
| 175 | MFP_XWAY(GPIO4, GPIO, GPT, EPHY, MII), | ||
| 176 | MFP_XWAY(GPIO5, GPIO, MII, ASC, GPT), | ||
| 177 | MFP_XWAY(GPIO6, GPIO, MII, ASC, EXIN), | ||
| 178 | MFP_XWAY(GPIO7, GPIO, SPI, MII, JTAG), | ||
| 179 | MFP_XWAY(GPIO8, GPIO, SPI, MII, JTAG), | ||
| 180 | MFP_XWAY(GPIO9, GPIO, SPI, MII, JTAG), | ||
| 181 | MFP_XWAY(GPIO10, GPIO, SPI, MII, JTAG), | ||
| 182 | MFP_XWAY(GPIO11, GPIO, EBU, CGU, JTAG), | ||
| 183 | MFP_XWAY(GPIO12, GPIO, EBU, MII, SDIO), | ||
| 184 | MFP_XWAY(GPIO13, GPIO, EBU, MII, CGU), | ||
| 185 | MFP_XWAY(GPIO14, GPIO, EBU, SPI, CGU), | ||
| 186 | MFP_XWAY(GPIO15, GPIO, EBU, SPI, SDIO), | ||
| 187 | MFP_XWAY(GPIO16, GPIO, NONE, NONE, NONE), | ||
| 188 | MFP_XWAY(GPIO17, GPIO, NONE, NONE, NONE), | ||
| 189 | MFP_XWAY(GPIO18, GPIO, NONE, NONE, NONE), | ||
| 190 | MFP_XWAY(GPIO19, GPIO, EBU, MII, SDIO), | ||
| 191 | MFP_XWAY(GPIO20, GPIO, EBU, MII, SDIO), | ||
| 192 | MFP_XWAY(GPIO21, GPIO, EBU, MII, SDIO), | ||
| 193 | MFP_XWAY(GPIO22, GPIO, EBU, MII, CGU), | ||
| 194 | MFP_XWAY(GPIO23, GPIO, EBU, MII, CGU), | ||
| 195 | MFP_XWAY(GPIO24, GPIO, EBU, NONE, MII), | ||
| 196 | MFP_XWAY(GPIO25, GPIO, EBU, MII, GPT), | ||
| 197 | MFP_XWAY(GPIO26, GPIO, EBU, MII, SDIO), | ||
| 198 | MFP_XWAY(GPIO27, GPIO, EBU, NONE, MII), | ||
| 199 | MFP_XWAY(GPIO28, GPIO, MII, EBU, SDIO), | ||
| 200 | MFP_XWAY(GPIO29, GPIO, EBU, MII, EXIN), | ||
| 201 | MFP_XWAY(GPIO30, GPIO, NONE, NONE, NONE), | ||
| 202 | MFP_XWAY(GPIO31, GPIO, NONE, NONE, NONE), | ||
| 203 | }; | ||
| 204 | |||
| 205 | static const unsigned pins_jtag[] = {GPIO15, GPIO16, GPIO17, GPIO19, GPIO35}; | ||
| 206 | static const unsigned pins_asc0[] = {GPIO11, GPIO12}; | ||
| 207 | static const unsigned pins_asc0_cts_rts[] = {GPIO9, GPIO10}; | ||
| 208 | static const unsigned pins_stp[] = {GPIO4, GPIO5, GPIO6}; | ||
| 209 | static const unsigned pins_nmi[] = {GPIO8}; | ||
| 210 | static const unsigned pins_mdio[] = {GPIO42, GPIO43}; | ||
| 211 | |||
| 212 | static const unsigned pins_ebu_a24[] = {GPIO13}; | ||
| 213 | static const unsigned pins_ebu_clk[] = {GPIO21}; | ||
| 214 | static const unsigned pins_ebu_cs1[] = {GPIO23}; | ||
| 215 | static const unsigned pins_ebu_a23[] = {GPIO24}; | ||
| 216 | static const unsigned pins_ebu_wait[] = {GPIO26}; | ||
| 217 | static const unsigned pins_ebu_a25[] = {GPIO31}; | ||
| 218 | static const unsigned pins_ebu_rdy[] = {GPIO48}; | ||
| 219 | static const unsigned pins_ebu_rd[] = {GPIO49}; | ||
| 220 | |||
| 221 | static const unsigned pins_nand_ale[] = {GPIO13}; | ||
| 222 | static const unsigned pins_nand_cs1[] = {GPIO23}; | ||
| 223 | static const unsigned pins_nand_cle[] = {GPIO24}; | ||
| 224 | static const unsigned pins_nand_rdy[] = {GPIO48}; | ||
| 225 | static const unsigned pins_nand_rd[] = {GPIO49}; | ||
| 226 | |||
| 227 | static const unsigned pins_exin0[] = {GPIO0}; | ||
| 228 | static const unsigned pins_exin1[] = {GPIO1}; | ||
| 229 | static const unsigned pins_exin2[] = {GPIO2}; | ||
| 230 | static const unsigned pins_exin3[] = {GPIO39}; | ||
| 231 | static const unsigned pins_exin4[] = {GPIO46}; | ||
| 232 | static const unsigned pins_exin5[] = {GPIO9}; | ||
| 233 | |||
| 234 | static const unsigned pins_spi[] = {GPIO16, GPIO17, GPIO18}; | ||
| 235 | static const unsigned pins_spi_cs1[] = {GPIO15}; | ||
| 236 | static const unsigned pins_spi_cs2[] = {GPIO21}; | ||
| 237 | static const unsigned pins_spi_cs3[] = {GPIO13}; | ||
| 238 | static const unsigned pins_spi_cs4[] = {GPIO10}; | ||
| 239 | static const unsigned pins_spi_cs5[] = {GPIO9}; | ||
| 240 | static const unsigned pins_spi_cs6[] = {GPIO11}; | ||
| 241 | |||
| 242 | static const unsigned pins_gpt1[] = {GPIO28}; | ||
| 243 | static const unsigned pins_gpt2[] = {GPIO21}; | ||
| 244 | static const unsigned pins_gpt3[] = {GPIO6}; | ||
| 245 | |||
| 246 | static const unsigned pins_clkout0[] = {GPIO8}; | ||
| 247 | static const unsigned pins_clkout1[] = {GPIO7}; | ||
| 248 | static const unsigned pins_clkout2[] = {GPIO3}; | ||
| 249 | static const unsigned pins_clkout3[] = {GPIO2}; | ||
| 250 | |||
| 251 | static const unsigned pins_pci_gnt1[] = {GPIO30}; | ||
| 252 | static const unsigned pins_pci_gnt2[] = {GPIO23}; | ||
| 253 | static const unsigned pins_pci_gnt3[] = {GPIO19}; | ||
| 254 | static const unsigned pins_pci_gnt4[] = {GPIO38}; | ||
| 255 | static const unsigned pins_pci_req1[] = {GPIO29}; | ||
| 256 | static const unsigned pins_pci_req2[] = {GPIO31}; | ||
| 257 | static const unsigned pins_pci_req3[] = {GPIO3}; | ||
| 258 | static const unsigned pins_pci_req4[] = {GPIO37}; | ||
| 259 | |||
| 260 | static const unsigned ase_pins_jtag[] = {GPIO7, GPIO8, GPIO9, GPIO10, GPIO11}; | ||
| 261 | static const unsigned ase_pins_asc[] = {GPIO5, GPIO6}; | ||
| 262 | static const unsigned ase_pins_stp[] = {GPIO1, GPIO2, GPIO3}; | ||
| 263 | static const unsigned ase_pins_ephy[] = {GPIO2, GPIO3, GPIO4}; | ||
| 264 | static const unsigned ase_pins_dfe[] = {GPIO1, GPIO2}; | ||
| 265 | |||
| 266 | static const unsigned ase_pins_spi[] = {GPIO8, GPIO9, GPIO10}; | ||
| 267 | static const unsigned ase_pins_spi_cs1[] = {GPIO7}; | ||
| 268 | static const unsigned ase_pins_spi_cs2[] = {GPIO15}; | ||
| 269 | static const unsigned ase_pins_spi_cs3[] = {GPIO14}; | ||
| 270 | |||
| 271 | static const unsigned ase_pins_exin0[] = {GPIO6}; | ||
| 272 | static const unsigned ase_pins_exin1[] = {GPIO29}; | ||
| 273 | static const unsigned ase_pins_exin2[] = {GPIO0}; | ||
| 274 | |||
| 275 | static const unsigned ase_pins_gpt1[] = {GPIO5}; | ||
| 276 | static const unsigned ase_pins_gpt2[] = {GPIO4}; | ||
| 277 | static const unsigned ase_pins_gpt3[] = {GPIO25}; | ||
| 278 | |||
| 279 | static const struct ltq_pin_group xway_grps[] = { | ||
| 280 | GRP_MUX("exin0", EXIN, pins_exin0), | ||
| 281 | GRP_MUX("exin1", EXIN, pins_exin1), | ||
| 282 | GRP_MUX("exin2", EXIN, pins_exin2), | ||
| 283 | GRP_MUX("jtag", JTAG, pins_jtag), | ||
| 284 | GRP_MUX("ebu a23", EBU, pins_ebu_a23), | ||
| 285 | GRP_MUX("ebu a24", EBU, pins_ebu_a24), | ||
| 286 | GRP_MUX("ebu a25", EBU, pins_ebu_a25), | ||
| 287 | GRP_MUX("ebu clk", EBU, pins_ebu_clk), | ||
| 288 | GRP_MUX("ebu cs1", EBU, pins_ebu_cs1), | ||
| 289 | GRP_MUX("ebu wait", EBU, pins_ebu_wait), | ||
| 290 | GRP_MUX("nand ale", EBU, pins_nand_ale), | ||
| 291 | GRP_MUX("nand cs1", EBU, pins_nand_cs1), | ||
| 292 | GRP_MUX("nand cle", EBU, pins_nand_cle), | ||
| 293 | GRP_MUX("spi", SPI, pins_spi), | ||
| 294 | GRP_MUX("spi_cs1", SPI, pins_spi_cs1), | ||
| 295 | GRP_MUX("spi_cs2", SPI, pins_spi_cs2), | ||
| 296 | GRP_MUX("spi_cs3", SPI, pins_spi_cs3), | ||
| 297 | GRP_MUX("spi_cs4", SPI, pins_spi_cs4), | ||
| 298 | GRP_MUX("spi_cs5", SPI, pins_spi_cs5), | ||
| 299 | GRP_MUX("spi_cs6", SPI, pins_spi_cs6), | ||
| 300 | GRP_MUX("asc0", ASC, pins_asc0), | ||
| 301 | GRP_MUX("asc0 cts rts", ASC, pins_asc0_cts_rts), | ||
| 302 | GRP_MUX("stp", STP, pins_stp), | ||
| 303 | GRP_MUX("nmi", NMI, pins_nmi), | ||
| 304 | GRP_MUX("gpt1", GPT, pins_gpt1), | ||
| 305 | GRP_MUX("gpt2", GPT, pins_gpt2), | ||
| 306 | GRP_MUX("gpt3", GPT, pins_gpt3), | ||
| 307 | GRP_MUX("clkout0", CGU, pins_clkout0), | ||
| 308 | GRP_MUX("clkout1", CGU, pins_clkout1), | ||
| 309 | GRP_MUX("clkout2", CGU, pins_clkout2), | ||
| 310 | GRP_MUX("clkout3", CGU, pins_clkout3), | ||
| 311 | GRP_MUX("gnt1", PCI, pins_pci_gnt1), | ||
| 312 | GRP_MUX("gnt2", PCI, pins_pci_gnt2), | ||
| 313 | GRP_MUX("gnt3", PCI, pins_pci_gnt3), | ||
| 314 | GRP_MUX("req1", PCI, pins_pci_req1), | ||
| 315 | GRP_MUX("req2", PCI, pins_pci_req2), | ||
| 316 | GRP_MUX("req3", PCI, pins_pci_req3), | ||
| 317 | /* xrx only */ | ||
| 318 | GRP_MUX("nand rdy", EBU, pins_nand_rdy), | ||
| 319 | GRP_MUX("nand rd", EBU, pins_nand_rd), | ||
| 320 | GRP_MUX("exin3", EXIN, pins_exin3), | ||
| 321 | GRP_MUX("exin4", EXIN, pins_exin4), | ||
| 322 | GRP_MUX("exin5", EXIN, pins_exin5), | ||
| 323 | GRP_MUX("gnt4", PCI, pins_pci_gnt4), | ||
| 324 | GRP_MUX("req4", PCI, pins_pci_gnt4), | ||
| 325 | GRP_MUX("mdio", MDIO, pins_mdio), | ||
| 326 | }; | ||
| 327 | |||
| 328 | static const struct ltq_pin_group ase_grps[] = { | ||
| 329 | GRP_MUX("exin0", EXIN, ase_pins_exin0), | ||
| 330 | GRP_MUX("exin1", EXIN, ase_pins_exin1), | ||
| 331 | GRP_MUX("exin2", EXIN, ase_pins_exin2), | ||
| 332 | GRP_MUX("jtag", JTAG, ase_pins_jtag), | ||
| 333 | GRP_MUX("stp", STP, ase_pins_stp), | ||
| 334 | GRP_MUX("asc", ASC, ase_pins_asc), | ||
| 335 | GRP_MUX("gpt1", GPT, ase_pins_gpt1), | ||
| 336 | GRP_MUX("gpt2", GPT, ase_pins_gpt2), | ||
| 337 | GRP_MUX("gpt3", GPT, ase_pins_gpt3), | ||
| 338 | GRP_MUX("ephy", EPHY, ase_pins_ephy), | ||
| 339 | GRP_MUX("dfe", DFE, ase_pins_dfe), | ||
| 340 | GRP_MUX("spi", SPI, ase_pins_spi), | ||
| 341 | GRP_MUX("spi_cs1", SPI, ase_pins_spi_cs1), | ||
| 342 | GRP_MUX("spi_cs2", SPI, ase_pins_spi_cs2), | ||
| 343 | GRP_MUX("spi_cs3", SPI, ase_pins_spi_cs3), | ||
| 344 | }; | ||
| 345 | |||
| 346 | static const char * const xway_pci_grps[] = {"gnt1", "gnt2", | ||
| 347 | "gnt3", "req1", | ||
| 348 | "req2", "req3"}; | ||
| 349 | static const char * const xway_spi_grps[] = {"spi", "spi_cs1", | ||
| 350 | "spi_cs2", "spi_cs3", | ||
| 351 | "spi_cs4", "spi_cs5", | ||
| 352 | "spi_cs6"}; | ||
| 353 | static const char * const xway_cgu_grps[] = {"clkout0", "clkout1", | ||
| 354 | "clkout2", "clkout3"}; | ||
| 355 | static const char * const xway_ebu_grps[] = {"ebu a23", "ebu a24", | ||
| 356 | "ebu a25", "ebu cs1", | ||
| 357 | "ebu wait", "ebu clk", | ||
| 358 | "nand ale", "nand cs1", | ||
| 359 | "nand cle"}; | ||
| 360 | static const char * const xway_exin_grps[] = {"exin0", "exin1", "exin2"}; | ||
| 361 | static const char * const xway_gpt_grps[] = {"gpt1", "gpt2", "gpt3"}; | ||
| 362 | static const char * const xway_asc_grps[] = {"asc0", "asc0 cts rts"}; | ||
| 363 | static const char * const xway_jtag_grps[] = {"jtag"}; | ||
| 364 | static const char * const xway_stp_grps[] = {"stp"}; | ||
| 365 | static const char * const xway_nmi_grps[] = {"nmi"}; | ||
| 366 | |||
| 367 | /* ar9/vr9/gr9 */ | ||
| 368 | static const char * const xrx_mdio_grps[] = {"mdio"}; | ||
| 369 | static const char * const xrx_ebu_grps[] = {"ebu a23", "ebu a24", | ||
| 370 | "ebu a25", "ebu cs1", | ||
| 371 | "ebu wait", "ebu clk", | ||
| 372 | "nand ale", "nand cs1", | ||
| 373 | "nand cle", "nand rdy", | ||
| 374 | "nand rd"}; | ||
| 375 | static const char * const xrx_exin_grps[] = {"exin0", "exin1", "exin2", | ||
| 376 | "exin3", "exin4", "exin5"}; | ||
| 377 | static const char * const xrx_pci_grps[] = {"gnt1", "gnt2", | ||
| 378 | "gnt3", "gnt4", | ||
| 379 | "req1", "req2", | ||
| 380 | "req3", "req4"}; | ||
| 381 | |||
| 382 | /* ase */ | ||
| 383 | static const char * const ase_exin_grps[] = {"exin0", "exin1", "exin2"}; | ||
| 384 | static const char * const ase_gpt_grps[] = {"gpt1", "gpt2", "gpt3"}; | ||
| 385 | static const char * const ase_dfe_grps[] = {"dfe"}; | ||
| 386 | static const char * const ase_ephy_grps[] = {"ephy"}; | ||
| 387 | static const char * const ase_asc_grps[] = {"asc"}; | ||
| 388 | static const char * const ase_jtag_grps[] = {"jtag"}; | ||
| 389 | static const char * const ase_stp_grps[] = {"stp"}; | ||
| 390 | static const char * const ase_spi_grps[] = {"spi", "spi_cs1", | ||
| 391 | "spi_cs2", "spi_cs3"}; | ||
| 392 | |||
| 393 | static const struct ltq_pmx_func danube_funcs[] = { | ||
| 394 | {"spi", ARRAY_AND_SIZE(xway_spi_grps)}, | ||
| 395 | {"asc", ARRAY_AND_SIZE(xway_asc_grps)}, | ||
| 396 | {"cgu", ARRAY_AND_SIZE(xway_cgu_grps)}, | ||
| 397 | {"jtag", ARRAY_AND_SIZE(xway_jtag_grps)}, | ||
| 398 | {"exin", ARRAY_AND_SIZE(xway_exin_grps)}, | ||
| 399 | {"stp", ARRAY_AND_SIZE(xway_stp_grps)}, | ||
| 400 | {"gpt", ARRAY_AND_SIZE(xway_gpt_grps)}, | ||
| 401 | {"nmi", ARRAY_AND_SIZE(xway_nmi_grps)}, | ||
| 402 | {"pci", ARRAY_AND_SIZE(xway_pci_grps)}, | ||
| 403 | {"ebu", ARRAY_AND_SIZE(xway_ebu_grps)}, | ||
| 404 | }; | ||
| 405 | |||
| 406 | static const struct ltq_pmx_func xrx_funcs[] = { | ||
| 407 | {"spi", ARRAY_AND_SIZE(xway_spi_grps)}, | ||
| 408 | {"asc", ARRAY_AND_SIZE(xway_asc_grps)}, | ||
| 409 | {"cgu", ARRAY_AND_SIZE(xway_cgu_grps)}, | ||
| 410 | {"jtag", ARRAY_AND_SIZE(xway_jtag_grps)}, | ||
| 411 | {"exin", ARRAY_AND_SIZE(xrx_exin_grps)}, | ||
| 412 | {"stp", ARRAY_AND_SIZE(xway_stp_grps)}, | ||
| 413 | {"gpt", ARRAY_AND_SIZE(xway_gpt_grps)}, | ||
| 414 | {"nmi", ARRAY_AND_SIZE(xway_nmi_grps)}, | ||
| 415 | {"pci", ARRAY_AND_SIZE(xrx_pci_grps)}, | ||
| 416 | {"ebu", ARRAY_AND_SIZE(xrx_ebu_grps)}, | ||
| 417 | {"mdio", ARRAY_AND_SIZE(xrx_mdio_grps)}, | ||
| 418 | }; | ||
| 419 | |||
| 420 | static const struct ltq_pmx_func ase_funcs[] = { | ||
| 421 | {"spi", ARRAY_AND_SIZE(ase_spi_grps)}, | ||
| 422 | {"asc", ARRAY_AND_SIZE(ase_asc_grps)}, | ||
| 423 | {"jtag", ARRAY_AND_SIZE(ase_jtag_grps)}, | ||
| 424 | {"exin", ARRAY_AND_SIZE(ase_exin_grps)}, | ||
| 425 | {"stp", ARRAY_AND_SIZE(ase_stp_grps)}, | ||
| 426 | {"gpt", ARRAY_AND_SIZE(ase_gpt_grps)}, | ||
| 427 | {"ephy", ARRAY_AND_SIZE(ase_ephy_grps)}, | ||
| 428 | {"dfe", ARRAY_AND_SIZE(ase_dfe_grps)}, | ||
| 429 | }; | ||
| 430 | |||
| 431 | /* --------- pinconf related code --------- */ | ||
| 432 | static int xway_pinconf_get(struct pinctrl_dev *pctldev, | ||
| 433 | unsigned pin, | ||
| 434 | unsigned long *config) | ||
| 435 | { | ||
| 436 | struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev); | ||
| 437 | enum ltq_pinconf_param param = LTQ_PINCONF_UNPACK_PARAM(*config); | ||
| 438 | int port = PORT(pin); | ||
| 439 | u32 reg; | ||
| 440 | |||
| 441 | switch (param) { | ||
| 442 | case LTQ_PINCONF_PARAM_OPEN_DRAIN: | ||
| 443 | if (port == PORT3) | ||
| 444 | reg = GPIO3_OD; | ||
| 445 | else | ||
| 446 | reg = GPIO_OD(port); | ||
| 447 | *config = LTQ_PINCONF_PACK(param, | ||
| 448 | !!gpio_getbit(info->membase[0], reg, PORT_PIN(port))); | ||
| 449 | break; | ||
| 450 | |||
| 451 | case LTQ_PINCONF_PARAM_PULL: | ||
| 452 | if (port == PORT3) | ||
| 453 | reg = GPIO3_PUDEN; | ||
| 454 | else | ||
| 455 | reg = GPIO_PUDEN(port); | ||
| 456 | if (!gpio_getbit(info->membase[0], reg, PORT_PIN(port))) { | ||
| 457 | *config = LTQ_PINCONF_PACK(param, 0); | ||
| 458 | break; | ||
| 459 | } | ||
| 460 | |||
| 461 | if (port == PORT3) | ||
| 462 | reg = GPIO3_PUDSEL; | ||
| 463 | else | ||
| 464 | reg = GPIO_PUDSEL(port); | ||
| 465 | if (!gpio_getbit(info->membase[0], reg, PORT_PIN(port))) | ||
| 466 | *config = LTQ_PINCONF_PACK(param, 2); | ||
| 467 | else | ||
| 468 | *config = LTQ_PINCONF_PACK(param, 1); | ||
| 469 | break; | ||
| 470 | |||
| 471 | default: | ||
| 472 | dev_err(pctldev->dev, "Invalid config param %04x\n", param); | ||
| 473 | return -ENOTSUPP; | ||
| 474 | } | ||
| 475 | return 0; | ||
| 476 | } | ||
| 477 | |||
| 478 | static int xway_pinconf_set(struct pinctrl_dev *pctldev, | ||
| 479 | unsigned pin, | ||
| 480 | unsigned long config) | ||
| 481 | { | ||
| 482 | struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev); | ||
| 483 | enum ltq_pinconf_param param = LTQ_PINCONF_UNPACK_PARAM(config); | ||
| 484 | int arg = LTQ_PINCONF_UNPACK_ARG(config); | ||
| 485 | int port = PORT(pin); | ||
| 486 | u32 reg; | ||
| 487 | |||
| 488 | switch (param) { | ||
| 489 | case LTQ_PINCONF_PARAM_OPEN_DRAIN: | ||
| 490 | if (port == PORT3) | ||
| 491 | reg = GPIO3_OD; | ||
| 492 | else | ||
| 493 | reg = GPIO_OD(port); | ||
| 494 | gpio_setbit(info->membase[0], reg, PORT_PIN(port)); | ||
| 495 | break; | ||
| 496 | |||
| 497 | case LTQ_PINCONF_PARAM_PULL: | ||
| 498 | if (port == PORT3) | ||
| 499 | reg = GPIO3_PUDEN; | ||
| 500 | else | ||
| 501 | reg = GPIO_PUDEN(port); | ||
| 502 | if (arg == 0) { | ||
| 503 | gpio_clearbit(info->membase[0], reg, PORT_PIN(port)); | ||
| 504 | break; | ||
| 505 | } | ||
| 506 | gpio_setbit(info->membase[0], reg, PORT_PIN(port)); | ||
| 507 | |||
| 508 | if (port == PORT3) | ||
| 509 | reg = GPIO3_PUDSEL; | ||
| 510 | else | ||
| 511 | reg = GPIO_PUDSEL(port); | ||
| 512 | if (arg == 1) | ||
| 513 | gpio_clearbit(info->membase[0], reg, PORT_PIN(port)); | ||
| 514 | else if (arg == 2) | ||
| 515 | gpio_setbit(info->membase[0], reg, PORT_PIN(port)); | ||
| 516 | else | ||
| 517 | dev_err(pctldev->dev, "Invalid pull value %d\n", arg); | ||
| 518 | break; | ||
| 519 | |||
| 520 | default: | ||
| 521 | dev_err(pctldev->dev, "Invalid config param %04x\n", param); | ||
| 522 | return -ENOTSUPP; | ||
| 523 | } | ||
| 524 | return 0; | ||
| 525 | } | ||
| 526 | |||
| 527 | struct pinconf_ops xway_pinconf_ops = { | ||
| 528 | .pin_config_get = xway_pinconf_get, | ||
| 529 | .pin_config_set = xway_pinconf_set, | ||
| 530 | }; | ||
| 531 | |||
| 532 | static struct pinctrl_desc xway_pctrl_desc = { | ||
| 533 | .owner = THIS_MODULE, | ||
| 534 | .confops = &xway_pinconf_ops, | ||
| 535 | }; | ||
| 536 | |||
| 537 | static inline int xway_mux_apply(struct pinctrl_dev *pctrldev, | ||
| 538 | int pin, int mux) | ||
| 539 | { | ||
| 540 | struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); | ||
| 541 | int port = PORT(pin); | ||
| 542 | u32 alt1_reg = GPIO_ALT1(pin); | ||
| 543 | |||
| 544 | if (port == PORT3) | ||
| 545 | alt1_reg = GPIO3_ALT1; | ||
| 546 | |||
| 547 | if (mux & MUX_ALT0) | ||
| 548 | gpio_setbit(info->membase[0], GPIO_ALT0(pin), PORT_PIN(pin)); | ||
| 549 | else | ||
| 550 | gpio_clearbit(info->membase[0], GPIO_ALT0(pin), PORT_PIN(pin)); | ||
| 551 | |||
| 552 | if (mux & MUX_ALT1) | ||
| 553 | gpio_setbit(info->membase[0], alt1_reg, PORT_PIN(pin)); | ||
| 554 | else | ||
| 555 | gpio_clearbit(info->membase[0], alt1_reg, PORT_PIN(pin)); | ||
| 556 | |||
| 557 | return 0; | ||
| 558 | } | ||
| 559 | |||
| 560 | static const struct ltq_cfg_param xway_cfg_params[] = { | ||
| 561 | {"lantiq,pull", LTQ_PINCONF_PARAM_PULL}, | ||
| 562 | {"lantiq,open-drain", LTQ_PINCONF_PARAM_OPEN_DRAIN}, | ||
| 563 | }; | ||
| 564 | |||
| 565 | static struct ltq_pinmux_info xway_info = { | ||
| 566 | .desc = &xway_pctrl_desc, | ||
| 567 | .apply_mux = xway_mux_apply, | ||
| 568 | .params = xway_cfg_params, | ||
| 569 | .num_params = ARRAY_SIZE(xway_cfg_params), | ||
| 570 | }; | ||
| 571 | |||
| 572 | /* --------- gpio_chip related code --------- */ | ||
| 573 | static void xway_gpio_set(struct gpio_chip *chip, unsigned int pin, int val) | ||
| 574 | { | ||
| 575 | struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev); | ||
| 576 | |||
| 577 | if (val) | ||
| 578 | gpio_setbit(info->membase[0], GPIO_OUT(pin), PORT_PIN(pin)); | ||
| 579 | else | ||
| 580 | gpio_clearbit(info->membase[0], GPIO_OUT(pin), PORT_PIN(pin)); | ||
| 581 | } | ||
| 582 | |||
| 583 | static int xway_gpio_get(struct gpio_chip *chip, unsigned int pin) | ||
| 584 | { | ||
| 585 | struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev); | ||
| 586 | |||
| 587 | return gpio_getbit(info->membase[0], GPIO_IN(pin), PORT_PIN(pin)); | ||
| 588 | } | ||
| 589 | |||
| 590 | static int xway_gpio_dir_in(struct gpio_chip *chip, unsigned int pin) | ||
| 591 | { | ||
| 592 | struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev); | ||
| 593 | |||
| 594 | gpio_clearbit(info->membase[0], GPIO_DIR(pin), PORT_PIN(pin)); | ||
| 595 | |||
| 596 | return 0; | ||
| 597 | } | ||
| 598 | |||
| 599 | static int xway_gpio_dir_out(struct gpio_chip *chip, unsigned int pin, int val) | ||
| 600 | { | ||
| 601 | struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev); | ||
| 602 | |||
| 603 | gpio_setbit(info->membase[0], GPIO_DIR(pin), PORT_PIN(pin)); | ||
| 604 | xway_gpio_set(chip, pin, val); | ||
| 605 | |||
| 606 | return 0; | ||
| 607 | } | ||
| 608 | |||
| 609 | static int xway_gpio_req(struct gpio_chip *chip, unsigned offset) | ||
| 610 | { | ||
| 611 | int gpio = chip->base + offset; | ||
| 612 | |||
| 613 | return pinctrl_request_gpio(gpio); | ||
| 614 | } | ||
| 615 | |||
| 616 | static void xway_gpio_free(struct gpio_chip *chip, unsigned offset) | ||
| 617 | { | ||
| 618 | int gpio = chip->base + offset; | ||
| 619 | |||
| 620 | pinctrl_free_gpio(gpio); | ||
| 621 | } | ||
| 622 | |||
| 623 | static struct gpio_chip xway_chip = { | ||
| 624 | .label = "gpio-xway", | ||
| 625 | .direction_input = xway_gpio_dir_in, | ||
| 626 | .direction_output = xway_gpio_dir_out, | ||
| 627 | .get = xway_gpio_get, | ||
| 628 | .set = xway_gpio_set, | ||
| 629 | .request = xway_gpio_req, | ||
| 630 | .free = xway_gpio_free, | ||
| 631 | .base = -1, | ||
| 632 | }; | ||
| 633 | |||
| 634 | |||
| 635 | /* --------- register the pinctrl layer --------- */ | ||
| 636 | static const unsigned xway_exin_pin_map[] = {GPIO0, GPIO1, GPIO2, GPIO39, GPIO46, GPIO9}; | ||
| 637 | static const unsigned ase_exin_pins_map[] = {GPIO6, GPIO29, GPIO0}; | ||
| 638 | |||
| 639 | static struct pinctrl_xway_soc { | ||
| 640 | int pin_count; | ||
| 641 | const struct ltq_mfp_pin *mfp; | ||
| 642 | const struct ltq_pin_group *grps; | ||
| 643 | unsigned int num_grps; | ||
| 644 | const struct ltq_pmx_func *funcs; | ||
| 645 | unsigned int num_funcs; | ||
| 646 | const unsigned *exin; | ||
| 647 | unsigned int num_exin; | ||
| 648 | } soc_cfg[] = { | ||
| 649 | /* legacy xway */ | ||
| 650 | {XWAY_MAX_PIN, xway_mfp, | ||
| 651 | xway_grps, ARRAY_SIZE(xway_grps), | ||
| 652 | danube_funcs, ARRAY_SIZE(danube_funcs), | ||
| 653 | xway_exin_pin_map, 3}, | ||
| 654 | /* xway xr9 series */ | ||
| 655 | {XR9_MAX_PIN, xway_mfp, | ||
| 656 | xway_grps, ARRAY_SIZE(xway_grps), | ||
| 657 | xrx_funcs, ARRAY_SIZE(xrx_funcs), | ||
| 658 | xway_exin_pin_map, 6}, | ||
| 659 | /* xway ase series */ | ||
| 660 | {XWAY_MAX_PIN, ase_mfp, | ||
| 661 | ase_grps, ARRAY_SIZE(ase_grps), | ||
| 662 | ase_funcs, ARRAY_SIZE(ase_funcs), | ||
| 663 | ase_exin_pins_map, 3}, | ||
| 664 | }; | ||
| 665 | |||
| 666 | static struct pinctrl_gpio_range xway_gpio_range = { | ||
| 667 | .name = "XWAY GPIO", | ||
| 668 | .gc = &xway_chip, | ||
| 669 | }; | ||
| 670 | |||
| 671 | static const struct of_device_id xway_match[] = { | ||
| 672 | { .compatible = "lantiq,pinctrl-xway", .data = &soc_cfg[0]}, | ||
| 673 | { .compatible = "lantiq,pinctrl-xr9", .data = &soc_cfg[1]}, | ||
| 674 | { .compatible = "lantiq,pinctrl-ase", .data = &soc_cfg[2]}, | ||
| 675 | {}, | ||
| 676 | }; | ||
| 677 | MODULE_DEVICE_TABLE(of, xway_match); | ||
| 678 | |||
| 679 | static int __devinit pinmux_xway_probe(struct platform_device *pdev) | ||
| 680 | { | ||
| 681 | const struct of_device_id *match; | ||
| 682 | const struct pinctrl_xway_soc *xway_soc; | ||
| 683 | struct resource *res; | ||
| 684 | int ret, i; | ||
| 685 | |||
| 686 | /* get and remap our register range */ | ||
| 687 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 688 | if (!res) { | ||
| 689 | dev_err(&pdev->dev, "Failed to get resource\n"); | ||
| 690 | return -ENOENT; | ||
| 691 | } | ||
| 692 | xway_info.membase[0] = devm_request_and_ioremap(&pdev->dev, res); | ||
| 693 | if (!xway_info.membase[0]) { | ||
| 694 | dev_err(&pdev->dev, "Failed to remap resource\n"); | ||
| 695 | return -ENOMEM; | ||
| 696 | } | ||
| 697 | |||
| 698 | match = of_match_device(xway_match, &pdev->dev); | ||
| 699 | if (match) | ||
| 700 | xway_soc = (const struct pinctrl_xway_soc *) match->data; | ||
| 701 | else | ||
| 702 | xway_soc = &soc_cfg[0]; | ||
| 703 | |||
| 704 | /* find out how many pads we have */ | ||
| 705 | xway_chip.ngpio = xway_soc->pin_count; | ||
| 706 | |||
| 707 | /* load our pad descriptors */ | ||
| 708 | xway_info.pads = devm_kzalloc(&pdev->dev, | ||
| 709 | sizeof(struct pinctrl_pin_desc) * xway_chip.ngpio, | ||
| 710 | GFP_KERNEL); | ||
| 711 | if (!xway_info.pads) { | ||
| 712 | dev_err(&pdev->dev, "Failed to allocate pads\n"); | ||
| 713 | return -ENOMEM; | ||
| 714 | } | ||
| 715 | for (i = 0; i < xway_chip.ngpio; i++) { | ||
| 716 | /* strlen("ioXY") + 1 = 5 */ | ||
| 717 | char *name = devm_kzalloc(&pdev->dev, 5, GFP_KERNEL); | ||
| 718 | |||
| 719 | if (!name) { | ||
| 720 | dev_err(&pdev->dev, "Failed to allocate pad name\n"); | ||
| 721 | return -ENOMEM; | ||
| 722 | } | ||
| 723 | snprintf(name, 5, "io%d", i); | ||
| 724 | xway_info.pads[i].number = GPIO0 + i; | ||
| 725 | xway_info.pads[i].name = name; | ||
| 726 | } | ||
| 727 | xway_pctrl_desc.pins = xway_info.pads; | ||
| 728 | |||
| 729 | /* load the gpio chip */ | ||
| 730 | xway_chip.dev = &pdev->dev; | ||
| 731 | of_gpiochip_add(&xway_chip); | ||
| 732 | ret = gpiochip_add(&xway_chip); | ||
| 733 | if (ret) { | ||
| 734 | dev_err(&pdev->dev, "Failed to register gpio chip\n"); | ||
| 735 | return ret; | ||
| 736 | } | ||
| 737 | |||
| 738 | /* setup the data needed by pinctrl */ | ||
| 739 | xway_pctrl_desc.name = dev_name(&pdev->dev); | ||
| 740 | xway_pctrl_desc.npins = xway_chip.ngpio; | ||
| 741 | |||
| 742 | xway_info.num_pads = xway_chip.ngpio; | ||
| 743 | xway_info.num_mfp = xway_chip.ngpio; | ||
| 744 | xway_info.mfp = xway_soc->mfp; | ||
| 745 | xway_info.grps = xway_soc->grps; | ||
| 746 | xway_info.num_grps = xway_soc->num_grps; | ||
| 747 | xway_info.funcs = xway_soc->funcs; | ||
| 748 | xway_info.num_funcs = xway_soc->num_funcs; | ||
| 749 | xway_info.exin = xway_soc->exin; | ||
| 750 | xway_info.num_exin = xway_soc->num_exin; | ||
| 751 | |||
| 752 | /* register with the generic lantiq layer */ | ||
| 753 | ret = ltq_pinctrl_register(pdev, &xway_info); | ||
| 754 | if (ret) { | ||
| 755 | dev_err(&pdev->dev, "Failed to register pinctrl driver\n"); | ||
| 756 | return ret; | ||
| 757 | } | ||
| 758 | |||
| 759 | /* finish with registering the gpio range in pinctrl */ | ||
| 760 | xway_gpio_range.npins = xway_chip.ngpio; | ||
| 761 | xway_gpio_range.base = xway_chip.base; | ||
| 762 | pinctrl_add_gpio_range(xway_info.pctrl, &xway_gpio_range); | ||
| 763 | dev_info(&pdev->dev, "Init done\n"); | ||
| 764 | return 0; | ||
| 765 | } | ||
| 766 | |||
| 767 | static struct platform_driver pinmux_xway_driver = { | ||
| 768 | .probe = pinmux_xway_probe, | ||
| 769 | .driver = { | ||
| 770 | .name = "pinctrl-xway", | ||
| 771 | .owner = THIS_MODULE, | ||
| 772 | .of_match_table = xway_match, | ||
| 773 | }, | ||
| 774 | }; | ||
| 775 | |||
| 776 | static int __init pinmux_xway_init(void) | ||
| 777 | { | ||
| 778 | return platform_driver_register(&pinmux_xway_driver); | ||
| 779 | } | ||
| 780 | |||
| 781 | core_initcall_sync(pinmux_xway_init); | ||
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig index ecc31a1f73fc..8c2ff2490d99 100644 --- a/drivers/spi/Kconfig +++ b/drivers/spi/Kconfig | |||
| @@ -237,6 +237,13 @@ config SPI_OC_TINY | |||
| 237 | help | 237 | help |
| 238 | This is the driver for OpenCores tiny SPI master controller. | 238 | This is the driver for OpenCores tiny SPI master controller. |
| 239 | 239 | ||
| 240 | config SPI_OCTEON | ||
| 241 | tristate "Cavium OCTEON SPI controller" | ||
| 242 | depends on CPU_CAVIUM_OCTEON | ||
| 243 | help | ||
| 244 | SPI host driver for the hardware found on some Cavium OCTEON | ||
| 245 | SOCs. | ||
| 246 | |||
| 240 | config SPI_OMAP_UWIRE | 247 | config SPI_OMAP_UWIRE |
| 241 | tristate "OMAP1 MicroWire" | 248 | tristate "OMAP1 MicroWire" |
| 242 | depends on ARCH_OMAP1 | 249 | depends on ARCH_OMAP1 |
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile index 22fd3a7251bc..c48df47e4b0f 100644 --- a/drivers/spi/Makefile +++ b/drivers/spi/Makefile | |||
| @@ -39,6 +39,7 @@ obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o | |||
| 39 | obj-$(CONFIG_SPI_MXS) += spi-mxs.o | 39 | obj-$(CONFIG_SPI_MXS) += spi-mxs.o |
| 40 | obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o | 40 | obj-$(CONFIG_SPI_NUC900) += spi-nuc900.o |
| 41 | obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o | 41 | obj-$(CONFIG_SPI_OC_TINY) += spi-oc-tiny.o |
| 42 | obj-$(CONFIG_SPI_OCTEON) += spi-octeon.o | ||
| 42 | obj-$(CONFIG_SPI_OMAP_UWIRE) += spi-omap-uwire.o | 43 | obj-$(CONFIG_SPI_OMAP_UWIRE) += spi-omap-uwire.o |
| 43 | obj-$(CONFIG_SPI_OMAP_100K) += spi-omap-100k.o | 44 | obj-$(CONFIG_SPI_OMAP_100K) += spi-omap-100k.o |
| 44 | obj-$(CONFIG_SPI_OMAP24XX) += spi-omap2-mcspi.o | 45 | obj-$(CONFIG_SPI_OMAP24XX) += spi-omap2-mcspi.o |
diff --git a/drivers/spi/spi-octeon.c b/drivers/spi/spi-octeon.c new file mode 100644 index 000000000000..ea8fb2efb0f8 --- /dev/null +++ b/drivers/spi/spi-octeon.c | |||
| @@ -0,0 +1,362 @@ | |||
| 1 | /* | ||
| 2 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 3 | * License. See the file "COPYING" in the main directory of this archive | ||
| 4 | * for more details. | ||
| 5 | * | ||
| 6 | * Copyright (C) 2011, 2012 Cavium, Inc. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/platform_device.h> | ||
| 10 | #include <linux/interrupt.h> | ||
| 11 | #include <linux/spi/spi.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/delay.h> | ||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/io.h> | ||
| 16 | #include <linux/of.h> | ||
| 17 | |||
| 18 | #include <asm/octeon/octeon.h> | ||
| 19 | #include <asm/octeon/cvmx-mpi-defs.h> | ||
| 20 | |||
| 21 | #define OCTEON_SPI_CFG 0 | ||
| 22 | #define OCTEON_SPI_STS 0x08 | ||
| 23 | #define OCTEON_SPI_TX 0x10 | ||
| 24 | #define OCTEON_SPI_DAT0 0x80 | ||
| 25 | |||
| 26 | #define OCTEON_SPI_MAX_BYTES 9 | ||
| 27 | |||
| 28 | #define OCTEON_SPI_MAX_CLOCK_HZ 16000000 | ||
| 29 | |||
| 30 | struct octeon_spi { | ||
| 31 | struct spi_master *my_master; | ||
| 32 | u64 register_base; | ||
| 33 | u64 last_cfg; | ||
| 34 | u64 cs_enax; | ||
| 35 | }; | ||
| 36 | |||
| 37 | struct octeon_spi_setup { | ||
| 38 | u32 max_speed_hz; | ||
| 39 | u8 chip_select; | ||
| 40 | u8 mode; | ||
| 41 | u8 bits_per_word; | ||
| 42 | }; | ||
| 43 | |||
| 44 | static void octeon_spi_wait_ready(struct octeon_spi *p) | ||
| 45 | { | ||
| 46 | union cvmx_mpi_sts mpi_sts; | ||
| 47 | unsigned int loops = 0; | ||
| 48 | |||
| 49 | do { | ||
| 50 | if (loops++) | ||
| 51 | __delay(500); | ||
| 52 | mpi_sts.u64 = cvmx_read_csr(p->register_base + OCTEON_SPI_STS); | ||
| 53 | } while (mpi_sts.s.busy); | ||
| 54 | } | ||
| 55 | |||
| 56 | static int octeon_spi_do_transfer(struct octeon_spi *p, | ||
| 57 | struct spi_message *msg, | ||
| 58 | struct spi_transfer *xfer, | ||
| 59 | bool last_xfer) | ||
| 60 | { | ||
| 61 | union cvmx_mpi_cfg mpi_cfg; | ||
| 62 | union cvmx_mpi_tx mpi_tx; | ||
| 63 | unsigned int clkdiv; | ||
| 64 | unsigned int speed_hz; | ||
| 65 | int mode; | ||
| 66 | bool cpha, cpol; | ||
| 67 | int bits_per_word; | ||
| 68 | const u8 *tx_buf; | ||
| 69 | u8 *rx_buf; | ||
| 70 | int len; | ||
| 71 | int i; | ||
| 72 | |||
| 73 | struct octeon_spi_setup *msg_setup = spi_get_ctldata(msg->spi); | ||
| 74 | |||
| 75 | speed_hz = msg_setup->max_speed_hz; | ||
| 76 | mode = msg_setup->mode; | ||
| 77 | cpha = mode & SPI_CPHA; | ||
| 78 | cpol = mode & SPI_CPOL; | ||
| 79 | bits_per_word = msg_setup->bits_per_word; | ||
| 80 | |||
| 81 | if (xfer->speed_hz) | ||
| 82 | speed_hz = xfer->speed_hz; | ||
| 83 | if (xfer->bits_per_word) | ||
| 84 | bits_per_word = xfer->bits_per_word; | ||
| 85 | |||
| 86 | if (speed_hz > OCTEON_SPI_MAX_CLOCK_HZ) | ||
| 87 | speed_hz = OCTEON_SPI_MAX_CLOCK_HZ; | ||
| 88 | |||
| 89 | clkdiv = octeon_get_io_clock_rate() / (2 * speed_hz); | ||
| 90 | |||
| 91 | mpi_cfg.u64 = 0; | ||
| 92 | |||
| 93 | mpi_cfg.s.clkdiv = clkdiv; | ||
| 94 | mpi_cfg.s.cshi = (mode & SPI_CS_HIGH) ? 1 : 0; | ||
| 95 | mpi_cfg.s.lsbfirst = (mode & SPI_LSB_FIRST) ? 1 : 0; | ||
| 96 | mpi_cfg.s.wireor = (mode & SPI_3WIRE) ? 1 : 0; | ||
| 97 | mpi_cfg.s.idlelo = cpha != cpol; | ||
| 98 | mpi_cfg.s.cslate = cpha ? 1 : 0; | ||
| 99 | mpi_cfg.s.enable = 1; | ||
| 100 | |||
| 101 | if (msg_setup->chip_select < 4) | ||
| 102 | p->cs_enax |= 1ull << (12 + msg_setup->chip_select); | ||
| 103 | mpi_cfg.u64 |= p->cs_enax; | ||
| 104 | |||
| 105 | if (mpi_cfg.u64 != p->last_cfg) { | ||
| 106 | p->last_cfg = mpi_cfg.u64; | ||
| 107 | cvmx_write_csr(p->register_base + OCTEON_SPI_CFG, mpi_cfg.u64); | ||
| 108 | } | ||
| 109 | tx_buf = xfer->tx_buf; | ||
| 110 | rx_buf = xfer->rx_buf; | ||
| 111 | len = xfer->len; | ||
| 112 | while (len > OCTEON_SPI_MAX_BYTES) { | ||
| 113 | for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) { | ||
| 114 | u8 d; | ||
| 115 | if (tx_buf) | ||
| 116 | d = *tx_buf++; | ||
| 117 | else | ||
| 118 | d = 0; | ||
| 119 | cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d); | ||
| 120 | } | ||
| 121 | mpi_tx.u64 = 0; | ||
| 122 | mpi_tx.s.csid = msg_setup->chip_select; | ||
| 123 | mpi_tx.s.leavecs = 1; | ||
| 124 | mpi_tx.s.txnum = tx_buf ? OCTEON_SPI_MAX_BYTES : 0; | ||
| 125 | mpi_tx.s.totnum = OCTEON_SPI_MAX_BYTES; | ||
| 126 | cvmx_write_csr(p->register_base + OCTEON_SPI_TX, mpi_tx.u64); | ||
| 127 | |||
| 128 | octeon_spi_wait_ready(p); | ||
| 129 | if (rx_buf) | ||
| 130 | for (i = 0; i < OCTEON_SPI_MAX_BYTES; i++) { | ||
| 131 | u64 v = cvmx_read_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i)); | ||
| 132 | *rx_buf++ = (u8)v; | ||
| 133 | } | ||
| 134 | len -= OCTEON_SPI_MAX_BYTES; | ||
| 135 | } | ||
| 136 | |||
| 137 | for (i = 0; i < len; i++) { | ||
| 138 | u8 d; | ||
| 139 | if (tx_buf) | ||
| 140 | d = *tx_buf++; | ||
| 141 | else | ||
| 142 | d = 0; | ||
| 143 | cvmx_write_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i), d); | ||
| 144 | } | ||
| 145 | |||
| 146 | mpi_tx.u64 = 0; | ||
| 147 | mpi_tx.s.csid = msg_setup->chip_select; | ||
| 148 | if (last_xfer) | ||
| 149 | mpi_tx.s.leavecs = xfer->cs_change; | ||
| 150 | else | ||
| 151 | mpi_tx.s.leavecs = !xfer->cs_change; | ||
| 152 | mpi_tx.s.txnum = tx_buf ? len : 0; | ||
| 153 | mpi_tx.s.totnum = len; | ||
| 154 | cvmx_write_csr(p->register_base + OCTEON_SPI_TX, mpi_tx.u64); | ||
| 155 | |||
| 156 | octeon_spi_wait_ready(p); | ||
| 157 | if (rx_buf) | ||
| 158 | for (i = 0; i < len; i++) { | ||
| 159 | u64 v = cvmx_read_csr(p->register_base + OCTEON_SPI_DAT0 + (8 * i)); | ||
| 160 | *rx_buf++ = (u8)v; | ||
| 161 | } | ||
| 162 | |||
| 163 | if (xfer->delay_usecs) | ||
| 164 | udelay(xfer->delay_usecs); | ||
| 165 | |||
| 166 | return xfer->len; | ||
| 167 | } | ||
| 168 | |||
| 169 | static int octeon_spi_validate_bpw(struct spi_device *spi, u32 speed) | ||
| 170 | { | ||
| 171 | switch (speed) { | ||
| 172 | case 8: | ||
| 173 | break; | ||
| 174 | default: | ||
| 175 | dev_err(&spi->dev, "Error: %d bits per word not supported\n", | ||
| 176 | speed); | ||
| 177 | return -EINVAL; | ||
| 178 | } | ||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | static int octeon_spi_transfer_one_message(struct spi_master *master, | ||
| 183 | struct spi_message *msg) | ||
| 184 | { | ||
| 185 | struct octeon_spi *p = spi_master_get_devdata(master); | ||
| 186 | unsigned int total_len = 0; | ||
| 187 | int status = 0; | ||
| 188 | struct spi_transfer *xfer; | ||
| 189 | |||
| 190 | /* | ||
| 191 | * We better have set the configuration via a call to .setup | ||
| 192 | * before we get here. | ||
| 193 | */ | ||
| 194 | if (spi_get_ctldata(msg->spi) == NULL) { | ||
| 195 | status = -EINVAL; | ||
| 196 | goto err; | ||
| 197 | } | ||
| 198 | |||
| 199 | list_for_each_entry(xfer, &msg->transfers, transfer_list) { | ||
| 200 | if (xfer->bits_per_word) { | ||
| 201 | status = octeon_spi_validate_bpw(msg->spi, | ||
| 202 | xfer->bits_per_word); | ||
| 203 | if (status) | ||
| 204 | goto err; | ||
| 205 | } | ||
| 206 | } | ||
| 207 | |||
| 208 | list_for_each_entry(xfer, &msg->transfers, transfer_list) { | ||
| 209 | bool last_xfer = &xfer->transfer_list == msg->transfers.prev; | ||
| 210 | int r = octeon_spi_do_transfer(p, msg, xfer, last_xfer); | ||
| 211 | if (r < 0) { | ||
| 212 | status = r; | ||
| 213 | goto err; | ||
| 214 | } | ||
| 215 | total_len += r; | ||
| 216 | } | ||
| 217 | err: | ||
| 218 | msg->status = status; | ||
| 219 | msg->actual_length = total_len; | ||
| 220 | spi_finalize_current_message(master); | ||
| 221 | return status; | ||
| 222 | } | ||
| 223 | |||
| 224 | static struct octeon_spi_setup *octeon_spi_new_setup(struct spi_device *spi) | ||
| 225 | { | ||
| 226 | struct octeon_spi_setup *setup = kzalloc(sizeof(*setup), GFP_KERNEL); | ||
| 227 | if (!setup) | ||
| 228 | return NULL; | ||
| 229 | |||
| 230 | setup->max_speed_hz = spi->max_speed_hz; | ||
| 231 | setup->chip_select = spi->chip_select; | ||
| 232 | setup->mode = spi->mode; | ||
| 233 | setup->bits_per_word = spi->bits_per_word; | ||
| 234 | return setup; | ||
| 235 | } | ||
| 236 | |||
| 237 | static int octeon_spi_setup(struct spi_device *spi) | ||
| 238 | { | ||
| 239 | int r; | ||
| 240 | struct octeon_spi_setup *new_setup; | ||
| 241 | struct octeon_spi_setup *old_setup = spi_get_ctldata(spi); | ||
| 242 | |||
| 243 | r = octeon_spi_validate_bpw(spi, spi->bits_per_word); | ||
| 244 | if (r) | ||
| 245 | return r; | ||
| 246 | |||
| 247 | new_setup = octeon_spi_new_setup(spi); | ||
| 248 | if (!new_setup) | ||
| 249 | return -ENOMEM; | ||
| 250 | |||
| 251 | spi_set_ctldata(spi, new_setup); | ||
| 252 | kfree(old_setup); | ||
| 253 | |||
| 254 | return 0; | ||
| 255 | } | ||
| 256 | |||
| 257 | static void octeon_spi_cleanup(struct spi_device *spi) | ||
| 258 | { | ||
| 259 | struct octeon_spi_setup *old_setup = spi_get_ctldata(spi); | ||
| 260 | spi_set_ctldata(spi, NULL); | ||
| 261 | kfree(old_setup); | ||
| 262 | } | ||
| 263 | |||
| 264 | static int octeon_spi_nop_transfer_hardware(struct spi_master *master) | ||
| 265 | { | ||
| 266 | return 0; | ||
| 267 | } | ||
| 268 | |||
| 269 | static int __devinit octeon_spi_probe(struct platform_device *pdev) | ||
| 270 | { | ||
| 271 | |||
| 272 | struct resource *res_mem; | ||
| 273 | struct spi_master *master; | ||
| 274 | struct octeon_spi *p; | ||
| 275 | int err = -ENOENT; | ||
| 276 | |||
| 277 | master = spi_alloc_master(&pdev->dev, sizeof(struct octeon_spi)); | ||
| 278 | if (!master) | ||
| 279 | return -ENOMEM; | ||
| 280 | p = spi_master_get_devdata(master); | ||
| 281 | platform_set_drvdata(pdev, p); | ||
| 282 | p->my_master = master; | ||
| 283 | |||
| 284 | res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
| 285 | |||
| 286 | if (res_mem == NULL) { | ||
| 287 | dev_err(&pdev->dev, "found no memory resource\n"); | ||
| 288 | err = -ENXIO; | ||
| 289 | goto fail; | ||
| 290 | } | ||
| 291 | if (!devm_request_mem_region(&pdev->dev, res_mem->start, | ||
| 292 | resource_size(res_mem), res_mem->name)) { | ||
| 293 | dev_err(&pdev->dev, "request_mem_region failed\n"); | ||
| 294 | goto fail; | ||
| 295 | } | ||
| 296 | p->register_base = (u64)devm_ioremap(&pdev->dev, res_mem->start, | ||
| 297 | resource_size(res_mem)); | ||
| 298 | |||
| 299 | /* Dynamic bus numbering */ | ||
| 300 | master->bus_num = -1; | ||
| 301 | master->num_chipselect = 4; | ||
| 302 | master->mode_bits = SPI_CPHA | | ||
| 303 | SPI_CPOL | | ||
| 304 | SPI_CS_HIGH | | ||
| 305 | SPI_LSB_FIRST | | ||
| 306 | SPI_3WIRE; | ||
| 307 | |||
| 308 | master->setup = octeon_spi_setup; | ||
| 309 | master->cleanup = octeon_spi_cleanup; | ||
| 310 | master->prepare_transfer_hardware = octeon_spi_nop_transfer_hardware; | ||
| 311 | master->transfer_one_message = octeon_spi_transfer_one_message; | ||
| 312 | master->unprepare_transfer_hardware = octeon_spi_nop_transfer_hardware; | ||
| 313 | |||
| 314 | master->dev.of_node = pdev->dev.of_node; | ||
| 315 | err = spi_register_master(master); | ||
| 316 | if (err) { | ||
| 317 | dev_err(&pdev->dev, "register master failed: %d\n", err); | ||
| 318 | goto fail; | ||
| 319 | } | ||
| 320 | |||
| 321 | dev_info(&pdev->dev, "OCTEON SPI bus driver\n"); | ||
| 322 | |||
| 323 | return 0; | ||
| 324 | fail: | ||
| 325 | spi_master_put(master); | ||
| 326 | return err; | ||
| 327 | } | ||
| 328 | |||
| 329 | static int __devexit octeon_spi_remove(struct platform_device *pdev) | ||
| 330 | { | ||
| 331 | struct octeon_spi *p = platform_get_drvdata(pdev); | ||
| 332 | u64 register_base = p->register_base; | ||
| 333 | |||
| 334 | spi_unregister_master(p->my_master); | ||
| 335 | |||
| 336 | /* Clear the CSENA* and put everything in a known state. */ | ||
| 337 | cvmx_write_csr(register_base + OCTEON_SPI_CFG, 0); | ||
| 338 | |||
| 339 | return 0; | ||
| 340 | } | ||
| 341 | |||
| 342 | static struct of_device_id octeon_spi_match[] = { | ||
| 343 | { .compatible = "cavium,octeon-3010-spi", }, | ||
| 344 | {}, | ||
| 345 | }; | ||
| 346 | MODULE_DEVICE_TABLE(of, octeon_spi_match); | ||
| 347 | |||
| 348 | static struct platform_driver octeon_spi_driver = { | ||
| 349 | .driver = { | ||
| 350 | .name = "spi-octeon", | ||
| 351 | .owner = THIS_MODULE, | ||
| 352 | .of_match_table = octeon_spi_match, | ||
| 353 | }, | ||
| 354 | .probe = octeon_spi_probe, | ||
| 355 | .remove = __devexit_p(octeon_spi_remove), | ||
| 356 | }; | ||
| 357 | |||
| 358 | module_platform_driver(octeon_spi_driver); | ||
| 359 | |||
| 360 | MODULE_DESCRIPTION("Cavium, Inc. OCTEON SPI bus driver"); | ||
| 361 | MODULE_AUTHOR("David Daney"); | ||
| 362 | MODULE_LICENSE("GPL"); | ||
