How to bind my driver?

It may not matter, I use ‘tegra_defconfig’ file, not use ‘menuconfig’.

[tegra_defconfig]

CONFIG_SPI_MICROCHIP_EEPROM=m

[Kconfig]

config SPI_MICROCHIP_EEPROM
tristate “Microchip 93xx56 EEPROM support”
select SPI_MICROCHIP_EEPROM
help
This enables master mode support for the 93xx56.

[Makefile]

obj-$(CONFIG_SPI_MICROCHIP_EEPROM) += spi-eep.o

My driver’s description is above. And I think configuration mechanism is follows.
When the right side letter is ‘m’, my driver is in the kernel.
When It is ‘y’, my driver is probing by the kernel.

Is my image correct ?

hello t.hirose,

it’ll built-in to kernel images if you have configuration, CONFIG_SPI_MICROCHIP_EEPROM=y. (a.k.a obj-y += spi-eep.o)

so, you’re now having your driver loaded during kernel initialization.

OMG! I understood it !
But I tried both ‘m’ and ‘y’. I seem it not worked.
My driver using ‘printk’. if it was probed , print the message.
I never seem the print message yet.

What do the other things need?

Thank you.

hello t.hirose,

please check out-side the driver layer, to check if your driver has called by the kernel APIs.
for example, you may check EXPORT_SYMBOL_GPL(...) for the API function calls.
thanks

Hello.
It means the driver doesn’t handle as file system, don’t it ?
Shouldn’t I worry the driver handles as file system ?

By the way, the description of ‘tegra-defconfig’ to ‘y’, my driver combined the kernel.
But it is not seem as file system. In this case, I should use EXPORT_SYMBOL.
Is it correct ?

Thank you.

Hello. I’m trying this topic yet.
I look like the kernel is recognizing SPI driver and my eeprom driver.
The latest settings follows:

[common.dtsi]

spi@7000d400 { /* alias ‘spi0’ */
status = “okay”;
compatible = “spidev”;
reg = <0x0>;
nvidia,enable-hw-based-cs;
nvidia,rx-clk-tap-delay = <7>;
};

[eeprom-manager.dtsi]
/ {
maker_eep: eep@0 {
status = “okay”;
bus = <&spi0>;
compatible = “microchip,eeprom-93xx56”;
devnode = “m_eeprom”;
spi-max-frequency = <1000000>;
spi-cs-high;
spi-cpha;
spi-3wire;
size = <256>;
data-size = <16>; /* 93LC56B */
};
};

[Booting log]
U-Boot 2016.07-g0536cf2a27 (Dec 09 2019 - 22:40:32 -0800)

TEGRA210
Model: NVIDIA P3450-Porg
Board: NVIDIA P3450-PORG
DRAM: 4 GiB
MMC: Tegra SD/MMC: 0, Tegra SD/MMC: 1
SF: Failed to get idcodes
*** Warning - spi_flash_probe() failed, using default environment

[ 3.987015] spidev: module is already loaded

[lsmod]

spi_93xx56 9059 0

I wonder why ‘spidev’ was read twice, and why doesn’t spi device appear ‘/dev’.
Please tell me some advices.

Thank you.

hello t.hirose,

please also check similar discussion thread, for example, Topic 127294, and Topic 73338 for reference,
thanks

hello, jerry.
i tried both topics, but it was not succeed.
my ‘lsmod’ list content my eeprom driver(named ‘spi-93xx56’) instead of ‘spidev’.
‘/dev/spi*’ has not indicated .

is there some suggestions?

thank you.

hello.
my spi bus connection image is follows:

tegra-SoC
    + ----SPI
            + ----EEPROM(93xx56)

I think to need the GPIO’s mux setting, SPI compatible setting, and EEP compatible setting. that way, the kernel can recognize to use SPI bus, and can load the compatible module.
I think the EEPROM is connect on SPI as slave device, so the Device Tree needs the EEPROM compatible description.

Here is the DTSI file , please tell me some advice.
( Sorry, I don’t know how to devide the files, too long… )

