diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux-6.6/linux-yocto-6.6/0028-spi-spidev-Add-dummy-spidev-device-to-SPI-bus-for_0030-amd-xgbe-ptp-add-hw-time-stamp-changes.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux-6.6/linux-yocto-6.6/0028-spi-spidev-Add-dummy-spidev-device-to-SPI-bus-for_0030-amd-xgbe-ptp-add-hw-time-stamp-changes.patch | 611 |
1 files changed, 611 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux-6.6/linux-yocto-6.6/0028-spi-spidev-Add-dummy-spidev-device-to-SPI-bus-for_0030-amd-xgbe-ptp-add-hw-time-stamp-changes.patch b/meta-amd-bsp/recipes-kernel/linux-6.6/linux-yocto-6.6/0028-spi-spidev-Add-dummy-spidev-device-to-SPI-bus-for_0030-amd-xgbe-ptp-add-hw-time-stamp-changes.patch new file mode 100644 index 00000000..6bf6e84f --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux-6.6/linux-yocto-6.6/0028-spi-spidev-Add-dummy-spidev-device-to-SPI-bus-for_0030-amd-xgbe-ptp-add-hw-time-stamp-changes.patch @@ -0,0 +1,611 @@ +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-common.h b/drivers/net/ethernet/amd/xgbe/xgbe-common.h +index 1d936cdc13cf..57feec00e21a 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-common.h ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-common.h +@@ -332,6 +332,10 @@ + #define MAC_TSSR 0x0d20 + #define MAC_TXSNR 0x0d30 + #define MAC_TXSSR 0x0d34 ++#define MAC_TICNR 0x0d58 ++#define MAC_TICSNR 0x0d5C ++#define MAC_TECNR 0x0d60 ++#define MAC_TECSNR 0x0d64 + #define MAC_AUXCR 0x0d40 + #define MAC_ATSNR 0x0d48 + #define MAC_ATSSR 0x0d4C +@@ -537,6 +541,8 @@ + #define MAC_TSCR_SNAPTYPSEL_WIDTH 2 + #define MAC_TSCR_TSADDREG_INDEX 5 + #define MAC_TSCR_TSADDREG_WIDTH 1 ++#define MAC_TSCR_TSUPDT_INDEX 3 ++#define MAC_TSCR_TSUPDT_WIDTH 1 + #define MAC_TSCR_TSCFUPDT_INDEX 1 + #define MAC_TSCR_TSCFUPDT_WIDTH 1 + #define MAC_TSCR_TSCTRLSSR_INDEX 9 +@@ -578,6 +584,10 @@ + #define MAC_TSSR_AUXTSTRIG_WIDTH 1 + #define MAC_TXSNR_TXTSSTSMIS_INDEX 31 + #define MAC_TXSNR_TXTSSTSMIS_WIDTH 1 ++#define MAC_TICSNR_TSICSNS_INDEX 8 ++#define MAC_TICSNR_TSICSNS_WIDTH 8 ++#define MAC_TECSNR_TSECSNS_INDEX 8 ++#define MAC_TECSNR_TSECSNS_WIDTH 8 + #define MAC_AUXCR_ATSEN3_INDEX 7 + #define MAC_AUXCR_ATSEN3_WIDTH 1 + #define MAC_AUXCR_ATSEN2_INDEX 6 +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +index b7061e24e643..bc1cd7d37d93 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c +@@ -1635,6 +1635,28 @@ static void xgbe_rx_desc_init(struct xgbe_channel *channel) + DBGPR("<--rx_desc_init\n"); + } + ++static void xgbe_update_tstamp_time(struct xgbe_prv_data *pdata, unsigned int sec, ++ unsigned int nsec) ++{ ++ unsigned int count = 10000; ++ ++ /* Set the time values and tell the device */ ++ XGMAC_IOWRITE(pdata, MAC_STSUR, sec); ++ XGMAC_IOWRITE(pdata, MAC_STNUR, nsec); ++ ++ /* issue command to update the system time value */ ++ XGMAC_IOWRITE(pdata, MAC_TSCR, ++ XGMAC_IOREAD(pdata, MAC_TSCR) | (1 << MAC_TSCR_TSUPDT_INDEX)); ++ ++ /* Wait for the time till update complete */ ++ while (--count && XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSUPDT)) ++ udelay(5); ++ ++ if (!count) ++ netdev_err(pdata->netdev, "timed out updating system timestamp\n"); ++} ++ ++ + static void xgbe_update_tstamp_addend(struct xgbe_prv_data *pdata, + unsigned int addend) + { +@@ -1713,8 +1735,8 @@ static void xgbe_get_rx_tstamp(struct xgbe_packet_data *packet, + if (XGMAC_GET_BITS_LE(rdesc->desc3, RX_CONTEXT_DESC3, TSA) && + !XGMAC_GET_BITS_LE(rdesc->desc3, RX_CONTEXT_DESC3, TSD)) { + nsec = le32_to_cpu(rdesc->desc1); +- nsec <<= 32; +- nsec |= le32_to_cpu(rdesc->desc0); ++ nsec *= NSEC_PER_SEC; ++ nsec += le32_to_cpu(rdesc->desc0); + if (nsec != 0xffffffffffffffffULL) { + packet->rx_tstamp = nsec; + XGMAC_SET_BITS(packet->attributes, RX_PACKET_ATTRIBUTES, +@@ -1722,36 +1744,13 @@ static void xgbe_get_rx_tstamp(struct xgbe_packet_data *packet, + } + } + } +- +-static int xgbe_config_tstamp(struct xgbe_prv_data *pdata, ++static void xgbe_config_tstamp(struct xgbe_prv_data *pdata, + unsigned int mac_tscr) + { +- /* Set one nano-second accuracy */ +- XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCTRLSSR, 1); +- +- /* Set fine timestamp update */ +- XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCFUPDT, 1); +- +- /* Overwrite earlier timestamps */ +- XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TXTSSTSM, 1); +- +- XGMAC_IOWRITE(pdata, MAC_TSCR, mac_tscr); +- +- /* Exit if timestamping is not enabled */ +- if (!XGMAC_GET_BITS(mac_tscr, MAC_TSCR, TSENA)) +- return 0; +- +- /* Initialize time registers */ +- XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SSINC, XGBE_TSTAMP_SSINC); +- XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SNSINC, XGBE_TSTAMP_SNSINC); +- xgbe_update_tstamp_addend(pdata, pdata->tstamp_addend); +- xgbe_set_tstamp_time(pdata, 0, 0); +- +- /* Initialize the timecounter */ +- timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, +- ktime_to_ns(ktime_get_real())); +- +- return 0; ++ unsigned int value = 0; ++ value = XGMAC_IOREAD(pdata, MAC_TSCR); ++ value |= mac_tscr; ++ XGMAC_IOWRITE(pdata, MAC_TSCR, value); + } + + static void xgbe_tx_start_xmit(struct xgbe_channel *channel, +@@ -1779,6 +1778,82 @@ static void xgbe_tx_start_xmit(struct xgbe_channel *channel, + ring->tx.xmit_more = 0; + } + ++ ++static void xgbe_init_ptp(struct xgbe_prv_data *pdata) ++{ ++ unsigned int mac_tscr = 0; ++ struct timespec64 now; ++ u64 dividend; ++ ++ /* Register Settings to be done based on the link speed. */ ++ switch(pdata->phy.speed) { ++ case SPEED_1000: ++ XGMAC_IOWRITE(pdata, MAC_TICNR, MAC_TICNR_1G_INITVAL); ++ XGMAC_IOWRITE(pdata, MAC_TECNR, MAC_TECNR_1G_INITVAL); ++ break; ++ case SPEED_2500: ++ case SPEED_10000: ++ XGMAC_IOWRITE_BITS(pdata, MAC_TICSNR, TSICSNS, MAC_TICSNR_10G_INITVAL); ++ XGMAC_IOWRITE(pdata, MAC_TECNR, MAC_TECNR_10G_INITVAL); ++ XGMAC_IOWRITE_BITS(pdata, MAC_TECSNR, TSECSNS, MAC_TECSNR_10G_INITVAL); ++ break; ++ case SPEED_UNKNOWN: ++ default: ++ break; ++ } ++ ++ /* Enable IEEE1588 PTP clock. */ ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSENA, 1); ++ ++ /* Overwrite earlier timestamps */ ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TXTSSTSM, 1); ++ ++ /* Set one nano-second accuracy */ ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCTRLSSR, 1); ++ ++ /* Set fine timestamp update */ ++ XGMAC_SET_BITS(mac_tscr, MAC_TSCR, TSCFUPDT, 1); ++ ++ xgbe_config_tstamp(pdata, mac_tscr); ++ ++ /* Exit if timestamping is not enabled */ ++ if (!XGMAC_GET_BITS(mac_tscr, MAC_TSCR, TSENA)) ++ return; ++ ++ if (pdata->vdata->tstamp_ptp_clock_freq) { ++ /* Initialize time registers based on 125MHz PTP Clock Frequency */ ++ XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SSINC, XGBE_V2_TSTAMP_SSINC); ++ XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SNSINC, XGBE_V2_TSTAMP_SNSINC); ++ } else { ++ /* Initialize time registers based on 50MHz PTP Clock Frequency*/ ++ XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SSINC, XGBE_TSTAMP_SSINC); ++ XGMAC_IOWRITE_BITS(pdata, MAC_SSIR, SNSINC, XGBE_TSTAMP_SNSINC); ++ } ++ ++ /* Calculate the addend: ++ * addend = 2^32 / (PTP ref clock / (PTP clock based on SSINC)) ++ * = (2^32 * (PTP clock based on SSINC)) / PTP ref clock ++ */ ++ if (pdata->vdata->tstamp_ptp_clock_freq) ++ dividend = 100000000; // PTP clock frequency is 125MHz ++ else ++ dividend = 50000000; // PTP clock frequency is 50MHz ++ ++ dividend <<= 32; ++ pdata->tstamp_addend = div_u64(dividend, pdata->ptpclk_rate); ++ ++ xgbe_update_tstamp_addend(pdata, pdata->tstamp_addend); ++ ++ dma_wmb(); ++ /* initialize system time */ ++ ktime_get_real_ts64(&now); ++ ++ /* lower 32 bits of tv_sec are safe until y2106 */ ++ xgbe_set_tstamp_time(pdata, (u32)now.tv_sec, now.tv_nsec); ++ ++} ++ ++ + static void xgbe_dev_xmit(struct xgbe_channel *channel) + { + struct xgbe_prv_data *pdata = channel->pdata; +@@ -3735,9 +3810,11 @@ void xgbe_init_function_ptrs_dev(struct xgbe_hw_if *hw_if) + hw_if->read_mmc_stats = xgbe_read_mmc_stats; + + /* For PTP config */ ++ hw_if->init_ptp = xgbe_init_ptp; + hw_if->config_tstamp = xgbe_config_tstamp; + hw_if->update_tstamp_addend = xgbe_update_tstamp_addend; + hw_if->set_tstamp_time = xgbe_set_tstamp_time; ++ hw_if->update_tstamp_time = xgbe_update_tstamp_time; + hw_if->get_tstamp_time = xgbe_get_tstamp_time; + hw_if->get_tx_tstamp = xgbe_get_tx_tstamp; + +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +index 6923d17a2432..47502ab698cc 100755 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c +@@ -1487,7 +1487,6 @@ static void xgbe_tx_tstamp(struct work_struct *work) + struct xgbe_prv_data, + tx_tstamp_work); + struct skb_shared_hwtstamps hwtstamps; +- u64 nsec; + unsigned long flags; + + spin_lock_irqsave(&pdata->tstamp_lock, flags); +@@ -1495,11 +1494,9 @@ static void xgbe_tx_tstamp(struct work_struct *work) + goto unlock; + + if (pdata->tx_tstamp) { +- nsec = timecounter_cyc2time(&pdata->tstamp_tc, +- pdata->tx_tstamp); + + memset(&hwtstamps, 0, sizeof(hwtstamps)); +- hwtstamps.hwtstamp = ns_to_ktime(nsec); ++ hwtstamps.hwtstamp = ns_to_ktime(pdata->tx_tstamp); + skb_tstamp_tx(pdata->tx_tstamp_skb, &hwtstamps); + } + +@@ -1885,7 +1882,8 @@ static int xgbe_open(struct net_device *netdev) + INIT_WORK(&pdata->restart_work, xgbe_restart); + INIT_WORK(&pdata->stopdev_work, xgbe_stopdev); + INIT_WORK(&pdata->tx_tstamp_work, xgbe_tx_tstamp); +- ++/* Initialize PTP timestamping and clock. */ ++ pdata->hw_if.init_ptp(pdata); + ret = xgbe_alloc_memory(pdata); + if (ret) + goto err_ptpclk; +@@ -2649,12 +2647,9 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget) + + if (XGMAC_GET_BITS(packet->attributes, + RX_PACKET_ATTRIBUTES, RX_TSTAMP)) { +- u64 nsec; + +- nsec = timecounter_cyc2time(&pdata->tstamp_tc, +- packet->rx_tstamp); + hwtstamps = skb_hwtstamps(skb); +- hwtstamps->hwtstamp = ns_to_ktime(nsec); ++ hwtstamps->hwtstamp = ns_to_ktime(packet->rx_tstamp); + } + + if (XGMAC_GET_BITS(packet->attributes, +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +index 397b350902a2..b0eaa933f00b 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-pci.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-pci.c +@@ -482,6 +482,7 @@ static struct xgbe_version_data xgbe_v2a = { + .tx_max_fifo_size = 229376, + .rx_max_fifo_size = 229376, + .tx_tstamp_workaround = 1, ++ .tstamp_ptp_clock_freq = 1, + .ecc_support = 1, + .i2c_support = 1, + .irq_reissue_support = 1, +@@ -498,6 +499,7 @@ static struct xgbe_version_data xgbe_v2b = { + .tx_max_fifo_size = 65536, + .rx_max_fifo_size = 65536, + .tx_tstamp_workaround = 1, ++ .tstamp_ptp_clock_freq = 1, + .ecc_support = 1, + .i2c_support = 1, + .irq_reissue_support = 1, +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c +index 648a85070219..a953bbfcfadb 100644 +--- a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c ++++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c +@@ -122,17 +122,6 @@ + #include "xgbe.h" + #include "xgbe-common.h" + +-static u64 xgbe_cc_read(const struct cyclecounter *cc) +-{ +- struct xgbe_prv_data *pdata = container_of(cc, +- struct xgbe_prv_data, +- tstamp_cc); +- u64 nsec; +- +- nsec = pdata->hw_if.get_tstamp_time(pdata); +- +- return nsec; +-} + + static int xgbe_adjfine(struct ptp_clock_info *info, long scaled_ppm) + { +@@ -140,6 +129,29 @@ static int xgbe_adjfine(struct ptp_clock_info *info, long scaled_ppm) + struct xgbe_prv_data, + ptp_clock_info); + unsigned long flags; ++ unsigned int sec, nsec; ++ unsigned int neg_adjust = 0; ++ u32 quotient, reminder; ++ ++ if (delta < 0) { ++ neg_adjust = 1; ++ delta = -delta; ++ } ++ ++ quotient = div_u64_rem(delta, 1000000000ULL, &reminder); ++ sec = quotient; ++ nsec = reminder; ++ ++ /* Negative adjustment for Hw timer register. */ ++ if (neg_adjust) { ++ sec = -sec; ++ if (XGMAC_IOREAD_BITS(pdata, MAC_TSCR, TSCTRLSSR)) ++ nsec = (1000000000UL - nsec); ++ else ++ nsec = (0x80000000UL - nsec); ++ } ++ nsec = (neg_adjust << 31) | nsec; ++ + u64 addend; + + addend = adjust_by_scaled_ppm(pdata->tstamp_addend, scaled_ppm); +@@ -167,17 +179,25 @@ static int xgbe_adjtime(struct ptp_clock_info *info, s64 delta) + return 0; + } + +-static int xgbe_gettime(struct ptp_clock_info *info, struct timespec64 *ts) ++static int xgbe_gettimex(struct ptp_clock_info *info, ++ struct timespec64 *ts, ++ struct ptp_system_timestamp *sts) + { + struct xgbe_prv_data *pdata = container_of(info, + struct xgbe_prv_data, + ptp_clock_info); + unsigned long flags; + u64 nsec; ++ static int count = 3; + ++ if (count > 0 && count--) ++ dump_stack(); + spin_lock_irqsave(&pdata->tstamp_lock, flags); + +- nsec = timecounter_read(&pdata->tstamp_tc); ++ ptp_read_system_prets(sts); ++ nsec = pdata->hw_if.get_tstamp_time(pdata); ++ ptp_read_system_postts(sts); ++ + + spin_unlock_irqrestore(&pdata->tstamp_lock, flags); + +@@ -193,13 +213,10 @@ static int xgbe_settime(struct ptp_clock_info *info, + struct xgbe_prv_data, + ptp_clock_info); + unsigned long flags; +- u64 nsec; + +- nsec = timespec64_to_ns(ts); + + spin_lock_irqsave(&pdata->tstamp_lock, flags); +- +- timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, nsec); ++ pdata->hw_if.set_tstamp_time(pdata, ts->tv_sec, ts->tv_nsec); + + spin_unlock_irqrestore(&pdata->tstamp_lock, flags); + +@@ -268,22 +285,6 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata) + + pdata->ptp_clock = clock; + +- /* Calculate the addend: +- * addend = 2^32 / (PTP ref clock / 50Mhz) +- * = (2^32 * 50Mhz) / PTP ref clock +- */ +- dividend = 50000000; +- dividend <<= 32; +- pdata->tstamp_addend = div_u64(dividend, pdata->ptpclk_rate); +- +- /* Setup the timecounter */ +- cc->read = xgbe_cc_read; +- cc->mask = CLOCKSOURCE_MASK(64); +- cc->mult = 1; +- cc->shift = 0; +- +- timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, +- ktime_to_ns(ktime_get_real())); + + /* Disable all timestamping to start */ + XGMAC_IOWRITE(pdata, MAC_TSCR, 0); +diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h +index 11df8e463c2f..7eff27409e6d 100755 +--- a/drivers/net/ethernet/amd/xgbe/xgbe.h ++++ b/drivers/net/ethernet/amd/xgbe/xgbe.h +@@ -225,6 +225,14 @@ + /* PCI MSI/MSIx support */ + #define XGBE_MSI_BASE_COUNT 4 + #define XGBE_MSI_MIN_COUNT (XGBE_MSI_BASE_COUNT + 1) ++/* Initial PTP register values based on Link Speed. */ ++#define MAC_TICNR_1G_INITVAL 0x10 ++#define MAC_TECNR_1G_INITVAL 0x28 ++ ++#define MAC_TICSNR_10G_INITVAL 0x33 ++#define MAC_TECNR_10G_INITVAL 0x14 ++#define MAC_TECSNR_10G_INITVAL 0xCC ++ + + /* PCI clock frequencies */ + #define XGBE_V2_DMA_CLOCK_FREQ 500000000 /* 500 MHz */ +@@ -235,6 +243,9 @@ + */ + #define XGBE_TSTAMP_SSINC 20 + #define XGBE_TSTAMP_SNSINC 0 ++#define XGBE_V2_TSTAMP_SSINC 0xA ++#define XGBE_V2_TSTAMP_SNSINC 0 ++ + + /* Driver PMT macros */ + #define XGMAC_DRIVER_CONTEXT 1 +@@ -846,10 +857,15 @@ struct xgbe_hw_if { + void (*read_mmc_stats)(struct xgbe_prv_data *); + + /* For Timestamp config */ +- int (*config_tstamp)(struct xgbe_prv_data *, unsigned int); ++ void (*init_ptp)(struct xgbe_prv_data *); ++ void (*config_tstamp)(struct xgbe_prv_data *, unsigned int); ++ + void (*update_tstamp_addend)(struct xgbe_prv_data *, unsigned int); + void (*set_tstamp_time)(struct xgbe_prv_data *, unsigned int sec, + unsigned int nsec); ++ void (*update_tstamp_time)(struct xgbe_prv_data *, unsigned int sec, ++ unsigned int nsec); ++ + u64 (*get_tstamp_time)(struct xgbe_prv_data *); + u64 (*get_tx_tstamp)(struct xgbe_prv_data *); + u64 (*get_aux_snp)(struct xgbe_prv_data *); +@@ -1050,6 +1066,7 @@ struct xgbe_version_data { + unsigned int tx_max_fifo_size; + unsigned int rx_max_fifo_size; + unsigned int tx_tstamp_workaround; ++ unsigned int tstamp_ptp_clock_freq; + unsigned int ecc_support; + unsigned int i2c_support; + unsigned int irq_reissue_support; +@@ -1236,8 +1253,6 @@ struct xgbe_prv_data { + struct ptp_clock_info ptp_clock_info; + struct ptp_clock *ptp_clock; + struct hwtstamp_config tstamp_config; +- struct cyclecounter tstamp_cc; +- struct timecounter tstamp_tc; + unsigned int tstamp_addend; + struct work_struct tx_tstamp_work; + struct sk_buff *tx_tstamp_skb; +diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c +index 399e81d37b3b..ed189bb3de8e 100644 +--- a/drivers/spi/spi.c ++++ b/drivers/spi/spi.c +@@ -3373,6 +3373,43 @@ int spi_controller_resume(struct spi_controller *ctlr) + } + EXPORT_SYMBOL_GPL(spi_controller_resume); + ++static int __spi_controller_match(struct device *dev, const void *data) ++{ ++ struct spi_controller *ctlr; ++ const u16 *bus_num = data; ++ ++ ctlr = container_of(dev, struct spi_controller, dev); ++ return ctlr->bus_num == *bus_num; ++} ++ ++/** ++ * spi_busnum_to_master - look up master associated with bus_num ++ * @bus_num: the master's bus number ++ * Context: can sleep ++ * ++ * This call may be used with devices that are registered after ++ * arch init time. It returns a refcounted pointer to the relevant ++ * spi_controller (which the caller must release), or NULL if there is ++ * no such master registered. ++ * ++ * Return: the SPI master structure on success, else NULL. ++ */ ++struct spi_controller *spi_busnum_to_master(u16 bus_num) ++{ ++ struct device *dev; ++ struct spi_controller *ctlr = NULL; ++ ++ dev = class_find_device(&spi_master_class, NULL, &bus_num, ++ __spi_controller_match); ++ if (dev) ++ ctlr = container_of(dev, struct spi_controller, dev); ++ /* reference got in class_find_device */ ++ return ctlr; ++} ++EXPORT_SYMBOL_GPL(spi_busnum_to_master); ++ ++ ++ + /*-------------------------------------------------------------------------*/ + + /* Core methods for spi_message alterations */ +diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c +index d13dc15cc191..ce39aa46fa3f 100644 +--- a/drivers/spi/spidev.c ++++ b/drivers/spi/spidev.c +@@ -26,7 +26,9 @@ + + #include <linux/uaccess.h> + +- ++#define SPI_BUS 0 ++#define SPI_BUS_CS1 0 ++ + /* + * This supports access to SPI devices using normal userspace I/O calls. + * Note that while traditional UNIX/POSIX I/O semantics are half duplex, +@@ -712,6 +714,7 @@ static const struct spi_device_id spidev_spi_ids[] = { + { .name = "m53cpld" }, + { .name = "spi-petra" }, + { .name = "spi-authenta" }, ++ { .name = "spidev" }, + { .name = "em3581" }, + { .name = "si3210" }, + {}, +@@ -768,7 +771,7 @@ static const struct acpi_device_id spidev_acpi_ids[] = { + MODULE_DEVICE_TABLE(acpi, spidev_acpi_ids); + + /*-------------------------------------------------------------------------*/ +- ++struct spi_device *spi_device; + static int spidev_probe(struct spi_device *spi) + { + int (*match)(struct device *dev); +@@ -828,6 +831,30 @@ static int spidev_probe(struct spi_device *spi) + return status; + } + ++static int __init add_spi_device_to_bus(void) ++{ ++ struct spi_master *spi_master; ++ struct spi_board_info spi_info; ++ ++ spi_master = spi_busnum_to_master(SPI_BUS); ++ if (!spi_master) { ++ printk(KERN_ALERT "Please make sure to \'modprobe " ++ "spi_amd\' driver first\n"); ++ return -1; ++ } ++ memset(&spi_info, 0, sizeof(struct spi_board_info)); ++ ++ strlcpy(spi_info.modalias, "spidev", SPI_NAME_SIZE); ++ spi_info.bus_num = SPI_BUS; //Bus number of SPI master ++ spi_info.chip_select = SPI_BUS_CS1; //CS on which SPI device is connected ++ ++ spi_device = spi_new_device(spi_master, &spi_info); ++ if (!spi_device) ++ return -ENODEV; ++ ++ return 0; ++} ++ + static void spidev_remove(struct spi_device *spi) + { + struct spidev_data *spidev = spi_get_drvdata(spi); +@@ -889,6 +916,12 @@ static int __init spidev_init(void) + class_destroy(spidev_class); + unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name); + } ++ status = add_spi_device_to_bus(); ++ if (status < 0) { ++ spi_unregister_driver(&spidev_spi_driver); ++ class_destroy(spidev_class); ++ unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name); ++ } + return status; + } + module_init(spidev_init); +@@ -896,6 +929,7 @@ module_init(spidev_init); + static void __exit spidev_exit(void) + { + spi_unregister_driver(&spidev_spi_driver); ++ spi_unregister_device(spi_device); + class_destroy(spidev_class); + unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name); + } +diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h +index 8cc7a99927f9..7b5d87f1ddaf 100644 +--- a/include/linux/spi/spi.h ++++ b/include/linux/spi/spi.h +@@ -873,7 +873,7 @@ extern struct spi_device *acpi_spi_device_alloc(struct spi_controller *ctlr, + int index); + int acpi_spi_count_resources(struct acpi_device *adev); + #endif +- ++extern struct spi_controller *spi_busnum_to_master(u16 busnum); + /* + * SPI resource management while processing a SPI message + */ |