[tegra210-porg-pinmux-p3448-0002-b00.dtsi]
/ {
    pinmux: pinmux@700008d4 {
    status = "okay";
    pinctrl-names = "default", "drive", "unused";
    pinctrl-0 = <&pinmux_default>;
    pinctrl-1 = <&drive_default>;
    pinctrl-2 = <&pinmux_unused_lowpower>;

    pinmux_default: common {
     ...
    spi1_mosi_pc0 {
        nvidia,pins = "spi1_mosi_pc0";
        nvidia,function = "spi1";
        nvidia,pull = <TEGRA_PIN_PULL_NONE>;
        nvidia,tristate = <TEGRA_PIN_DISABLE>;
        nvidia,enable-input = <TEGRA_PIN_DISABLE>;
    };

    spi1_miso_pc1 {
        nvidia,pins = "spi1_miso_pc1";
        nvidia,function = "spi1";
        nvidia,pull = <TEGRA_PIN_PULL_DOWN>;
        nvidia,tristate = <TEGRA_PIN_DISABLE>;
        nvidia,enable-input = <TEGRA_PIN_ENABLE>;
    };

    spi1_sck_pc2 {
        nvidia,pins = "spi1_sck_pc2";
        nvidia,function = "spi1";
        nvidia,pull = <TEGRA_PIN_PULL_NONE>;
        nvidia,tristate = <TEGRA_PIN_DISABLE>;
        nvidia,enable-input = <TEGRA_PIN_DISABLE>;
    };

    spi1_cs0_pc3 {
        nvidia,pins = "spi1_cs0_pc3";
        nvidia,function = "spi1";
        nvidia,pull = <TEGRA_PIN_PULL_NONE>;
        nvidia,tristate = <TEGRA_PIN_DISABLE>;
        nvidia,enable-input = <TEGRA_PIN_DISABLE>;
    };
    .....
    };
    };
};

[tegra210-porg-p3448-common.dtsi]
/{
    nvidia,boardids = "3448";
    nvidia,proc-boardid = "3448";
    nvidia,pmu-boardid = "3448";
    nvidia,fastboot-usb-pid = <0xb442>;

    chosen {
        nvidia,tegra-porg-sku;
        stdout-path = "/serial@70006000";
        nvidia,tegra-always-on-personality;
        no-tnid-sn;
        bootargs = "kmemleak=on earlycon=uart8250,mmio32,0x70006000";
    };
    ....
    spi@7000d400 {
        status = "okay";
        compatible = "spidev";
        reg = <0x0 0x7000d400 0x0 0x200>;
        spi-max-frequency = <20000000>;
        nvidia,enable-hw-based-cs;
        nvidia,cs-setup-clk-count = <0x1e>;
        nvidia,cs-hold-clk-count = <0x1e>;
        nvidia,rx-clk-tap-delay = <0x1f>;
        nvidia,tx-clk-tap-delay = <0x0>;
    };
    ....
    gpio: gpio@6000d000 {
        suspend_gpio: system-suspend-gpio {
            status = "okay";
            gpio-hog;
            output-high;
            gpio-suspend;
            suspend-output-low;
            gpios = <
                TEGRA_GPIO(A, 6) 0
                >;
        };
    };
    ....
    pinmux@700008d4 {
        dvfs_pwm_active_state: dvfs_pwm_active {
            dvfs_pwm_pbb1 {
                  nvidia,pins = "dvfs_pwm_pbb1";
                  nvidia,tristate = <TEGRA_PIN_DISABLE>;
            };
        };

        dvfs_pwm_inactive_state: dvfs_pwm_inactive {
            dvfs_pwm_pbb1 {
                nvidia,pins = "dvfs_pwm_pbb1";
                nvidia,tristate = <TEGRA_PIN_ENABLE>;
            };
        };
    };
    .....
};

[tegra210-porg-eeprom-manager.dtsi]
/ { 
    maker_eep: eep@0 {
    status = "okay";
    bus = <&spi0>;
    compatible = "microchip,eeprom-93xx56";
    devnode = "m_eeprom";
    spi-max-frequency = <1000000>;
    spi-cs-high;
    spi-cpha;
    spi-3wire;
    size = <256>;
    data-size = <16>;	/* 93LC56B	*/
    };
};

In this case,

  • don’t appear ‘/dev/spi*’ or ‘/dev/*eep*’ file.
  • ‘spi_93xx56’ indicated in ‘lsmod’ lists.
  • In ‘/sys/bus/spi/drivers/’, both ‘spi_93xx56’ and ‘spidev’ are exsist.
  • the message ‘spidev: module is already loaded’ in ‘dmesg’.

thanks.

hello t.hirose,

you should also update device tree property, please make compatible as same as your SPI driver’s compatible variable.
for example,

  spi@7000d400 {
        status = "okay";
        compatible = "spidev";

please also look into kernel logs, please share what’s the message shown for your SPI driver probing process,
thanks

hello, Jerry.

SPI driver’s compatible variable and ‘compatible’ description in device tree are same, and the kernel log is follows.

[ 3.745025] spidev: module is already loaded

There are no other messages about SPI in the kernel log.

The spidev.c source code ( probe function ) is follows:

    ....
    #ifdef CONFIG_OF
    static const struct of_device_id spidev_dt_ids[] = {
        { .compatible = "spidev" },
        { .compatible = "rohm,dh2228fv" },
        { .compatible = "lineartechnology,ltc2488" },
        {},
    };
    MODULE_DEVICE_TABLE(of, spidev_dt_ids);
    #endif
    ....
static int spidev_probe(struct spi_device *spi)
{
    struct spidev_data	*spidev;
    int			status;
    unsigned long		minor;

    /*
     * spidev should never be referenced in DT without a specific
     * compatible string, it is a Linux implementation thing
     * rather than a description of the hardware.
     */
    if (spi->dev.of_node && !of_match_device(spidev_dt_ids, &spi->dev)) {
        dev_err(&spi->dev, "buggy DT: spidev listed directly in DT\n");
        WARN_ON(spi->dev.of_node &&
                     !of_match_device(spidev_dt_ids, &spi->dev));
    }
    
    spidev_probe_acpi(spi);
    
    /* Allocate driver data */
    spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);
    if (!spidev)
        return -ENOMEM;
    
    /* Initialize the driver data */
    spidev->spi = spi;
    spin_lock_init(&spidev->spi_lock);
    mutex_init(&spidev->buf_lock);
    
    INIT_LIST_HEAD(&spidev->device_entry);
    
    /* If we can allocate a minor number, hook up this device.
     * Reusing minors is fine so long as udev or mdev is working.
     */
    mutex_lock(&device_list_lock);
    minor = find_first_zero_bit(minors, N_SPI_MINORS);
    if (minor < N_SPI_MINORS) {
        struct device *dev;
    
        spidev->devt = MKDEV(SPIDEV_MAJOR, minor);
        dev = device_create(spidev_class, &spi->dev, spidev->devt,
                                               spidev, "spidev%d.%d",
                                               spi->master->bus_num, spi->chip_select);
        status = PTR_ERR_OR_ZERO(dev);
    } else {
        dev_dbg(&spi->dev, "no minor number available!\n");
        status = -ENODEV;
    }
    if (status == 0) {
        set_bit(minor, minors);
        list_add(&spidev->device_entry, &device_list);
    }
    mutex_unlock(&device_list_lock);
    
    spidev->speed_hz = spi->max_speed_hz;
    
    if (status == 0)
        spi_set_drvdata(spi, spidev);
    else
        kfree(spidev);
    
    return status;
    }

I can’t find the problem in this code, and can’t undestand why the kernel tells me ‘already loaded’.

thanks.

hello t.hirose,

may I know what’s your steps to bind your driver?
it seems you’d already loaded the kernel module, which cannot load again.
please refer to the source of driver,
for example,
$L4T_Sources/r32.4.4/Linux_for_Tegra/source/public/kernel/kernel-4.9/kernel/module.c

1735  static int mod_sysfs_init(struct module *mod)
...
1746  	kobj = kset_find_obj(module_kset, mod->name);
1747  	if (kobj) {
1748  		pr_err("%s: module is already loaded\n", mod->name);
1749  		kobject_put(kobj);
1750  		err = -EINVAL;
1751  		goto out;
1752  	}

hello, Jerry.

Does that mean SPI driver is loaded by the kernel automatically without SPI driver setting ?

Thanks.

hello t.hirose,

your driver should be loaded during kernel initialization once you’d modify kernel configuration to make it as built-in driver.
thanks

Hello, Jerry. Thank you for your advice.
I found SPI setting as ‘spi1_prod’ in ‘tegra210-prods.dtsi’. It seem the SPI settings had already finished at the end of boot.
Does my interpretation correct ?

My EEPROM driver has read as device driver module. but it is not appeared under the ‘/dev’ folder. I’m thinking all of device drivers is handling as like file operation, but my driver is not.

How to do make my driver can be handle as like file operation ?
Or when user application can call my driver’s function directly, does it correct ?

hello t.hirose,

please check the API calls, i.e. EXPORT_SYMBOL_GPL(...)
your user-space application may call those APIs to access your driver.
thanks

hello, Jerry.

I understood, the driver does not necessarily have to be treated as a file
It has resolved.

Thank you so much!