Update Centec platform support for Bullseye and 5.10 kernel (#7)
1. Fix build for armhf and arm64 2. upgrade centec tsingma bsp support to 5.10 kernel 3. modify centec platform driver for linux 5.10 Co-authored-by: Shi Lei <shil@centecnetworks.com>
This commit is contained in:
parent
b4dda1c18d
commit
5b284767f6
@ -1,13 +1,13 @@
|
|||||||
## Debian mirror for ARM
|
## Debian mirror for ARM
|
||||||
## Not the repo mirror site can change in future, and needs to be updated to be in sync
|
## Not the repo mirror site can change in future, and needs to be updated to be in sync
|
||||||
|
|
||||||
deb [arch=arm64] http://deb.debian.org/debian buster main contrib non-free
|
deb [arch=arm64] http://deb.debian.org/debian bullseye main contrib non-free
|
||||||
deb-src [arch=arm64] http://deb.debian.org/debian buster main contrib non-free
|
deb-src [arch=arm64] http://deb.debian.org/debian bullseye main contrib non-free
|
||||||
deb [arch=arm64] http://deb.debian.org/debian buster-updates main contrib non-free
|
deb [arch=arm64] http://deb.debian.org/debian bullseye-updates main contrib non-free
|
||||||
deb-src [arch=arm64] http://deb.debian.org/debian buster-updates main contrib non-free
|
deb-src [arch=arm64] http://deb.debian.org/debian bullseye-updates main contrib non-free
|
||||||
deb [arch=arm64] http://ftp.debian.org/debian buster-backports main
|
deb [arch=arm64] http://ftp.debian.org/debian bullseye-backports main
|
||||||
deb [arch=arm64] http://packages.trafficmanager.net/debian/debian buster main contrib non-free
|
# deb [arch=arm64] http://packages.trafficmanager.net/debian/debian bullseye main contrib non-free
|
||||||
deb-src [arch=arm64] http://packages.trafficmanager.net/debian/debian buster main contrib non-free
|
# deb-src [arch=arm64] http://packages.trafficmanager.net/debian/debian bullseye main contrib non-free
|
||||||
deb [arch=arm64] http://packages.trafficmanager.net/debian/debian buster-updates main contrib non-free
|
# deb [arch=arm64] http://packages.trafficmanager.net/debian/debian bullseye-updates main contrib non-free
|
||||||
deb-src [arch=arm64] http://packages.trafficmanager.net/debian/debian buster-updates main contrib non-free
|
# deb-src [arch=arm64] http://packages.trafficmanager.net/debian/debian bullseye-updates main contrib non-free
|
||||||
deb [arch=arm64] http://packages.trafficmanager.net/debian/debian buster-backports main
|
# deb [arch=arm64] http://packages.trafficmanager.net/debian/debian bullseye-backports main
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
## Debian mirror for ARM
|
## Debian mirror for ARM
|
||||||
## Not the repo mirror site can change in future, and needs to be updated to be in sync
|
## Not the repo mirror site can change in future, and needs to be updated to be in sync
|
||||||
|
|
||||||
deb [arch=armhf] http://deb.debian.org/debian buster main contrib non-free
|
deb [arch=armhf] http://deb.debian.org/debian bullseye main contrib non-free
|
||||||
deb-src [arch=armhf] http://deb.debian.org/debian buster main contrib non-free
|
deb-src [arch=armhf] http://deb.debian.org/debian bullseye main contrib non-free
|
||||||
deb [arch=armhf] http://deb.debian.org/debian buster-updates main contrib non-free
|
deb [arch=armhf] http://deb.debian.org/debian bullseye-updates main contrib non-free
|
||||||
deb-src [arch=armhf] http://deb.debian.org/debian buster-updates main contrib non-free
|
deb-src [arch=armhf] http://deb.debian.org/debian bullseye-updates main contrib non-free
|
||||||
deb [arch=armhf] http://ftp.debian.org/debian buster-backports main
|
deb [arch=armhf] http://ftp.debian.org/debian bullseye-backports main
|
||||||
deb [arch=armhf] http://packages.trafficmanager.net/debian/debian buster main contrib non-free
|
# deb [arch=armhf] http://packages.trafficmanager.net/debian/debian bullseye main contrib non-free
|
||||||
deb-src [arch=armhf] http://packages.trafficmanager.net/debian/debian buster main contrib non-free
|
# deb-src [arch=armhf] http://packages.trafficmanager.net/debian/debian bullseye main contrib non-free
|
||||||
deb [arch=armhf] http://packages.trafficmanager.net/debian/debian buster-updates main contrib non-free
|
# deb [arch=armhf] http://packages.trafficmanager.net/debian/debian bullseye-updates main contrib non-free
|
||||||
deb-src [arch=armhf] http://packages.trafficmanager.net/debian/debian buster-updates main contrib non-free
|
# deb-src [arch=armhf] http://packages.trafficmanager.net/debian/debian bullseye-updates main contrib non-free
|
||||||
deb [arch=armhf] http://packages.trafficmanager.net/debian/debian buster-backports main
|
# deb [arch=armhf] http://packages.trafficmanager.net/debian/debian bullseye-backports main
|
||||||
|
@ -643,7 +643,7 @@ clean_proc() {
|
|||||||
sudo umount /proc || true
|
sudo umount /proc || true
|
||||||
}
|
}
|
||||||
trap_push clean_proc
|
trap_push clean_proc
|
||||||
sudo mount proc /proc -t proc
|
sudo mount proc /proc -t proc || true
|
||||||
sudo mkdir $FILESYSTEM_ROOT/target
|
sudo mkdir $FILESYSTEM_ROOT/target
|
||||||
sudo mount --bind target $FILESYSTEM_ROOT/target
|
sudo mount --bind target $FILESYSTEM_ROOT/target
|
||||||
sudo LANG=C DOCKER_HOST="$DOCKER_HOST" chroot $FILESYSTEM_ROOT docker info
|
sudo LANG=C DOCKER_HOST="$DOCKER_HOST" chroot $FILESYSTEM_ROOT docker info
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
deb [arch=arm64] http://deb.debian.org/debian buster main contrib non-free
|
deb [arch=arm64] http://deb.debian.org/debian bullseye main contrib non-free
|
||||||
deb-src [arch=arm64] http://deb.debian.org/debian buster main contrib non-free
|
deb-src [arch=arm64] http://deb.debian.org/debian bullseye main contrib non-free
|
||||||
deb [arch=arm64] http://deb.debian.org/debian buster-updates main contrib non-free
|
deb [arch=arm64] http://deb.debian.org/debian bullseye-updates main contrib non-free
|
||||||
deb-src [arch=arm64] http://deb.debian.org/debian buster-updates main contrib non-free
|
deb-src [arch=arm64] http://deb.debian.org/debian bullseye-updates main contrib non-free
|
||||||
deb [arch=arm64] http://security.debian.org buster/updates main contrib non-free
|
deb [arch=arm64] http://security.debian.org bullseye-security main contrib non-free
|
||||||
deb-src [arch=arm64] http://security.debian.org buster/updates main contrib non-free
|
deb-src [arch=arm64] http://security.debian.org bullseye-security main contrib non-free
|
||||||
deb [arch=arm64] https://download.docker.com/linux/debian buster stable
|
deb [arch=arm64] https://download.docker.com/linux/debian bullseye stable
|
||||||
deb [arch=arm64] http://ftp.debian.org/debian buster-backports main
|
deb [arch=arm64] http://ftp.debian.org/debian bullseye-backports main
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
deb [arch=armhf] http://deb.debian.org/debian buster main contrib non-free
|
deb [arch=armhf] http://deb.debian.org/debian bullseye main contrib non-free
|
||||||
deb-src [arch=armhf] http://deb.debian.org/debian buster main contrib non-free
|
deb-src [arch=armhf] http://deb.debian.org/debian bullseye main contrib non-free
|
||||||
deb [arch=armhf] http://deb.debian.org/debian buster-updates main contrib non-free
|
deb [arch=armhf] http://deb.debian.org/debian bullseye-updates main contrib non-free
|
||||||
deb-src [arch=armhf] http://deb.debian.org/debian buster-updates main contrib non-free
|
deb-src [arch=armhf] http://deb.debian.org/debian bullseye-updates main contrib non-free
|
||||||
deb [arch=armhf] http://security.debian.org buster/updates main contrib non-free
|
deb [arch=armhf] http://security.debian.org bullseye-security main contrib non-free
|
||||||
deb-src [arch=armhf] http://security.debian.org buster/updates main contrib non-free
|
deb-src [arch=armhf] http://security.debian.org bullseye-security main contrib non-free
|
||||||
deb [arch=armhf] https://download.docker.com/linux/debian buster stable
|
deb [arch=armhf] https://download.docker.com/linux/debian bullseye stable
|
||||||
deb [arch=armhf] http://ftp.debian.org/debian buster-backports main
|
deb [arch=armhf] http://ftp.debian.org/debian bullseye-backports main
|
||||||
|
|
||||||
|
@ -10,7 +10,6 @@ rtc-sd2405
|
|||||||
ctc5236_switch
|
ctc5236_switch
|
||||||
ctc5236_mdio
|
ctc5236_mdio
|
||||||
ctcmac
|
ctcmac
|
||||||
ctcmac_test
|
|
||||||
ctc5236-mc
|
ctc5236-mc
|
||||||
ctc_wdt
|
ctc_wdt
|
||||||
ehci-ctc
|
ehci-ctc
|
||||||
@ -20,3 +19,4 @@ pwm-ctc
|
|||||||
ext4
|
ext4
|
||||||
overlay
|
overlay
|
||||||
squashfs
|
squashfs
|
||||||
|
mars
|
||||||
|
@ -1 +1,3 @@
|
|||||||
|
KBUILD_EXTRA_SYMBOLS = /sonic/platform/centec-arm64/sonic-platform-modules-e530/pca954x/Module.symvers
|
||||||
|
|
||||||
obj-m := centec_e530_24x2c_platform.o
|
obj-m := centec_e530_24x2c_platform.o
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/platform_data/pca954x.h>
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/kdev_t.h>
|
#include <linux/kdev_t.h>
|
||||||
#include <linux/leds.h>
|
#include <linux/leds.h>
|
||||||
@ -129,7 +128,7 @@ static int e530_24x2c_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio0 = i2c_new_device(i2c_adp_gpio0, &i2c_dev_gpio0);
|
i2c_client_gpio0 = i2c_new_client_device(i2c_adp_gpio0, &i2c_dev_gpio0);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio0))
|
if(IS_INVALID_PTR(i2c_client_gpio0))
|
||||||
{
|
{
|
||||||
i2c_client_gpio0 = NULL;
|
i2c_client_gpio0 = NULL;
|
||||||
@ -145,7 +144,7 @@ static int e530_24x2c_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio1 = i2c_new_device(i2c_adp_gpio1, &i2c_dev_gpio1);
|
i2c_client_gpio1 = i2c_new_client_device(i2c_adp_gpio1, &i2c_dev_gpio1);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio1))
|
if(IS_INVALID_PTR(i2c_client_gpio1))
|
||||||
{
|
{
|
||||||
i2c_client_gpio1 = NULL;
|
i2c_client_gpio1 = NULL;
|
||||||
@ -161,7 +160,7 @@ static int e530_24x2c_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio2 = i2c_new_device(i2c_adp_gpio2, &i2c_dev_gpio2);
|
i2c_client_gpio2 = i2c_new_client_device(i2c_adp_gpio2, &i2c_dev_gpio2);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio2))
|
if(IS_INVALID_PTR(i2c_client_gpio2))
|
||||||
{
|
{
|
||||||
i2c_client_gpio2 = NULL;
|
i2c_client_gpio2 = NULL;
|
||||||
|
@ -1 +1,3 @@
|
|||||||
|
KBUILD_EXTRA_SYMBOLS = /sonic/platform/centec-arm64/sonic-platform-modules-e530/pca954x/Module.symvers
|
||||||
|
|
||||||
obj-m := centec_e530_24x2q_platform.o
|
obj-m := centec_e530_24x2q_platform.o
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/platform_data/pca954x.h>
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/kdev_t.h>
|
#include <linux/kdev_t.h>
|
||||||
#include <linux/leds.h>
|
#include <linux/leds.h>
|
||||||
@ -129,7 +128,7 @@ static int e530_24x2q_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio0 = i2c_new_device(i2c_adp_gpio0, &i2c_dev_gpio0);
|
i2c_client_gpio0 = i2c_new_client_device(i2c_adp_gpio0, &i2c_dev_gpio0);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio0))
|
if(IS_INVALID_PTR(i2c_client_gpio0))
|
||||||
{
|
{
|
||||||
i2c_client_gpio0 = NULL;
|
i2c_client_gpio0 = NULL;
|
||||||
@ -145,7 +144,7 @@ static int e530_24x2q_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio1 = i2c_new_device(i2c_adp_gpio1, &i2c_dev_gpio1);
|
i2c_client_gpio1 = i2c_new_client_device(i2c_adp_gpio1, &i2c_dev_gpio1);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio1))
|
if(IS_INVALID_PTR(i2c_client_gpio1))
|
||||||
{
|
{
|
||||||
i2c_client_gpio1 = NULL;
|
i2c_client_gpio1 = NULL;
|
||||||
@ -161,7 +160,7 @@ static int e530_24x2q_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio2 = i2c_new_device(i2c_adp_gpio2, &i2c_dev_gpio2);
|
i2c_client_gpio2 = i2c_new_client_device(i2c_adp_gpio2, &i2c_dev_gpio2);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio2))
|
if(IS_INVALID_PTR(i2c_client_gpio2))
|
||||||
{
|
{
|
||||||
i2c_client_gpio2 = NULL;
|
i2c_client_gpio2 = NULL;
|
||||||
|
@ -1 +1,3 @@
|
|||||||
|
KBUILD_EXTRA_SYMBOLS = /sonic/platform/centec-arm64/sonic-platform-modules-e530/pca954x/Module.symvers
|
||||||
|
|
||||||
obj-m := centec_e530_48s4x_platform.o
|
obj-m := centec_e530_48s4x_platform.o
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/platform_data/pca954x.h>
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/kdev_t.h>
|
#include <linux/kdev_t.h>
|
||||||
#include <linux/leds.h>
|
#include <linux/leds.h>
|
||||||
@ -197,7 +196,7 @@ static int e530_48s4x_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio0 = i2c_new_device(i2c_adp_gpio0, &i2c_dev_gpio0);
|
i2c_client_gpio0 = i2c_new_client_device(i2c_adp_gpio0, &i2c_dev_gpio0);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio0))
|
if(IS_INVALID_PTR(i2c_client_gpio0))
|
||||||
{
|
{
|
||||||
i2c_client_gpio0 = NULL;
|
i2c_client_gpio0 = NULL;
|
||||||
@ -213,7 +212,7 @@ static int e530_48s4x_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio1 = i2c_new_device(i2c_adp_gpio1, &i2c_dev_gpio1);
|
i2c_client_gpio1 = i2c_new_client_device(i2c_adp_gpio1, &i2c_dev_gpio1);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio1))
|
if(IS_INVALID_PTR(i2c_client_gpio1))
|
||||||
{
|
{
|
||||||
i2c_client_gpio1 = NULL;
|
i2c_client_gpio1 = NULL;
|
||||||
@ -274,7 +273,7 @@ static int e530_48s4x_init_i2c_epld(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_epld = i2c_new_device(i2c_adp_master, &i2c_dev_epld);
|
i2c_client_epld = i2c_new_client_device(i2c_adp_master, &i2c_dev_epld);
|
||||||
if(IS_INVALID_PTR(i2c_client_epld))
|
if(IS_INVALID_PTR(i2c_client_epld))
|
||||||
{
|
{
|
||||||
i2c_client_epld = NULL;
|
i2c_client_epld = NULL;
|
||||||
|
@ -1 +1,3 @@
|
|||||||
|
KBUILD_EXTRA_SYMBOLS = /sonic/platform/centec-arm64/sonic-platform-modules-e530/pca954x/Module.symvers
|
||||||
|
|
||||||
obj-m := centec_e530_48t4x_p_platform.o
|
obj-m := centec_e530_48t4x_p_platform.o
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/platform_data/pca954x.h>
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/kdev_t.h>
|
#include <linux/kdev_t.h>
|
||||||
#include <linux/leds.h>
|
#include <linux/leds.h>
|
||||||
@ -195,7 +194,7 @@ static int e530_48t4x_p_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio0 = i2c_new_device(i2c_adp_gpio0, &i2c_dev_gpio0);
|
i2c_client_gpio0 = i2c_new_client_device(i2c_adp_gpio0, &i2c_dev_gpio0);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio0))
|
if(IS_INVALID_PTR(i2c_client_gpio0))
|
||||||
{
|
{
|
||||||
i2c_client_gpio0 = NULL;
|
i2c_client_gpio0 = NULL;
|
||||||
|
@ -7,20 +7,20 @@ Standards-Version: 3.9.3
|
|||||||
|
|
||||||
Package: platform-modules-e530-48t4x-p
|
Package: platform-modules-e530-48t4x-p
|
||||||
Architecture: arm64
|
Architecture: arm64
|
||||||
Depends: linux-image-4.19.0-12-2-arm64-unsigned
|
Depends: linux-image-5.10.0-8-2-arm64-unsigned
|
||||||
Description: kernel modules for platform devices such as fan, led, sfp
|
Description: kernel modules for platform devices such as fan, led, sfp
|
||||||
|
|
||||||
Package: platform-modules-e530-24x2c
|
Package: platform-modules-e530-24x2c
|
||||||
Architecture: arm64
|
Architecture: arm64
|
||||||
Depends: linux-image-4.19.0-12-2-arm64-unsigned
|
Depends: linux-image-5.10.0-8-2-arm64-unsigned
|
||||||
Description: kernel modules for platform devices such as fan, led, sfp
|
Description: kernel modules for platform devices such as fan, led, sfp
|
||||||
|
|
||||||
Package: platform-modules-e530-48s4x
|
Package: platform-modules-e530-48s4x
|
||||||
Architecture: arm64
|
Architecture: arm64
|
||||||
Depends: linux-image-4.19.0-12-2-arm64-unsigned
|
Depends: linux-image-5.10.0-8-2-arm64-unsigned
|
||||||
Description: kernel modules for platform devices such as fan, led, sfp
|
Description: kernel modules for platform devices such as fan, led, sfp
|
||||||
|
|
||||||
Package: platform-modules-e530-24x2q
|
Package: platform-modules-e530-24x2q
|
||||||
Architecture: arm64
|
Architecture: arm64
|
||||||
Depends: linux-image-4.19.0-12-2-arm64-unsigned
|
Depends: linux-image-5.10.0-8-2-arm64-unsigned
|
||||||
Description: kernel modules for platform devices such as fan, led, sfp
|
Description: kernel modules for platform devices such as fan, led, sfp
|
||||||
|
@ -17,10 +17,6 @@ function install_python_api_package()
|
|||||||
device="/usr/share/sonic/device"
|
device="/usr/share/sonic/device"
|
||||||
platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform)
|
platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform)
|
||||||
|
|
||||||
rv=$(pip2 show sonic-platform > /dev/null 2>/dev/null)
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
rv=$(pip2 install $device/$platform/sonic_platform-1.0-py2-none-any.whl)
|
|
||||||
fi
|
|
||||||
rv=$(pip3 show sonic-platform > /dev/null 2>/dev/null)
|
rv=$(pip3 show sonic-platform > /dev/null 2>/dev/null)
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
rv=$(pip3 install $device/$platform/sonic_platform-1.0-py3-none-any.whl)
|
rv=$(pip3 install $device/$platform/sonic_platform-1.0-py3-none-any.whl)
|
||||||
@ -34,6 +30,7 @@ function load_kernel_modules()
|
|||||||
ifconfig eth0 hw ether $hwaddr
|
ifconfig eth0 hw ether $hwaddr
|
||||||
fi
|
fi
|
||||||
depmod -a
|
depmod -a
|
||||||
|
modprobe ctc-i2c-mux-pca954x
|
||||||
modprobe centec_e530_24x2c_platform
|
modprobe centec_e530_24x2c_platform
|
||||||
modprobe fan-ctc5236
|
modprobe fan-ctc5236
|
||||||
modprobe dal
|
modprobe dal
|
||||||
@ -48,6 +45,7 @@ function remove_kernel_modules()
|
|||||||
modprobe -r dal
|
modprobe -r dal
|
||||||
modprobe -r fan-ctc5236
|
modprobe -r fan-ctc5236
|
||||||
modprobe -r centec_e530_24x2c_platform
|
modprobe -r centec_e530_24x2c_platform
|
||||||
|
modprobe -r ctc-i2c-mux-pca954x
|
||||||
}
|
}
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
|
@ -1,2 +1 @@
|
|||||||
24x2c/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/arm64-centec_e530_24x2c-r0
|
|
||||||
24x2c/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/arm64-centec_e530_24x2c-r0
|
24x2c/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/arm64-centec_e530_24x2c-r0
|
||||||
|
@ -17,10 +17,6 @@ function install_python_api_package()
|
|||||||
device="/usr/share/sonic/device"
|
device="/usr/share/sonic/device"
|
||||||
platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform)
|
platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform)
|
||||||
|
|
||||||
rv=$(pip2 show sonic-platform > /dev/null 2>/dev/null)
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
rv=$(pip2 install $device/$platform/sonic_platform-1.0-py2-none-any.whl)
|
|
||||||
fi
|
|
||||||
rv=$(pip3 show sonic-platform > /dev/null 2>/dev/null)
|
rv=$(pip3 show sonic-platform > /dev/null 2>/dev/null)
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
rv=$(pip3 install $device/$platform/sonic_platform-1.0-py3-none-any.whl)
|
rv=$(pip3 install $device/$platform/sonic_platform-1.0-py3-none-any.whl)
|
||||||
@ -34,6 +30,7 @@ function load_kernel_modules()
|
|||||||
ifconfig eth0 hw ether $hwaddr
|
ifconfig eth0 hw ether $hwaddr
|
||||||
fi
|
fi
|
||||||
depmod -a
|
depmod -a
|
||||||
|
modprobe ctc-i2c-mux-pca954x
|
||||||
modprobe centec_e530_24x2q_platform
|
modprobe centec_e530_24x2q_platform
|
||||||
modprobe fan-ctc5236
|
modprobe fan-ctc5236
|
||||||
modprobe dal
|
modprobe dal
|
||||||
@ -48,6 +45,7 @@ function remove_kernel_modules()
|
|||||||
modprobe -r dal
|
modprobe -r dal
|
||||||
modprobe -r fan-ctc5236
|
modprobe -r fan-ctc5236
|
||||||
modprobe -r centec_e530_24x2q_platform
|
modprobe -r centec_e530_24x2q_platform
|
||||||
|
modprobe -r ctc-i2c-mux-pca954x
|
||||||
}
|
}
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
|
@ -1,2 +1 @@
|
|||||||
24x2q/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/arm64-centec_e530_24x2q-r0
|
|
||||||
24x2q/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/arm64-centec_e530_24x2q-r0
|
24x2q/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/arm64-centec_e530_24x2q-r0
|
||||||
|
@ -17,10 +17,6 @@ function install_python_api_package()
|
|||||||
device="/usr/share/sonic/device"
|
device="/usr/share/sonic/device"
|
||||||
platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform)
|
platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform)
|
||||||
|
|
||||||
rv=$(pip2 show sonic-platform > /dev/null 2>/dev/null)
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
rv=$(pip2 install $device/$platform/sonic_platform-1.0-py2-none-any.whl)
|
|
||||||
fi
|
|
||||||
rv=$(pip3 show sonic-platform > /dev/null 2>/dev/null)
|
rv=$(pip3 show sonic-platform > /dev/null 2>/dev/null)
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
rv=$(pip3 install $device/$platform/sonic_platform-1.0-py3-none-any.whl)
|
rv=$(pip3 install $device/$platform/sonic_platform-1.0-py3-none-any.whl)
|
||||||
@ -34,6 +30,7 @@ function load_kernel_modules()
|
|||||||
ifconfig eth0 hw ether $hwaddr
|
ifconfig eth0 hw ether $hwaddr
|
||||||
fi
|
fi
|
||||||
depmod -a
|
depmod -a
|
||||||
|
modprobe ctc-i2c-mux-pca954x
|
||||||
modprobe centec_e530_48s4x_platform
|
modprobe centec_e530_48s4x_platform
|
||||||
modprobe fan-ctc5236
|
modprobe fan-ctc5236
|
||||||
modprobe dal
|
modprobe dal
|
||||||
@ -48,6 +45,7 @@ function remove_kernel_modules()
|
|||||||
modprobe -r dal
|
modprobe -r dal
|
||||||
modprobe -r fan-ctc5236
|
modprobe -r fan-ctc5236
|
||||||
modprobe -r centec_e530_48s4x_platform
|
modprobe -r centec_e530_48s4x_platform
|
||||||
|
modprobe -r ctc-i2c-mux-pca954x
|
||||||
}
|
}
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
|
@ -1,2 +1 @@
|
|||||||
48s4x/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/arm64-centec_e530_48s4x-r0
|
|
||||||
48s4x/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/arm64-centec_e530_48s4x-r0
|
48s4x/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/arm64-centec_e530_48s4x-r0
|
||||||
|
@ -17,10 +17,6 @@ function install_python_api_package()
|
|||||||
device="/usr/share/sonic/device"
|
device="/usr/share/sonic/device"
|
||||||
platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform)
|
platform=$(/usr/local/bin/sonic-cfggen -H -v DEVICE_METADATA.localhost.platform)
|
||||||
|
|
||||||
rv=$(pip2 show sonic-platform > /dev/null 2>/dev/null)
|
|
||||||
if [ $? -ne 0 ]; then
|
|
||||||
rv=$(pip2 install $device/$platform/sonic_platform-1.0-py2-none-any.whl)
|
|
||||||
fi
|
|
||||||
rv=$(pip3 show sonic-platform > /dev/null 2>/dev/null)
|
rv=$(pip3 show sonic-platform > /dev/null 2>/dev/null)
|
||||||
if [ $? -ne 0 ]; then
|
if [ $? -ne 0 ]; then
|
||||||
rv=$(pip3 install $device/$platform/sonic_platform-1.0-py3-none-any.whl)
|
rv=$(pip3 install $device/$platform/sonic_platform-1.0-py3-none-any.whl)
|
||||||
@ -34,6 +30,7 @@ function load_kernel_modules()
|
|||||||
ifconfig eth0 hw ether $hwaddr
|
ifconfig eth0 hw ether $hwaddr
|
||||||
fi
|
fi
|
||||||
depmod -a
|
depmod -a
|
||||||
|
modprobe ctc-i2c-mux-pca954x
|
||||||
modprobe centec_e530_48t4x_p_platform
|
modprobe centec_e530_48t4x_p_platform
|
||||||
modprobe fan-ctc5236
|
modprobe fan-ctc5236
|
||||||
modprobe dal
|
modprobe dal
|
||||||
@ -48,6 +45,7 @@ function remove_kernel_modules()
|
|||||||
modprobe -r dal
|
modprobe -r dal
|
||||||
modprobe -r fan-ctc5236
|
modprobe -r fan-ctc5236
|
||||||
modprobe -r centec_e530_48t4x_p_platform
|
modprobe -r centec_e530_48t4x_p_platform
|
||||||
|
modprobe -r ctc-i2c-mux-pca954x
|
||||||
}
|
}
|
||||||
|
|
||||||
case "$1" in
|
case "$1" in
|
||||||
|
@ -1,2 +1 @@
|
|||||||
48t4x-p/modules/sonic_platform-1.0-py2-none-any.whl usr/share/sonic/device/arm64-centec_e530_48t4x_p-r0
|
|
||||||
48t4x-p/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/arm64-centec_e530_48t4x_p-r0
|
48t4x-p/modules/sonic_platform-1.0-py3-none-any.whl usr/share/sonic/device/arm64-centec_e530_48t4x_p-r0
|
||||||
|
@ -24,6 +24,7 @@ CLASSES_DIR := classes
|
|||||||
CONF_DIR := conf
|
CONF_DIR := conf
|
||||||
KDAL_DIR := ../../centec/centec-dal/
|
KDAL_DIR := ../../centec/centec-dal/
|
||||||
FAN_DIR := fan
|
FAN_DIR := fan
|
||||||
|
PCA954X_DIR := pca954x
|
||||||
|
|
||||||
%:
|
%:
|
||||||
dh $@
|
dh $@
|
||||||
@ -41,10 +42,12 @@ build:
|
|||||||
(for mod in $(FAN_DIR); do \
|
(for mod in $(FAN_DIR); do \
|
||||||
make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/; \
|
make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/; \
|
||||||
done)
|
done)
|
||||||
|
(for mod in $(PCA954X_DIR); do \
|
||||||
|
make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/; \
|
||||||
|
done)
|
||||||
(for mod in $(MODULE_DIRS); do \
|
(for mod in $(MODULE_DIRS); do \
|
||||||
make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \
|
make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \
|
||||||
cd $${mod}; \
|
cd $${mod}; \
|
||||||
python2.7 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
|
|
||||||
python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
|
python3 setup.py bdist_wheel -d $(MOD_SRC_DIR)/$${mod}/modules; \
|
||||||
cd -; \
|
cd -; \
|
||||||
done)
|
done)
|
||||||
@ -73,6 +76,7 @@ binary-indep:
|
|||||||
cp $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
|
cp $(MOD_SRC_DIR)/$${mod}/$(MODULE_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
|
||||||
cp $(MOD_SRC_DIR)/$(KDAL_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
|
cp $(MOD_SRC_DIR)/$(KDAL_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
|
||||||
cp $(MOD_SRC_DIR)/$(FAN_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
|
cp $(MOD_SRC_DIR)/$(FAN_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
|
||||||
|
cp $(MOD_SRC_DIR)/$(PCA954X_DIR)/*.ko debian/$(PACKAGE_PRE_NAME)-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
|
||||||
cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system/; \
|
cp $(MOD_SRC_DIR)/$${mod}/$(SERVICE_DIR)/*.service debian/$(PACKAGE_PRE_NAME)-$${mod}/lib/systemd/system/; \
|
||||||
done)
|
done)
|
||||||
# Resuming debhelper scripts
|
# Resuming debhelper scripts
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
obj-m := ctc-i2c-mux-pca954x.o
|
@ -0,0 +1,581 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* I2C multiplexer
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
|
||||||
|
* Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
|
||||||
|
*
|
||||||
|
* This module supports the PCA954x and PCA984x series of I2C multiplexer/switch
|
||||||
|
* chips made by NXP Semiconductors.
|
||||||
|
* This includes the:
|
||||||
|
* PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547,
|
||||||
|
* PCA9548, PCA9846, PCA9847, PCA9848 and PCA9849.
|
||||||
|
*
|
||||||
|
* These chips are all controlled via the I2C bus itself, and all have a
|
||||||
|
* single 8-bit register. The upstream "parent" bus fans out to two,
|
||||||
|
* four, or eight downstream busses or channels; which of these
|
||||||
|
* are selected is determined by the chip type and register contents. A
|
||||||
|
* mux can select only one sub-bus at a time; a switch can select any
|
||||||
|
* combination simultaneously.
|
||||||
|
*
|
||||||
|
* Based on:
|
||||||
|
* pca954x.c from Kumar Gala <galak@kernel.crashing.org>
|
||||||
|
* Copyright (C) 2006
|
||||||
|
*
|
||||||
|
* Based on:
|
||||||
|
* pca954x.c from Ken Harrenstien
|
||||||
|
* Copyright (C) 2004 Google, Inc. (Ken Harrenstien)
|
||||||
|
*
|
||||||
|
* Based on:
|
||||||
|
* i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com>
|
||||||
|
* and
|
||||||
|
* pca9540.c from Jean Delvare <jdelvare@suse.de>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/i2c-mux.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/pm.h>
|
||||||
|
#include <linux/property.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <dt-bindings/mux/mux.h>
|
||||||
|
#include "ctc-pca954x.h"
|
||||||
|
|
||||||
|
#define PCA954X_MAX_NCHANS 8
|
||||||
|
|
||||||
|
#define PCA954X_IRQ_OFFSET 4
|
||||||
|
|
||||||
|
enum pca_type {
|
||||||
|
pca_9540,
|
||||||
|
pca_9542,
|
||||||
|
pca_9543,
|
||||||
|
pca_9544,
|
||||||
|
pca_9545,
|
||||||
|
pca_9546,
|
||||||
|
pca_9547,
|
||||||
|
pca_9548,
|
||||||
|
pca_9846,
|
||||||
|
pca_9847,
|
||||||
|
pca_9848,
|
||||||
|
pca_9849,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct chip_desc {
|
||||||
|
u8 nchans;
|
||||||
|
u8 enable; /* used for muxes only */
|
||||||
|
u8 has_irq;
|
||||||
|
enum muxtype {
|
||||||
|
pca954x_ismux = 0,
|
||||||
|
pca954x_isswi
|
||||||
|
} muxtype;
|
||||||
|
struct i2c_device_identity id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pca954x {
|
||||||
|
const struct chip_desc *chip;
|
||||||
|
|
||||||
|
u8 last_chan; /* last register value */
|
||||||
|
/* MUX_IDLE_AS_IS, MUX_IDLE_DISCONNECT or >= 0 for channel */
|
||||||
|
s32 idle_state;
|
||||||
|
|
||||||
|
struct i2c_client *client;
|
||||||
|
|
||||||
|
struct irq_domain *irq;
|
||||||
|
unsigned int irq_mask;
|
||||||
|
raw_spinlock_t lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Provide specs for the PCA954x types we know about */
|
||||||
|
static const struct chip_desc chips[] = {
|
||||||
|
[pca_9540] = {
|
||||||
|
.nchans = 2,
|
||||||
|
.enable = 0x4,
|
||||||
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9542] = {
|
||||||
|
.nchans = 2,
|
||||||
|
.enable = 0x4,
|
||||||
|
.has_irq = 1,
|
||||||
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9543] = {
|
||||||
|
.nchans = 2,
|
||||||
|
.has_irq = 1,
|
||||||
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9544] = {
|
||||||
|
.nchans = 4,
|
||||||
|
.enable = 0x4,
|
||||||
|
.has_irq = 1,
|
||||||
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9545] = {
|
||||||
|
.nchans = 4,
|
||||||
|
.has_irq = 1,
|
||||||
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9546] = {
|
||||||
|
.nchans = 4,
|
||||||
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9547] = {
|
||||||
|
.nchans = 8,
|
||||||
|
.enable = 0x8,
|
||||||
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9548] = {
|
||||||
|
.nchans = 8,
|
||||||
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9846] = {
|
||||||
|
.nchans = 4,
|
||||||
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = {
|
||||||
|
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
|
||||||
|
.part_id = 0x10b,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[pca_9847] = {
|
||||||
|
.nchans = 8,
|
||||||
|
.enable = 0x8,
|
||||||
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = {
|
||||||
|
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
|
||||||
|
.part_id = 0x108,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[pca_9848] = {
|
||||||
|
.nchans = 8,
|
||||||
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = {
|
||||||
|
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
|
||||||
|
.part_id = 0x10a,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[pca_9849] = {
|
||||||
|
.nchans = 4,
|
||||||
|
.enable = 0x4,
|
||||||
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = {
|
||||||
|
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
|
||||||
|
.part_id = 0x109,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct i2c_device_id pca954x_id[] = {
|
||||||
|
{ "ctc_pca9540", pca_9540 },
|
||||||
|
{ "ctc_pca9542", pca_9542 },
|
||||||
|
{ "ctc_pca9543", pca_9543 },
|
||||||
|
{ "ctc_pca9544", pca_9544 },
|
||||||
|
{ "ctc_pca9545", pca_9545 },
|
||||||
|
{ "ctc_pca9546", pca_9546 },
|
||||||
|
{ "ctc_pca9547", pca_9547 },
|
||||||
|
{ "ctc_pca9548", pca_9548 },
|
||||||
|
{ "ctc_pca9846", pca_9846 },
|
||||||
|
{ "ctc_pca9847", pca_9847 },
|
||||||
|
{ "ctc_pca9848", pca_9848 },
|
||||||
|
{ "ctc_pca9849", pca_9849 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, pca954x_id);
|
||||||
|
|
||||||
|
static const struct of_device_id pca954x_of_match[] = {
|
||||||
|
{ .compatible = "nxp,ctc_pca9540", .data = &chips[pca_9540] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9542", .data = &chips[pca_9542] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9543", .data = &chips[pca_9543] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9544", .data = &chips[pca_9544] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9545", .data = &chips[pca_9545] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9546", .data = &chips[pca_9546] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9547", .data = &chips[pca_9547] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9548", .data = &chips[pca_9548] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9846", .data = &chips[pca_9846] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9847", .data = &chips[pca_9847] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9848", .data = &chips[pca_9848] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9849", .data = &chips[pca_9849] },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, pca954x_of_match);
|
||||||
|
|
||||||
|
/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
|
||||||
|
for this as they will try to lock adapter a second time */
|
||||||
|
static int pca954x_reg_write(struct i2c_adapter *adap,
|
||||||
|
struct i2c_client *client, u8 val)
|
||||||
|
{
|
||||||
|
union i2c_smbus_data dummy;
|
||||||
|
|
||||||
|
return __i2c_smbus_xfer(adap, client->addr, client->flags,
|
||||||
|
I2C_SMBUS_WRITE, val,
|
||||||
|
I2C_SMBUS_BYTE, &dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 pca954x_regval(struct pca954x *data, u8 chan)
|
||||||
|
{
|
||||||
|
/* We make switches look like muxes, not sure how to be smarter. */
|
||||||
|
if (data->chip->muxtype == pca954x_ismux)
|
||||||
|
return chan | data->chip->enable;
|
||||||
|
else
|
||||||
|
return 1 << chan;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
|
||||||
|
{
|
||||||
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
|
struct i2c_client *client = data->client;
|
||||||
|
u8 regval;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
regval = pca954x_regval(data, chan);
|
||||||
|
/* Only select the channel if its different from the last channel */
|
||||||
|
if (data->last_chan != regval) {
|
||||||
|
ret = pca954x_reg_write(muxc->parent, client, regval);
|
||||||
|
data->last_chan = ret < 0 ? 0 : regval;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
|
||||||
|
{
|
||||||
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
|
struct i2c_client *client = data->client;
|
||||||
|
s32 idle_state;
|
||||||
|
|
||||||
|
idle_state = READ_ONCE(data->idle_state);
|
||||||
|
if (idle_state >= 0)
|
||||||
|
/* Set the mux back to a predetermined channel */
|
||||||
|
return pca954x_select_chan(muxc, idle_state);
|
||||||
|
|
||||||
|
if (idle_state == MUX_IDLE_DISCONNECT) {
|
||||||
|
/* Deselect active channel */
|
||||||
|
data->last_chan = 0;
|
||||||
|
return pca954x_reg_write(muxc->parent, client,
|
||||||
|
data->last_chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* otherwise leave as-is */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t idle_state_show(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||||
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", READ_ONCE(data->idle_state));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t idle_state_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||||
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
|
int val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = kstrtoint(buf, 0, &val);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (val != MUX_IDLE_AS_IS && val != MUX_IDLE_DISCONNECT &&
|
||||||
|
(val < 0 || val >= data->chip->nchans))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
i2c_lock_bus(muxc->parent, I2C_LOCK_SEGMENT);
|
||||||
|
|
||||||
|
WRITE_ONCE(data->idle_state, val);
|
||||||
|
/*
|
||||||
|
* Set the mux into a state consistent with the new
|
||||||
|
* idle_state.
|
||||||
|
*/
|
||||||
|
if (data->last_chan || val != MUX_IDLE_DISCONNECT)
|
||||||
|
ret = pca954x_deselect_mux(muxc, 0);
|
||||||
|
|
||||||
|
i2c_unlock_bus(muxc->parent, I2C_LOCK_SEGMENT);
|
||||||
|
|
||||||
|
return ret < 0 ? ret : count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RW(idle_state);
|
||||||
|
|
||||||
|
static irqreturn_t pca954x_irq_handler(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct pca954x *data = dev_id;
|
||||||
|
unsigned long pending;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
ret = i2c_smbus_read_byte(data->client);
|
||||||
|
if (ret < 0)
|
||||||
|
return IRQ_NONE;
|
||||||
|
|
||||||
|
pending = (ret >> PCA954X_IRQ_OFFSET) & (BIT(data->chip->nchans) - 1);
|
||||||
|
for_each_set_bit(i, &pending, data->chip->nchans)
|
||||||
|
handle_nested_irq(irq_linear_revmap(data->irq, i));
|
||||||
|
|
||||||
|
return IRQ_RETVAL(pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type)
|
||||||
|
{
|
||||||
|
if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_LOW)
|
||||||
|
return -EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct irq_chip pca954x_irq_chip = {
|
||||||
|
.name = "i2c-mux-pca954x",
|
||||||
|
.irq_set_type = pca954x_irq_set_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pca954x_irq_setup(struct i2c_mux_core *muxc)
|
||||||
|
{
|
||||||
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
|
struct i2c_client *client = data->client;
|
||||||
|
int c, irq;
|
||||||
|
|
||||||
|
if (!data->chip->has_irq || client->irq <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
raw_spin_lock_init(&data->lock);
|
||||||
|
|
||||||
|
data->irq = irq_domain_add_linear(client->dev.of_node,
|
||||||
|
data->chip->nchans,
|
||||||
|
&irq_domain_simple_ops, data);
|
||||||
|
if (!data->irq)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
for (c = 0; c < data->chip->nchans; c++) {
|
||||||
|
irq = irq_create_mapping(data->irq, c);
|
||||||
|
if (!irq) {
|
||||||
|
dev_err(&client->dev, "failed irq create map\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
irq_set_chip_data(irq, data);
|
||||||
|
irq_set_chip_and_handler(irq, &pca954x_irq_chip,
|
||||||
|
handle_simple_irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pca954x_cleanup(struct i2c_mux_core *muxc)
|
||||||
|
{
|
||||||
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
|
int c, irq;
|
||||||
|
|
||||||
|
if (data->irq) {
|
||||||
|
for (c = 0; c < data->chip->nchans; c++) {
|
||||||
|
irq = irq_find_mapping(data->irq, c);
|
||||||
|
irq_dispose_mapping(irq);
|
||||||
|
}
|
||||||
|
irq_domain_remove(data->irq);
|
||||||
|
}
|
||||||
|
i2c_mux_del_adapters(muxc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca954x_init(struct i2c_client *client, struct pca954x *data)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (data->idle_state >= 0)
|
||||||
|
data->last_chan = pca954x_regval(data, data->idle_state);
|
||||||
|
else
|
||||||
|
data->last_chan = 0; /* Disconnect multiplexer */
|
||||||
|
|
||||||
|
ret = i2c_smbus_write_byte(client, data->last_chan);
|
||||||
|
if (ret < 0)
|
||||||
|
data->last_chan = 0;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I2C init/probing/exit functions
|
||||||
|
*/
|
||||||
|
static int pca954x_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct i2c_adapter *adap = client->adapter;
|
||||||
|
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||||
|
struct device *dev = &client->dev;
|
||||||
|
struct gpio_desc *gpio;
|
||||||
|
int num, force, class;
|
||||||
|
struct i2c_mux_core *muxc;
|
||||||
|
struct pca954x *data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
muxc = i2c_mux_alloc(adap, dev, PCA954X_MAX_NCHANS, sizeof(*data), 0,
|
||||||
|
pca954x_select_chan, pca954x_deselect_mux);
|
||||||
|
if (!muxc)
|
||||||
|
return -ENOMEM;
|
||||||
|
data = i2c_mux_priv(muxc);
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, muxc);
|
||||||
|
data->client = client;
|
||||||
|
|
||||||
|
/* Reset the mux if a reset GPIO is specified. */
|
||||||
|
gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
|
||||||
|
if (IS_ERR(gpio))
|
||||||
|
return PTR_ERR(gpio);
|
||||||
|
if (gpio) {
|
||||||
|
udelay(1);
|
||||||
|
gpiod_set_value_cansleep(gpio, 0);
|
||||||
|
/* Give the chip some time to recover. */
|
||||||
|
udelay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->chip = device_get_match_data(dev);
|
||||||
|
if (!data->chip)
|
||||||
|
data->chip = &chips[id->driver_data];
|
||||||
|
|
||||||
|
if (data->chip->id.manufacturer_id != I2C_DEVICE_ID_NONE) {
|
||||||
|
struct i2c_device_identity id;
|
||||||
|
|
||||||
|
ret = i2c_get_device_id(client, &id);
|
||||||
|
if (ret && ret != -EOPNOTSUPP)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (!ret &&
|
||||||
|
(id.manufacturer_id != data->chip->id.manufacturer_id ||
|
||||||
|
id.part_id != data->chip->id.part_id)) {
|
||||||
|
dev_warn(dev, "unexpected device id %03x-%03x-%x\n",
|
||||||
|
id.manufacturer_id, id.part_id,
|
||||||
|
id.die_revision);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data->idle_state = MUX_IDLE_AS_IS;
|
||||||
|
if (device_property_read_u32(dev, "idle-state", &data->idle_state)) {
|
||||||
|
if (device_property_read_bool(dev, "i2c-mux-idle-disconnect"))
|
||||||
|
data->idle_state = MUX_IDLE_DISCONNECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the mux register at addr to verify
|
||||||
|
* that the mux is in fact present. This also
|
||||||
|
* initializes the mux to a channel
|
||||||
|
* or disconnected state.
|
||||||
|
*/
|
||||||
|
ret = pca954x_init(client, data);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_warn(dev, "probe failed\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = pca954x_irq_setup(muxc);
|
||||||
|
if (ret)
|
||||||
|
goto fail_cleanup;
|
||||||
|
|
||||||
|
/* Now create an adapter for each channel */
|
||||||
|
for (num = 0; num < data->chip->nchans; num++) {
|
||||||
|
force = 0; /* dynamic adap number */
|
||||||
|
class = 0; /* no class by default */
|
||||||
|
if (pdata) {
|
||||||
|
if (num < pdata->num_modes) {
|
||||||
|
/* force static number */
|
||||||
|
force = pdata->modes[num].adap_id;
|
||||||
|
class = pdata->modes[num].class;
|
||||||
|
} else
|
||||||
|
/* discard unconfigured channels */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i2c_mux_add_adapter(muxc, force, num, class);
|
||||||
|
if (ret)
|
||||||
|
goto fail_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->irq) {
|
||||||
|
ret = devm_request_threaded_irq(dev, data->client->irq,
|
||||||
|
NULL, pca954x_irq_handler,
|
||||||
|
IRQF_ONESHOT | IRQF_SHARED,
|
||||||
|
"pca954x", data);
|
||||||
|
if (ret)
|
||||||
|
goto fail_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The attr probably isn't going to be needed in most cases,
|
||||||
|
* so don't fail completely on error.
|
||||||
|
*/
|
||||||
|
device_create_file(dev, &dev_attr_idle_state);
|
||||||
|
|
||||||
|
dev_info(dev, "registered %d multiplexed busses for I2C %s %s\n",
|
||||||
|
num, data->chip->muxtype == pca954x_ismux
|
||||||
|
? "mux" : "switch", client->name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail_cleanup:
|
||||||
|
pca954x_cleanup(muxc);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca954x_remove(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
device_remove_file(&client->dev, &dev_attr_idle_state);
|
||||||
|
|
||||||
|
pca954x_cleanup(muxc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static int pca954x_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||||
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = pca954x_init(client, data);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(&client->dev, "failed to verify mux presence\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(pca954x_pm, NULL, pca954x_resume);
|
||||||
|
|
||||||
|
static struct i2c_driver pca954x_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "ctc_pca954x",
|
||||||
|
.pm = &pca954x_pm,
|
||||||
|
.of_match_table = pca954x_of_match,
|
||||||
|
},
|
||||||
|
.probe = pca954x_probe,
|
||||||
|
.remove = pca954x_remove,
|
||||||
|
.id_table = pca954x_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_i2c_driver(pca954x_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
|
||||||
|
MODULE_DESCRIPTION("PCA954x I2C mux/switch driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* pca954x.h - I2C multiplexer/switch support
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2009 Rodolfo Giometti <giometti@xxxxxxxx>
|
||||||
|
* Copyright (c) 2008-2009 Eurotech S.p.A. <info@xxxxxxxxxxx>
|
||||||
|
* Michael Lawnick <michael.lawnick.ext@xxxxxxx>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _LINUX_I2C_PCA954X_H
|
||||||
|
#define _LINUX_I2C_PCA954X_H
|
||||||
|
|
||||||
|
/* Platform data for the PCA954x I2C multiplexers */
|
||||||
|
|
||||||
|
/* Per channel initialisation data:
|
||||||
|
* @adap_id: bus number for the adapter. 0 = don't care
|
||||||
|
* @deselect_on_exit: set this entry to 1, if your H/W needs deselection
|
||||||
|
* of this channel after transaction.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct pca954x_platform_mode {
|
||||||
|
int adap_id;
|
||||||
|
unsigned int deselect_on_exit:1;
|
||||||
|
unsigned int class;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Per mux/switch data, used with i2c_register_board_info */
|
||||||
|
struct pca954x_platform_data {
|
||||||
|
struct pca954x_platform_mode *modes;
|
||||||
|
int num_modes;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _LINUX_I2C_PCA954X_H */
|
@ -12,7 +12,7 @@
|
|||||||
images {
|
images {
|
||||||
kernel_ctc {
|
kernel_ctc {
|
||||||
description = "ARM64 Kernel";
|
description = "ARM64 Kernel";
|
||||||
data = /incbin/("./vmlinuz-4.19.0-12-2-arm64");
|
data = /incbin/("./vmlinuz-5.10.0-8-2-arm64");
|
||||||
type = "kernel";
|
type = "kernel";
|
||||||
arch = "arm64";
|
arch = "arm64";
|
||||||
os = "linux";
|
os = "linux";
|
||||||
@ -25,7 +25,7 @@
|
|||||||
};
|
};
|
||||||
initramfs {
|
initramfs {
|
||||||
description = "initramfs";
|
description = "initramfs";
|
||||||
data = /incbin/("./initrd.img-4.19.0-12-2-arm64");
|
data = /incbin/("./initrd.img-5.10.0-8-2-arm64");
|
||||||
type = "ramdisk";
|
type = "ramdisk";
|
||||||
arch = "arm64";
|
arch = "arm64";
|
||||||
os = "linux";
|
os = "linux";
|
||||||
|
@ -7,5 +7,5 @@ Standards-Version: 3.9.3
|
|||||||
|
|
||||||
Package: tsingma-bsp
|
Package: tsingma-bsp
|
||||||
Architecture: arm64
|
Architecture: arm64
|
||||||
Depends: linux-image-4.19.0-12-2-arm64-unsigned
|
Depends: linux-image-5.10.0-8-2-arm64-unsigned
|
||||||
Description: kernel modules for tsingma bsp
|
Description: kernel modules for tsingma bsp
|
||||||
|
2
platform/centec-arm64/tsingma-bsp/debian/rules
Normal file → Executable file
2
platform/centec-arm64/tsingma-bsp/debian/rules
Normal file → Executable file
@ -15,7 +15,7 @@ PACKAGE_PRE_NAME := tsingma-bsp
|
|||||||
KVERSION ?= $(shell uname -r)
|
KVERSION ?= $(shell uname -r)
|
||||||
KERNEL_SRC := /lib/modules/$(KVERSION)
|
KERNEL_SRC := /lib/modules/$(KVERSION)
|
||||||
MOD_SRC_DIR:= $(shell pwd)
|
MOD_SRC_DIR:= $(shell pwd)
|
||||||
MODULE_DIRS:= ctc5236-mc ctc5236_switch ctcmac ctc_wdt ehci-ctc gpio-ctc i2c-ctc pinctrl-ctc pwm-ctc rtc-sd2405 sdhci-ctc5236 spi-ctc-qspi
|
MODULE_DIRS:= ctc5236-mc ctc5236_switch ctcmac ctc_wdt ehci-ctc gpio-ctc i2c-ctc pinctrl-ctc pwm-ctc rtc-sd2405 sdhci-ctc5236 spi-ctc-qspi ctc-phy
|
||||||
DTS_DIR := ctc-dts
|
DTS_DIR := ctc-dts
|
||||||
MODULE_DIR := src
|
MODULE_DIR := src
|
||||||
UTILS_DIR := utils
|
UTILS_DIR := utils
|
||||||
|
@ -1,17 +1,17 @@
|
|||||||
src/ctc5236-mc/ctc5236-mc.ko /lib/modules/4.19.0-12-2-arm64/kernel/extra
|
src/ctc5236-mc/ctc5236-mc.ko /lib/modules/5.10.0-8-2-arm64/kernel/extra
|
||||||
src/pwm-ctc/pwm-ctc.ko /lib/modules/4.19.0-12-2-arm64/kernel/extra
|
src/pwm-ctc/pwm-ctc.ko /lib/modules/5.10.0-8-2-arm64/kernel/extra
|
||||||
src/ctc5236_switch/ctc5236_switch.ko /lib/modules/4.19.0-12-2-arm64/kernel/extra
|
src/ctc5236_switch/ctc5236_switch.ko /lib/modules/5.10.0-8-2-arm64/kernel/extra
|
||||||
src/pinctrl-ctc/pinctrl-ctc.ko /lib/modules/4.19.0-12-2-arm64/kernel/extra
|
src/pinctrl-ctc/pinctrl-ctc.ko /lib/modules/5.10.0-8-2-arm64/kernel/extra
|
||||||
src/ctc_wdt/ctc_wdt.ko /lib/modules/4.19.0-12-2-arm64/kernel/extra
|
src/ctc_wdt/ctc_wdt.ko /lib/modules/5.10.0-8-2-arm64/kernel/extra
|
||||||
src/ctcmac/ctcmac.ko /lib/modules/4.19.0-12-2-arm64/kernel/extra
|
src/ctcmac/ctcmac.ko /lib/modules/5.10.0-8-2-arm64/kernel/extra
|
||||||
src/ctcmac/ctcmac_test.ko /lib/modules/4.19.0-12-2-arm64/kernel/extra
|
src/ctcmac/ctc5236_mdio.ko /lib/modules/5.10.0-8-2-arm64/kernel/extra
|
||||||
src/ctcmac/ctc5236_mdio.ko /lib/modules/4.19.0-12-2-arm64/kernel/extra
|
src/ctc-phy/mars.ko /lib/modules/5.10.0-8-2-arm64/kernel/extra
|
||||||
src/i2c-ctc/i2c-ctc.ko /lib/modules/4.19.0-12-2-arm64/kernel/extra
|
src/i2c-ctc/i2c-ctc.ko /lib/modules/5.10.0-8-2-arm64/kernel/extra
|
||||||
src/gpio-ctc/gpio-ctc.ko /lib/modules/4.19.0-12-2-arm64/kernel/extra
|
src/gpio-ctc/gpio-ctc.ko /lib/modules/5.10.0-8-2-arm64/kernel/extra
|
||||||
src/ehci-ctc/ehci-ctc.ko /lib/modules/4.19.0-12-2-arm64/kernel/extra
|
src/ehci-ctc/ehci-ctc.ko /lib/modules/5.10.0-8-2-arm64/kernel/extra
|
||||||
src/rtc-sd2405/rtc-sd2405.ko /lib/modules/4.19.0-12-2-arm64/kernel/extra
|
src/rtc-sd2405/rtc-sd2405.ko /lib/modules/5.10.0-8-2-arm64/kernel/extra
|
||||||
src/sdhci-ctc5236/sdhci-ctc5236.ko /lib/modules/4.19.0-12-2-arm64/kernel/extra
|
src/sdhci-ctc5236/sdhci-ctc5236.ko /lib/modules/5.10.0-8-2-arm64/kernel/extra
|
||||||
src/spi-ctc-qspi/spi-ctc-qspi.ko /lib/modules/4.19.0-12-2-arm64/kernel/extra
|
src/spi-ctc-qspi/spi-ctc-qspi.ko /lib/modules/5.10.0-8-2-arm64/kernel/extra
|
||||||
src/ctc-dts/e530-ctc5236.dtb /boot/
|
src/ctc-dts/e530-ctc5236.dtb /boot/
|
||||||
src/config/fw_env.config /etc/
|
src/config/fw_env.config /etc/
|
||||||
src/config/tsingma-bsp.service /lib/systemd/system
|
src/config/tsingma-bsp.service /lib/systemd/system
|
||||||
|
1
platform/centec-arm64/tsingma-bsp/src/ctc-dts/arm-gic.h
Normal file → Executable file
1
platform/centec-arm64/tsingma-bsp/src/ctc-dts/arm-gic.h
Normal file → Executable file
@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
|
||||||
/*
|
/*
|
||||||
* This header provides constants for the ARM GIC.
|
* This header provides constants for the ARM GIC.
|
||||||
*/
|
*/
|
||||||
|
66
platform/centec-arm64/tsingma-bsp/src/ctc-dts/ctc5236.dtsi
Normal file → Executable file
66
platform/centec-arm64/tsingma-bsp/src/ctc-dts/ctc5236.dtsi
Normal file → Executable file
@ -88,7 +88,11 @@
|
|||||||
memory-controller@30600000 {
|
memory-controller@30600000 {
|
||||||
compatible = "ctc,ctc5236-ddr-ctrl";
|
compatible = "ctc,ctc5236-ddr-ctrl";
|
||||||
reg = <0x0 0x30600000 0x0 0x100000>;
|
reg = <0x0 0x30600000 0x0 0x100000>;
|
||||||
interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
|
interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>,
|
||||||
|
<GIC_SPI 100 IRQ_TYPE_EDGE_RISING>,
|
||||||
|
<GIC_SPI 101 IRQ_TYPE_EDGE_RISING>,
|
||||||
|
<GIC_SPI 6 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
ctc,sysctrl = <&sysctrl>;
|
||||||
};
|
};
|
||||||
|
|
||||||
sysctrl: sysctrl@33200000 {
|
sysctrl: sysctrl@33200000 {
|
||||||
@ -136,12 +140,15 @@
|
|||||||
#size-cells = <2>;
|
#size-cells = <2>;
|
||||||
interrupt-parent = <&gic>;
|
interrupt-parent = <&gic>;
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
local-mac-address = [00 00 00 00 00 00];
|
||||||
index = <0x00>;
|
index = <0x00>;
|
||||||
reg = <0x0 0x33410000 0x0 0x10000>,
|
reg = <0x0 0x33410000 0x0 0x10000>,
|
||||||
<0x0 0x33400000 0x0 0x10000>;
|
<0x0 0x33400000 0x0 0x10000>;
|
||||||
interrupts = <GIC_SPI 40 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
|
interrupts = <GIC_SPI 40 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
|
||||||
<GIC_SPI 41 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
|
<GIC_SPI 41 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
|
||||||
<GIC_SPI 44 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
|
<GIC_SPI 44 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
|
||||||
|
<GIC_SPI 136 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
|
||||||
|
<GIC_SPI 102 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
|
||||||
ctc,sysctrl = <&sysctrl>;
|
ctc,sysctrl = <&sysctrl>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -152,12 +159,15 @@
|
|||||||
#size-cells = <2>;
|
#size-cells = <2>;
|
||||||
interrupt-parent = <&gic>;
|
interrupt-parent = <&gic>;
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
|
local-mac-address = [00 00 00 00 00 00];
|
||||||
index = <0x01>;
|
index = <0x01>;
|
||||||
reg = <0x0 0x33420000 0x0 0x10000>,
|
reg = <0x0 0x33420000 0x0 0x10000>,
|
||||||
<0x0 0x33400000 0x0 0x10000>;
|
<0x0 0x33400000 0x0 0x10000>;
|
||||||
interrupts = <GIC_SPI 42 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
|
interrupts = <GIC_SPI 42 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
|
||||||
<GIC_SPI 43 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
|
<GIC_SPI 43 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
|
||||||
<GIC_SPI 44 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
|
<GIC_SPI 44 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
|
||||||
|
<GIC_SPI 137 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>,
|
||||||
|
<GIC_SPI 103 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
|
||||||
ctc,sysctrl = <&sysctrl>;
|
ctc,sysctrl = <&sysctrl>;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -165,6 +175,7 @@
|
|||||||
compatible = "ctc-ehci";
|
compatible = "ctc-ehci";
|
||||||
reg = <0x0 0x30500000 0x0 0x1000>;
|
reg = <0x0 0x30500000 0x0 0x1000>;
|
||||||
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
|
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
|
ctc,sysctrl = <&sysctrl>;
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -172,7 +183,7 @@
|
|||||||
compatible = "generic-ohci";
|
compatible = "generic-ohci";
|
||||||
reg = <0x0 0x30580000 0x0 0x1000>;
|
reg = <0x0 0x30580000 0x0 0x1000>;
|
||||||
interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
|
interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
status = "disabled";
|
status = "okay";
|
||||||
};
|
};
|
||||||
|
|
||||||
spi: spi@33100000 {
|
spi: spi@33100000 {
|
||||||
@ -188,7 +199,7 @@
|
|||||||
status ="disabled";
|
status ="disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
qspi: qspi@10000000 {
|
qspi: spi@10000000 {
|
||||||
compatible = "ctc, igdaxi001a-qspi";
|
compatible = "ctc, igdaxi001a-qspi";
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
@ -228,6 +239,8 @@
|
|||||||
reg = <0x0 0x33700000 0x0 0x1000>;
|
reg = <0x0 0x33700000 0x0 0x1000>;
|
||||||
interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
|
interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
clocks = <&i2c_clk>;
|
clocks = <&i2c_clk>;
|
||||||
|
ctc,sysctrl = <&sysctrl>;
|
||||||
|
i2c-num = <0>;
|
||||||
status ="disabled";
|
status ="disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -238,6 +251,8 @@
|
|||||||
reg = <0x0 0x33701000 0x0 0x1000>;
|
reg = <0x0 0x33701000 0x0 0x1000>;
|
||||||
interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
|
interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
|
||||||
clocks = <&i2c_clk>;
|
clocks = <&i2c_clk>;
|
||||||
|
ctc,sysctrl = <&sysctrl>;
|
||||||
|
i2c-num = <1>;
|
||||||
status ="disabled";
|
status ="disabled";
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -257,7 +272,8 @@
|
|||||||
interrupt-names = "msi","aer","pme";
|
interrupt-names = "msi","aer","pme";
|
||||||
msi-parent = <&pcie>;
|
msi-parent = <&pcie>;
|
||||||
bus-range = <0 0xff>;
|
bus-range = <0 0xff>;
|
||||||
ranges = <0x43000000 0 0x00000000 0 0x40000000 0 0x40000000>;
|
ranges = <0x42000000 0 0x00000000 0 0x40000000 0 0x20000000
|
||||||
|
0x02000000 0 0x20000000 0 0x60000000 0 0x20000000>;
|
||||||
num-lanes = <1>;
|
num-lanes = <1>;
|
||||||
ctc,sysctrl = <&sysctrl>;
|
ctc,sysctrl = <&sysctrl>;
|
||||||
status ="disabled";
|
status ="disabled";
|
||||||
@ -338,6 +354,7 @@
|
|||||||
reg = <0x0 0x33610000 0x0 0x10000>;
|
reg = <0x0 0x33610000 0x0 0x10000>;
|
||||||
#address-cells = <1>;
|
#address-cells = <1>;
|
||||||
#size-cells = <0>;
|
#size-cells = <0>;
|
||||||
|
ctc,sysctrl = <&sysctrl>;
|
||||||
|
|
||||||
porta: gpio-port@0 {
|
porta: gpio-port@0 {
|
||||||
compatible = "ctc,apb-gpio-porta";
|
compatible = "ctc,apb-gpio-porta";
|
||||||
@ -368,7 +385,42 @@
|
|||||||
ctc,pinctrl-bank0 = <16>;
|
ctc,pinctrl-bank0 = <16>;
|
||||||
ctc,pinctrl-bank1 = <8>;
|
ctc,pinctrl-bank1 = <8>;
|
||||||
ctc,sysctrl = <&sysctrl>;
|
ctc,sysctrl = <&sysctrl>;
|
||||||
status = "okay";
|
|
||||||
|
spi0 {
|
||||||
|
spi_pin: spi_pin {
|
||||||
|
ctc,pins = <0 0 PIN_FUNC_SPI>,
|
||||||
|
<0 2 PIN_FUNC_SPI>,
|
||||||
|
<0 3 PIN_FUNC_SPI>,
|
||||||
|
<0 4 PIN_FUNC_SPI>,
|
||||||
|
<0 5 PIN_FUNC_SPI>,
|
||||||
|
<0 6 PIN_FUNC_SPI>,
|
||||||
|
<0 7 PIN_FUNC_SPI>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
uart2 {
|
||||||
|
uart2_pin: uart2_pin {
|
||||||
|
ctc,pins = <0 10 PIN_FUNC_UART>,
|
||||||
|
<0 11 PIN_FUNC_UART>,
|
||||||
|
<0 12 PIN_FUNC_UART>,
|
||||||
|
<0 13 PIN_FUNC_UART>,
|
||||||
|
<0 14 PIN_FUNC_UART>,
|
||||||
|
<0 15 PIN_FUNC_UART>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
fc {
|
||||||
|
fc_pin: fc_pin {
|
||||||
|
ctc,pins = <1 0 PIN_FUNC_FC>,
|
||||||
|
<1 1 PIN_FUNC_FC>,
|
||||||
|
<1 2 PIN_FUNC_FC>,
|
||||||
|
<1 3 PIN_FUNC_FC>,
|
||||||
|
<1 4 PIN_FUNC_FC>,
|
||||||
|
<1 5 PIN_FUNC_FC>,
|
||||||
|
<1 6 PIN_FUNC_FC>,
|
||||||
|
<1 7 PIN_FUNC_FC>;
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -157,6 +157,7 @@
|
|||||||
non-removable;
|
non-removable;
|
||||||
no-sd;
|
no-sd;
|
||||||
no-sdio;
|
no-sdio;
|
||||||
|
cap-mmc-hw-reset;
|
||||||
voltage-ranges = <3300 3300>;
|
voltage-ranges = <3300 3300>;
|
||||||
status = "okay";
|
status = "okay";
|
||||||
};
|
};
|
||||||
@ -187,7 +188,7 @@
|
|||||||
|
|
||||||
|
|
||||||
&pinctrl {
|
&pinctrl {
|
||||||
spi {
|
spi0 {
|
||||||
spi_pin: spi_pin {
|
spi_pin: spi_pin {
|
||||||
status = "disabled";
|
status = "disabled";
|
||||||
ctc,pins = <0 0 PIN_FUNC_SPI>,
|
ctc,pins = <0 0 PIN_FUNC_SPI>,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 OR MIT */
|
||||||
/*
|
/*
|
||||||
* This header provides constants for most IRQ bindings.
|
* This header provides constants for most IRQ bindings.
|
||||||
*
|
*
|
||||||
|
1
platform/centec-arm64/tsingma-bsp/src/ctc-phy/Makefile
Normal file
1
platform/centec-arm64/tsingma-bsp/src/ctc-phy/Makefile
Normal file
@ -0,0 +1 @@
|
|||||||
|
obj-m = mars.o
|
316
platform/centec-arm64/tsingma-bsp/src/ctc-phy/mars.c
Normal file
316
platform/centec-arm64/tsingma-bsp/src/ctc-phy/mars.c
Normal file
@ -0,0 +1,316 @@
|
|||||||
|
/*
|
||||||
|
* drivers/net/phy/mars.c
|
||||||
|
*
|
||||||
|
* Driver for Centec PHYs
|
||||||
|
*
|
||||||
|
* Author: liuht
|
||||||
|
*
|
||||||
|
* Copyright 2002-2018, Centec Networks (Suzhou) Co., Ltd.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/string.h>
|
||||||
|
#include <linux/errno.h>
|
||||||
|
#include <linux/unistd.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/netdevice.h>
|
||||||
|
#include <linux/etherdevice.h>
|
||||||
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/mii.h>
|
||||||
|
#include <linux/ethtool.h>
|
||||||
|
#include <linux/phy.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
|
||||||
|
#include <linux/io.h>
|
||||||
|
#include <asm/irq.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
|
||||||
|
/* Mask used for ID comparisons */
|
||||||
|
#define CTC_PHY_ID_MASK 0xffffffff
|
||||||
|
|
||||||
|
/* Known PHY IDs */
|
||||||
|
#define CTC_PHY_ID_MARS1S_V1 0x00782013
|
||||||
|
#define CTC_PHY_ID_MARS1S 0x01E04013
|
||||||
|
#define CTC_PHY_ID_MARS1P_V1 0x00782011
|
||||||
|
#define CTC_PHY_ID_MARS1P 0x01E04011
|
||||||
|
#define CTC_PHY_IMASK 0x12
|
||||||
|
#define CTC_PHY_IEVENT 0x13
|
||||||
|
|
||||||
|
#define CTC_PHY_IMASK_INIT 0x6c00
|
||||||
|
#define CTC_PHY_IMASK_CLEAR 0x0000
|
||||||
|
|
||||||
|
#define CTC_PHY_REG_SPACE 0
|
||||||
|
#define CTC_SDS_REG_SPACE 1
|
||||||
|
|
||||||
|
static int mars_ext_read(struct phy_device *phydev, u32 regnum)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = phy_write(phydev, 0x1e, regnum);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return phy_read(phydev, 0x1f);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mars_ext_write(struct phy_device *phydev, u32 regnum, u16 val)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = phy_write(phydev, 0x1e, regnum);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return phy_write(phydev, 0x1f, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mars_select_reg_space(struct phy_device *phydev, int space)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (space == CTC_PHY_REG_SPACE) {
|
||||||
|
ret = mars_ext_write(phydev, 0xa000, 0x0);
|
||||||
|
} else {
|
||||||
|
ret = mars_ext_write(phydev, 0xa000, 0x2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mars_config_advert(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
int err, bmsr, changed = 0;
|
||||||
|
u32 adv;
|
||||||
|
|
||||||
|
/* Only allow advertising what this PHY supports */
|
||||||
|
linkmode_and(phydev->advertising, phydev->advertising,
|
||||||
|
phydev->supported);
|
||||||
|
|
||||||
|
adv = linkmode_adv_to_mii_adv_t(phydev->advertising);
|
||||||
|
|
||||||
|
/* Setup standard advertisement */
|
||||||
|
err = phy_modify_changed(phydev, MII_ADVERTISE,
|
||||||
|
ADVERTISE_ALL | ADVERTISE_100BASE4 |
|
||||||
|
ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM,
|
||||||
|
adv);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
if (err > 0)
|
||||||
|
changed = 1;
|
||||||
|
|
||||||
|
bmsr = phy_read(phydev, MII_BMSR);
|
||||||
|
if (bmsr < 0)
|
||||||
|
return bmsr;
|
||||||
|
|
||||||
|
/* Per 802.3-2008, Section 22.2.4.2.16 Extended status all
|
||||||
|
* 1000Mbits/sec capable PHYs shall have the BMSR_ESTATEN bit set to a
|
||||||
|
* logical 1.
|
||||||
|
*/
|
||||||
|
if (!(bmsr & BMSR_ESTATEN))
|
||||||
|
return changed;
|
||||||
|
|
||||||
|
adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
|
||||||
|
|
||||||
|
err = phy_modify_changed(phydev, MII_CTRL1000,
|
||||||
|
ADVERTISE_1000FULL | ADVERTISE_1000HALF, adv);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
if (err > 0)
|
||||||
|
changed = 1;
|
||||||
|
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mars1s_config_aneg(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
int err, changed = 0;
|
||||||
|
|
||||||
|
if (AUTONEG_ENABLE != phydev->autoneg)
|
||||||
|
return genphy_setup_forced(phydev);
|
||||||
|
|
||||||
|
err = mars_config_advert(phydev);
|
||||||
|
if (err < 0) /* error */
|
||||||
|
return err;
|
||||||
|
|
||||||
|
changed |= err;
|
||||||
|
|
||||||
|
if (changed == 0) {
|
||||||
|
/* Advertisement hasn't changed, but maybe aneg was never on to
|
||||||
|
* begin with? Or maybe phy was isolated?
|
||||||
|
*/
|
||||||
|
int ctl = phy_read(phydev, MII_BMCR);
|
||||||
|
|
||||||
|
if (ctl < 0)
|
||||||
|
return ctl;
|
||||||
|
|
||||||
|
if (!(ctl & BMCR_ANENABLE) || (ctl & BMCR_ISOLATE))
|
||||||
|
changed = 1; /* do restart aneg */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only restart aneg if we are advertising something different
|
||||||
|
* than we were before.
|
||||||
|
*/
|
||||||
|
if (changed > 0)
|
||||||
|
return genphy_restart_aneg(phydev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mars_ack_interrupt(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
/* Clear the interrupts by reading the reg */
|
||||||
|
err = phy_read(phydev, CTC_PHY_IEVENT);
|
||||||
|
#else
|
||||||
|
err = mars_ext_read(phydev, 0xa011);
|
||||||
|
#endif
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mars_config_intr(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
|
||||||
|
err = phy_write(phydev, CTC_PHY_IMASK, CTC_PHY_IMASK_INIT);
|
||||||
|
else
|
||||||
|
err = phy_write(phydev, CTC_PHY_IMASK, CTC_PHY_IMASK_CLEAR);
|
||||||
|
#else
|
||||||
|
if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
|
||||||
|
err = mars_ext_write(phydev, 0xa010, 0xffff);
|
||||||
|
else
|
||||||
|
err = mars_ext_write(phydev, 0xa010, 0x0000);
|
||||||
|
#endif
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static int mars_set_link_timer_6_3ms(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = mars_select_reg_space(phydev, CTC_SDS_REG_SPACE);
|
||||||
|
if (!ret)
|
||||||
|
mars_ext_write(phydev, 0xa5, 0xc);
|
||||||
|
mars_select_reg_space(phydev, CTC_PHY_REG_SPACE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int mars_set_link_timer_2_6ms(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
ret = mars_select_reg_space(phydev, CTC_SDS_REG_SPACE);
|
||||||
|
if (!ret)
|
||||||
|
mars_ext_write(phydev, 0xa5, 0x5);
|
||||||
|
mars_select_reg_space(phydev, CTC_PHY_REG_SPACE);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mars_config_init(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
return mars_set_link_timer_2_6ms(phydev);
|
||||||
|
}
|
||||||
|
|
||||||
|
int mars1p_config_init(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
/*RGMII clock 2.5M when link down, bit12:1->0 */
|
||||||
|
mars_ext_write(phydev, 0xc, 0x8051);
|
||||||
|
/*Disable sleep mode, bit15:1->0 */
|
||||||
|
mars_ext_write(phydev, 0x27, 0x2029);
|
||||||
|
/* disable PHY to respond to MDIO access with PHYAD0 */
|
||||||
|
/* MMD7 8001h: bit6: 0, change value: 0x7f --> 0x3f */
|
||||||
|
phy_write(phydev, 0xd, 0x7);
|
||||||
|
phy_write(phydev, 0xe, 0x8001);
|
||||||
|
phy_write(phydev, 0xd, 0x4007);
|
||||||
|
phy_write(phydev, 0xe, 0x3f);
|
||||||
|
|
||||||
|
return mars_set_link_timer_2_6ms(phydev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct phy_driver ctc_drivers[] = {
|
||||||
|
{
|
||||||
|
.phy_id = CTC_PHY_ID_MARS1S,
|
||||||
|
.phy_id_mask = CTC_PHY_ID_MASK,
|
||||||
|
.name = "CTC MARS1S",
|
||||||
|
.config_init = mars_config_init,
|
||||||
|
.features = PHY_GBIT_FEATURES,
|
||||||
|
.config_aneg = mars1s_config_aneg,
|
||||||
|
.ack_interrupt = &mars_ack_interrupt,
|
||||||
|
.config_intr = &mars_config_intr,
|
||||||
|
.read_status = genphy_read_status,
|
||||||
|
.suspend = genphy_suspend,
|
||||||
|
.resume = genphy_resume,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.phy_id = CTC_PHY_ID_MARS1S_V1,
|
||||||
|
.phy_id_mask = CTC_PHY_ID_MASK,
|
||||||
|
.name = "CTC MARS1S_V1",
|
||||||
|
.config_init = mars_config_init,
|
||||||
|
.features = PHY_GBIT_FEATURES,
|
||||||
|
.config_aneg = mars1s_config_aneg,
|
||||||
|
.ack_interrupt = &mars_ack_interrupt,
|
||||||
|
.config_intr = &mars_config_intr,
|
||||||
|
.read_status = genphy_read_status,
|
||||||
|
.suspend = genphy_suspend,
|
||||||
|
.resume = genphy_resume,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.phy_id = CTC_PHY_ID_MARS1P,
|
||||||
|
.phy_id_mask = CTC_PHY_ID_MASK,
|
||||||
|
.name = "CTC MARS1P",
|
||||||
|
.config_init = mars1p_config_init,
|
||||||
|
.features = PHY_GBIT_FEATURES,
|
||||||
|
.config_aneg = mars1s_config_aneg,
|
||||||
|
.ack_interrupt = &mars_ack_interrupt,
|
||||||
|
.config_intr = &mars_config_intr,
|
||||||
|
.read_status = genphy_read_status,
|
||||||
|
.suspend = genphy_suspend,
|
||||||
|
.resume = genphy_resume,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.phy_id = CTC_PHY_ID_MARS1P_V1,
|
||||||
|
.phy_id_mask = CTC_PHY_ID_MASK,
|
||||||
|
.name = "CTC MARS1P_V1",
|
||||||
|
.config_init = mars1p_config_init,
|
||||||
|
.features = PHY_GBIT_FEATURES,
|
||||||
|
.config_aneg = mars1s_config_aneg,
|
||||||
|
.ack_interrupt = &mars_ack_interrupt,
|
||||||
|
.config_intr = &mars_config_intr,
|
||||||
|
.read_status = genphy_read_status,
|
||||||
|
.suspend = genphy_suspend,
|
||||||
|
.resume = genphy_resume,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
module_phy_driver(ctc_drivers);
|
||||||
|
|
||||||
|
static struct mdio_device_id __maybe_unused mars_tbl[] = {
|
||||||
|
{CTC_PHY_ID_MARS1S, CTC_PHY_ID_MASK},
|
||||||
|
{CTC_PHY_ID_MARS1S_V1, CTC_PHY_ID_MASK},
|
||||||
|
{CTC_PHY_ID_MARS1P, CTC_PHY_ID_MASK},
|
||||||
|
{CTC_PHY_ID_MARS1P_V1, CTC_PHY_ID_MASK},
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_DEVICE_TABLE(mdio, mars_tbl);
|
254
platform/centec-arm64/tsingma-bsp/src/ctc5236-mc/ctc5236-mc.c
Normal file → Executable file
254
platform/centec-arm64/tsingma-bsp/src/ctc5236-mc/ctc5236-mc.c
Normal file → Executable file
@ -1,4 +1,5 @@
|
|||||||
/* Centec TsingMa Memory Controller Driver
|
/*
|
||||||
|
* Centec TsingMa Memory Contoller Driver
|
||||||
*
|
*
|
||||||
* Author: lius <lius@centecnetworks.com>
|
* Author: lius <lius@centecnetworks.com>
|
||||||
*
|
*
|
||||||
@ -22,22 +23,29 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
|
#include "../include/sysctl.h"
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
|
|
||||||
struct ctc5236_mc {
|
struct ctc5236_mc {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
void __iomem *base;
|
void __iomem *base;
|
||||||
int irq;
|
int irq;
|
||||||
|
int irq1; /* one bit ecc error irq num, only use in TM1.1 */
|
||||||
|
int irq2; /* more than one bit ecc error irq num, only use in TM1.1 */
|
||||||
|
int irq_cache_ecc; /* cache error interrupt */
|
||||||
|
struct regmap *regmap_base;
|
||||||
|
unsigned int soc_ver;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* DDR interrupt enable register */
|
/* DDR interrupt enable register */
|
||||||
#define DDR_ERR_INT_EN 0xF0
|
#define DDR_ERR_INT_EN 0xF0
|
||||||
|
|
||||||
/* DDR interrupt status register */
|
/* DDR interrupt status register */
|
||||||
#define DDR_ERR_INT_STATUS 0xF4
|
#define DDR_ERR_INT_STATUS 0xF4
|
||||||
|
|
||||||
/* over top-bound info register*/
|
/* over top-bound info register*/
|
||||||
#define DDR_ERR_INT_OVER_TOPBOUND_L 0xF8
|
#define DDR_ERR_INT_OVER_TOPBOUND_L 0xF8
|
||||||
#define DDR_ERR_INT_OVER_TOPBOUND_H 0xFC
|
#define DDR_ERR_INT_OVER_TOPBOUND_H 0xFC
|
||||||
|
|
||||||
#define DDR_PORT0_ERR_INT_STATUS 0x1
|
#define DDR_PORT0_ERR_INT_STATUS 0x1
|
||||||
@ -45,15 +53,16 @@ struct ctc5236_mc {
|
|||||||
#define DDR_PORT2_ERR_INT_STATUS 0x3
|
#define DDR_PORT2_ERR_INT_STATUS 0x3
|
||||||
#define DDR_PORT3_ERR_INT_STATUS 0x4
|
#define DDR_PORT3_ERR_INT_STATUS 0x4
|
||||||
#define DDR_ERR_ECC_INT_STATUS 0x10000
|
#define DDR_ERR_ECC_INT_STATUS 0x10000
|
||||||
|
#define DDR_ERR_CRC_INT_STATUS 0x200000
|
||||||
#define DDR_ERR_WR_PORT_REC_UNDERFLOW 0x20000
|
#define DDR_ERR_WR_PORT_REC_UNDERFLOW 0x20000
|
||||||
#define DDR_ERR_WR_PORT_REC_OVERFLOW 0x40000
|
#define DDR_ERR_WR_PORT_REC_OVERFLOW 0x40000
|
||||||
#define DDR_ERR_RD_PORT_REC_UNDERFLOW 0x80000
|
#define DDR_ERR_RD_PORT_REC_UNDERFLOW 0x80000
|
||||||
#define DDR_ERR_RD_PORT_REC_OVERFLOW 0x100000
|
#define DDR_ERR_RD_PORT_REC_OVERFLOW 0x100000
|
||||||
|
|
||||||
#define DDR_PORT0_STATUS 0xB0
|
#define DDR_PORT0_STATUS 0xB0
|
||||||
#define DDR_PORT1_STATUS 0xB4
|
#define DDR_PORT1_STATUS 0xB4
|
||||||
#define DDR_PORT2_STATUS 0xB8
|
#define DDR_PORT2_STATUS 0xB8
|
||||||
#define DDR_PORT3_STATUS 0xBC
|
#define DDR_PORT3_STATUS 0xBC
|
||||||
|
|
||||||
#define DDR_ERR_OVER_TOPBOUND 0x20000
|
#define DDR_ERR_OVER_TOPBOUND 0x20000
|
||||||
#define DDR_ERR_WCMDQ_OVER 0x40000
|
#define DDR_ERR_WCMDQ_OVER 0x40000
|
||||||
@ -76,10 +85,10 @@ struct ctc5236_mc {
|
|||||||
#define DDR_PORT2_BASE 0xB8
|
#define DDR_PORT2_BASE 0xB8
|
||||||
#define DDR_PORT3_BASE 0xBc
|
#define DDR_PORT3_BASE 0xBc
|
||||||
|
|
||||||
#define DDR_PORT0 0
|
#define DDR_PORT0 0
|
||||||
#define DDR_PORT1 1
|
#define DDR_PORT1 1
|
||||||
#define DDR_PORT2 2
|
#define DDR_PORT2 2
|
||||||
#define DDR_PORT3 3
|
#define DDR_PORT3 3
|
||||||
|
|
||||||
static int port_err_status(int status, int port, void *dev_id)
|
static int port_err_status(int status, int port, void *dev_id)
|
||||||
{
|
{
|
||||||
@ -98,53 +107,80 @@ static int port_err_status(int status, int port, void *dev_id)
|
|||||||
temp = (addr_l | (((unsigned long)((addr_h >> 12) & 0x3)) << 32)
|
temp = (addr_l | (((unsigned long)((addr_h >> 12) & 0x3)) << 32)
|
||||||
);
|
);
|
||||||
|
|
||||||
pr_emerg("ERROR:port%d is out of top-bound range!\n"
|
printk(KERN_EMERG
|
||||||
"The error address is 0x%p\n",
|
"ERROR:port%d is out of top-bound range!\n The error address is 0x%p\n",
|
||||||
id, (void *)temp);
|
id, (void *)temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_WCMDQ_OVER)
|
if (status & DDR_ERR_WCMDQ_OVER) {
|
||||||
pr_err("ERROR:port%d write command queue is overflow!\n", id);
|
printk(KERN_ERR
|
||||||
|
"ERROR:port%d write command queue is overflow!\n", id);
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_WCMDQ_UNDER)
|
if (status & DDR_ERR_WCMDQ_UNDER) {
|
||||||
pr_err("ERROR:port%d write command queue is underflow!\n", id);
|
printk(KERN_ERR
|
||||||
|
"ERROR:port%d write command queue is underflow!\n", id);
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_WDATAQ_OVER)
|
if (status & DDR_ERR_WDATAQ_OVER) {
|
||||||
pr_err("ERROR:port%d write data queue is overflow!\n", id);
|
printk(KERN_ERR "ERROR:port%d write data queue is overflow!\n",
|
||||||
|
id);
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_WDATAQ_UNDER)
|
if (status & DDR_ERR_WDATAQ_UNDER) {
|
||||||
pr_err("ERROR:port%d write data queue is underflow!\n", id);
|
printk(KERN_ERR "ERROR:port%d write data queue is underflow!\n",
|
||||||
|
id);
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_WESPQ_OVER)
|
if (status & DDR_ERR_WESPQ_OVER) {
|
||||||
pr_err("ERROR:port%d write response queue is overflow!\n", id);
|
printk(KERN_ERR
|
||||||
|
"ERROR:port%d write response queue is overflow!\n", id);
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_WESPQ_UNDER)
|
if (status & DDR_ERR_WESPQ_UNDER) {
|
||||||
pr_err("ERROR:port%d write response queue is underflow!\n", id);
|
printk(KERN_ERR
|
||||||
|
"ERROR:port%d write response queue is underflow!\n", id);
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_WINFOQ_OVER)
|
if (status & DDR_ERR_WINFOQ_OVER) {
|
||||||
pr_err("ERROR:port%d write info queue is overflow!\n", id);
|
printk(KERN_ERR "ERROR:port%d write info queue is overflow!\n",
|
||||||
|
id);
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_WINFOQ_UNDER)
|
if (status & DDR_ERR_WINFOQ_UNDER) {
|
||||||
pr_err("ERROR:port%d write info queue is underflow!\n", id);
|
printk(KERN_ERR "ERROR:port%d write info queue is underflow!\n",
|
||||||
|
id);
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_RCMDQ_OVER)
|
if (status & DDR_ERR_RCMDQ_OVER) {
|
||||||
pr_err("ERROR:port%d read command queue is overflow!\n", id);
|
printk(KERN_ERR
|
||||||
|
"ERROR:port%d read command queue is overflow!\n", id);
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_RCMDQ_UNDER)
|
if (status & DDR_ERR_RCMDQ_UNDER) {
|
||||||
pr_err("ERROR:port%d read command queue is underflow!\n", id);
|
printk(KERN_ERR
|
||||||
|
"ERROR:port%d read command queue is underflow!\n", id);
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_RDATAQ_OVER)
|
if (status & DDR_ERR_RDATAQ_OVER) {
|
||||||
pr_err("ERROR:port%d read data queue is overflow!\n", id);
|
printk(KERN_ERR "ERROR:port%d read data queue is overflow!\n",
|
||||||
|
id);
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_RDATAQ_UNDER)
|
if (status & DDR_ERR_RDATAQ_UNDER) {
|
||||||
pr_err("ERROR:port%d read data queue is underflow!\n", id);
|
printk(KERN_ERR "ERROR:port%d read data queue is underflow!\n",
|
||||||
|
id);
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_RESPQ_OVER)
|
if (status & DDR_ERR_RESPQ_OVER) {
|
||||||
pr_err("ERROR:port%d read response queue is overflow!\n", id);
|
printk(KERN_ERR
|
||||||
|
"ERROR:port%d read response queue is overflow!\n", id);
|
||||||
if (status & DDR_ERR_RESPQ_UNDER)
|
}
|
||||||
pr_err("ERROR:port%d read response queue is underflow!\n", id);
|
|
||||||
|
|
||||||
|
if (status & DDR_ERR_RESPQ_UNDER) {
|
||||||
|
printk(KERN_ERR
|
||||||
|
"ERROR:port%d read response queue is underflow!\n", id);
|
||||||
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,20 +213,29 @@ static irqreturn_t ctc_mc_err_handler(int irq, void *dev_id)
|
|||||||
port_err_status(ret, DDR_PORT3, mci);
|
port_err_status(ret, DDR_PORT3, mci);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_ECC_INT_STATUS)
|
if (status & DDR_ERR_ECC_INT_STATUS) {
|
||||||
pr_err("ERROR:The ecc more than 1-bit error !\n");
|
printk(KERN_ERR "ERROR:The ecc more than 1-bit error !\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_WR_PORT_REC_UNDERFLOW)
|
if (status & DDR_ERR_WR_PORT_REC_UNDERFLOW) {
|
||||||
pr_err("ERROR:MPARB wr_port_rec FIFO is underflow!\n");
|
printk(KERN_ERR "ERROR:MPARB wr_port_rec FIFO is underflow!\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_WR_PORT_REC_OVERFLOW)
|
if (status & DDR_ERR_WR_PORT_REC_OVERFLOW) {
|
||||||
pr_err("ERROR:MPARB wr_port_rec FIFO is overflow!\n");
|
printk(KERN_ERR "ERROR:MPARB wr_port_rec FIFO is overflow!\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_RD_PORT_REC_UNDERFLOW)
|
if (status & DDR_ERR_RD_PORT_REC_UNDERFLOW) {
|
||||||
pr_err("ERROR:MPARB rd_port_rec FIFO is underflow!\n");
|
printk(KERN_ERR "ERROR:MPARB rd_port_rec FIFO is underflow!\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (status & DDR_ERR_RD_PORT_REC_OVERFLOW)
|
if (status & DDR_ERR_RD_PORT_REC_OVERFLOW) {
|
||||||
pr_err("ERROR:MPARB rd_port_rec FIFO is underflow!\n");
|
printk(KERN_ERR "ERROR:MPARB rd_port_rec FIFO is overflow!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status & DDR_ERR_CRC_INT_STATUS) {
|
||||||
|
printk(KERN_ERR "ERROR:The crc error from DRAM!\n");
|
||||||
|
}
|
||||||
|
|
||||||
/* disable DDR interrupt */
|
/* disable DDR interrupt */
|
||||||
writel(0x0, mci->base + DDR_ERR_INT_EN);
|
writel(0x0, mci->base + DDR_ERR_INT_EN);
|
||||||
@ -198,6 +243,43 @@ static irqreturn_t ctc_mc_err_handler(int irq, void *dev_id)
|
|||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static irqreturn_t ctc_mc_onebit_ecc_err_handler(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct ctc5236_mc *mci = dev_id;
|
||||||
|
unsigned int val;
|
||||||
|
|
||||||
|
printk(KERN_ERR "ERROR:One-Bit ECC Error!\n");
|
||||||
|
regmap_read(mci->regmap_base,
|
||||||
|
offsetof(struct SysCtl_regs, SysDdrEccCtl), &val);
|
||||||
|
printk(KERN_ERR "One-Bit ECC Error Count is %d\n", ((val >> 8) & 0xf));
|
||||||
|
printk(KERN_ERR "more than One-Bit ECC Error Count is %d\n",
|
||||||
|
((val >> 12) & 0xf));
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t ctc_mc_twobit_ecc_err_handler(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct ctc5236_mc *mci = dev_id;
|
||||||
|
unsigned int val;
|
||||||
|
|
||||||
|
printk(KERN_ERR "ERROR:more than One-Bit ECC Error!\n");
|
||||||
|
regmap_read(mci->regmap_base,
|
||||||
|
offsetof(struct SysCtl_regs, SysDdrEccCtl), &val);
|
||||||
|
printk(KERN_ERR "One-Bit ECC Error Count is %d\n", ((val >> 8) & 0xf));
|
||||||
|
printk(KERN_ERR "more than One-Bit ECC Error Count is %d\n",
|
||||||
|
((val >> 12) & 0xf));
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
static irqreturn_t ctc_cache_err_handler(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
|
||||||
|
printk(KERN_ERR "ERROR:Cache ECC Error!\n");
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct of_device_id ctc5236_ddr_ctrl_of_match[] = {
|
static const struct of_device_id ctc5236_ddr_ctrl_of_match[] = {
|
||||||
{
|
{
|
||||||
.compatible = "ctc,ctc5236-ddr-ctrl",
|
.compatible = "ctc,ctc5236-ddr-ctrl",
|
||||||
@ -212,6 +294,7 @@ static int ctc5236_mc_probe(struct platform_device *pdev)
|
|||||||
const struct of_device_id *id;
|
const struct of_device_id *id;
|
||||||
struct ctc5236_mc *mci;
|
struct ctc5236_mc *mci;
|
||||||
int ret;
|
int ret;
|
||||||
|
unsigned int val;
|
||||||
|
|
||||||
id = of_match_device(ctc5236_ddr_ctrl_of_match, &pdev->dev);
|
id = of_match_device(ctc5236_ddr_ctrl_of_match, &pdev->dev);
|
||||||
if (!id)
|
if (!id)
|
||||||
@ -225,12 +308,67 @@ static int ctc5236_mc_probe(struct platform_device *pdev)
|
|||||||
if (IS_ERR(mci->base))
|
if (IS_ERR(mci->base))
|
||||||
return PTR_ERR(mci->base);
|
return PTR_ERR(mci->base);
|
||||||
|
|
||||||
|
mci->regmap_base =
|
||||||
|
syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "ctc,sysctrl");
|
||||||
|
if (IS_ERR(mci->regmap_base))
|
||||||
|
return PTR_ERR(mci->regmap_base);
|
||||||
|
|
||||||
|
regmap_read(mci->regmap_base,
|
||||||
|
offsetof(struct SysCtl_regs, SysCtlSysRev), &val);
|
||||||
|
mci->soc_ver = val;
|
||||||
|
|
||||||
mci->irq = platform_get_irq(pdev, 0);
|
mci->irq = platform_get_irq(pdev, 0);
|
||||||
ret =
|
ret =
|
||||||
devm_request_irq(&pdev->dev, mci->irq, ctc_mc_err_handler, 0,
|
devm_request_irq(&pdev->dev, mci->irq, ctc_mc_err_handler, 0,
|
||||||
dev_name(&pdev->dev), mci);
|
"DDR Ecc", mci);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(&pdev->dev, "Unable to request irq %d\n", mci->irq);
|
dev_err(&pdev->dev, "Unable to request ddr error irq %d\n",
|
||||||
|
mci->irq);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
val = readl(mci->base);
|
||||||
|
/* register ecc interrupt when use TM1.1 soc and enable ecc function */
|
||||||
|
if ((0x0 != (val & BIT(10))) && (0x1 == mci->soc_ver)) {
|
||||||
|
/* clean ecc status */
|
||||||
|
regmap_write(mci->regmap_base,
|
||||||
|
offsetof(struct SysCtl_regs, SysDdrEccCtl), 0x1);
|
||||||
|
regmap_write(mci->regmap_base,
|
||||||
|
offsetof(struct SysCtl_regs, SysDdrEccCtl), 0x0);
|
||||||
|
|
||||||
|
mci->irq1 = platform_get_irq(pdev, 1);
|
||||||
|
ret =
|
||||||
|
devm_request_irq(&pdev->dev, mci->irq1,
|
||||||
|
ctc_mc_twobit_ecc_err_handler, 0,
|
||||||
|
"DDR two-bit Ecc(TM1.1)", mci);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&pdev->dev,
|
||||||
|
"Unable to request ddr two-bit ecc error irq %d\n",
|
||||||
|
mci->irq1);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
mci->irq2 = platform_get_irq(pdev, 2);
|
||||||
|
ret =
|
||||||
|
devm_request_irq(&pdev->dev, mci->irq2,
|
||||||
|
ctc_mc_onebit_ecc_err_handler, 0,
|
||||||
|
"DDR one-bit Ecc(TM1.1)", mci);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&pdev->dev,
|
||||||
|
"Unable to request one-bit ecc error irq %d\n",
|
||||||
|
mci->irq2);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mci->irq_cache_ecc = platform_get_irq(pdev, 3);
|
||||||
|
ret =
|
||||||
|
devm_request_irq(&pdev->dev, mci->irq_cache_ecc,
|
||||||
|
ctc_cache_err_handler, 0, "Cache Ecc", mci);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(&pdev->dev,
|
||||||
|
"Unable to request cache ecc error irq %d\n",
|
||||||
|
mci->irq_cache_ecc);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -276,4 +414,4 @@ module_exit(ctc5236_mc_exit);
|
|||||||
|
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Centec Network");
|
MODULE_AUTHOR("Centec Network");
|
||||||
MODULE_DESCRIPTION("Centec TsingMa memory controller driver");
|
MODULE_DESCRIPTION("Centec TsingMa memory contoller driver");
|
||||||
|
129
platform/centec-arm64/tsingma-bsp/src/ctc5236_switch/ctc5236_switch.c
Normal file → Executable file
129
platform/centec-arm64/tsingma-bsp/src/ctc5236_switch/ctc5236_switch.c
Normal file → Executable file
@ -1,4 +1,5 @@
|
|||||||
/* (C) Copyright 2004-2017 Centec Networks (suzhou) Co., LTD.
|
/*
|
||||||
|
* (C) Copyright 2004-2017 Centec Networks (suzhou) Co., LTD.
|
||||||
* Wangyb <wangyb@centecnetworks.com>
|
* Wangyb <wangyb@centecnetworks.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: GPL-2.0+
|
* SPDX-License-Identifier: GPL-2.0+
|
||||||
@ -9,15 +10,15 @@
|
|||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <../include/ctc5236_switch.h>
|
#include "../include/ctc5236_switch.h"
|
||||||
|
|
||||||
struct ctc_access_t *access;
|
ctc_access_t *access;
|
||||||
|
|
||||||
#define SWITCH_DTS_OFFSET 0x1000
|
#define SWITCH_DTS_OFFSET 0x1000
|
||||||
|
|
||||||
int ctc5236_switch_read(u32 offset, u32 len, u32 *p_value)
|
int ctc5236_switch_read(u32 offset, u32 len, u32 * p_value)
|
||||||
{
|
{
|
||||||
union ctc_switch_cmd_status_u_t cmd_status_u;
|
ctc_switch_cmd_status_u_t cmd_status_u;
|
||||||
u32 timeout = 0x6400;
|
u32 timeout = 0x6400;
|
||||||
u32 cmd_len = 0;
|
u32 cmd_len = 0;
|
||||||
u8 index = 0;
|
u8 index = 0;
|
||||||
@ -28,8 +29,8 @@ int ctc5236_switch_read(u32 offset, u32 len, u32 *p_value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* switch only have 16 databuf, len must not exceed 16 */
|
/* switch only have 16 databuf, len must not exceed 16 */
|
||||||
if (len > 16 || len == 0) {
|
if ((16 < len) || (0 == len)) {
|
||||||
pr_err("switch read: length error! len = %d\n", len);
|
pr_err("switch read: length error! len = %d \n", len);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* cmdDataLen must be power of 2 */
|
/* cmdDataLen must be power of 2 */
|
||||||
@ -39,22 +40,23 @@ int ctc5236_switch_read(u32 offset, u32 len, u32 *p_value)
|
|||||||
cmd_len = len;
|
cmd_len = len;
|
||||||
do {
|
do {
|
||||||
cmd_len++;
|
cmd_len++;
|
||||||
} while ((cmd_len <= 16) && (cmd_len & (cmd_len - 1)));
|
}
|
||||||
|
while ((cmd_len <= 16) && (cmd_len & (cmd_len - 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 1. write CmdStatusReg */
|
/* 1. write CmdStatusReg */
|
||||||
memset(&cmd_status_u, 0, sizeof(union ctc_switch_cmd_status_u_t));
|
memset(&cmd_status_u, 0, sizeof(ctc_switch_cmd_status_u_t));
|
||||||
cmd_status_u.cmd_status.cmdReadType = 1;
|
cmd_status_u.cmd_status.cmdReadType = 1;
|
||||||
/* normal operate only support 1 entry */
|
cmd_status_u.cmd_status.cmdEntryWords = (len == 16) ? 0 : len; /* normal operate only support 1 entry */
|
||||||
cmd_status_u.cmd_status.cmdEntryWords = (len == 16) ? 0 : len;
|
|
||||||
cmd_status_u.cmd_status.cmdDataLen = len;
|
cmd_status_u.cmd_status.cmdDataLen = len;
|
||||||
writel(cmd_status_u.val, &access->cmd_status);
|
writel(cmd_status_u.val, &access->cmd_status);
|
||||||
/* 2. write AddrReg */
|
/* 2. write AddrReg */
|
||||||
writel(offset, &access->addr);
|
writel(offset, &access->addr);
|
||||||
/* 3. polling status and check */
|
/* 3. polling status and check */
|
||||||
cmd_status_u.val = readl(&access->cmd_status);
|
cmd_status_u.val = readl(&access->cmd_status);
|
||||||
while (!(cmd_status_u.cmd_status.reqProcDone) && (--timeout))
|
while (!(cmd_status_u.cmd_status.reqProcDone) && (--timeout)) {
|
||||||
cmd_status_u.val = readl(&access->cmd_status);
|
cmd_status_u.val = readl(&access->cmd_status);
|
||||||
|
}
|
||||||
/* 4. check cmd done */
|
/* 4. check cmd done */
|
||||||
if (!(cmd_status_u.cmd_status.reqProcDone)) {
|
if (!(cmd_status_u.cmd_status.reqProcDone)) {
|
||||||
pr_err("switch read error! cmd_status = %x\n",
|
pr_err("switch read error! cmd_status = %x\n",
|
||||||
@ -69,15 +71,16 @@ int ctc5236_switch_read(u32 offset, u32 len, u32 *p_value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 6. read data from buffer */
|
/* 6. read data from buffer */
|
||||||
for (index = 0; index < len; index++)
|
for (index = 0; index < len; index++) {
|
||||||
p_value[index] = readl(&access->data[index]);
|
p_value[index] = readl(&access->data[index]);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ctc5236_switch_write(u32 offset, u32 len, u32 *p_value)
|
int ctc5236_switch_write(u32 offset, u32 len, u32 * p_value)
|
||||||
{
|
{
|
||||||
union ctc_switch_cmd_status_u_t cmd_status_u;
|
ctc_switch_cmd_status_u_t cmd_status_u;
|
||||||
u32 timeout = 0x6400; /* need to be confirmed */
|
u32 timeout = 0x6400; /* need to be confirmed */
|
||||||
u32 cmd_len = 0;
|
u32 cmd_len = 0;
|
||||||
u8 index = 0;
|
u8 index = 0;
|
||||||
@ -88,8 +91,8 @@ int ctc5236_switch_write(u32 offset, u32 len, u32 *p_value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* switch only have 16 databuf, len must not exceed 16 */
|
/* switch only have 16 databuf, len must not exceed 16 */
|
||||||
if (len > 16 || len == 0) {
|
if ((16 < len) || (0 == len)) {
|
||||||
pr_err("switch write length error! len = %d\n", len);
|
pr_err("switch write length error! len = %d \n", len);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,28 +103,28 @@ int ctc5236_switch_write(u32 offset, u32 len, u32 *p_value)
|
|||||||
cmd_len = len;
|
cmd_len = len;
|
||||||
do {
|
do {
|
||||||
cmd_len++;
|
cmd_len++;
|
||||||
} while ((cmd_len <= 16) && (cmd_len & (cmd_len - 1)));
|
}
|
||||||
|
while ((cmd_len <= 16) && (cmd_len & (cmd_len - 1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 1. write CmdStatusReg */
|
/* 1. write CmdStatusReg */
|
||||||
memset(&cmd_status_u, 0, sizeof(struct ctc_switch_cmd_status_t));
|
memset(&cmd_status_u, 0, sizeof(ctc_switch_cmd_status_t));
|
||||||
cmd_status_u.cmd_status.cmdReadType = 0;
|
cmd_status_u.cmd_status.cmdReadType = 0;
|
||||||
cmd_status_u.cmd_status.cmdEntryWords = (len == 16) ? 0 : len;
|
cmd_status_u.cmd_status.cmdEntryWords = (len == 16) ? 0 : len;
|
||||||
/* Notice: for 1 entry op, cmdDatalen eq cmdEntryWords,
|
cmd_status_u.cmd_status.cmdDataLen = len; /* Notice: for 1 entry op, cmdDatalen eq cmdEntryWords, but for mutil entry, len = cmd_len */
|
||||||
* but for mutil entry, len = cmd_len
|
|
||||||
*/
|
|
||||||
cmd_status_u.cmd_status.cmdDataLen = len;
|
|
||||||
writel(cmd_status_u.val, &access->cmd_status);
|
writel(cmd_status_u.val, &access->cmd_status);
|
||||||
/* 2. write AddrReg */
|
/* 2. write AddrReg */
|
||||||
writel(offset, &access->addr);
|
writel(offset, &access->addr);
|
||||||
/* 3. write data into databuffer */
|
/* 3. write data into databuffer */
|
||||||
for (index = 0; index < len; index++)
|
for (index = 0; index < len; index++) {
|
||||||
writel(p_value[index], &access->data[index]);
|
writel(p_value[index], &access->data[index]);
|
||||||
|
}
|
||||||
|
|
||||||
/* 4. polling status and check */
|
/* 4. polling status and check */
|
||||||
cmd_status_u.val = readl(&access->cmd_status);
|
cmd_status_u.val = readl(&access->cmd_status);
|
||||||
while (!(cmd_status_u.cmd_status.reqProcDone) && (--timeout))
|
while (!(cmd_status_u.cmd_status.reqProcDone) && (--timeout)) {
|
||||||
cmd_status_u.val = readl(&access->cmd_status);
|
cmd_status_u.val = readl(&access->cmd_status);
|
||||||
|
}
|
||||||
|
|
||||||
/* 5. check cmd done */
|
/* 5. check cmd done */
|
||||||
if (!(cmd_status_u.cmd_status.reqProcDone)) {
|
if (!(cmd_status_u.cmd_status.reqProcDone)) {
|
||||||
@ -141,29 +144,29 @@ int ctc5236_switch_write(u32 offset, u32 len, u32 *p_value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_sys_tsingma_peri_get_temp_with_code(u8 lchip, u32 temp_code, u32 *p_temp_val)
|
_sys_tsingma_peri_get_temp_with_code(u8 lchip, u32 temp_code, u32 * p_temp_val)
|
||||||
{
|
{
|
||||||
u16 temp_mapping_tbl[SYS_TSINGMA_TEMP_TABLE_NUM + 1] = {
|
u16 temp_mapping_tbl[SYS_TSINGMA_TEMP_TABLE_NUM + 1] = {
|
||||||
804, 801, 798, 795, 792, 790, 787, 784, 781, 778,
|
804, 801, 798, 795, 792, 790, 787, 784, 781, 778, 775, 772, 769, 766, 763, 761, 758, 755, 752, 749,
|
||||||
775, 772, 769, 766, 763, 761, 758, 755, 752, 749,
|
/*-40~-21*/
|
||||||
746, 743, 740, 737, 734, 731, 728, 725, 722, 719,
|
746, 743, 740, 737, 734, 731, 728, 725, 722, 719, 717, 714, 711, 708, 705, 702, 699, 696, 693, 690,
|
||||||
717, 714, 711, 708, 705, 702, 699, 696, 693, 690,
|
/*-20~-1*/
|
||||||
687, 684, 681, 678, 675, 672, 669, 666, 663, 660,
|
687, 684, 681, 678, 675, 672, 669, 666, 663, 660, 658, 655, 652, 649, 646, 643, 640, 637, 634, 631, /*0~19 */
|
||||||
658, 655, 652, 649, 646, 643, 640, 637, 634, 631,
|
628, 625, 622, 619, 616, 613, 610, 607, 604, 601, 599, 596, 593, 590, 587, 584, 581, 578, 575, 572, /*20~39 */
|
||||||
628, 625, 622, 619, 616, 613, 610, 607, 604, 601,
|
569, 566, 563, 560, 557, 554, 551, 548, 545, 542, 540, 537, 534, 531, 528, 525, 522, 519, 516, 513, /*40~59 */
|
||||||
599, 596, 593, 590, 587, 584, 581, 578, 575, 572,
|
510, 507, 504, 501, 498, 495, 492, 489, 486, 483, 481, 478, 475, 472, 469, 466, 463, 460, 457, 454, /*60~79 */
|
||||||
569, 566, 563, 560, 557, 554, 551, 548, 545, 542,
|
451, 448, 445, 442, 439, 436, 433, 430, 427, 424, 421, 418, 415, 412, 409, 406, 403, 400, 397, 394, /*80~99 */
|
||||||
540, 537, 534, 531, 528, 525, 522, 519, 516, 513,
|
391, 388, 385, 382, 379, 376, 373, 370, 367, 364, 361, 358, 355, 352, 349, 346, 343, 340, 337, 334, /*100~119 */
|
||||||
510, 507, 504, 501, 498, 495, 492, 489, 486, 483,
|
|
||||||
481, 478, 475, 472, 469, 466, 463, 460, 457, 454,
|
|
||||||
451, 448, 445, 442, 439, 436, 433, 430, 427, 424,
|
|
||||||
421, 418, 415, 412, 409, 406, 403, 400, 397, 394,
|
|
||||||
391, 388, 385, 382, 379, 376, 373, 370, 367, 364,
|
|
||||||
361, 358, 355, 352, 349, 346, 343, 340, 337, 334,
|
|
||||||
331, 328, 325, 322, 319, 316, 0
|
331, 328, 325, 322, 319, 316, 0
|
||||||
};
|
}; /*120~125 */
|
||||||
u8 index = 0;
|
u8 index = 0;
|
||||||
|
|
||||||
|
/*if ((temp_code > temp_mapping_tbl[0]) || (temp_code < temp_mapping_tbl[SYS_TSINGMA_TEMP_TABLE_NUM-1]))
|
||||||
|
{
|
||||||
|
SYS_PERI_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "temp code error %d\n", temp_code);
|
||||||
|
return CTC_E_HW_INVALID_INDEX;
|
||||||
|
} */
|
||||||
|
|
||||||
for (index = 0; index < SYS_TSINGMA_TEMP_TABLE_NUM; index++) {
|
for (index = 0; index < SYS_TSINGMA_TEMP_TABLE_NUM; index++) {
|
||||||
if ((temp_code <= temp_mapping_tbl[index])
|
if ((temp_code <= temp_mapping_tbl[index])
|
||||||
&& (temp_code > temp_mapping_tbl[index + 1])) {
|
&& (temp_code > temp_mapping_tbl[index + 1])) {
|
||||||
@ -171,10 +174,11 @@ _sys_tsingma_peri_get_temp_with_code(u8 lchip, u32 temp_code, u32 *p_temp_val)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index < 39)
|
if (index < 40) {
|
||||||
*p_temp_val = 40 - index + (1 << 31);
|
*p_temp_val = 40 - index + (1 << 31);
|
||||||
else
|
} else {
|
||||||
*p_temp_val = index - 40;
|
*p_temp_val = index - 40;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -189,27 +193,6 @@ int get_switch_temperature(void)
|
|||||||
offset = 0xf * 4;
|
offset = 0xf * 4;
|
||||||
ctc5236_switch_write(OMCMEM_BASE + offset, 1, &value);
|
ctc5236_switch_write(OMCMEM_BASE + offset, 1, &value);
|
||||||
|
|
||||||
/*config RTHMC_RST=1 */
|
|
||||||
/*mask_write tbl-reg OmcMem 0x10 offset 0x0 0x00000010 0x00000010 */
|
|
||||||
offset = 0x10 * 4;
|
|
||||||
ctc5236_switch_read(OMCMEM_BASE + offset, 1, &value);
|
|
||||||
value |= BIT(4);
|
|
||||||
ctc5236_switch_write(OMCMEM_BASE + offset, 1, &value);
|
|
||||||
|
|
||||||
/*wait RTHMC_RST=1 */
|
|
||||||
/*read tbl-reg OmcMem 0x10 offset 0x0 */
|
|
||||||
timeout = SYS_TSINGMA_SENSOR_TIMEOUT;
|
|
||||||
offset = 0x10 * 4;
|
|
||||||
while (timeout) {
|
|
||||||
timeout--;
|
|
||||||
ctc5236_switch_read(OMCMEM_BASE + offset, 1, &value);
|
|
||||||
if ((BIT(4) & value) == 0)
|
|
||||||
break;
|
|
||||||
msleep(1);
|
|
||||||
}
|
|
||||||
if (timeout == 0)
|
|
||||||
return 0xffff;
|
|
||||||
|
|
||||||
/*config ENBIAS=1£¬ENVR=1£¬ENAD=1 */
|
/*config ENBIAS=1£¬ENVR=1£¬ENAD=1 */
|
||||||
/*mask_write tbl-reg OmcMem 0x11 offset 0x0 0x02000007 0x03000007 */
|
/*mask_write tbl-reg OmcMem 0x11 offset 0x0 0x02000007 0x03000007 */
|
||||||
offset = 0x11 * 4;
|
offset = 0x11 * 4;
|
||||||
@ -237,6 +220,8 @@ int get_switch_temperature(void)
|
|||||||
value |= BIT(0);
|
value |= BIT(0);
|
||||||
ctc5236_switch_write(OMCMEM_BASE + offset, 1, &value);
|
ctc5236_switch_write(OMCMEM_BASE + offset, 1, &value);
|
||||||
|
|
||||||
|
msleep(1);
|
||||||
|
|
||||||
/*mask_write tbl-reg OmcMem 0x10 offset 0x0 0x00000001 0x00000001 */
|
/*mask_write tbl-reg OmcMem 0x10 offset 0x0 0x00000001 0x00000001 */
|
||||||
offset = 0x10 * 4;
|
offset = 0x10 * 4;
|
||||||
ctc5236_switch_read(OMCMEM_BASE + offset, 1, &value);
|
ctc5236_switch_read(OMCMEM_BASE + offset, 1, &value);
|
||||||
@ -262,8 +247,9 @@ int get_switch_temperature(void)
|
|||||||
|
|
||||||
msleep(1);
|
msleep(1);
|
||||||
}
|
}
|
||||||
if (timeout == 0)
|
if (0 == timeout) {
|
||||||
return 0xffff;
|
return 0xffff;
|
||||||
|
}
|
||||||
|
|
||||||
/*mask_write tbl-reg OmcMem 0x11 offset 0x0 0x00000006 0x00000006 */
|
/*mask_write tbl-reg OmcMem 0x11 offset 0x0 0x00000006 0x00000006 */
|
||||||
offset = 0x11 * 4;
|
offset = 0x11 * 4;
|
||||||
@ -284,6 +270,7 @@ int get_switch_temperature(void)
|
|||||||
return -temperature;
|
return -temperature;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(get_switch_temperature);
|
EXPORT_SYMBOL_GPL(get_switch_temperature);
|
||||||
|
|
||||||
static int ctc_switch_probe(struct platform_device *pdev)
|
static int ctc_switch_probe(struct platform_device *pdev)
|
||||||
@ -291,14 +278,16 @@ static int ctc_switch_probe(struct platform_device *pdev)
|
|||||||
struct resource *iomem;
|
struct resource *iomem;
|
||||||
void __iomem *ioaddr;
|
void __iomem *ioaddr;
|
||||||
resource_size_t start;
|
resource_size_t start;
|
||||||
|
uint val;
|
||||||
|
|
||||||
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
|
|
||||||
start = iomem->start - 0x1000;
|
start = iomem->start - 0x1000;
|
||||||
ioaddr = devm_ioremap(&pdev->dev, start, resource_size(iomem));
|
ioaddr = devm_ioremap(&pdev->dev, start, resource_size(iomem));
|
||||||
if (IS_ERR(ioaddr))
|
if (IS_ERR(ioaddr)) {
|
||||||
return -1;
|
return -1;
|
||||||
access = (struct ctc_access_t *) ioaddr;
|
}
|
||||||
|
access = (ctc_access_t *) ioaddr;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/*
|
||||||
/* drivers/char/watchdog/ctc-wdt.c
|
/* drivers/char/watchdog/ctc-wdt.c
|
||||||
*
|
*
|
||||||
* Watchdog driver for CTC TSINGMA, based on ARM SP805 watchdog module
|
* Watchdog driver for CTC TSINGMA, based on ARM SP805 watchdog module
|
||||||
@ -290,6 +291,12 @@ static int ctc_wdt_probe(struct amba_device *adev, const struct amba_id *id)
|
|||||||
if (IS_ERR(wdt->regmap_base))
|
if (IS_ERR(wdt->regmap_base))
|
||||||
return PTR_ERR(wdt->regmap_base);
|
return PTR_ERR(wdt->regmap_base);
|
||||||
|
|
||||||
|
/* reset wdt module */
|
||||||
|
regmap_write(wdt->regmap_base,
|
||||||
|
offsetof(struct SysCtl_regs, SysWdtResetCtl), 0x3);
|
||||||
|
regmap_write(wdt->regmap_base,
|
||||||
|
offsetof(struct SysCtl_regs, SysWdtResetCtl), 0x0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TsingMa SoC wdt reference clock is obtained by clockSub frequency
|
* TsingMa SoC wdt reference clock is obtained by clockSub frequency
|
||||||
* division,which is 500Mhz.So we need to set the frequency division
|
* division,which is 500Mhz.So we need to set the frequency division
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
KBUILD_EXTRA_SYMBOLS = /sonic/platform/centec-arm64/tsingma-bsp/src/ctc5236_switch/Module.symvers
|
KBUILD_EXTRA_SYMBOLS = /sonic/platform/centec-arm64/tsingma-bsp/src/ctc5236_switch/Module.symvers
|
||||||
|
|
||||||
obj-m = ctcmac.o ctcmac_test.o ctc5236_mdio.o
|
obj-m = ctcmac.o ctc5236_mdio.o
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/* Centec cpu_mac Ethernet Driver -- cpu_mac controller implementation
|
/*
|
||||||
|
* Centec CpuMac Ethernet Driver -- CpuMac controller implementation
|
||||||
* Provides Bus interface for MIIM regs
|
* Provides Bus interface for MIIM regs
|
||||||
*
|
*
|
||||||
* Author: liuht <liuht@centecnetworks.com>
|
* Author: liuht <liuht@centecnetworks.com>
|
||||||
@ -10,6 +11,7 @@
|
|||||||
* under the terms of the GNU General Public License as published by the
|
* under the terms of the GNU General Public License as published by the
|
||||||
* Free Software Foundation; either version 2 of the License, or (at your
|
* Free Software Foundation; either version 2 of the License, or (at your
|
||||||
* option) any later version.
|
* option) any later version.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
@ -44,7 +46,7 @@
|
|||||||
|
|
||||||
struct ctc_mdio_priv {
|
struct ctc_mdio_priv {
|
||||||
void __iomem *map;
|
void __iomem *map;
|
||||||
struct mdio_soc_regs *mdio_reg;
|
struct MdioSoc_regs *mdio_reg;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ctc_mdio_write(struct mii_bus *bus, int mii_id, int reg, u16 value)
|
static int ctc_mdio_write(struct mii_bus *bus, int mii_id, int reg, u16 value)
|
||||||
@ -57,14 +59,15 @@ static int ctc_mdio_write(struct mii_bus *bus, int mii_id, int reg, u16 value)
|
|||||||
cmd = CTCMAC_MDIO_CMD_REGAD(reg) | CTCMAC_MDIO_CMD_PHYAD(mii_id)
|
cmd = CTCMAC_MDIO_CMD_REGAD(reg) | CTCMAC_MDIO_CMD_PHYAD(mii_id)
|
||||||
| CTCMAC_MDIO_CMD_OPCODE(1) | CTCMAC_MDIO_CMD_DATA(value);
|
| CTCMAC_MDIO_CMD_OPCODE(1) | CTCMAC_MDIO_CMD_DATA(value);
|
||||||
|
|
||||||
writel(cmd, &priv->mdio_reg->mdio_soc_cmd_0[0]);
|
writel(cmd, &priv->mdio_reg->MdioSocCmd0[0]);
|
||||||
writel(1, &priv->mdio_reg->mdio_soc_cmd_0[1]);
|
writel(1, &priv->mdio_reg->MdioSocCmd0[1]);
|
||||||
|
|
||||||
ret = readl_poll_timeout(&priv->mdio_reg->mdio_soc_status_0,
|
ret = readl_poll_timeout(&priv->mdio_reg->MdioSocStatus0,
|
||||||
tmp, tmp & CTCMAC_MDIO_STAT(1), 1000, 10000);
|
tmp, tmp & CTCMAC_MDIO_STAT(1), 1000, 10000);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -80,18 +83,18 @@ static int ctc_mdio_read(struct mii_bus *bus, int mii_id, int reg)
|
|||||||
cmd = CTCMAC_MDIO_CMD_REGAD(reg) | CTCMAC_MDIO_CMD_PHYAD(mii_id)
|
cmd = CTCMAC_MDIO_CMD_REGAD(reg) | CTCMAC_MDIO_CMD_PHYAD(mii_id)
|
||||||
| CTCMAC_MDIO_CMD_OPCODE(2);
|
| CTCMAC_MDIO_CMD_OPCODE(2);
|
||||||
|
|
||||||
writel(cmd, &priv->mdio_reg->mdio_soc_cmd_0[0]);
|
writel(cmd, &priv->mdio_reg->MdioSocCmd0[0]);
|
||||||
writel(1, &priv->mdio_reg->mdio_soc_cmd_0[1]);
|
writel(1, &priv->mdio_reg->MdioSocCmd0[1]);
|
||||||
|
|
||||||
ret = readl_poll_timeout(&priv->mdio_reg->mdio_soc_status_0,
|
ret = readl_poll_timeout(&priv->mdio_reg->MdioSocStatus0,
|
||||||
status, status & CTCMAC_MDIO_STAT(1), 1000,
|
status, status & CTCMAC_MDIO_STAT(1), 1000,
|
||||||
10000);
|
10000);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
pr_err("ctc_mdio_read1\n");
|
printk(KERN_ERR "ctc_mdio_read1\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
value = (readl(&priv->mdio_reg->mdio_soc_status_0) & 0xffff);
|
value = (readl(&priv->mdio_reg->MdioSocStatus0) & 0xffff);
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
@ -100,7 +103,7 @@ static int ctc_mdio_reset(struct mii_bus *bus)
|
|||||||
{
|
{
|
||||||
struct ctc_mdio_priv *priv = (struct ctc_mdio_priv *)bus->priv;
|
struct ctc_mdio_priv *priv = (struct ctc_mdio_priv *)bus->priv;
|
||||||
|
|
||||||
writel(0x91f, &priv->mdio_reg->mdio_soc_cfg_0);
|
writel(0x91f, &priv->mdio_reg->MdioSocCfg0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -146,7 +149,7 @@ static int ctc_mdio_probe(struct platform_device *pdev)
|
|||||||
pr_err("of iomap fail %d!\n", err);
|
pr_err("of iomap fail %d!\n", err);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
priv->mdio_reg = (struct mdio_soc_regs *)priv->map;
|
priv->mdio_reg = (struct MdioSoc_regs *)priv->map;
|
||||||
new_bus->parent = &pdev->dev;
|
new_bus->parent = &pdev->dev;
|
||||||
platform_set_drvdata(pdev, new_bus);
|
platform_set_drvdata(pdev, new_bus);
|
||||||
|
|
||||||
|
2156
platform/centec-arm64/tsingma-bsp/src/ctcmac/ctcmac.c
Normal file → Executable file
2156
platform/centec-arm64/tsingma-bsp/src/ctcmac/ctcmac.c
Normal file → Executable file
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Centec cpu_mac Ethernet Driver -- cpu_mac controller implementation
|
* Centec CpuMac Ethernet Driver -- CpuMac controller implementation
|
||||||
* Provides Bus interface for MIIM regs
|
* Provides Bus interface for MIIM regs
|
||||||
*
|
*
|
||||||
* Author: liuht <liuht@centecnetworks.com>
|
* Author: liuht <liuht@centecnetworks.com>
|
||||||
@ -17,7 +17,7 @@
|
|||||||
#ifndef __CTCMAC_H
|
#ifndef __CTCMAC_H
|
||||||
#define __CTCMAC_H
|
#define __CTCMAC_H
|
||||||
|
|
||||||
#define TX_TIMEOUT (5 * HZ)
|
#define TX_TIMEOUT (5*HZ)
|
||||||
|
|
||||||
#define CTCMAC_DEFAULT_MTU 1500
|
#define CTCMAC_DEFAULT_MTU 1500
|
||||||
#define CTCMAC_MIN_PKT_LEN 64
|
#define CTCMAC_MIN_PKT_LEN 64
|
||||||
@ -47,14 +47,18 @@
|
|||||||
#define CTCMAC_TOKEN_PER_PKT 10
|
#define CTCMAC_TOKEN_PER_PKT 10
|
||||||
#define CTCMAC_TIMER_COMPENSATE 1
|
#define CTCMAC_TIMER_COMPENSATE 1
|
||||||
|
|
||||||
#define CTCMAC_NOR_RX1_R BIT(7)
|
#define CTCMAC_NOR_RX1_R (1<<7)
|
||||||
#define CTCMAC_NOR_RX0_R BIT(6)
|
#define CTCMAC_NOR_RX0_R (1<<6)
|
||||||
#define CTCMAC_NOR_RX1_D BIT(5)
|
#define CTCMAC_NOR_RX1_D (1<<5)
|
||||||
#define CTCMAC_NOR_RX0_D BIT(4)
|
#define CTCMAC_NOR_RX0_D (1<<4)
|
||||||
#define CTCMAC_NOR_TX_D BIT(3)
|
#define CTCMAC_NOR_TX_D (1<<3)
|
||||||
#define CTCMAC_NOR_AN_D BIT(2)
|
#define CTCMAC_NOR_AN_D (1<<2)
|
||||||
#define CTCMAC_NOR_LINK_DOWN BIT(1)
|
#define CTCMAC_NOR_LINK_DOWN (1<<1)
|
||||||
#define CTCMAC_NOR_LINK_UP BIT(0)
|
#define CTCMAC_NOR_LINK_UP (1<<0)
|
||||||
|
#define CTCMAC_FUNC0_RX_D (1<<0)
|
||||||
|
#define CTCMAC_FUNC0_RX_R (1<<1)
|
||||||
|
#define CTCMAC_FUNC1_RX_D (1<<0)
|
||||||
|
#define CTCMAC_FUNC1_RX_R (1<<1)
|
||||||
|
|
||||||
#define CTC_DDR_BASE 0x80000000
|
#define CTC_DDR_BASE 0x80000000
|
||||||
|
|
||||||
@ -72,25 +76,33 @@
|
|||||||
#define CSC_100M 0x02400000
|
#define CSC_100M 0x02400000
|
||||||
#define CSC_10M 0x18c00000
|
#define CSC_10M 0x18c00000
|
||||||
|
|
||||||
#define CTCMAC_DESC_INT_NUM 1
|
#define DESC_INT_COALESCE_CNT_MIN 1
|
||||||
|
#define DESC_TX_INT_COALESCE_CNT_DEFAULT 16
|
||||||
|
#define DESC_RX_INT_COALESCE_CNT_DEFAULT 16
|
||||||
|
|
||||||
|
/* emu 100us */
|
||||||
|
//#define CTCMAC_TIMER_THRD 0x4B0
|
||||||
|
/* board 100us */
|
||||||
|
#define CTCMAC_TIMER_THRD 0xc350
|
||||||
|
|
||||||
#define CTCMAC_SUPPORTED (SUPPORTED_10baseT_Full \
|
#define CTCMAC_SUPPORTED (SUPPORTED_10baseT_Full \
|
||||||
| SUPPORTED_100baseT_Full \
|
| SUPPORTED_100baseT_Full \
|
||||||
| SUPPORTED_1000baseT_Full \
|
| SUPPORTED_1000baseT_Full \
|
||||||
| SUPPORTED_Autoneg)
|
| SUPPORTED_Autoneg)
|
||||||
|
|
||||||
#define CTCMAC_STATS_LEN (sizeof(struct ctcmac_pkt_stats) / sizeof(u64))
|
#define CTCMAC_STATS_LEN (sizeof(struct ctcmac_pkt_stats)/sizeof(u64))
|
||||||
|
|
||||||
struct ctcmac_skb_cb {
|
struct ctcmac_skb_cb {
|
||||||
unsigned int bytes_sent; /* bytes-on-wire (i.e. no FCB) */
|
unsigned int bytes_sent; /* bytes-on-wire (i.e. no FCB) */
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CTCMAC_CB(skb) ((struct ctcmac_skb_cb *)((skb)->cb))
|
#define CTCMAC_CB(skb) ((struct ctcmac_skb_cb *)((skb)->cb))
|
||||||
|
|
||||||
enum ctcmac_irqinfo_id {
|
enum ctcmac_irqinfo_id {
|
||||||
CTCMAC_NORMAL = 0,
|
CTCMAC_NORMAL = 0,
|
||||||
CTCMAC_FUNC,
|
CTCMAC_FUNC,
|
||||||
CTCMAC_UNIT,
|
CTCMAC_UNIT,
|
||||||
|
CTCMAC_FUNC_RX0,
|
||||||
|
CTCMAC_FUNC_RX1,
|
||||||
CTCMAC_NUM_IRQS
|
CTCMAC_NUM_IRQS
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -105,6 +117,16 @@ enum ctcmac_int_type {
|
|||||||
CTCMAC_INT_MAX
|
CTCMAC_INT_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ctcmac_tx_pol_inv {
|
||||||
|
CTCMAC_TX_POL_INV_DISABLE,
|
||||||
|
CTCMAC_TX_POL_INV_ENABLE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ctcmac_rx_pol_inv {
|
||||||
|
CTCMAC_RX_POL_INV_DISABLE,
|
||||||
|
CTCMAC_RX_POL_INV_ENABLE,
|
||||||
|
};
|
||||||
|
|
||||||
enum ctcmac_autoneg {
|
enum ctcmac_autoneg {
|
||||||
CTCMAC_AUTONEG_1000BASEX_M,
|
CTCMAC_AUTONEG_1000BASEX_M,
|
||||||
CTCMAC_AUTONEG_PHY_M,
|
CTCMAC_AUTONEG_PHY_M,
|
||||||
@ -113,34 +135,46 @@ enum ctcmac_autoneg {
|
|||||||
CTCMAC_AUTONEG_MAX
|
CTCMAC_AUTONEG_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Per TX queue stats */
|
/*
|
||||||
|
* Per TX queue stats
|
||||||
|
*/
|
||||||
struct txq_stats {
|
struct txq_stats {
|
||||||
unsigned long tx_packets;
|
unsigned long tx_packets;
|
||||||
unsigned long tx_bytes;
|
unsigned long tx_bytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct tx_skb {
|
||||||
|
struct sk_buff *skb;
|
||||||
|
int frag_merge;
|
||||||
|
};
|
||||||
|
|
||||||
struct ctcmac_tx_buff {
|
struct ctcmac_tx_buff {
|
||||||
void *vaddr;
|
void *vaddr;
|
||||||
dma_addr_t dma;
|
dma_addr_t dma;
|
||||||
u32 len;
|
u32 len;
|
||||||
u32 offset;
|
u32 offset;
|
||||||
u8 alloc;
|
bool alloc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ctcmac_priv_tx_q {
|
struct ctcmac_priv_tx_q {
|
||||||
spinlock_t txlock __aligned(SMP_CACHE_BYTES);
|
spinlock_t txlock __attribute__ ((aligned(SMP_CACHE_BYTES)));
|
||||||
struct ctcmac_tx_buff tx_buff[CTCMAC_MAX_RING_SIZE + 1];
|
struct ctcmac_tx_buff tx_buff[CTCMAC_MAX_RING_SIZE + 1];
|
||||||
unsigned int num_txbdfree;
|
unsigned int num_txbdfree;
|
||||||
u16 tx_ring_size;
|
u16 tx_ring_size;
|
||||||
u16 qindex;
|
u16 qindex;
|
||||||
u16 next_to_alloc;
|
u16 skb_cur;
|
||||||
u16 next_to_clean;
|
u16 skb_dirty;
|
||||||
|
u16 desc_cur;
|
||||||
|
u16 desc_dirty;
|
||||||
struct txq_stats stats;
|
struct txq_stats stats;
|
||||||
struct net_device *dev;
|
struct net_device *dev;
|
||||||
struct sk_buff **tx_skbuff;
|
struct tx_skb *tx_skbuff;
|
||||||
|
struct napi_struct napi_tx;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*Per RX queue stats */
|
/*
|
||||||
|
* Per RX queue stats
|
||||||
|
*/
|
||||||
struct rxq_stats {
|
struct rxq_stats {
|
||||||
unsigned long rx_packets;
|
unsigned long rx_packets;
|
||||||
unsigned long rx_bytes;
|
unsigned long rx_bytes;
|
||||||
@ -167,6 +201,7 @@ struct ctcmac_priv_rx_q {
|
|||||||
u32 pps_limit;
|
u32 pps_limit;
|
||||||
u32 token, token_max;
|
u32 token, token_max;
|
||||||
u32 rx_trigger;
|
u32 rx_trigger;
|
||||||
|
struct napi_struct napi_rx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ctcmac_irqinfo {
|
struct ctcmac_irqinfo {
|
||||||
@ -189,9 +224,9 @@ struct ctcmac_private {
|
|||||||
struct device *dev;
|
struct device *dev;
|
||||||
struct net_device *ndev;
|
struct net_device *ndev;
|
||||||
void __iomem *iobase;
|
void __iomem *iobase;
|
||||||
struct cpu_mac_regs __iomem *cpumac_reg;
|
struct CpuMac_regs __iomem *cpumac_reg;
|
||||||
struct cpu_mac_mems __iomem *cpumac_mem;
|
struct CpuMac_mems __iomem *cpumac_mem;
|
||||||
struct cpu_mac_unit_regs *cpumacu_reg;
|
struct CpuMacUnit_regs *cpumacu_reg;
|
||||||
u32 device_flags;
|
u32 device_flags;
|
||||||
int irq_num;
|
int irq_num;
|
||||||
int index;
|
int index;
|
||||||
@ -213,9 +248,10 @@ struct ctcmac_private {
|
|||||||
|
|
||||||
struct work_struct reset_task;
|
struct work_struct reset_task;
|
||||||
struct platform_device *ofdev;
|
struct platform_device *ofdev;
|
||||||
struct napi_struct napi_rx;
|
|
||||||
struct napi_struct napi_tx;
|
|
||||||
struct ctcmac_irqinfo irqinfo[CTCMAC_NUM_IRQS];
|
struct ctcmac_irqinfo irqinfo[CTCMAC_NUM_IRQS];
|
||||||
|
struct napi_struct napi_tx;
|
||||||
|
struct napi_struct napi_rx;
|
||||||
|
struct napi_struct napi_rx1;
|
||||||
|
|
||||||
int hwts_rx_en;
|
int hwts_rx_en;
|
||||||
int hwts_tx_en;
|
int hwts_tx_en;
|
||||||
@ -223,8 +259,16 @@ struct ctcmac_private {
|
|||||||
u32 supported;
|
u32 supported;
|
||||||
u32 msg_enable;
|
u32 msg_enable;
|
||||||
u32 int_type;
|
u32 int_type;
|
||||||
|
u32 rx_int_coalesce_cnt;
|
||||||
|
u32 tx_int_coalesce_cnt;
|
||||||
u8 dfe_enable;
|
u8 dfe_enable;
|
||||||
|
u8 tx_pol_inv;
|
||||||
|
u8 rx_pol_inv;
|
||||||
struct timer_list token_timer;
|
struct timer_list token_timer;
|
||||||
|
u8 version;
|
||||||
|
u8 pause_aneg_en;
|
||||||
|
u8 tx_pause_en;
|
||||||
|
u8 rx_pause_en;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ctcmac_pkt_stats {
|
struct ctcmac_pkt_stats {
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
266
platform/centec-arm64/tsingma-bsp/src/ehci-ctc/ehci-ctc.c
Normal file → Executable file
266
platform/centec-arm64/tsingma-bsp/src/ehci-ctc/ehci-ctc.c
Normal file → Executable file
@ -14,13 +14,18 @@
|
|||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/phy/phy.h>
|
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/reset.h>
|
#include <linux/reset.h>
|
||||||
|
#include <linux/sys_soc.h>
|
||||||
|
#include <linux/timer.h>
|
||||||
#include <linux/usb.h>
|
#include <linux/usb.h>
|
||||||
#include <linux/usb/hcd.h>
|
#include <linux/usb/hcd.h>
|
||||||
#include <linux/usb/ehci_pdriver.h>
|
#include <linux/usb/ehci_pdriver.h>
|
||||||
|
#include <linux/usb/of.h>
|
||||||
|
|
||||||
|
#include "../include/sysctl.h"
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
#include "ehci.h"
|
#include "ehci.h"
|
||||||
|
|
||||||
#define DRIVER_DESC "Centec EHCI platform driver"
|
#define DRIVER_DESC "Centec EHCI platform driver"
|
||||||
@ -28,12 +33,15 @@
|
|||||||
#define EHCI_MAX_RSTS 4
|
#define EHCI_MAX_RSTS 4
|
||||||
#define hcd_to_ehci_priv(h) ((struct ehci_ctc_priv *)hcd_to_ehci(h)->priv)
|
#define hcd_to_ehci_priv(h) ((struct ehci_ctc_priv *)hcd_to_ehci(h)->priv)
|
||||||
|
|
||||||
|
static struct regmap *regmap_base;
|
||||||
|
|
||||||
struct ehci_ctc_priv {
|
struct ehci_ctc_priv {
|
||||||
struct clk *clks[EHCI_MAX_CLKS];
|
struct clk *clks[EHCI_MAX_CLKS];
|
||||||
struct reset_control *rsts[EHCI_MAX_RSTS];
|
struct reset_control *rsts;
|
||||||
struct phy **phys;
|
|
||||||
int num_phys;
|
|
||||||
bool reset_on_resume;
|
bool reset_on_resume;
|
||||||
|
bool quirk_poll;
|
||||||
|
struct timer_list poll_timer;
|
||||||
|
struct delayed_work poll_work;
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char hcd_name[] = "ehci-ctc";
|
static const char hcd_name[] = "ehci-ctc";
|
||||||
@ -67,7 +75,7 @@ static int ehci_ctc_power_on(struct platform_device *dev)
|
|||||||
{
|
{
|
||||||
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
||||||
struct ehci_ctc_priv *priv = hcd_to_ehci_priv(hcd);
|
struct ehci_ctc_priv *priv = hcd_to_ehci_priv(hcd);
|
||||||
int clk, ret, phy_num;
|
int clk, ret;
|
||||||
|
|
||||||
for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) {
|
for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) {
|
||||||
ret = clk_prepare_enable(priv->clks[clk]);
|
ret = clk_prepare_enable(priv->clks[clk]);
|
||||||
@ -75,24 +83,8 @@ static int ehci_ctc_power_on(struct platform_device *dev)
|
|||||||
goto err_disable_clks;
|
goto err_disable_clks;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
|
|
||||||
ret = phy_init(priv->phys[phy_num]);
|
|
||||||
if (ret)
|
|
||||||
goto err_exit_phy;
|
|
||||||
ret = phy_power_on(priv->phys[phy_num]);
|
|
||||||
if (ret) {
|
|
||||||
phy_exit(priv->phys[phy_num]);
|
|
||||||
goto err_exit_phy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_exit_phy:
|
|
||||||
while (--phy_num >= 0) {
|
|
||||||
phy_power_off(priv->phys[phy_num]);
|
|
||||||
phy_exit(priv->phys[phy_num]);
|
|
||||||
}
|
|
||||||
err_disable_clks:
|
err_disable_clks:
|
||||||
while (--clk >= 0)
|
while (--clk >= 0)
|
||||||
clk_disable_unprepare(priv->clks[clk]);
|
clk_disable_unprepare(priv->clks[clk]);
|
||||||
@ -104,12 +96,7 @@ static void ehci_ctc_power_off(struct platform_device *dev)
|
|||||||
{
|
{
|
||||||
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
||||||
struct ehci_ctc_priv *priv = hcd_to_ehci_priv(hcd);
|
struct ehci_ctc_priv *priv = hcd_to_ehci_priv(hcd);
|
||||||
int clk, phy_num;
|
int clk;
|
||||||
|
|
||||||
for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
|
|
||||||
phy_power_off(priv->phys[phy_num]);
|
|
||||||
phy_exit(priv->phys[phy_num]);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
|
for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
|
||||||
if (priv->clks[clk])
|
if (priv->clks[clk])
|
||||||
@ -124,22 +111,146 @@ static const struct ehci_driver_overrides platform_overrides __initconst = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct usb_ehci_pdata ehci_ctc_defaults = {
|
static struct usb_ehci_pdata ehci_ctc_defaults = {
|
||||||
.caps_offset = 0x100,
|
|
||||||
.dma_mask_64 = 1,
|
|
||||||
.power_on = ehci_ctc_power_on,
|
.power_on = ehci_ctc_power_on,
|
||||||
.power_suspend = ehci_ctc_power_off,
|
.power_suspend = ehci_ctc_power_off,
|
||||||
.power_off = ehci_ctc_power_off,
|
.power_off = ehci_ctc_power_off,
|
||||||
};
|
};
|
||||||
|
|
||||||
#define KERN_CTC KERN_ERR
|
#define KERN_CTC KERN_ERR
|
||||||
|
static bool quirk_poll_check_port_status(struct ehci_hcd *ehci)
|
||||||
|
{
|
||||||
|
u32 port_status = ehci_readl(ehci, &ehci->regs->port_status[0]);
|
||||||
|
|
||||||
|
if (!(port_status & PORT_OWNER) &&
|
||||||
|
(port_status & PORT_POWER) &&
|
||||||
|
!(port_status & PORT_CONNECT) && (port_status & PORT_LS_MASK))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* quirk_poll_rebind_companion - rebind comanion device to recover
|
||||||
|
* @ehci: the ehci hcd pointer
|
||||||
|
*
|
||||||
|
* Since EHCI/OHCI controllers on R-Car Gen3 SoCs are possible to be getting
|
||||||
|
* stuck very rarely after a full/low usb device was disconnected. To
|
||||||
|
* recover from such a situation, the controllers require changing the OHCI
|
||||||
|
* functional state.
|
||||||
|
*/
|
||||||
|
static void quirk_poll_rebind_companion(struct ehci_hcd *ehci)
|
||||||
|
{
|
||||||
|
struct device *companion_dev;
|
||||||
|
struct usb_hcd *hcd = ehci_to_hcd(ehci);
|
||||||
|
|
||||||
|
companion_dev = usb_of_get_companion_dev(hcd->self.controller);
|
||||||
|
if (!companion_dev)
|
||||||
|
return;
|
||||||
|
|
||||||
|
device_release_driver(companion_dev);
|
||||||
|
if (device_attach(companion_dev) < 0)
|
||||||
|
ehci_err(ehci, "%s: failed\n", __func__);
|
||||||
|
|
||||||
|
put_device(companion_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void quirk_poll_work(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct ehci_ctc_priv *priv =
|
||||||
|
container_of(to_delayed_work(work), struct ehci_ctc_priv,
|
||||||
|
poll_work);
|
||||||
|
struct ehci_hcd *ehci = container_of((void *)priv, struct ehci_hcd,
|
||||||
|
priv);
|
||||||
|
|
||||||
|
/* check the status twice to reduce misdetection rate */
|
||||||
|
if (!quirk_poll_check_port_status(ehci))
|
||||||
|
return;
|
||||||
|
udelay(10);
|
||||||
|
if (!quirk_poll_check_port_status(ehci))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ehci_dbg(ehci, "%s: detected getting stuck. rebind now!\n", __func__);
|
||||||
|
quirk_poll_rebind_companion(ehci);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void quirk_poll_timer(struct timer_list *t)
|
||||||
|
{
|
||||||
|
struct ehci_ctc_priv *priv = from_timer(priv, t, poll_timer);
|
||||||
|
struct ehci_hcd *ehci = container_of((void *)priv, struct ehci_hcd,
|
||||||
|
priv);
|
||||||
|
|
||||||
|
if (quirk_poll_check_port_status(ehci)) {
|
||||||
|
/*
|
||||||
|
* Now scheduling the work for testing the port more. Note that
|
||||||
|
* updating the status is possible to be delayed when
|
||||||
|
* reconnection. So, this uses delayed work with 5 ms delay
|
||||||
|
* to avoid misdetection.
|
||||||
|
*/
|
||||||
|
schedule_delayed_work(&priv->poll_work, msecs_to_jiffies(5));
|
||||||
|
}
|
||||||
|
|
||||||
|
mod_timer(&priv->poll_timer, jiffies + HZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void quirk_poll_init(struct ehci_ctc_priv *priv)
|
||||||
|
{
|
||||||
|
INIT_DELAYED_WORK(&priv->poll_work, quirk_poll_work);
|
||||||
|
timer_setup(&priv->poll_timer, quirk_poll_timer, 0);
|
||||||
|
mod_timer(&priv->poll_timer, jiffies + HZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void quirk_poll_end(struct ehci_ctc_priv *priv)
|
||||||
|
{
|
||||||
|
del_timer_sync(&priv->poll_timer);
|
||||||
|
cancel_delayed_work(&priv->poll_work);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct soc_device_attribute quirk_poll_match[] = {
|
||||||
|
{.family = "R-Car Gen3"},
|
||||||
|
{ /* sentinel */ }
|
||||||
|
};
|
||||||
|
|
||||||
static int ehci_ctc_probe(struct platform_device *dev)
|
static int ehci_ctc_probe(struct platform_device *dev)
|
||||||
{
|
{
|
||||||
|
u32 val;
|
||||||
struct usb_hcd *hcd;
|
struct usb_hcd *hcd;
|
||||||
struct resource *res_mem;
|
struct resource *res_mem;
|
||||||
struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
|
struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
|
||||||
struct ehci_ctc_priv *priv;
|
struct ehci_ctc_priv *priv;
|
||||||
struct ehci_hcd *ehci;
|
struct ehci_hcd *ehci;
|
||||||
int err, irq, phy_num, clk = 0, rst;
|
int err, irq, clk = 0;
|
||||||
|
|
||||||
|
regmap_base =
|
||||||
|
syscon_regmap_lookup_by_phandle(dev->dev.of_node, "ctc,sysctrl");
|
||||||
|
if (IS_ERR(regmap_base))
|
||||||
|
return PTR_ERR(regmap_base);
|
||||||
|
|
||||||
|
/* USB interface reset config */
|
||||||
|
val = 0x7f;
|
||||||
|
regmap_write(regmap_base, offsetof(struct SysCtl_regs, SysUsbResetCtl),
|
||||||
|
val);
|
||||||
|
udelay(1);
|
||||||
|
val &= ~SYS_USB_RESET_CTL_W0_CFG_USB_PHY_PWR_ON_RESET;
|
||||||
|
regmap_write(regmap_base, offsetof(struct SysCtl_regs, SysUsbResetCtl),
|
||||||
|
val);
|
||||||
|
udelay(1);
|
||||||
|
val &=
|
||||||
|
~(SYS_USB_RESET_CTL_W0_CFG_USB_PHY_RESET |
|
||||||
|
SYS_USB_RESET_CTL_W0_CFG_USB_PHY_PORT_RESET |
|
||||||
|
SYS_USB_RESET_CTL_W0_CFG_USB_UTMI_RESET);
|
||||||
|
regmap_write(regmap_base, offsetof(struct SysCtl_regs, SysUsbResetCtl),
|
||||||
|
val);
|
||||||
|
udelay(1);
|
||||||
|
val &=
|
||||||
|
~(SYS_USB_RESET_CTL_W0_CFG_USB_INTF_RESET |
|
||||||
|
SYS_USB_RESET_CTL_W0_CFG_USB_AUX_RESET);
|
||||||
|
regmap_write(regmap_base, offsetof(struct SysCtl_regs, SysUsbResetCtl),
|
||||||
|
val);
|
||||||
|
udelay(1);
|
||||||
|
val &= ~SYS_USB_RESET_CTL_W0_CFG_USB_PHY_ATE_RESET;
|
||||||
|
regmap_write(regmap_base, offsetof(struct SysCtl_regs, SysUsbResetCtl),
|
||||||
|
val);
|
||||||
|
mdelay(500);
|
||||||
|
|
||||||
if (usb_disabled())
|
if (usb_disabled())
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
@ -152,18 +263,17 @@ static int ehci_ctc_probe(struct platform_device *dev)
|
|||||||
pdata = &ehci_ctc_defaults;
|
pdata = &ehci_ctc_defaults;
|
||||||
|
|
||||||
err = dma_coerce_mask_and_coherent(&dev->dev,
|
err = dma_coerce_mask_and_coherent(&dev->dev,
|
||||||
pdata->dma_mask_64 ?
|
pdata->
|
||||||
DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
|
dma_mask_64 ? DMA_BIT_MASK(64) :
|
||||||
|
DMA_BIT_MASK(32));
|
||||||
if (err) {
|
if (err) {
|
||||||
dev_err(&dev->dev, "Error: DMA mask configuration failed\n");
|
dev_err(&dev->dev, "Error: DMA mask configuration failed\n");
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
irq = platform_get_irq(dev, 0);
|
irq = platform_get_irq(dev, 0);
|
||||||
if (irq < 0) {
|
if (irq < 0)
|
||||||
dev_err(&dev->dev, "no irq provided");
|
|
||||||
return irq;
|
return irq;
|
||||||
}
|
|
||||||
|
|
||||||
hcd = usb_create_hcd(&ehci_ctc_hc_driver, &dev->dev,
|
hcd = usb_create_hcd(&ehci_ctc_hc_driver, &dev->dev,
|
||||||
dev_name(&dev->dev));
|
dev_name(&dev->dev));
|
||||||
@ -174,6 +284,7 @@ static int ehci_ctc_probe(struct platform_device *dev)
|
|||||||
dev->dev.platform_data = pdata;
|
dev->dev.platform_data = pdata;
|
||||||
priv = hcd_to_ehci_priv(hcd);
|
priv = hcd_to_ehci_priv(hcd);
|
||||||
ehci = hcd_to_ehci(hcd);
|
ehci = hcd_to_ehci(hcd);
|
||||||
|
|
||||||
if (pdata == &ehci_ctc_defaults && dev->dev.of_node) {
|
if (pdata == &ehci_ctc_defaults && dev->dev.of_node) {
|
||||||
if (of_property_read_bool(dev->dev.of_node, "big-endian-regs"))
|
if (of_property_read_bool(dev->dev.of_node, "big-endian-regs"))
|
||||||
ehci->big_endian_mmio = 1;
|
ehci->big_endian_mmio = 1;
|
||||||
@ -192,28 +303,8 @@ static int ehci_ctc_probe(struct platform_device *dev)
|
|||||||
"has-transaction-translator"))
|
"has-transaction-translator"))
|
||||||
hcd->has_tt = 1;
|
hcd->has_tt = 1;
|
||||||
|
|
||||||
priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
|
if (soc_device_match(quirk_poll_match))
|
||||||
"phys",
|
priv->quirk_poll = true;
|
||||||
"#phy-cells");
|
|
||||||
|
|
||||||
if (priv->num_phys > 0) {
|
|
||||||
priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
|
|
||||||
sizeof(struct phy *),
|
|
||||||
GFP_KERNEL);
|
|
||||||
if (!priv->phys)
|
|
||||||
return -ENOMEM;
|
|
||||||
} else
|
|
||||||
priv->num_phys = 0;
|
|
||||||
|
|
||||||
for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
|
|
||||||
priv->phys[phy_num] =
|
|
||||||
devm_of_phy_get_by_index(&dev->dev,
|
|
||||||
dev->dev.of_node, phy_num);
|
|
||||||
if (IS_ERR(priv->phys[phy_num])) {
|
|
||||||
err = PTR_ERR(priv->phys[phy_num]);
|
|
||||||
goto err_put_hcd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
|
for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
|
||||||
priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
|
priv->clks[clk] = of_clk_get(dev->dev.of_node, clk);
|
||||||
@ -226,21 +317,17 @@ static int ehci_ctc_probe(struct platform_device *dev)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (rst = 0; rst < EHCI_MAX_RSTS; rst++) {
|
|
||||||
priv->rsts[rst] =
|
|
||||||
devm_reset_control_get_shared_by_index(&dev->dev, rst);
|
|
||||||
if (IS_ERR(priv->rsts[rst])) {
|
|
||||||
err = PTR_ERR(priv->rsts[rst]);
|
|
||||||
if (err == -EPROBE_DEFER)
|
|
||||||
goto err_reset;
|
|
||||||
priv->rsts[rst] = NULL;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = reset_control_deassert(priv->rsts[rst]);
|
priv->rsts = devm_reset_control_array_get_optional_shared(&dev->dev);
|
||||||
if (err)
|
if (IS_ERR(priv->rsts)) {
|
||||||
goto err_reset;
|
err = PTR_ERR(priv->rsts);
|
||||||
|
goto err_put_clks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = reset_control_deassert(priv->rsts);
|
||||||
|
if (err)
|
||||||
|
goto err_put_clks;
|
||||||
|
|
||||||
if (pdata->big_endian_desc)
|
if (pdata->big_endian_desc)
|
||||||
ehci->big_endian_desc = 1;
|
ehci->big_endian_desc = 1;
|
||||||
if (pdata->big_endian_mmio)
|
if (pdata->big_endian_mmio)
|
||||||
@ -272,6 +359,7 @@ static int ehci_ctc_probe(struct platform_device *dev)
|
|||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto err_reset;
|
goto err_reset;
|
||||||
}
|
}
|
||||||
|
|
||||||
res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
|
||||||
hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
|
hcd->regs = devm_ioremap_resource(&dev->dev, res_mem);
|
||||||
if (IS_ERR(hcd->regs)) {
|
if (IS_ERR(hcd->regs)) {
|
||||||
@ -280,23 +368,29 @@ static int ehci_ctc_probe(struct platform_device *dev)
|
|||||||
}
|
}
|
||||||
hcd->rsrc_start = res_mem->start;
|
hcd->rsrc_start = res_mem->start;
|
||||||
hcd->rsrc_len = resource_size(res_mem);
|
hcd->rsrc_len = resource_size(res_mem);
|
||||||
|
|
||||||
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
err = usb_add_hcd(hcd, irq, IRQF_SHARED);
|
||||||
if (err)
|
if (err)
|
||||||
goto err_power;
|
goto err_power;
|
||||||
|
|
||||||
device_wakeup_enable(hcd->self.controller);
|
device_wakeup_enable(hcd->self.controller);
|
||||||
|
device_enable_async_suspend(hcd->self.controller);
|
||||||
platform_set_drvdata(dev, hcd);
|
platform_set_drvdata(dev, hcd);
|
||||||
|
|
||||||
|
if (priv->quirk_poll)
|
||||||
|
quirk_poll_init(priv);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err_power:
|
err_power:
|
||||||
if (pdata->power_off)
|
if (pdata->power_off)
|
||||||
pdata->power_off(dev);
|
pdata->power_off(dev);
|
||||||
err_reset:
|
err_reset:
|
||||||
while (--rst >= 0)
|
reset_control_assert(priv->rsts);
|
||||||
reset_control_assert(priv->rsts[rst]);
|
|
||||||
err_put_clks:
|
err_put_clks:
|
||||||
while (--clk >= 0)
|
while (--clk >= 0)
|
||||||
clk_put(priv->clks[clk]);
|
clk_put(priv->clks[clk]);
|
||||||
err_put_hcd:
|
|
||||||
if (pdata == &ehci_ctc_defaults)
|
if (pdata == &ehci_ctc_defaults)
|
||||||
dev->dev.platform_data = NULL;
|
dev->dev.platform_data = NULL;
|
||||||
|
|
||||||
@ -310,15 +404,17 @@ static int ehci_ctc_remove(struct platform_device *dev)
|
|||||||
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
struct usb_hcd *hcd = platform_get_drvdata(dev);
|
||||||
struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
|
struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
|
||||||
struct ehci_ctc_priv *priv = hcd_to_ehci_priv(hcd);
|
struct ehci_ctc_priv *priv = hcd_to_ehci_priv(hcd);
|
||||||
int clk, rst;
|
int clk;
|
||||||
|
|
||||||
|
if (priv->quirk_poll)
|
||||||
|
quirk_poll_end(priv);
|
||||||
|
|
||||||
usb_remove_hcd(hcd);
|
usb_remove_hcd(hcd);
|
||||||
|
|
||||||
if (pdata->power_off)
|
if (pdata->power_off)
|
||||||
pdata->power_off(dev);
|
pdata->power_off(dev);
|
||||||
|
|
||||||
for (rst = 0; rst < EHCI_MAX_RSTS && priv->rsts[rst]; rst++)
|
reset_control_assert(priv->rsts);
|
||||||
reset_control_assert(priv->rsts[rst]);
|
|
||||||
|
|
||||||
for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++)
|
for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++)
|
||||||
clk_put(priv->clks[clk]);
|
clk_put(priv->clks[clk]);
|
||||||
@ -337,9 +433,13 @@ static int ehci_ctc_suspend(struct device *dev)
|
|||||||
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
struct usb_hcd *hcd = dev_get_drvdata(dev);
|
||||||
struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
|
struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
|
||||||
struct platform_device *pdev = to_platform_device(dev);
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
|
struct ehci_ctc_priv *priv = hcd_to_ehci_priv(hcd);
|
||||||
bool do_wakeup = device_may_wakeup(dev);
|
bool do_wakeup = device_may_wakeup(dev);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (priv->quirk_poll)
|
||||||
|
quirk_poll_end(priv);
|
||||||
|
|
||||||
ret = ehci_suspend(hcd, do_wakeup);
|
ret = ehci_suspend(hcd, do_wakeup);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
@ -356,15 +456,25 @@ static int ehci_ctc_resume(struct device *dev)
|
|||||||
struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
|
struct usb_ehci_pdata *pdata = dev_get_platdata(dev);
|
||||||
struct platform_device *pdev = to_platform_device(dev);
|
struct platform_device *pdev = to_platform_device(dev);
|
||||||
struct ehci_ctc_priv *priv = hcd_to_ehci_priv(hcd);
|
struct ehci_ctc_priv *priv = hcd_to_ehci_priv(hcd);
|
||||||
|
struct device *companion_dev;
|
||||||
|
|
||||||
if (pdata->power_on) {
|
if (pdata->power_on) {
|
||||||
int err = pdata->power_on(pdev);
|
int err = pdata->power_on(pdev);
|
||||||
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
companion_dev = usb_of_get_companion_dev(hcd->self.controller);
|
||||||
|
if (companion_dev) {
|
||||||
|
device_pm_wait_for_dev(hcd->self.controller, companion_dev);
|
||||||
|
put_device(companion_dev);
|
||||||
|
}
|
||||||
|
|
||||||
ehci_resume(hcd, priv->reset_on_resume);
|
ehci_resume(hcd, priv->reset_on_resume);
|
||||||
|
|
||||||
|
if (priv->quirk_poll)
|
||||||
|
quirk_poll_init(priv);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_PM_SLEEP */
|
#endif /* CONFIG_PM_SLEEP */
|
||||||
@ -394,7 +504,7 @@ static struct platform_driver ehci_ctc_driver = {
|
|||||||
.name = "ehci-ctc",
|
.name = "ehci-ctc",
|
||||||
.pm = &ehci_ctc_pm_ops,
|
.pm = &ehci_ctc_pm_ops,
|
||||||
.of_match_table = ctc_ehci_ids,
|
.of_match_table = ctc_ehci_ids,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static int __init ehci_ctc_init(void)
|
static int __init ehci_ctc_init(void)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0+
|
/* SPDX-License-Identifier: GPL-2.0+ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2001-2002 by David Brownell
|
* Copyright (c) 2001-2002 by David Brownell
|
||||||
*/
|
*/
|
||||||
@ -31,14 +31,14 @@ typedef __u16 __bitwise __hc16;
|
|||||||
|
|
||||||
struct ehci_stats {
|
struct ehci_stats {
|
||||||
/* irq usage */
|
/* irq usage */
|
||||||
unsigned long normal;
|
unsigned long normal;
|
||||||
unsigned long error;
|
unsigned long error;
|
||||||
unsigned long iaa;
|
unsigned long iaa;
|
||||||
unsigned long lost_iaa;
|
unsigned long lost_iaa;
|
||||||
|
|
||||||
/* termination of urbs from core */
|
/* termination of urbs from core */
|
||||||
unsigned long complete;
|
unsigned long complete;
|
||||||
unsigned long unlink;
|
unsigned long unlink;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -46,22 +46,22 @@ struct ehci_stats {
|
|||||||
* high-speed devices and full/low-speed devices lying behind a TT.
|
* high-speed devices and full/low-speed devices lying behind a TT.
|
||||||
*/
|
*/
|
||||||
struct ehci_per_sched {
|
struct ehci_per_sched {
|
||||||
struct usb_device *udev; /* access to the TT */
|
struct usb_device *udev; /* access to the TT */
|
||||||
struct usb_host_endpoint *ep;
|
struct usb_host_endpoint *ep;
|
||||||
struct list_head ps_list; /* node on ehci_tt's ps_list */
|
struct list_head ps_list; /* node on ehci_tt's ps_list */
|
||||||
u16 tt_usecs; /* time on the FS/LS bus */
|
u16 tt_usecs; /* time on the FS/LS bus */
|
||||||
u16 cs_mask; /* C-mask and S-mask bytes */
|
u16 cs_mask; /* C-mask and S-mask bytes */
|
||||||
u16 period; /* actual period in frames */
|
u16 period; /* actual period in frames */
|
||||||
u16 phase; /* actual phase, frame part */
|
u16 phase; /* actual phase, frame part */
|
||||||
u8 bw_phase; /* same, for bandwidth
|
u8 bw_phase; /* same, for bandwidth
|
||||||
reservation */
|
reservation */
|
||||||
u8 phase_uf; /* uframe part of the phase */
|
u8 phase_uf; /* uframe part of the phase */
|
||||||
u8 usecs, c_usecs; /* times on the HS bus */
|
u8 usecs, c_usecs; /* times on the HS bus */
|
||||||
u8 bw_uperiod; /* period in microframes, for
|
u8 bw_uperiod; /* period in microframes, for
|
||||||
bandwidth reservation */
|
bandwidth reservation */
|
||||||
u8 bw_period; /* same, in frames */
|
u8 bw_period; /* same, in frames */
|
||||||
};
|
};
|
||||||
#define NO_FRAME 29999 /* frame not assigned yet */
|
#define NO_FRAME 29999 /* frame not assigned yet */
|
||||||
|
|
||||||
/* ehci_hcd->lock guards shared data against other CPUs:
|
/* ehci_hcd->lock guards shared data against other CPUs:
|
||||||
* ehci_hcd: async, unlink, periodic (and shadow), ...
|
* ehci_hcd: async, unlink, periodic (and shadow), ...
|
||||||
@ -73,7 +73,7 @@ struct ehci_per_sched {
|
|||||||
* when updating hw_* fields in shared qh/qtd/... structures.
|
* when updating hw_* fields in shared qh/qtd/... structures.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */
|
#define EHCI_MAX_ROOT_PORTS 15 /* see HCS_N_PORTS */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ehci_rh_state values of EHCI_RH_RUNNING or above mean that the
|
* ehci_rh_state values of EHCI_RH_RUNNING or above mean that the
|
||||||
@ -92,180 +92,180 @@ enum ehci_rh_state {
|
|||||||
* ehci-timer.c) in parallel with this list.
|
* ehci-timer.c) in parallel with this list.
|
||||||
*/
|
*/
|
||||||
enum ehci_hrtimer_event {
|
enum ehci_hrtimer_event {
|
||||||
EHCI_HRTIMER_POLL_ASS, /* Poll for async schedule off */
|
EHCI_HRTIMER_POLL_ASS, /* Poll for async schedule off */
|
||||||
EHCI_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */
|
EHCI_HRTIMER_POLL_PSS, /* Poll for periodic schedule off */
|
||||||
EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */
|
EHCI_HRTIMER_POLL_DEAD, /* Wait for dead controller to stop */
|
||||||
EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */
|
EHCI_HRTIMER_UNLINK_INTR, /* Wait for interrupt QH unlink */
|
||||||
EHCI_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */
|
EHCI_HRTIMER_FREE_ITDS, /* Wait for unused iTDs and siTDs */
|
||||||
EHCI_HRTIMER_ACTIVE_UNLINK, /* Wait while unlinking an active QH */
|
EHCI_HRTIMER_ACTIVE_UNLINK, /* Wait while unlinking an active QH */
|
||||||
EHCI_HRTIMER_START_UNLINK_INTR, /* Unlink empty interrupt QHs */
|
EHCI_HRTIMER_START_UNLINK_INTR, /* Unlink empty interrupt QHs */
|
||||||
EHCI_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */
|
EHCI_HRTIMER_ASYNC_UNLINKS, /* Unlink empty async QHs */
|
||||||
EHCI_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */
|
EHCI_HRTIMER_IAA_WATCHDOG, /* Handle lost IAA interrupts */
|
||||||
EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
|
EHCI_HRTIMER_DISABLE_PERIODIC, /* Wait to disable periodic sched */
|
||||||
EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */
|
EHCI_HRTIMER_DISABLE_ASYNC, /* Wait to disable async sched */
|
||||||
EHCI_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */
|
EHCI_HRTIMER_IO_WATCHDOG, /* Check for missing IRQs */
|
||||||
EHCI_HRTIMER_NUM_EVENTS /* Must come last */
|
EHCI_HRTIMER_NUM_EVENTS /* Must come last */
|
||||||
};
|
};
|
||||||
#define EHCI_HRTIMER_NO_EVENT 99
|
#define EHCI_HRTIMER_NO_EVENT 99
|
||||||
|
|
||||||
struct ehci_hcd { /* one per controller */
|
struct ehci_hcd { /* one per controller */
|
||||||
/* timing support */
|
/* timing support */
|
||||||
enum ehci_hrtimer_event next_hrtimer_event;
|
enum ehci_hrtimer_event next_hrtimer_event;
|
||||||
unsigned enabled_hrtimer_events;
|
unsigned enabled_hrtimer_events;
|
||||||
ktime_t hr_timeouts[EHCI_HRTIMER_NUM_EVENTS];
|
ktime_t hr_timeouts[EHCI_HRTIMER_NUM_EVENTS];
|
||||||
struct hrtimer hrtimer;
|
struct hrtimer hrtimer;
|
||||||
|
|
||||||
int PSS_poll_count;
|
int PSS_poll_count;
|
||||||
int ASS_poll_count;
|
int ASS_poll_count;
|
||||||
int died_poll_count;
|
int died_poll_count;
|
||||||
|
|
||||||
/* glue to PCI and HCD framework */
|
/* glue to PCI and HCD framework */
|
||||||
struct ehci_caps __iomem *caps;
|
struct ehci_caps __iomem *caps;
|
||||||
struct ehci_regs __iomem *regs;
|
struct ehci_regs __iomem *regs;
|
||||||
struct ehci_dbg_port __iomem *debug;
|
struct ehci_dbg_port __iomem *debug;
|
||||||
|
|
||||||
__u32 hcs_params; /* cached register copy */
|
__u32 hcs_params; /* cached register copy */
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
enum ehci_rh_state rh_state;
|
enum ehci_rh_state rh_state;
|
||||||
|
|
||||||
/* general schedule support */
|
/* general schedule support */
|
||||||
bool scanning:1;
|
bool scanning:1;
|
||||||
bool need_rescan:1;
|
bool need_rescan:1;
|
||||||
bool intr_unlinking:1;
|
bool intr_unlinking:1;
|
||||||
bool iaa_in_progress:1;
|
bool iaa_in_progress:1;
|
||||||
bool async_unlinking:1;
|
bool async_unlinking:1;
|
||||||
bool shutdown:1;
|
bool shutdown:1;
|
||||||
struct ehci_qh *qh_scan_next;
|
struct ehci_qh *qh_scan_next;
|
||||||
|
|
||||||
/* async schedule support */
|
/* async schedule support */
|
||||||
struct ehci_qh *async;
|
struct ehci_qh *async;
|
||||||
struct ehci_qh *dummy; /* For AMD quirk use */
|
struct ehci_qh *dummy; /* For AMD quirk use */
|
||||||
struct list_head async_unlink;
|
struct list_head async_unlink;
|
||||||
struct list_head async_idle;
|
struct list_head async_idle;
|
||||||
unsigned async_unlink_cycle;
|
unsigned async_unlink_cycle;
|
||||||
unsigned async_count; /* async activity count */
|
unsigned async_count; /* async activity count */
|
||||||
__hc32 old_current; /* Test for QH becoming */
|
__hc32 old_current; /* Test for QH becoming */
|
||||||
__hc32 old_token; /* inactive during unlink */
|
__hc32 old_token; /* inactive during unlink */
|
||||||
|
|
||||||
/* periodic schedule support */
|
/* periodic schedule support */
|
||||||
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
|
#define DEFAULT_I_TDPS 1024 /* some HCs can do less */
|
||||||
unsigned periodic_size;
|
unsigned periodic_size;
|
||||||
__hc32 *periodic; /* hw periodic table */
|
__hc32 *periodic; /* hw periodic table */
|
||||||
dma_addr_t periodic_dma;
|
dma_addr_t periodic_dma;
|
||||||
struct list_head intr_qh_list;
|
struct list_head intr_qh_list;
|
||||||
unsigned i_thresh; /* uframes HC might cache */
|
unsigned i_thresh; /* uframes HC might cache */
|
||||||
|
|
||||||
union ehci_shadow *pshadow; /* mirror hw periodic table */
|
|
||||||
struct list_head intr_unlink_wait;
|
|
||||||
struct list_head intr_unlink;
|
|
||||||
unsigned intr_unlink_wait_cycle;
|
|
||||||
unsigned intr_unlink_cycle;
|
|
||||||
unsigned now_frame; /* frame from HC hardware */
|
|
||||||
unsigned last_iso_frame; /* last frame scanned for iso */
|
|
||||||
unsigned intr_count; /* intr activity count */
|
|
||||||
unsigned isoc_count; /* isoc activity count */
|
|
||||||
unsigned periodic_count; /* periodic activity count */
|
|
||||||
unsigned uframe_periodic_max; /* max periodic time per uframe */
|
|
||||||
|
|
||||||
|
union ehci_shadow *pshadow; /* mirror hw periodic table */
|
||||||
|
struct list_head intr_unlink_wait;
|
||||||
|
struct list_head intr_unlink;
|
||||||
|
unsigned intr_unlink_wait_cycle;
|
||||||
|
unsigned intr_unlink_cycle;
|
||||||
|
unsigned now_frame; /* frame from HC hardware */
|
||||||
|
unsigned last_iso_frame; /* last frame scanned for iso */
|
||||||
|
unsigned intr_count; /* intr activity count */
|
||||||
|
unsigned isoc_count; /* isoc activity count */
|
||||||
|
unsigned periodic_count; /* periodic activity count */
|
||||||
|
unsigned uframe_periodic_max; /* max periodic time per uframe */
|
||||||
|
|
||||||
/* list of itds & sitds completed while now_frame was still active */
|
/* list of itds & sitds completed while now_frame was still active */
|
||||||
struct list_head cached_itd_list;
|
struct list_head cached_itd_list;
|
||||||
struct ehci_itd *last_itd_to_free;
|
struct ehci_itd *last_itd_to_free;
|
||||||
struct list_head cached_sitd_list;
|
struct list_head cached_sitd_list;
|
||||||
struct ehci_sitd *last_sitd_to_free;
|
struct ehci_sitd *last_sitd_to_free;
|
||||||
|
|
||||||
/* per root hub port */
|
/* per root hub port */
|
||||||
unsigned long reset_done[EHCI_MAX_ROOT_PORTS];
|
unsigned long reset_done[EHCI_MAX_ROOT_PORTS];
|
||||||
|
|
||||||
/* bit vectors (one bit per port) */
|
/* bit vectors (one bit per port) */
|
||||||
unsigned long bus_suspended; /* which ports were
|
unsigned long bus_suspended; /* which ports were
|
||||||
already suspended at the start of a bus suspend */
|
already suspended at the start of a bus suspend */
|
||||||
unsigned long companion_ports; /* which ports are
|
unsigned long companion_ports; /* which ports are
|
||||||
dedicated to the companion controller */
|
dedicated to the companion controller */
|
||||||
unsigned long owned_ports; /* which ports are
|
unsigned long owned_ports; /* which ports are
|
||||||
owned by the companion during a bus suspend */
|
owned by the companion during a bus suspend */
|
||||||
unsigned long port_c_suspend; /* which ports have
|
unsigned long port_c_suspend; /* which ports have
|
||||||
the change-suspend feature turned on */
|
the change-suspend feature turned on */
|
||||||
unsigned long suspended_ports; /* which ports are
|
unsigned long suspended_ports; /* which ports are
|
||||||
suspended */
|
suspended */
|
||||||
unsigned long resuming_ports; /* which ports have
|
unsigned long resuming_ports; /* which ports have
|
||||||
started to resume */
|
started to resume */
|
||||||
|
|
||||||
/* per-HC memory pools (could be per-bus, but ...) */
|
/* per-HC memory pools (could be per-bus, but ...) */
|
||||||
struct dma_pool *qh_pool; /* qh per active urb */
|
struct dma_pool *qh_pool; /* qh per active urb */
|
||||||
struct dma_pool *qtd_pool; /* one or more per qh */
|
struct dma_pool *qtd_pool; /* one or more per qh */
|
||||||
struct dma_pool *itd_pool; /* itd per iso urb */
|
struct dma_pool *itd_pool; /* itd per iso urb */
|
||||||
struct dma_pool *sitd_pool; /* sitd per split iso urb */
|
struct dma_pool *sitd_pool; /* sitd per split iso urb */
|
||||||
|
|
||||||
unsigned random_frame;
|
unsigned random_frame;
|
||||||
unsigned long next_statechange;
|
unsigned long next_statechange;
|
||||||
ktime_t last_periodic_enable;
|
ktime_t last_periodic_enable;
|
||||||
u32 command;
|
u32 command;
|
||||||
|
|
||||||
/* SILICON QUIRKS */
|
/* SILICON QUIRKS */
|
||||||
unsigned no_selective_suspend:1;
|
unsigned no_selective_suspend:1;
|
||||||
unsigned has_fsl_port_bug:1; /* FreeScale */
|
unsigned has_fsl_port_bug:1; /* FreeScale */
|
||||||
unsigned has_fsl_hs_errata:1; /* Freescale HS quirk */
|
unsigned has_fsl_hs_errata:1; /* Freescale HS quirk */
|
||||||
unsigned has_fsl_susp_errata:1; /* NXP SUSP quirk */
|
unsigned has_fsl_susp_errata:1; /* NXP SUSP quirk */
|
||||||
unsigned big_endian_mmio:1;
|
unsigned big_endian_mmio:1;
|
||||||
unsigned big_endian_desc:1;
|
unsigned big_endian_desc:1;
|
||||||
unsigned big_endian_capbase:1;
|
unsigned big_endian_capbase:1;
|
||||||
unsigned has_amcc_usb23:1;
|
unsigned has_amcc_usb23:1;
|
||||||
unsigned need_io_watchdog:1;
|
unsigned need_io_watchdog:1;
|
||||||
unsigned amd_pll_fix:1;
|
unsigned amd_pll_fix:1;
|
||||||
unsigned use_dummy_qh:1; /* AMD Frame List table quirk*/
|
unsigned use_dummy_qh:1; /* AMD Frame List table quirk */
|
||||||
unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
|
unsigned has_synopsys_hc_bug:1; /* Synopsys HC */
|
||||||
unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
|
unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
|
||||||
unsigned need_oc_pp_cycle:1; /* MPC834X port power */
|
unsigned need_oc_pp_cycle:1; /* MPC834X port power */
|
||||||
unsigned imx28_write_fix:1; /* For Freescale i.MX28 */
|
unsigned imx28_write_fix:1; /* For Freescale i.MX28 */
|
||||||
|
|
||||||
/* required for usb32 quirk */
|
/* required for usb32 quirk */
|
||||||
#define OHCI_CTRL_HCFS (3 << 6)
|
#define OHCI_CTRL_HCFS (3 << 6)
|
||||||
#define OHCI_USB_OPER (2 << 6)
|
#define OHCI_USB_OPER (2 << 6)
|
||||||
#define OHCI_USB_SUSPEND (3 << 6)
|
#define OHCI_USB_SUSPEND (3 << 6)
|
||||||
|
|
||||||
#define OHCI_HCCTRL_OFFSET 0x4
|
#define OHCI_HCCTRL_OFFSET 0x4
|
||||||
#define OHCI_HCCTRL_LEN 0x4
|
#define OHCI_HCCTRL_LEN 0x4
|
||||||
__hc32 *ohci_hcctrl_reg;
|
__hc32 *ohci_hcctrl_reg;
|
||||||
unsigned has_hostpc:1;
|
unsigned has_hostpc:1;
|
||||||
unsigned has_tdi_phy_lpm:1;
|
unsigned has_tdi_phy_lpm:1;
|
||||||
unsigned has_ppcd:1; /* support per-port change bits */
|
unsigned has_ppcd:1; /* support per-port change bits */
|
||||||
u8 sbrn; /* packed release number */
|
u8 sbrn; /* packed release number */
|
||||||
|
|
||||||
/* irq statistics */
|
/* irq statistics */
|
||||||
#ifdef EHCI_STATS
|
#ifdef EHCI_STATS
|
||||||
struct ehci_stats stats;
|
struct ehci_stats stats;
|
||||||
# define COUNT(x) ((x)++)
|
# define INCR(x) ((x)++)
|
||||||
#else
|
#else
|
||||||
# define COUNT(x)
|
# define INCR(x) do {} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* debug files */
|
/* debug files */
|
||||||
#ifdef CONFIG_DYNAMIC_DEBUG
|
#ifdef CONFIG_DYNAMIC_DEBUG
|
||||||
struct dentry *debug_dir;
|
struct dentry *debug_dir;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* bandwidth usage */
|
/* bandwidth usage */
|
||||||
#define EHCI_BANDWIDTH_SIZE 64
|
#define EHCI_BANDWIDTH_SIZE 64
|
||||||
#define EHCI_BANDWIDTH_FRAMES (EHCI_BANDWIDTH_SIZE >> 3)
|
#define EHCI_BANDWIDTH_FRAMES (EHCI_BANDWIDTH_SIZE >> 3)
|
||||||
u8 bandwidth[EHCI_BANDWIDTH_SIZE];
|
u8 bandwidth[EHCI_BANDWIDTH_SIZE];
|
||||||
/* us allocated per uframe */
|
/* us allocated per uframe */
|
||||||
u8 tt_budget[EHCI_BANDWIDTH_SIZE];
|
u8 tt_budget[EHCI_BANDWIDTH_SIZE];
|
||||||
/* us budgeted per uframe */
|
/* us budgeted per uframe */
|
||||||
struct list_head tt_list;
|
struct list_head tt_list;
|
||||||
|
|
||||||
/* platform-specific data -- must come last */
|
/* platform-specific data -- must come last */
|
||||||
unsigned long priv[0] __aligned(sizeof(s64));
|
unsigned long priv[] __aligned(sizeof(s64));
|
||||||
};
|
};
|
||||||
|
|
||||||
/* convert between an HCD pointer and the corresponding EHCI_HCD */
|
/* convert between an HCD pointer and the corresponding EHCI_HCD */
|
||||||
static inline struct ehci_hcd *hcd_to_ehci(struct usb_hcd *hcd)
|
static inline struct ehci_hcd *hcd_to_ehci(struct usb_hcd *hcd)
|
||||||
{
|
{
|
||||||
return (struct ehci_hcd *) (hcd->hcd_priv);
|
return (struct ehci_hcd *)(hcd->hcd_priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct usb_hcd *ehci_to_hcd(struct ehci_hcd *ehci)
|
static inline struct usb_hcd *ehci_to_hcd(struct ehci_hcd *ehci)
|
||||||
{
|
{
|
||||||
return container_of((void *) ehci, struct usb_hcd, hcd_priv);
|
return container_of((void *)ehci, struct usb_hcd, hcd_priv);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
@ -286,9 +286,9 @@ static inline struct usb_hcd *ehci_to_hcd(struct ehci_hcd *ehci)
|
|||||||
*/
|
*/
|
||||||
struct ehci_qtd {
|
struct ehci_qtd {
|
||||||
/* first part defined by EHCI spec */
|
/* first part defined by EHCI spec */
|
||||||
__hc32 hw_next; /* see EHCI 3.5.1 */
|
__hc32 hw_next; /* see EHCI 3.5.1 */
|
||||||
__hc32 hw_alt_next; /* see EHCI 3.5.2 */
|
__hc32 hw_alt_next; /* see EHCI 3.5.2 */
|
||||||
__hc32 hw_token; /* see EHCI 3.5.3 */
|
__hc32 hw_token; /* see EHCI 3.5.3 */
|
||||||
#define QTD_TOGGLE (1 << 31) /* data toggle */
|
#define QTD_TOGGLE (1 << 31) /* data toggle */
|
||||||
#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
|
#define QTD_LENGTH(tok) (((tok)>>16) & 0x7fff)
|
||||||
#define QTD_IOC (1 << 15) /* interrupt on complete */
|
#define QTD_IOC (1 << 15) /* interrupt on complete */
|
||||||
@ -307,14 +307,14 @@ struct ehci_qtd {
|
|||||||
#define HALT_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_HALT)
|
#define HALT_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_HALT)
|
||||||
#define STATUS_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_STS)
|
#define STATUS_BIT(ehci) cpu_to_hc32(ehci, QTD_STS_STS)
|
||||||
|
|
||||||
__hc32 hw_buf[5]; /* see EHCI 3.5.4 */
|
__hc32 hw_buf[5]; /* see EHCI 3.5.4 */
|
||||||
__hc32 hw_buf_hi[5]; /* Appendix B */
|
__hc32 hw_buf_hi[5]; /* Appendix B */
|
||||||
|
|
||||||
/* the rest is HCD-private */
|
/* the rest is HCD-private */
|
||||||
dma_addr_t qtd_dma; /* qtd address */
|
dma_addr_t qtd_dma; /* qtd address */
|
||||||
struct list_head qtd_list; /* sw qtd list */
|
struct list_head qtd_list; /* sw qtd list */
|
||||||
struct urb *urb; /* qtd's urb */
|
struct urb *urb; /* qtd's urb */
|
||||||
size_t length; /* length of buffer */
|
size_t length; /* length of buffer */
|
||||||
} __aligned(32);
|
} __aligned(32);
|
||||||
|
|
||||||
/* mask NakCnt+T in qh->hw_alt_next */
|
/* mask NakCnt+T in qh->hw_alt_next */
|
||||||
@ -345,7 +345,7 @@ struct ehci_qtd {
|
|||||||
(cpu_to_hc32(ehci, (((u32) dma) & ~0x01f) | Q_TYPE_QH))
|
(cpu_to_hc32(ehci, (((u32) dma) & ~0x01f) | Q_TYPE_QH))
|
||||||
|
|
||||||
/* for periodic/async schedules and qtd lists, mark end of list */
|
/* for periodic/async schedules and qtd lists, mark end of list */
|
||||||
#define EHCI_LIST_END(ehci) cpu_to_hc32(ehci, 1) /* "null pointer" to hw */
|
#define EHCI_LIST_END(ehci) cpu_to_hc32(ehci, 1) /* "null pointer" to hw */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Entries in periodic shadow table are pointers to one of four kinds
|
* Entries in periodic shadow table are pointers to one of four kinds
|
||||||
@ -356,12 +356,12 @@ struct ehci_qtd {
|
|||||||
* For entries in the async schedule, the type tag always says "qh".
|
* For entries in the async schedule, the type tag always says "qh".
|
||||||
*/
|
*/
|
||||||
union ehci_shadow {
|
union ehci_shadow {
|
||||||
struct ehci_qh *qh; /* Q_TYPE_QH */
|
struct ehci_qh *qh; /* Q_TYPE_QH */
|
||||||
struct ehci_itd *itd; /* Q_TYPE_ITD */
|
struct ehci_itd *itd; /* Q_TYPE_ITD */
|
||||||
struct ehci_sitd *sitd; /* Q_TYPE_SITD */
|
struct ehci_sitd *sitd; /* Q_TYPE_SITD */
|
||||||
struct ehci_fstn *fstn; /* Q_TYPE_FSTN */
|
struct ehci_fstn *fstn; /* Q_TYPE_FSTN */
|
||||||
__hc32 *hw_next; /* (all types) */
|
__hc32 *hw_next; /* (all types) */
|
||||||
void *ptr;
|
void *ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
@ -376,8 +376,8 @@ union ehci_shadow {
|
|||||||
|
|
||||||
/* first part defined by EHCI spec */
|
/* first part defined by EHCI spec */
|
||||||
struct ehci_qh_hw {
|
struct ehci_qh_hw {
|
||||||
__hc32 hw_next; /* see EHCI 3.6.1 */
|
__hc32 hw_next; /* see EHCI 3.6.1 */
|
||||||
__hc32 hw_info1; /* see EHCI 3.6.2 */
|
__hc32 hw_info1; /* see EHCI 3.6.2 */
|
||||||
#define QH_CONTROL_EP (1 << 27) /* FS/LS control endpoint */
|
#define QH_CONTROL_EP (1 << 27) /* FS/LS control endpoint */
|
||||||
#define QH_HEAD (1 << 15) /* Head of async reclamation list */
|
#define QH_HEAD (1 << 15) /* Head of async reclamation list */
|
||||||
#define QH_TOGGLE_CTL (1 << 14) /* Data toggle control */
|
#define QH_TOGGLE_CTL (1 << 14) /* Data toggle control */
|
||||||
@ -385,59 +385,59 @@ struct ehci_qh_hw {
|
|||||||
#define QH_LOW_SPEED (1 << 12)
|
#define QH_LOW_SPEED (1 << 12)
|
||||||
#define QH_FULL_SPEED (0 << 12)
|
#define QH_FULL_SPEED (0 << 12)
|
||||||
#define QH_INACTIVATE (1 << 7) /* Inactivate on next transaction */
|
#define QH_INACTIVATE (1 << 7) /* Inactivate on next transaction */
|
||||||
__hc32 hw_info2; /* see EHCI 3.6.2 */
|
__hc32 hw_info2; /* see EHCI 3.6.2 */
|
||||||
#define QH_SMASK 0x000000ff
|
#define QH_SMASK 0x000000ff
|
||||||
#define QH_CMASK 0x0000ff00
|
#define QH_CMASK 0x0000ff00
|
||||||
#define QH_HUBADDR 0x007f0000
|
#define QH_HUBADDR 0x007f0000
|
||||||
#define QH_HUBPORT 0x3f800000
|
#define QH_HUBPORT 0x3f800000
|
||||||
#define QH_MULT 0xc0000000
|
#define QH_MULT 0xc0000000
|
||||||
__hc32 hw_current; /* qtd list - see EHCI 3.6.4 */
|
__hc32 hw_current; /* qtd list - see EHCI 3.6.4 */
|
||||||
|
|
||||||
/* qtd overlay (hardware parts of a struct ehci_qtd) */
|
/* qtd overlay (hardware parts of a struct ehci_qtd) */
|
||||||
__hc32 hw_qtd_next;
|
__hc32 hw_qtd_next;
|
||||||
__hc32 hw_alt_next;
|
__hc32 hw_alt_next;
|
||||||
__hc32 hw_token;
|
__hc32 hw_token;
|
||||||
__hc32 hw_buf[5];
|
__hc32 hw_buf[5];
|
||||||
__hc32 hw_buf_hi[5];
|
__hc32 hw_buf_hi[5];
|
||||||
} __aligned(32);
|
} __aligned(32);
|
||||||
|
|
||||||
struct ehci_qh {
|
struct ehci_qh {
|
||||||
struct ehci_qh_hw *hw; /* Must come first */
|
struct ehci_qh_hw *hw; /* Must come first */
|
||||||
/* the rest is HCD-private */
|
/* the rest is HCD-private */
|
||||||
dma_addr_t qh_dma; /* address of qh */
|
dma_addr_t qh_dma; /* address of qh */
|
||||||
union ehci_shadow qh_next; /* ptr to qh; or periodic */
|
union ehci_shadow qh_next; /* ptr to qh; or periodic */
|
||||||
struct list_head qtd_list; /* sw qtd list */
|
struct list_head qtd_list; /* sw qtd list */
|
||||||
struct list_head intr_node; /* list of intr QHs */
|
struct list_head intr_node; /* list of intr QHs */
|
||||||
struct ehci_qtd *dummy;
|
struct ehci_qtd *dummy;
|
||||||
struct list_head unlink_node;
|
struct list_head unlink_node;
|
||||||
struct ehci_per_sched ps; /* scheduling info */
|
struct ehci_per_sched ps; /* scheduling info */
|
||||||
|
|
||||||
unsigned unlink_cycle;
|
unsigned unlink_cycle;
|
||||||
|
|
||||||
u8 qh_state;
|
u8 qh_state;
|
||||||
#define QH_STATE_LINKED 1 /* HC sees this */
|
#define QH_STATE_LINKED 1 /* HC sees this */
|
||||||
#define QH_STATE_UNLINK 2 /* HC may still see this */
|
#define QH_STATE_UNLINK 2 /* HC may still see this */
|
||||||
#define QH_STATE_IDLE 3 /* HC doesn't see this */
|
#define QH_STATE_IDLE 3 /* HC doesn't see this */
|
||||||
#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on unlink q */
|
#define QH_STATE_UNLINK_WAIT 4 /* LINKED and on unlink q */
|
||||||
#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
|
#define QH_STATE_COMPLETING 5 /* don't touch token.HALT */
|
||||||
|
|
||||||
u8 xacterrs; /* XactErr retry counter */
|
u8 xacterrs; /* XactErr retry counter */
|
||||||
#define QH_XACTERR_MAX 32 /* XactErr retry limit */
|
#define QH_XACTERR_MAX 32 /* XactErr retry limit */
|
||||||
|
|
||||||
u8 unlink_reason;
|
u8 unlink_reason;
|
||||||
#define QH_UNLINK_HALTED 0x01 /* Halt flag is set */
|
#define QH_UNLINK_HALTED 0x01 /* Halt flag is set */
|
||||||
#define QH_UNLINK_SHORT_READ 0x02 /* Recover from a short read */
|
#define QH_UNLINK_SHORT_READ 0x02 /* Recover from a short read */
|
||||||
#define QH_UNLINK_DUMMY_OVERLAY 0x04 /* QH overlayed the dummy TD */
|
#define QH_UNLINK_DUMMY_OVERLAY 0x04 /* QH overlayed the dummy TD */
|
||||||
#define QH_UNLINK_SHUTDOWN 0x08 /* The HC isn't running */
|
#define QH_UNLINK_SHUTDOWN 0x08 /* The HC isn't running */
|
||||||
#define QH_UNLINK_QUEUE_EMPTY 0x10 /* Reached end of the queue */
|
#define QH_UNLINK_QUEUE_EMPTY 0x10 /* Reached end of the queue */
|
||||||
#define QH_UNLINK_REQUESTED 0x20 /* Disable, reset, or dequeue */
|
#define QH_UNLINK_REQUESTED 0x20 /* Disable, reset, or dequeue */
|
||||||
|
|
||||||
u8 gap_uf; /* uframes split/csplit gap */
|
u8 gap_uf; /* uframes split/csplit gap */
|
||||||
|
|
||||||
unsigned is_out:1; /* bulk or intr OUT */
|
unsigned is_out:1; /* bulk or intr OUT */
|
||||||
unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
|
unsigned clearing_tt:1; /* Clear-TT-Buf in progress */
|
||||||
unsigned dequeue_during_giveback:1;
|
unsigned dequeue_during_giveback:1;
|
||||||
unsigned should_be_inactive:1;
|
unsigned should_be_inactive:1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
@ -445,11 +445,11 @@ struct ehci_qh {
|
|||||||
/* description of one iso transaction (up to 3 KB data if highspeed) */
|
/* description of one iso transaction (up to 3 KB data if highspeed) */
|
||||||
struct ehci_iso_packet {
|
struct ehci_iso_packet {
|
||||||
/* These will be copied to iTD when scheduling */
|
/* These will be copied to iTD when scheduling */
|
||||||
u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */
|
u64 bufp; /* itd->hw_bufp{,_hi}[pg] |= */
|
||||||
__hc32 transaction; /* itd->hw_transaction[i] |= */
|
__hc32 transaction; /* itd->hw_transaction[i] |= */
|
||||||
u8 cross; /* buf crosses pages */
|
u8 cross; /* buf crosses pages */
|
||||||
/* for full speed OUT splits */
|
/* for full speed OUT splits */
|
||||||
u32 buf1;
|
u32 buf1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* temporary schedule data for packets from iso urbs (both speeds)
|
/* temporary schedule data for packets from iso urbs (both speeds)
|
||||||
@ -457,10 +457,10 @@ struct ehci_iso_packet {
|
|||||||
* beginning at stream->next_uframe
|
* beginning at stream->next_uframe
|
||||||
*/
|
*/
|
||||||
struct ehci_iso_sched {
|
struct ehci_iso_sched {
|
||||||
struct list_head td_list;
|
struct list_head td_list;
|
||||||
unsigned span;
|
unsigned span;
|
||||||
unsigned first_packet;
|
unsigned first_packet;
|
||||||
struct ehci_iso_packet packet[0];
|
struct ehci_iso_packet packet[];
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -469,32 +469,32 @@ struct ehci_iso_sched {
|
|||||||
*/
|
*/
|
||||||
struct ehci_iso_stream {
|
struct ehci_iso_stream {
|
||||||
/* first field matches ehci_hq, but is NULL */
|
/* first field matches ehci_hq, but is NULL */
|
||||||
struct ehci_qh_hw *hw;
|
struct ehci_qh_hw *hw;
|
||||||
|
|
||||||
u8 bEndpointAddress;
|
u8 bEndpointAddress;
|
||||||
u8 highspeed;
|
u8 highspeed;
|
||||||
struct list_head td_list; /* queued itds/sitds */
|
struct list_head td_list; /* queued itds/sitds */
|
||||||
struct list_head free_list; /* list of unused itds/sitds */
|
struct list_head free_list; /* list of unused itds/sitds */
|
||||||
|
|
||||||
/* output of (re)scheduling */
|
/* output of (re)scheduling */
|
||||||
struct ehci_per_sched ps; /* scheduling info */
|
struct ehci_per_sched ps; /* scheduling info */
|
||||||
unsigned next_uframe;
|
unsigned next_uframe;
|
||||||
__hc32 splits;
|
__hc32 splits;
|
||||||
|
|
||||||
/* the rest is derived from the endpoint descriptor,
|
/* the rest is derived from the endpoint descriptor,
|
||||||
* including the extra info for hw_bufp[0..2]
|
* including the extra info for hw_bufp[0..2]
|
||||||
*/
|
*/
|
||||||
u16 uperiod; /* period in uframes */
|
u16 uperiod; /* period in uframes */
|
||||||
u16 maxp;
|
u16 maxp;
|
||||||
unsigned bandwidth;
|
unsigned bandwidth;
|
||||||
|
|
||||||
/* This is used to initialize iTD's hw_bufp fields */
|
/* This is used to initialize iTD's hw_bufp fields */
|
||||||
__hc32 buf0;
|
__hc32 buf0;
|
||||||
__hc32 buf1;
|
__hc32 buf1;
|
||||||
__hc32 buf2;
|
__hc32 buf2;
|
||||||
|
|
||||||
/* this is used to initialize sITD's tt info */
|
/* this is used to initialize sITD's tt info */
|
||||||
__hc32 address;
|
__hc32 address;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
@ -507,32 +507,32 @@ struct ehci_iso_stream {
|
|||||||
*/
|
*/
|
||||||
struct ehci_itd {
|
struct ehci_itd {
|
||||||
/* first part defined by EHCI spec */
|
/* first part defined by EHCI spec */
|
||||||
__hc32 hw_next; /* see EHCI 3.3.1 */
|
__hc32 hw_next; /* see EHCI 3.3.1 */
|
||||||
__hc32 hw_transaction[8]; /* see EHCI 3.3.2 */
|
__hc32 hw_transaction[8]; /* see EHCI 3.3.2 */
|
||||||
#define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */
|
#define EHCI_ISOC_ACTIVE (1<<31) /* activate transfer this slot */
|
||||||
#define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */
|
#define EHCI_ISOC_BUF_ERR (1<<30) /* Data buffer error */
|
||||||
#define EHCI_ISOC_BABBLE (1<<29) /* babble detected */
|
#define EHCI_ISOC_BABBLE (1<<29) /* babble detected */
|
||||||
#define EHCI_ISOC_XACTERR (1<<28) /* XactErr - transaction error */
|
#define EHCI_ISOC_XACTERR (1<<28) /* XactErr - transaction error */
|
||||||
#define EHCI_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff)
|
#define EHCI_ITD_LENGTH(tok) (((tok)>>16) & 0x0fff)
|
||||||
#define EHCI_ITD_IOC (1 << 15) /* interrupt on complete */
|
#define EHCI_ITD_IOC (1 << 15) /* interrupt on complete */
|
||||||
|
|
||||||
#define ITD_ACTIVE(ehci) cpu_to_hc32(ehci, EHCI_ISOC_ACTIVE)
|
#define ITD_ACTIVE(ehci) cpu_to_hc32(ehci, EHCI_ISOC_ACTIVE)
|
||||||
|
|
||||||
__hc32 hw_bufp[7]; /* see EHCI 3.3.3 */
|
__hc32 hw_bufp[7]; /* see EHCI 3.3.3 */
|
||||||
__hc32 hw_bufp_hi[7]; /* Appendix B */
|
__hc32 hw_bufp_hi[7]; /* Appendix B */
|
||||||
|
|
||||||
/* the rest is HCD-private */
|
/* the rest is HCD-private */
|
||||||
dma_addr_t itd_dma; /* for this itd */
|
dma_addr_t itd_dma; /* for this itd */
|
||||||
union ehci_shadow itd_next; /* ptr to periodic q entry */
|
union ehci_shadow itd_next; /* ptr to periodic q entry */
|
||||||
|
|
||||||
struct urb *urb;
|
struct urb *urb;
|
||||||
struct ehci_iso_stream *stream; /* endpoint's queue */
|
struct ehci_iso_stream *stream; /* endpoint's queue */
|
||||||
struct list_head itd_list; /* list of stream's itds */
|
struct list_head itd_list; /* list of stream's itds */
|
||||||
|
|
||||||
/* any/all hw_transactions here may be used by that urb */
|
/* any/all hw_transactions here may be used by that urb */
|
||||||
unsigned frame; /* where scheduled */
|
unsigned frame; /* where scheduled */
|
||||||
unsigned pg;
|
unsigned pg;
|
||||||
unsigned index[8]; /* in urb->iso_frame_desc */
|
unsigned index[8]; /* in urb->iso_frame_desc */
|
||||||
} __aligned(32);
|
} __aligned(32);
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
@ -545,11 +545,11 @@ struct ehci_itd {
|
|||||||
*/
|
*/
|
||||||
struct ehci_sitd {
|
struct ehci_sitd {
|
||||||
/* first part defined by EHCI spec */
|
/* first part defined by EHCI spec */
|
||||||
__hc32 hw_next;
|
__hc32 hw_next;
|
||||||
/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
|
/* uses bit field macros above - see EHCI 0.95 Table 3-8 */
|
||||||
__hc32 hw_fullspeed_ep; /* EHCI table 3-9 */
|
__hc32 hw_fullspeed_ep; /* EHCI table 3-9 */
|
||||||
__hc32 hw_uframe; /* EHCI table 3-10 */
|
__hc32 hw_uframe; /* EHCI table 3-10 */
|
||||||
__hc32 hw_results; /* EHCI table 3-11 */
|
__hc32 hw_results; /* EHCI table 3-11 */
|
||||||
#define SITD_IOC (1 << 31) /* interrupt on completion */
|
#define SITD_IOC (1 << 31) /* interrupt on completion */
|
||||||
#define SITD_PAGE (1 << 30) /* buffer 0/1 */
|
#define SITD_PAGE (1 << 30) /* buffer 0/1 */
|
||||||
#define SITD_LENGTH(x) (((x) >> 16) & 0x3ff)
|
#define SITD_LENGTH(x) (((x) >> 16) & 0x3ff)
|
||||||
@ -563,19 +563,19 @@ struct ehci_sitd {
|
|||||||
|
|
||||||
#define SITD_ACTIVE(ehci) cpu_to_hc32(ehci, SITD_STS_ACTIVE)
|
#define SITD_ACTIVE(ehci) cpu_to_hc32(ehci, SITD_STS_ACTIVE)
|
||||||
|
|
||||||
__hc32 hw_buf[2]; /* EHCI table 3-12 */
|
__hc32 hw_buf[2]; /* EHCI table 3-12 */
|
||||||
__hc32 hw_backpointer; /* EHCI table 3-13 */
|
__hc32 hw_backpointer; /* EHCI table 3-13 */
|
||||||
__hc32 hw_buf_hi[2]; /* Appendix B */
|
__hc32 hw_buf_hi[2]; /* Appendix B */
|
||||||
|
|
||||||
/* the rest is HCD-private */
|
/* the rest is HCD-private */
|
||||||
dma_addr_t sitd_dma;
|
dma_addr_t sitd_dma;
|
||||||
union ehci_shadow sitd_next; /* ptr to periodic q entry */
|
union ehci_shadow sitd_next; /* ptr to periodic q entry */
|
||||||
|
|
||||||
struct urb *urb;
|
struct urb *urb;
|
||||||
struct ehci_iso_stream *stream; /* endpoint's queue */
|
struct ehci_iso_stream *stream; /* endpoint's queue */
|
||||||
struct list_head sitd_list; /* list of stream's sitds */
|
struct list_head sitd_list; /* list of stream's sitds */
|
||||||
unsigned frame;
|
unsigned frame;
|
||||||
unsigned index;
|
unsigned index;
|
||||||
} __aligned(32);
|
} __aligned(32);
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
@ -590,12 +590,12 @@ struct ehci_sitd {
|
|||||||
* it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
|
* it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
|
||||||
*/
|
*/
|
||||||
struct ehci_fstn {
|
struct ehci_fstn {
|
||||||
__hc32 hw_next; /* any periodic q entry */
|
__hc32 hw_next; /* any periodic q entry */
|
||||||
__hc32 hw_prev; /* qh or EHCI_LIST_END */
|
__hc32 hw_prev; /* qh or EHCI_LIST_END */
|
||||||
|
|
||||||
/* the rest is HCD-private */
|
/* the rest is HCD-private */
|
||||||
dma_addr_t fstn_dma;
|
dma_addr_t fstn_dma;
|
||||||
union ehci_shadow fstn_next; /* ptr to periodic q entry */
|
union ehci_shadow fstn_next; /* ptr to periodic q entry */
|
||||||
} __aligned(32);
|
} __aligned(32);
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
@ -619,12 +619,12 @@ struct ehci_fstn {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
struct ehci_tt {
|
struct ehci_tt {
|
||||||
u16 bandwidth[EHCI_BANDWIDTH_FRAMES];
|
u16 bandwidth[EHCI_BANDWIDTH_FRAMES];
|
||||||
|
|
||||||
struct list_head tt_list; /* List of all ehci_tt's */
|
struct list_head tt_list; /* List of all ehci_tt's */
|
||||||
struct list_head ps_list; /* Items using this TT */
|
struct list_head ps_list; /* Items using this TT */
|
||||||
struct usb_tt *usb_tt;
|
struct usb_tt *usb_tt;
|
||||||
int tt_port; /* TT port number */
|
int tt_port; /* TT port number */
|
||||||
};
|
};
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
@ -736,12 +736,10 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
|
static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
|
||||||
__u32 __iomem *regs)
|
__u32 __iomem * regs)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||||
return ehci_big_endian_mmio(ehci) ?
|
return ehci_big_endian_mmio(ehci) ? readl_be(regs) : readl(regs);
|
||||||
readl_be(regs) :
|
|
||||||
readl(regs);
|
|
||||||
#else
|
#else
|
||||||
return readl(regs);
|
return readl(regs);
|
||||||
#endif
|
#endif
|
||||||
@ -749,23 +747,21 @@ static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
|
|||||||
|
|
||||||
#ifdef CONFIG_SOC_IMX28
|
#ifdef CONFIG_SOC_IMX28
|
||||||
static inline void imx28_ehci_writel(const unsigned int val,
|
static inline void imx28_ehci_writel(const unsigned int val,
|
||||||
volatile __u32 __iomem *addr)
|
volatile __u32 __iomem * addr)
|
||||||
{
|
{
|
||||||
__asm__ ("swp %0, %0, [%1]" : : "r"(val), "r"(addr));
|
__asm__("swp %0, %0, [%1]": :"r"(val), "r"(addr));
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static inline void imx28_ehci_writel(const unsigned int val,
|
static inline void imx28_ehci_writel(const unsigned int val,
|
||||||
volatile __u32 __iomem *addr)
|
volatile __u32 __iomem * addr)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
static inline void ehci_writel(const struct ehci_hcd *ehci,
|
static inline void ehci_writel(const struct ehci_hcd *ehci,
|
||||||
const unsigned int val, __u32 __iomem *regs)
|
const unsigned int val, __u32 __iomem * regs)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||||
ehci_big_endian_mmio(ehci) ?
|
ehci_big_endian_mmio(ehci) ? writel_be(val, regs) : writel(val, regs);
|
||||||
writel_be(val, regs) :
|
|
||||||
writel(val, regs);
|
|
||||||
#else
|
#else
|
||||||
if (ehci->imx28_write_fix)
|
if (ehci->imx28_write_fix)
|
||||||
imx28_ehci_writel(val, regs);
|
imx28_ehci_writel(val, regs);
|
||||||
@ -791,11 +787,12 @@ static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
|
|||||||
hc_control |= OHCI_USB_SUSPEND;
|
hc_control |= OHCI_USB_SUSPEND;
|
||||||
|
|
||||||
writel_be(hc_control, ehci->ohci_hcctrl_reg);
|
writel_be(hc_control, ehci->ohci_hcctrl_reg);
|
||||||
(void) readl_be(ehci->ohci_hcctrl_reg);
|
(void)readl_be(ehci->ohci_hcctrl_reg);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
|
static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
|
||||||
{ }
|
{
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
/*-------------------------------------------------------------------------*/
|
||||||
@ -814,23 +811,23 @@ static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational)
|
|||||||
static inline __hc32 cpu_to_hc32(const struct ehci_hcd *ehci, const u32 x)
|
static inline __hc32 cpu_to_hc32(const struct ehci_hcd *ehci, const u32 x)
|
||||||
{
|
{
|
||||||
return ehci_big_endian_desc(ehci)
|
return ehci_big_endian_desc(ehci)
|
||||||
? (__force __hc32)cpu_to_be32(x)
|
? (__force __hc32) cpu_to_be32(x)
|
||||||
: (__force __hc32)cpu_to_le32(x);
|
: (__force __hc32) cpu_to_le32(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ehci to cpu */
|
/* ehci to cpu */
|
||||||
static inline u32 hc32_to_cpu(const struct ehci_hcd *ehci, const __hc32 x)
|
static inline u32 hc32_to_cpu(const struct ehci_hcd *ehci, const __hc32 x)
|
||||||
{
|
{
|
||||||
return ehci_big_endian_desc(ehci)
|
return ehci_big_endian_desc(ehci)
|
||||||
? be32_to_cpu((__force __be32)x)
|
? be32_to_cpu((__force __be32) x)
|
||||||
: le32_to_cpu((__force __le32)x);
|
: le32_to_cpu((__force __le32) x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 hc32_to_cpup(const struct ehci_hcd *ehci, const __hc32 *x)
|
static inline u32 hc32_to_cpup(const struct ehci_hcd *ehci, const __hc32 * x)
|
||||||
{
|
{
|
||||||
return ehci_big_endian_desc(ehci)
|
return ehci_big_endian_desc(ehci)
|
||||||
? be32_to_cpup((__force __be32 *)x)
|
? be32_to_cpup((__force __be32 *) x)
|
||||||
: le32_to_cpup((__force __le32 *)x);
|
: le32_to_cpup((__force __le32 *) x);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -847,7 +844,7 @@ static inline u32 hc32_to_cpu(const struct ehci_hcd *ehci, const __hc32 x)
|
|||||||
return le32_to_cpu(x);
|
return le32_to_cpu(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u32 hc32_to_cpup(const struct ehci_hcd *ehci, const __hc32 *x)
|
static inline u32 hc32_to_cpup(const struct ehci_hcd *ehci, const __hc32 * x)
|
||||||
{
|
{
|
||||||
return le32_to_cpup(x);
|
return le32_to_cpup(x);
|
||||||
}
|
}
|
||||||
@ -870,25 +867,24 @@ static inline u32 hc32_to_cpup(const struct ehci_hcd *ehci, const __hc32 *x)
|
|||||||
/* Declarations of things exported for use by ehci platform drivers */
|
/* Declarations of things exported for use by ehci platform drivers */
|
||||||
|
|
||||||
struct ehci_driver_overrides {
|
struct ehci_driver_overrides {
|
||||||
size_t extra_priv_size;
|
size_t extra_priv_size;
|
||||||
int (*reset)(struct usb_hcd *hcd);
|
int (*reset) (struct usb_hcd * hcd);
|
||||||
int (*port_power)(struct usb_hcd *hcd,
|
int (*port_power) (struct usb_hcd * hcd, int portnum, bool enable);
|
||||||
int portnum, bool enable);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern void ehci_init_driver(struct hc_driver *drv,
|
extern void ehci_init_driver(struct hc_driver *drv,
|
||||||
const struct ehci_driver_overrides *over);
|
const struct ehci_driver_overrides *over);
|
||||||
extern int ehci_setup(struct usb_hcd *hcd);
|
extern int ehci_setup(struct usb_hcd *hcd);
|
||||||
extern int ehci_handshake(struct ehci_hcd *ehci, void __iomem *ptr,
|
extern int ehci_handshake(struct ehci_hcd *ehci, void __iomem * ptr,
|
||||||
u32 mask, u32 done, int usec);
|
u32 mask, u32 done, int usec);
|
||||||
extern int ehci_reset(struct ehci_hcd *ehci);
|
extern int ehci_reset(struct ehci_hcd *ehci);
|
||||||
|
|
||||||
extern int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup);
|
extern int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup);
|
||||||
extern int ehci_resume(struct usb_hcd *hcd, bool force_reset);
|
extern int ehci_resume(struct usb_hcd *hcd, bool force_reset);
|
||||||
extern void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
|
extern void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
|
||||||
bool suspending, bool do_wakeup);
|
bool suspending, bool do_wakeup);
|
||||||
|
|
||||||
extern int ehci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
extern int ehci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
||||||
u16 wIndex, char *buf, u16 wLength);
|
u16 wIndex, char *buf, u16 wLength);
|
||||||
|
|
||||||
#endif /* __LINUX_EHCI_HCD_H */
|
#endif /* __LINUX_EHCI_HCD_H */
|
||||||
|
98
platform/centec-arm64/tsingma-bsp/src/gpio-ctc/gpio-ctc.c
Normal file → Executable file
98
platform/centec-arm64/tsingma-bsp/src/gpio-ctc/gpio-ctc.c
Normal file → Executable file
@ -25,12 +25,19 @@
|
|||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include "gpio-ctcapb.h"
|
#include "gpio-ctcapb.h"
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include "gpiolib.h"
|
#include "gpiolib.h"
|
||||||
|
#include "../include/sysctl.h"
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
#include "gpiolib-acpi.h"
|
||||||
|
|
||||||
#define DWAPB_MAX_PORTS 2
|
#define DWAPB_MAX_PORTS 2
|
||||||
|
|
||||||
struct ctcapb_gpio;
|
struct ctcapb_gpio;
|
||||||
|
|
||||||
|
static u32 soc_v;
|
||||||
|
|
||||||
struct ctcapb_gpio_port {
|
struct ctcapb_gpio_port {
|
||||||
bool is_registered;
|
bool is_registered;
|
||||||
unsigned int idx;
|
unsigned int idx;
|
||||||
@ -45,14 +52,15 @@ struct ctcapb_gpio {
|
|||||||
unsigned int nr_ports;
|
unsigned int nr_ports;
|
||||||
struct GpioSoc_regs *regs;
|
struct GpioSoc_regs *regs;
|
||||||
struct ctcapb_gpio_port *ports;
|
struct ctcapb_gpio_port *ports;
|
||||||
|
struct regmap *regmap_base;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void clrsetbits(unsigned __iomem *addr, u32 clr, u32 set)
|
static void clrsetbits(unsigned __iomem * addr, u32 clr, u32 set)
|
||||||
{
|
{
|
||||||
writel((readl(addr) & ~(clr)) | (set), addr);
|
writel((readl(addr) & ~(clr)) | (set), addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctcapb_gpio_to_irq(struct gpio_chip *gc, unsigned int offset)
|
static int ctcapb_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
|
||||||
{
|
{
|
||||||
struct ctcapb_gpio_port *port = gpiochip_get_data(gc);
|
struct ctcapb_gpio_port *port = gpiochip_get_data(gc);
|
||||||
|
|
||||||
@ -123,6 +131,20 @@ static void ctcapb_irq_unmask(struct irq_data *d)
|
|||||||
ctcapb_irq_enable(d);
|
ctcapb_irq_enable(d);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
static void ctcapb_irq_disable(struct irq_data *d)
|
||||||
|
{
|
||||||
|
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
|
||||||
|
struct ctcapb_gpio_port *port = igc->private;
|
||||||
|
struct gpio_chip *gc = &port->gc;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&gc->bgpio_lock, flags);
|
||||||
|
clrsetbits(&port->regs->GpioIntrEn, ~BIT(d->hwirq), 0);
|
||||||
|
spin_unlock_irqrestore(&gc->bgpio_lock, flags);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int ctcapb_irq_reqres(struct irq_data *d)
|
static int ctcapb_irq_reqres(struct irq_data *d)
|
||||||
{
|
{
|
||||||
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
|
struct irq_chip_generic *igc = irq_data_get_irq_chip_data(d);
|
||||||
@ -152,7 +174,7 @@ static int ctcapb_irq_set_type(struct irq_data *d, u32 type)
|
|||||||
struct ctcapb_gpio_port *port = igc->private;
|
struct ctcapb_gpio_port *port = igc->private;
|
||||||
struct gpio_chip *gc = &port->gc;
|
struct gpio_chip *gc = &port->gc;
|
||||||
int bit = d->hwirq;
|
int bit = d->hwirq;
|
||||||
unsigned long level, polarity, flags;
|
unsigned long level, polarity, flags, datactl, outctl;
|
||||||
|
|
||||||
if (type & ~(IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
|
if (type & ~(IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING |
|
||||||
IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
|
IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
|
||||||
@ -162,6 +184,21 @@ static int ctcapb_irq_set_type(struct irq_data *d, u32 type)
|
|||||||
level = readl(&port->regs->GpioIntrLevel);
|
level = readl(&port->regs->GpioIntrLevel);
|
||||||
polarity = readl(&port->regs->GpioIntrPolarity);
|
polarity = readl(&port->regs->GpioIntrPolarity);
|
||||||
|
|
||||||
|
if (!soc_v) {
|
||||||
|
datactl = readl(&port->regs->GpioDataCtl);
|
||||||
|
outctl = readl(&port->regs->GpioOutCtl);
|
||||||
|
|
||||||
|
datactl &= ~BIT(bit);
|
||||||
|
outctl |= BIT(bit);
|
||||||
|
|
||||||
|
writel(datactl, &port->regs->GpioDataCtl);
|
||||||
|
writel(outctl, &port->regs->GpioOutCtl);
|
||||||
|
|
||||||
|
udelay(10);
|
||||||
|
|
||||||
|
outctl &= ~BIT(bit);
|
||||||
|
writel(outctl, &port->regs->GpioOutCtl);
|
||||||
|
}
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case IRQ_TYPE_EDGE_BOTH:
|
case IRQ_TYPE_EDGE_BOTH:
|
||||||
level &= ~BIT(bit);
|
level &= ~BIT(bit);
|
||||||
@ -195,7 +232,7 @@ static int ctcapb_irq_set_type(struct irq_data *d, u32 type)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int ctcapb_gpio_set_debounce(struct gpio_chip *gc,
|
static int ctcapb_gpio_set_debounce(struct gpio_chip *gc,
|
||||||
unsigned int offset, unsigned int debounce)
|
unsigned offset, unsigned debounce)
|
||||||
{
|
{
|
||||||
struct ctcapb_gpio_port *port = gpiochip_get_data(gc);
|
struct ctcapb_gpio_port *port = gpiochip_get_data(gc);
|
||||||
unsigned long flags, val_deb;
|
unsigned long flags, val_deb;
|
||||||
@ -445,7 +482,8 @@ static struct ctcapb_platform_data *ctcapb_gpio_get_pdata(struct device *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (dev->of_node && fwnode_property_read_bool(fwnode,
|
if (dev->of_node && fwnode_property_read_bool(fwnode,
|
||||||
"interrupt-controller")) {
|
"interrupt-controller"))
|
||||||
|
{
|
||||||
pp->irq = irq_of_parse_and_map(to_of_node(fwnode), 0);
|
pp->irq = irq_of_parse_and_map(to_of_node(fwnode), 0);
|
||||||
if (!pp->irq)
|
if (!pp->irq)
|
||||||
dev_warn(dev, "no irq for port%d\n", pp->idx);
|
dev_warn(dev, "no irq for port%d\n", pp->idx);
|
||||||
@ -461,12 +499,42 @@ static struct ctcapb_platform_data *ctcapb_gpio_get_pdata(struct device *dev)
|
|||||||
return pdata;
|
return pdata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ctc_bgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
|
||||||
|
{
|
||||||
|
unsigned long mask;
|
||||||
|
|
||||||
|
if (gc->be_bits)
|
||||||
|
mask = BIT(gc->bgpio_bits - 1 - gpio);
|
||||||
|
else
|
||||||
|
mask = BIT(gpio);
|
||||||
|
|
||||||
|
if (soc_v) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
if (val)
|
||||||
|
gc->bgpio_data |= mask;
|
||||||
|
else
|
||||||
|
gc->bgpio_data &= ~mask;
|
||||||
|
|
||||||
|
gc->write_reg(gc->reg_set, gc->bgpio_data);
|
||||||
|
|
||||||
|
if (gc->be_bits)
|
||||||
|
gc->bgpio_dir |= BIT(gc->bgpio_bits - 1 - gpio);
|
||||||
|
else
|
||||||
|
gc->bgpio_dir |= BIT(gpio);
|
||||||
|
|
||||||
|
gc->write_reg(gc->reg_dir_out, gc->bgpio_dir);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int ctcapb_gpio_probe(struct platform_device *pdev)
|
static int ctcapb_gpio_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
struct ctcapb_gpio *gpio;
|
struct ctcapb_gpio *gpio;
|
||||||
int err;
|
int err, val;
|
||||||
struct device *dev = &pdev->dev;
|
struct device *dev = &pdev->dev;
|
||||||
struct ctcapb_platform_data *pdata = dev_get_platdata(dev);
|
struct ctcapb_platform_data *pdata = dev_get_platdata(dev);
|
||||||
|
|
||||||
@ -491,6 +559,18 @@ static int ctcapb_gpio_probe(struct platform_device *pdev)
|
|||||||
if (!gpio->ports)
|
if (!gpio->ports)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
gpio->regmap_base =
|
||||||
|
syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "ctc,sysctrl");
|
||||||
|
if (IS_ERR(gpio->regmap_base))
|
||||||
|
return PTR_ERR(gpio->regmap_base);
|
||||||
|
|
||||||
|
regmap_read(gpio->regmap_base,
|
||||||
|
offsetof(struct SysCtl_regs, SysCtlSysRev), &val);
|
||||||
|
|
||||||
|
soc_v = val;
|
||||||
|
|
||||||
|
printk("soc version = 0x%x\n", soc_v);
|
||||||
|
|
||||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||||
gpio->regs =
|
gpio->regs =
|
||||||
(struct GpioSoc_regs *)devm_ioremap_resource(&pdev->dev, res);
|
(struct GpioSoc_regs *)devm_ioremap_resource(&pdev->dev, res);
|
||||||
@ -508,8 +588,9 @@ static int ctcapb_gpio_probe(struct platform_device *pdev)
|
|||||||
|
|
||||||
out_unregister:
|
out_unregister:
|
||||||
ctcapb_gpio_unregister(gpio);
|
ctcapb_gpio_unregister(gpio);
|
||||||
for (i = 0; i < gpio->nr_ports; i++)
|
for (i = 0; i < gpio->nr_ports; i++) {
|
||||||
ctcapb_irq_teardown(&gpio->ports[i]);
|
ctcapb_irq_teardown(&gpio->ports[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -520,8 +601,9 @@ static int ctcapb_gpio_remove(struct platform_device *pdev)
|
|||||||
struct ctcapb_gpio *gpio = platform_get_drvdata(pdev);
|
struct ctcapb_gpio *gpio = platform_get_drvdata(pdev);
|
||||||
|
|
||||||
ctcapb_gpio_unregister(gpio);
|
ctcapb_gpio_unregister(gpio);
|
||||||
for (i = 0; i < gpio->nr_ports; i++)
|
for (i = 0; i < gpio->nr_ports; i++) {
|
||||||
ctcapb_irq_teardown(&gpio->ports[i]);
|
ctcapb_irq_teardown(&gpio->ports[i]);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,27 +1,22 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0 */
|
||||||
/*
|
/*
|
||||||
* Internal GPIO functions.
|
* Internal GPIO functions.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013, Intel Corporation
|
* Copyright (C) 2013, Intel Corporation
|
||||||
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
|
* Author: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef GPIOLIB_H
|
#ifndef GPIOLIB_H
|
||||||
#define GPIOLIB_H
|
#define GPIOLIB_H
|
||||||
|
|
||||||
#include <linux/gpio/driver.h>
|
#include <linux/gpio/driver.h>
|
||||||
#include <linux/gpio/consumer.h> /* for enum gpiod_flags */
|
#include <linux/gpio/consumer.h> /* for enum gpiod_flags */
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/cdev.h>
|
#include <linux/cdev.h>
|
||||||
|
|
||||||
enum of_gpio_flags;
|
#define GPIOCHIP_NAME "gpiochip"
|
||||||
enum gpio_lookup_flags;
|
|
||||||
struct acpi_device;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct gpio_device - internal state container for GPIO devices
|
* struct gpio_device - internal state container for GPIO devices
|
||||||
@ -49,18 +44,19 @@ struct acpi_device;
|
|||||||
* userspace.
|
* userspace.
|
||||||
*/
|
*/
|
||||||
struct gpio_device {
|
struct gpio_device {
|
||||||
int id;
|
int id;
|
||||||
struct device dev;
|
struct device dev;
|
||||||
struct cdev chrdev;
|
struct cdev chrdev;
|
||||||
struct device *mockdev;
|
struct device *mockdev;
|
||||||
struct module *owner;
|
struct module *owner;
|
||||||
struct gpio_chip *chip;
|
struct gpio_chip *chip;
|
||||||
struct gpio_desc *descs;
|
struct gpio_desc *descs;
|
||||||
int base;
|
int base;
|
||||||
u16 ngpio;
|
u16 ngpio;
|
||||||
const char *label;
|
const char *label;
|
||||||
void *data;
|
void *data;
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
|
struct blocking_notifier_head notifier;
|
||||||
|
|
||||||
#ifdef CONFIG_PINCTRL
|
#ifdef CONFIG_PINCTRL
|
||||||
/*
|
/*
|
||||||
@ -73,138 +69,36 @@ struct gpio_device {
|
|||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/* gpio suffixes used for ACPI and device tree lookup */
|
||||||
* struct acpi_gpio_info - ACPI GPIO specific information
|
static __maybe_unused const char *const gpio_suffixes[] = { "gpios", "gpio" };
|
||||||
* @adev: reference to ACPI device which consumes GPIO resource
|
|
||||||
* @flags: GPIO initialization flags
|
struct gpio_array {
|
||||||
* @gpioint: if %true this GPIO is of type GpioInt otherwise type is GpioIo
|
struct gpio_desc **desc;
|
||||||
* @polarity: interrupt polarity as provided by ACPI
|
unsigned int size;
|
||||||
* @triggering: triggering type as provided by ACPI
|
struct gpio_chip *chip;
|
||||||
* @quirks: Linux specific quirks as provided by struct acpi_gpio_mapping
|
unsigned long *get_mask;
|
||||||
*/
|
unsigned long *set_mask;
|
||||||
struct acpi_gpio_info {
|
unsigned long invert_mask[];
|
||||||
struct acpi_device *adev;
|
|
||||||
enum gpiod_flags flags;
|
|
||||||
bool gpioint;
|
|
||||||
int polarity;
|
|
||||||
int triggering;
|
|
||||||
unsigned int quirks;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* gpio suffixes used for ACPI and device tree lookup */
|
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *gc, unsigned int hwnum);
|
||||||
static __maybe_unused const char * const gpio_suffixes[] = { "gpios", "gpio" };
|
|
||||||
|
|
||||||
#ifdef CONFIG_OF_GPIO
|
|
||||||
struct gpio_desc *of_find_gpio(struct device *dev,
|
|
||||||
const char *con_id,
|
|
||||||
unsigned int idx,
|
|
||||||
enum gpio_lookup_flags *flags);
|
|
||||||
struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
|
|
||||||
const char *list_name, int index, enum of_gpio_flags *flags);
|
|
||||||
int of_gpiochip_add(struct gpio_chip *gc);
|
|
||||||
void of_gpiochip_remove(struct gpio_chip *gc);
|
|
||||||
#else
|
|
||||||
static inline struct gpio_desc *of_find_gpio(struct device *dev,
|
|
||||||
const char *con_id,
|
|
||||||
unsigned int idx,
|
|
||||||
enum gpio_lookup_flags *flags)
|
|
||||||
{
|
|
||||||
return ERR_PTR(-ENOENT);
|
|
||||||
}
|
|
||||||
static inline struct gpio_desc *of_get_named_gpiod_flags(struct device_node *np,
|
|
||||||
const char *list_name, int index, enum of_gpio_flags *flags)
|
|
||||||
{
|
|
||||||
return ERR_PTR(-ENOENT);
|
|
||||||
}
|
|
||||||
static inline int of_gpiochip_add(struct gpio_chip *gc) { return 0; }
|
|
||||||
static inline void of_gpiochip_remove(struct gpio_chip *gc) { }
|
|
||||||
#endif /* CONFIG_OF_GPIO */
|
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
|
||||||
void acpi_gpiochip_add(struct gpio_chip *chip);
|
|
||||||
void acpi_gpiochip_remove(struct gpio_chip *chip);
|
|
||||||
|
|
||||||
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
|
|
||||||
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
|
|
||||||
|
|
||||||
int acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags,
|
|
||||||
struct acpi_gpio_info *info);
|
|
||||||
|
|
||||||
struct gpio_desc *acpi_find_gpio(struct device *dev,
|
|
||||||
const char *con_id,
|
|
||||||
unsigned int idx,
|
|
||||||
enum gpiod_flags *dflags,
|
|
||||||
enum gpio_lookup_flags *lookupflags);
|
|
||||||
struct gpio_desc *acpi_node_get_gpiod(struct fwnode_handle *fwnode,
|
|
||||||
const char *propname, int index,
|
|
||||||
struct acpi_gpio_info *info);
|
|
||||||
|
|
||||||
int acpi_gpio_count(struct device *dev, const char *con_id);
|
|
||||||
|
|
||||||
bool acpi_can_fallback_to_crs(struct acpi_device *adev, const char *con_id);
|
|
||||||
#else
|
|
||||||
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
|
|
||||||
static inline void acpi_gpiochip_remove(struct gpio_chip *chip) { }
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
acpi_gpiochip_request_interrupts(struct gpio_chip *chip) { }
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
acpi_gpio_update_gpiod_flags(enum gpiod_flags *flags, struct acpi_gpio_info *info)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline struct gpio_desc *
|
|
||||||
acpi_find_gpio(struct device *dev, const char *con_id,
|
|
||||||
unsigned int idx, enum gpiod_flags *dflags,
|
|
||||||
enum gpio_lookup_flags *lookupflags)
|
|
||||||
{
|
|
||||||
return ERR_PTR(-ENOENT);
|
|
||||||
}
|
|
||||||
static inline struct gpio_desc *
|
|
||||||
acpi_node_get_gpiod(struct fwnode_handle *fwnode, const char *propname,
|
|
||||||
int index, struct acpi_gpio_info *info)
|
|
||||||
{
|
|
||||||
return ERR_PTR(-ENXIO);
|
|
||||||
}
|
|
||||||
static inline int acpi_gpio_count(struct device *dev, const char *con_id)
|
|
||||||
{
|
|
||||||
return -ENODEV;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool acpi_can_fallback_to_crs(struct acpi_device *adev,
|
|
||||||
const char *con_id)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct gpio_desc *gpiochip_get_desc(struct gpio_chip *chip, u16 hwnum);
|
|
||||||
int gpiod_get_array_value_complex(bool raw, bool can_sleep,
|
int gpiod_get_array_value_complex(bool raw, bool can_sleep,
|
||||||
unsigned int array_size,
|
unsigned int array_size,
|
||||||
struct gpio_desc **desc_array,
|
struct gpio_desc **desc_array,
|
||||||
int *value_array);
|
struct gpio_array *array_info,
|
||||||
|
unsigned long *value_bitmap);
|
||||||
int gpiod_set_array_value_complex(bool raw, bool can_sleep,
|
int gpiod_set_array_value_complex(bool raw, bool can_sleep,
|
||||||
unsigned int array_size,
|
unsigned int array_size,
|
||||||
struct gpio_desc **desc_array,
|
struct gpio_desc **desc_array,
|
||||||
int *value_array);
|
struct gpio_array *array_info,
|
||||||
|
unsigned long *value_bitmap);
|
||||||
|
|
||||||
/* This is just passed between gpiolib and devres */
|
extern spinlock_t gpio_lock;
|
||||||
struct gpio_desc *gpiod_get_from_of_node(struct device_node *node,
|
|
||||||
const char *propname, int index,
|
|
||||||
enum gpiod_flags dflags,
|
|
||||||
const char *label);
|
|
||||||
|
|
||||||
extern struct spinlock gpio_lock;
|
|
||||||
extern struct list_head gpio_devices;
|
extern struct list_head gpio_devices;
|
||||||
|
|
||||||
struct gpio_desc {
|
struct gpio_desc {
|
||||||
struct gpio_device *gdev;
|
struct gpio_device *gdev;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
/* flag symbols are bit numbers */
|
/* flag symbols are bit numbers */
|
||||||
#define FLAG_REQUESTED 0
|
#define FLAG_REQUESTED 0
|
||||||
#define FLAG_IS_OUT 1
|
#define FLAG_IS_OUT 1
|
||||||
@ -214,21 +108,34 @@ struct gpio_desc {
|
|||||||
#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
|
#define FLAG_OPEN_DRAIN 7 /* Gpio is open drain type */
|
||||||
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
|
#define FLAG_OPEN_SOURCE 8 /* Gpio is open source type */
|
||||||
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
|
#define FLAG_USED_AS_IRQ 9 /* GPIO is connected to an IRQ */
|
||||||
|
#define FLAG_IRQ_IS_ENABLED 10 /* GPIO is connected to an enabled IRQ */
|
||||||
#define FLAG_IS_HOGGED 11 /* GPIO is hogged */
|
#define FLAG_IS_HOGGED 11 /* GPIO is hogged */
|
||||||
#define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */
|
#define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */
|
||||||
|
#define FLAG_PULL_UP 13 /* GPIO has pull up enabled */
|
||||||
|
#define FLAG_PULL_DOWN 14 /* GPIO has pull down enabled */
|
||||||
|
#define FLAG_BIAS_DISABLE 15 /* GPIO has pull disabled */
|
||||||
|
#define FLAG_EDGE_RISING 16 /* GPIO CDEV detects rising edge events */
|
||||||
|
#define FLAG_EDGE_FALLING 17 /* GPIO CDEV detects falling edge events */
|
||||||
|
|
||||||
/* Connection label */
|
/* Connection label */
|
||||||
const char *label;
|
const char *label;
|
||||||
/* Name of the GPIO */
|
/* Name of the GPIO */
|
||||||
const char *name;
|
const char *name;
|
||||||
|
#ifdef CONFIG_OF_DYNAMIC
|
||||||
|
struct device_node *hog;
|
||||||
|
#endif
|
||||||
|
#ifdef CONFIG_GPIO_CDEV
|
||||||
|
/* debounce period in microseconds */
|
||||||
|
unsigned int debounce_period_us;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
int gpiod_request(struct gpio_desc *desc, const char *label);
|
int gpiod_request(struct gpio_desc *desc, const char *label);
|
||||||
void gpiod_free(struct gpio_desc *desc);
|
void gpiod_free(struct gpio_desc *desc);
|
||||||
int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
|
int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
|
||||||
unsigned long lflags, enum gpiod_flags dflags);
|
unsigned long lflags, enum gpiod_flags dflags);
|
||||||
int gpiod_hog(struct gpio_desc *desc, const char *name,
|
int gpiod_hog(struct gpio_desc *desc, const char *name,
|
||||||
unsigned long lflags, enum gpiod_flags dflags);
|
unsigned long lflags, enum gpiod_flags dflags);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the GPIO number of the passed descriptor relative to its chip
|
* Return the GPIO number of the passed descriptor relative to its chip
|
||||||
@ -238,9 +145,6 @@ static inline int gpio_chip_hwgpio(const struct gpio_desc *desc)
|
|||||||
return desc - &desc->gdev->descs[0];
|
return desc - &desc->gdev->descs[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
void devprop_gpiochip_set_names(struct gpio_chip *chip,
|
|
||||||
const struct fwnode_handle *fwnode);
|
|
||||||
|
|
||||||
/* With descriptor prefix */
|
/* With descriptor prefix */
|
||||||
|
|
||||||
#define gpiod_emerg(desc, fmt, ...) \
|
#define gpiod_emerg(desc, fmt, ...) \
|
||||||
@ -264,35 +168,17 @@ void devprop_gpiochip_set_names(struct gpio_chip *chip,
|
|||||||
|
|
||||||
/* With chip prefix */
|
/* With chip prefix */
|
||||||
|
|
||||||
#define chip_emerg(chip, fmt, ...) \
|
#define chip_emerg(gc, fmt, ...) \
|
||||||
dev_emerg(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__)
|
dev_emerg(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
|
||||||
#define chip_crit(chip, fmt, ...) \
|
#define chip_crit(gc, fmt, ...) \
|
||||||
dev_crit(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__)
|
dev_crit(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
|
||||||
#define chip_err(chip, fmt, ...) \
|
#define chip_err(gc, fmt, ...) \
|
||||||
dev_err(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__)
|
dev_err(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
|
||||||
#define chip_warn(chip, fmt, ...) \
|
#define chip_warn(gc, fmt, ...) \
|
||||||
dev_warn(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__)
|
dev_warn(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
|
||||||
#define chip_info(chip, fmt, ...) \
|
#define chip_info(gc, fmt, ...) \
|
||||||
dev_info(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__)
|
dev_info(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
|
||||||
#define chip_dbg(chip, fmt, ...) \
|
#define chip_dbg(gc, fmt, ...) \
|
||||||
dev_dbg(&chip->gpiodev->dev, "(%s): " fmt, chip->label, ##__VA_ARGS__)
|
dev_dbg(&gc->gpiodev->dev, "(%s): " fmt, gc->label, ##__VA_ARGS__)
|
||||||
|
|
||||||
#ifdef CONFIG_GPIO_SYSFS
|
|
||||||
|
|
||||||
int gpiochip_sysfs_register(struct gpio_device *gdev);
|
|
||||||
void gpiochip_sysfs_unregister(struct gpio_device *gdev);
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static inline int gpiochip_sysfs_register(struct gpio_device *gdev)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void gpiochip_sysfs_unregister(struct gpio_device *gdev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* CONFIG_GPIO_SYSFS */
|
|
||||||
|
|
||||||
#endif /* GPIOLIB_H */
|
#endif /* GPIOLIB_H */
|
||||||
|
147
platform/centec-arm64/tsingma-bsp/src/i2c-ctc/i2c-ctc.c
Normal file → Executable file
147
platform/centec-arm64/tsingma-bsp/src/i2c-ctc/i2c-ctc.c
Normal file → Executable file
@ -1,4 +1,5 @@
|
|||||||
/* Centec I2C controller driver
|
/*
|
||||||
|
* Centec I2C controller driver
|
||||||
*
|
*
|
||||||
* Author: Wangyb <wangyb@centecnetworks.com>
|
* Author: Wangyb <wangyb@centecnetworks.com>
|
||||||
*
|
*
|
||||||
@ -20,6 +21,10 @@
|
|||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include "i2c-ctc.h"
|
#include "i2c-ctc.h"
|
||||||
|
#include "../pinctrl-ctc/pinctrl-ctc.h"
|
||||||
|
#include "../include/sysctl.h"
|
||||||
|
#include <linux/mfd/syscon.h>
|
||||||
|
#include <linux/regmap.h>
|
||||||
|
|
||||||
#define IC_ICK_NS(f) (1000000000 / f)
|
#define IC_ICK_NS(f) (1000000000 / f)
|
||||||
|
|
||||||
@ -30,7 +35,7 @@ static char *abort_sources[] = {
|
|||||||
[ABRT_10ADDR2_NOACK] =
|
[ABRT_10ADDR2_NOACK] =
|
||||||
"second address byte not acknowledged (10bit mode)",
|
"second address byte not acknowledged (10bit mode)",
|
||||||
[ABRT_TXDATA_NOACK] = "data not acknowledged",
|
[ABRT_TXDATA_NOACK] = "data not acknowledged",
|
||||||
[ABRT_GCALL_NOACK] = "no acknowledgment for a general call",
|
[ABRT_GCALL_NOACK] = "no acknowledgement for a general call",
|
||||||
[ABRT_GCALL_READ] = "read after general call",
|
[ABRT_GCALL_READ] = "read after general call",
|
||||||
[ABRT_SBYTE_ACKDET] = "start byte acknowledged",
|
[ABRT_SBYTE_ACKDET] = "start byte acknowledged",
|
||||||
[ABRT_SBYTE_NORSTRT] =
|
[ABRT_SBYTE_NORSTRT] =
|
||||||
@ -99,8 +104,7 @@ int i2c_ctc_init(struct ctc_i2c_dev *dev)
|
|||||||
__i2c_ctc_enable(dev, false);
|
__i2c_ctc_enable(dev, false);
|
||||||
|
|
||||||
/* Set SCL timing parameters */
|
/* Set SCL timing parameters */
|
||||||
if ((dev->master_cfg & CTC_IC_CON_SPEED_MASK)
|
if ((dev->master_cfg & CTC_IC_CON_SPEED_MASK) == CTC_IC_CON_SPEED_FAST) {
|
||||||
== CTC_IC_CON_SPEED_FAST) {
|
|
||||||
hcnt = __ctc_calc_fs_cnt(dev->clk_freq) - 14 - 4;
|
hcnt = __ctc_calc_fs_cnt(dev->clk_freq) - 14 - 4;
|
||||||
lcnt = __ctc_calc_fs_cnt(dev->clk_freq) - 1 - 2;
|
lcnt = __ctc_calc_fs_cnt(dev->clk_freq) - 1 - 2;
|
||||||
|
|
||||||
@ -122,8 +126,9 @@ int i2c_ctc_init(struct ctc_i2c_dev *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Configure SDA Hold Time if required */
|
/* Configure SDA Hold Time if required */
|
||||||
if (dev->sda_hold_time)
|
if (dev->sda_hold_time) {
|
||||||
ctc_writel(dev, dev->sda_hold_time, CTC_IC_SDA_HOLD);
|
ctc_writel(dev, dev->sda_hold_time, CTC_IC_SDA_HOLD);
|
||||||
|
}
|
||||||
|
|
||||||
/* Configure Tx/Rx FIFO threshold levels */
|
/* Configure Tx/Rx FIFO threshold levels */
|
||||||
comp_param1 = ctc_readl(dev, CTC_IC_COMP_PARAM_1);
|
comp_param1 = ctc_readl(dev, CTC_IC_COMP_PARAM_1);
|
||||||
@ -139,6 +144,33 @@ int i2c_ctc_init(struct ctc_i2c_dev *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int i2c_ctc_recover_bus(struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
struct ctc_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||||
|
u32 val = 0;
|
||||||
|
|
||||||
|
dev_info(dev->dev, "Trying i2c bus recovery\n");
|
||||||
|
|
||||||
|
if (dev->i2c_num == 0)
|
||||||
|
val = 0x1;
|
||||||
|
if (dev->i2c_num == 1)
|
||||||
|
val = 0x2;
|
||||||
|
|
||||||
|
regmap_write(dev->regmap_base,
|
||||||
|
offsetof(struct SysCtl_regs, SysI2CResetCtl), val);
|
||||||
|
val = 0x0;
|
||||||
|
regmap_write(dev->regmap_base,
|
||||||
|
offsetof(struct SysCtl_regs, SysI2CResetCtl), val);
|
||||||
|
|
||||||
|
if (dev->soc_ver == CTC_REV_TM_1_1) {
|
||||||
|
ctc_writel(dev, 0x1, CTC_IC_BUS_CLEAR_EN);
|
||||||
|
}
|
||||||
|
|
||||||
|
i2c_ctc_init(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int i2c_ctc_wait_bus_not_busy(struct ctc_i2c_dev *dev)
|
static int i2c_ctc_wait_bus_not_busy(struct ctc_i2c_dev *dev)
|
||||||
{
|
{
|
||||||
int timeout = 20;
|
int timeout = 20;
|
||||||
@ -146,7 +178,15 @@ static int i2c_ctc_wait_bus_not_busy(struct ctc_i2c_dev *dev)
|
|||||||
while (ctc_readl(dev, CTC_IC_STATUS) & CTC_IC_STATUS_ACTIVITY) {
|
while (ctc_readl(dev, CTC_IC_STATUS) & CTC_IC_STATUS_ACTIVITY) {
|
||||||
if (timeout <= 0) {
|
if (timeout <= 0) {
|
||||||
dev_warn(dev->dev, "timeout waiting for bus ready\n");
|
dev_warn(dev->dev, "timeout waiting for bus ready\n");
|
||||||
return -ETIMEDOUT;
|
i2c_recover_bus(&dev->adapter);
|
||||||
|
|
||||||
|
if (ctc_readl(dev, CTC_IC_STATUS) &
|
||||||
|
CTC_IC_STATUS_ACTIVITY) {
|
||||||
|
dev_warn(dev->dev,
|
||||||
|
"timeout waiting for bus ready again\n");
|
||||||
|
return -ETIMEDOUT;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
timeout--;
|
timeout--;
|
||||||
usleep_range(1000, 1100);
|
usleep_range(1000, 1100);
|
||||||
@ -154,6 +194,16 @@ static int i2c_ctc_wait_bus_not_busy(struct ctc_i2c_dev *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void i2c_ctc_disable(struct ctc_i2c_dev *dev)
|
||||||
|
{
|
||||||
|
/* Disable controller */
|
||||||
|
__i2c_ctc_enable(dev, false);
|
||||||
|
|
||||||
|
/* Disable all interupts */
|
||||||
|
ctc_writel(dev, 0, CTC_IC_INTR_MASK);
|
||||||
|
ctc_readl(dev, CTC_IC_CLR_INTR);
|
||||||
|
}
|
||||||
|
|
||||||
void i2c_ctc_disable_intr(struct ctc_i2c_dev *dev)
|
void i2c_ctc_disable_intr(struct ctc_i2c_dev *dev)
|
||||||
{
|
{
|
||||||
ctc_writel(dev, 0, CTC_IC_INTR_MASK);
|
ctc_writel(dev, 0, CTC_IC_INTR_MASK);
|
||||||
@ -189,7 +239,7 @@ static void i2c_ctc_xfer_init(struct ctc_i2c_dev *dev)
|
|||||||
|
|
||||||
/* Clear and enable interrupts */
|
/* Clear and enable interrupts */
|
||||||
ctc_readl(dev, CTC_IC_CLR_INTR);
|
ctc_readl(dev, CTC_IC_CLR_INTR);
|
||||||
ctc_writel(dev, CTC_IC_INTR_DEFAULT_MASK, CTC_IC_INTR_MASK);
|
ctc_writel(dev, CTC_IC_INTR_MASTER_MASK, CTC_IC_INTR_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int i2c_ctc_handle_tx_abort(struct ctc_i2c_dev *dev)
|
static int i2c_ctc_handle_tx_abort(struct ctc_i2c_dev *dev)
|
||||||
@ -199,13 +249,12 @@ static int i2c_ctc_handle_tx_abort(struct ctc_i2c_dev *dev)
|
|||||||
|
|
||||||
if (abort_source & CTC_IC_TX_ABRT_NOACK) {
|
if (abort_source & CTC_IC_TX_ABRT_NOACK) {
|
||||||
for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
|
for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
|
||||||
dev_dbg(dev->dev, "%s: %s\n", __func__,
|
dev_dbg(dev->dev, "%s: %s\n", __func__, abort_sources[i]);
|
||||||
abort_sources[i]);
|
|
||||||
return -EREMOTEIO;
|
return -EREMOTEIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
|
for_each_set_bit(i, &abort_source, ARRAY_SIZE(abort_sources))
|
||||||
dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]);
|
dev_err(dev->dev, "%s: %s\n", __func__, abort_sources[i]);
|
||||||
|
|
||||||
if (abort_source & CTC_IC_TX_ARB_LOST)
|
if (abort_source & CTC_IC_TX_ARB_LOST)
|
||||||
return -EAGAIN;
|
return -EAGAIN;
|
||||||
@ -241,7 +290,7 @@ static int i2c_ctc_interrupt_transfer(struct ctc_i2c_dev *dev)
|
|||||||
/* wait for tx to complete */
|
/* wait for tx to complete */
|
||||||
if (!wait_for_completion_timeout(&dev->cmd_complete, HZ)) {
|
if (!wait_for_completion_timeout(&dev->cmd_complete, HZ)) {
|
||||||
dev_err(dev->dev, "controller timed out\n");
|
dev_err(dev->dev, "controller timed out\n");
|
||||||
i2c_ctc_init(dev);
|
i2c_recover_bus(&dev->adapter);
|
||||||
ret = -ETIMEDOUT;
|
ret = -ETIMEDOUT;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -287,8 +336,7 @@ static int ctc_i2c_xfer_finish(struct ctc_i2c_dev *dev)
|
|||||||
CTC_IC_INTR_STOP_DET)) {
|
CTC_IC_INTR_STOP_DET)) {
|
||||||
ctc_readl(dev, CTC_IC_CLR_STOP_DET);
|
ctc_readl(dev, CTC_IC_CLR_STOP_DET);
|
||||||
break;
|
break;
|
||||||
} else if (time_after(jiffies, start_stop_det +
|
} else if (time_after(jiffies, start_stop_det + I2C_STOPDET_TO)) {
|
||||||
I2C_STOPDET_TO)) {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,8 +350,8 @@ static int ctc_i2c_xfer_finish(struct ctc_i2c_dev *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __ctc_i2c_read(struct ctc_i2c_dev *dev, __u16 chip_addr, u8 *offset,
|
static int __ctc_i2c_read(struct ctc_i2c_dev *dev, __u16 chip_addr, u8 * offset,
|
||||||
__u16 olen, u8 *data, __u16 dlen)
|
__u16 olen, u8 * data, __u16 dlen)
|
||||||
{
|
{
|
||||||
unsigned int active = 0;
|
unsigned int active = 0;
|
||||||
unsigned int flag = 0;
|
unsigned int flag = 0;
|
||||||
@ -371,7 +419,7 @@ static int __ctc_i2c_read(struct ctc_i2c_dev *dev, __u16 chip_addr, u8 *offset,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int __ctc_i2c_write(struct ctc_i2c_dev *dev, __u16 chip_addr,
|
static int __ctc_i2c_write(struct ctc_i2c_dev *dev, __u16 chip_addr,
|
||||||
u8 *offset, __u16 olen, u8 *data, __u16 dlen)
|
u8 * offset, __u16 olen, u8 * data, __u16 dlen)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
unsigned long start_time_tx;
|
unsigned long start_time_tx;
|
||||||
@ -401,8 +449,9 @@ static int __ctc_i2c_write(struct ctc_i2c_dev *dev, __u16 chip_addr,
|
|||||||
}
|
}
|
||||||
data++;
|
data++;
|
||||||
start_time_tx = jiffies;
|
start_time_tx = jiffies;
|
||||||
} else if (time_after(jiffies, start_time_tx +
|
} else
|
||||||
(nb * I2C_BYTE_TO))) {
|
if (time_after(jiffies, start_time_tx + (nb * I2C_BYTE_TO)))
|
||||||
|
{
|
||||||
dev_err(dev->dev, "Timed out. i2c write Failed\n");
|
dev_err(dev->dev, "Timed out. i2c write Failed\n");
|
||||||
return -ETIMEDOUT;
|
return -ETIMEDOUT;
|
||||||
}
|
}
|
||||||
@ -418,8 +467,7 @@ static int i2c_ctc_polling_transfer(struct ctc_i2c_dev *dev)
|
|||||||
memset(&dummy, 0, sizeof(struct i2c_msg));
|
memset(&dummy, 0, sizeof(struct i2c_msg));
|
||||||
|
|
||||||
/* We expect either two messages (one with an offset and one with the
|
/* We expect either two messages (one with an offset and one with the
|
||||||
* actucal data) or one message (just data)
|
* actucal data) or one message (just data) */
|
||||||
*/
|
|
||||||
if (dev->msgs_num > 2 || dev->msgs_num == 0) {
|
if (dev->msgs_num > 2 || dev->msgs_num == 0) {
|
||||||
dev_err(dev->dev, "%s: Only one or two messages are supported.",
|
dev_err(dev->dev, "%s: Only one or two messages are supported.",
|
||||||
__func__);
|
__func__);
|
||||||
@ -469,7 +517,7 @@ static void i2c_ctc_xfer_msg(struct ctc_i2c_dev *dev)
|
|||||||
u8 *buf = dev->tx_buf;
|
u8 *buf = dev->tx_buf;
|
||||||
bool need_restart = false;
|
bool need_restart = false;
|
||||||
|
|
||||||
intr_mask = CTC_IC_INTR_DEFAULT_MASK;
|
intr_mask = CTC_IC_INTR_MASTER_MASK;
|
||||||
|
|
||||||
/* msg_write_idx */
|
/* msg_write_idx */
|
||||||
for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
|
for (; dev->msg_write_idx < dev->msgs_num; dev->msg_write_idx++) {
|
||||||
@ -519,14 +567,11 @@ static void i2c_ctc_xfer_msg(struct ctc_i2c_dev *dev)
|
|||||||
if (rx_limit - dev->rx_outstanding <= 0)
|
if (rx_limit - dev->rx_outstanding <= 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* 1 = Read */
|
ctc_writel(dev, cmd | CTC_CMD_READ, CTC_IC_DATA_CMD); /* 1 = Read */
|
||||||
ctc_writel(dev, cmd | CTC_CMD_READ,
|
|
||||||
CTC_IC_DATA_CMD);
|
|
||||||
rx_limit--;
|
rx_limit--;
|
||||||
dev->rx_outstanding++;
|
dev->rx_outstanding++;
|
||||||
} else
|
} else
|
||||||
/* 0 = Write */
|
ctc_writel(dev, cmd | *buf++, CTC_IC_DATA_CMD); /* 0 = Write */
|
||||||
ctc_writel(dev, cmd | *buf++, CTC_IC_DATA_CMD);
|
|
||||||
tx_limit--;
|
tx_limit--;
|
||||||
buf_len--;
|
buf_len--;
|
||||||
}
|
}
|
||||||
@ -538,8 +583,8 @@ static void i2c_ctc_xfer_msg(struct ctc_i2c_dev *dev)
|
|||||||
/* more bytes to be written */
|
/* more bytes to be written */
|
||||||
dev->status |= STATUS_WRITE_IN_PROGRESS;
|
dev->status |= STATUS_WRITE_IN_PROGRESS;
|
||||||
break;
|
break;
|
||||||
}
|
} else
|
||||||
dev->status &= ~STATUS_WRITE_IN_PROGRESS;
|
dev->status &= ~STATUS_WRITE_IN_PROGRESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dev->msg_write_idx == dev->msgs_num)
|
if (dev->msg_write_idx == dev->msgs_num)
|
||||||
@ -584,8 +629,8 @@ static void i2c_ctc_read(struct ctc_i2c_dev *dev)
|
|||||||
dev->rx_buf_len = len;
|
dev->rx_buf_len = len;
|
||||||
dev->rx_buf = buf;
|
dev->rx_buf = buf;
|
||||||
return;
|
return;
|
||||||
}
|
} else
|
||||||
dev->status &= ~STATUS_READ_IN_PROGRESS;
|
dev->status &= ~STATUS_READ_IN_PROGRESS;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -627,6 +672,7 @@ static irqreturn_t i2c_ctc_isr(int this_irq, void *dev_id)
|
|||||||
|
|
||||||
enabled = ctc_readl(dev, CTC_IC_ENABLE);
|
enabled = ctc_readl(dev, CTC_IC_ENABLE);
|
||||||
stat = ctc_readl(dev, CTC_IC_RAW_INTR_STAT);
|
stat = ctc_readl(dev, CTC_IC_RAW_INTR_STAT);
|
||||||
|
|
||||||
dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__, enabled,
|
dev_dbg(dev->dev, "%s: enabled=%#x stat=%#x\n", __func__, enabled,
|
||||||
stat);
|
stat);
|
||||||
if (!enabled || !(stat & ~CTC_IC_INTR_ACTIVITY))
|
if (!enabled || !(stat & ~CTC_IC_INTR_ACTIVITY))
|
||||||
@ -658,7 +704,6 @@ tx_aborted:
|
|||||||
static u32 i2c_ctc_func(struct i2c_adapter *adap)
|
static u32 i2c_ctc_func(struct i2c_adapter *adap)
|
||||||
{
|
{
|
||||||
struct ctc_i2c_dev *dev = i2c_get_adapdata(adap);
|
struct ctc_i2c_dev *dev = i2c_get_adapdata(adap);
|
||||||
|
|
||||||
return dev->functionality;
|
return dev->functionality;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,6 +712,10 @@ static struct i2c_algorithm i2c_ctc_algo = {
|
|||||||
.functionality = i2c_ctc_func,
|
.functionality = i2c_ctc_func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct i2c_bus_recovery_info i2c_ctc_recovery_info = {
|
||||||
|
.recover_bus = i2c_ctc_recover_bus,
|
||||||
|
};
|
||||||
|
|
||||||
int i2c_ctc_probe(struct ctc_i2c_dev *dev)
|
int i2c_ctc_probe(struct ctc_i2c_dev *dev)
|
||||||
{
|
{
|
||||||
struct i2c_adapter *adap = &dev->adapter;
|
struct i2c_adapter *adap = &dev->adapter;
|
||||||
@ -680,6 +729,7 @@ int i2c_ctc_probe(struct ctc_i2c_dev *dev)
|
|||||||
snprintf(adap->name, sizeof(adap->name),
|
snprintf(adap->name, sizeof(adap->name),
|
||||||
"Centec TsingMa SoC's I2C adapter");
|
"Centec TsingMa SoC's I2C adapter");
|
||||||
adap->algo = &i2c_ctc_algo;
|
adap->algo = &i2c_ctc_algo;
|
||||||
|
adap->bus_recovery_info = &i2c_ctc_recovery_info;
|
||||||
adap->dev.parent = dev->dev;
|
adap->dev.parent = dev->dev;
|
||||||
i2c_set_adapdata(adap, dev);
|
i2c_set_adapdata(adap, dev);
|
||||||
|
|
||||||
@ -708,6 +758,7 @@ static int ctc_i2c_plat_probe(struct platform_device *pdev)
|
|||||||
struct resource *mem;
|
struct resource *mem;
|
||||||
int irq, ret;
|
int irq, ret;
|
||||||
u32 clk_freq, ht;
|
u32 clk_freq, ht;
|
||||||
|
u32 val, i2c_num;
|
||||||
|
|
||||||
irq = platform_get_irq(pdev, 0);
|
irq = platform_get_irq(pdev, 0);
|
||||||
if (irq < 0)
|
if (irq < 0)
|
||||||
@ -722,6 +773,15 @@ static int ctc_i2c_plat_probe(struct platform_device *pdev)
|
|||||||
if (IS_ERR(dev->base))
|
if (IS_ERR(dev->base))
|
||||||
return PTR_ERR(dev->base);
|
return PTR_ERR(dev->base);
|
||||||
|
|
||||||
|
dev->regmap_base =
|
||||||
|
syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "ctc,sysctrl");
|
||||||
|
if (IS_ERR(dev->regmap_base))
|
||||||
|
return PTR_ERR(dev->regmap_base);
|
||||||
|
|
||||||
|
regmap_read(dev->regmap_base,
|
||||||
|
offsetof(struct SysCtl_regs, SysCtlSysRev), &val);
|
||||||
|
dev->soc_ver = ((val == 0x1) ? CTC_REV_TM_1_1 : CTC_REV_TM_1_0);
|
||||||
|
|
||||||
dev->dev = &pdev->dev;
|
dev->dev = &pdev->dev;
|
||||||
dev->irq = irq;
|
dev->irq = irq;
|
||||||
platform_set_drvdata(pdev, dev);
|
platform_set_drvdata(pdev, dev);
|
||||||
@ -738,17 +798,6 @@ static int ctc_i2c_plat_probe(struct platform_device *pdev)
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->master_cfg |=
|
|
||||||
CTC_IC_CON_MASTER | CTC_IC_CON_SLAVE_DISABLE |
|
|
||||||
CTC_IC_CON_RESTART_EN;
|
|
||||||
|
|
||||||
dev->functionality =
|
|
||||||
I2C_FUNC_I2C |
|
|
||||||
I2C_FUNC_10BIT_ADDR |
|
|
||||||
I2C_FUNC_SMBUS_BYTE |
|
|
||||||
I2C_FUNC_SMBUS_BYTE_DATA |
|
|
||||||
I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_I2C_BLOCK;
|
|
||||||
|
|
||||||
dev->clk = devm_clk_get(&pdev->dev, NULL);
|
dev->clk = devm_clk_get(&pdev->dev, NULL);
|
||||||
clk_prepare_enable(dev->clk);
|
clk_prepare_enable(dev->clk);
|
||||||
|
|
||||||
@ -757,10 +806,8 @@ static int ctc_i2c_plat_probe(struct platform_device *pdev)
|
|||||||
dev->sda_hold_time = ht / IC_ICK_NS(clk_get_rate(dev->clk));
|
dev->sda_hold_time = ht / IC_ICK_NS(clk_get_rate(dev->clk));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (of_property_read_bool(pdev->dev.of_node, "i2c-polling-xfer"))
|
of_property_read_u32(pdev->dev.of_node, "i2c-num", &i2c_num);
|
||||||
dev->xfer_type = CTC_IC_POLLING_TRANSFER;
|
dev->i2c_num = i2c_num;
|
||||||
else
|
|
||||||
dev->xfer_type = CTC_IC_INTERRUPT_TRANSFER;
|
|
||||||
|
|
||||||
dev->adapter.nr = pdev->id;
|
dev->adapter.nr = pdev->id;
|
||||||
adap = &dev->adapter;
|
adap = &dev->adapter;
|
||||||
@ -769,6 +816,7 @@ static int ctc_i2c_plat_probe(struct platform_device *pdev)
|
|||||||
adap->dev.of_node = pdev->dev.of_node;
|
adap->dev.of_node = pdev->dev.of_node;
|
||||||
|
|
||||||
ret = i2c_ctc_probe(dev);
|
ret = i2c_ctc_probe(dev);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -778,12 +826,7 @@ static int ctc_i2c_plat_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
i2c_del_adapter(&dev->adapter);
|
i2c_del_adapter(&dev->adapter);
|
||||||
|
|
||||||
/* Disable controller */
|
i2c_ctc_disable(dev);
|
||||||
__i2c_ctc_enable(dev, false);
|
|
||||||
|
|
||||||
/* Disable all interupts */
|
|
||||||
ctc_writel(dev, 0, CTC_IC_INTR_MASK);
|
|
||||||
ctc_readl(dev, CTC_IC_CLR_INTR);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/* Author: Wangyb <wangyb@centecnetworks.com>
|
/*
|
||||||
|
* Author: Wangyb <wangyb@centecnetworks.com>
|
||||||
*
|
*
|
||||||
* Copyright 2005-2018, Centec Networks (Suzhou) Co., Ltd.
|
* Copyright 2005-2018, Centec Networks (Suzhou) Co., Ltd.
|
||||||
*
|
*
|
||||||
@ -71,7 +72,6 @@
|
|||||||
#define CTC_IC_INTR_GEN_CALL 0x800
|
#define CTC_IC_INTR_GEN_CALL 0x800
|
||||||
|
|
||||||
#define CTC_IC_INTR_DEFAULT_MASK (CTC_IC_INTR_RX_FULL | \
|
#define CTC_IC_INTR_DEFAULT_MASK (CTC_IC_INTR_RX_FULL | \
|
||||||
CTC_IC_INTR_TX_EMPTY | \
|
|
||||||
CTC_IC_INTR_TX_ABRT | \
|
CTC_IC_INTR_TX_ABRT | \
|
||||||
CTC_IC_INTR_STOP_DET)
|
CTC_IC_INTR_STOP_DET)
|
||||||
|
|
||||||
@ -112,7 +112,7 @@
|
|||||||
CTC_IC_TX_ABRT_TXDATA_NOACK | \
|
CTC_IC_TX_ABRT_TXDATA_NOACK | \
|
||||||
CTC_IC_TX_ABRT_GCALL_NOACK)
|
CTC_IC_TX_ABRT_GCALL_NOACK)
|
||||||
|
|
||||||
#define CTC_CMD_READ 0x0100
|
#define CTC_CMD_READ 0x0100
|
||||||
#define CTC_STOP 0x0200
|
#define CTC_STOP 0x0200
|
||||||
#define CTC_RESTART 0x0400
|
#define CTC_RESTART 0x0400
|
||||||
|
|
||||||
@ -125,6 +125,38 @@
|
|||||||
#define CTC_IC_STATUS_MA 0x0020
|
#define CTC_IC_STATUS_MA 0x0020
|
||||||
#define CTC_IC_STATUS_TFE 0x0004
|
#define CTC_IC_STATUS_TFE 0x0004
|
||||||
|
|
||||||
|
#define CTC_IC_DEFAULT_FUNCTIONALITY (I2C_FUNC_I2C | \
|
||||||
|
I2C_FUNC_SMBUS_BYTE | \
|
||||||
|
I2C_FUNC_SMBUS_BYTE_DATA | \
|
||||||
|
I2C_FUNC_SMBUS_WORD_DATA | \
|
||||||
|
I2C_FUNC_SMBUS_BLOCK_DATA | \
|
||||||
|
I2C_FUNC_SMBUS_I2C_BLOCK)
|
||||||
|
|
||||||
|
#define CTC_IC_INTR_MASTER_MASK (CTC_IC_INTR_DEFAULT_MASK | \
|
||||||
|
CTC_IC_INTR_TX_EMPTY)
|
||||||
|
|
||||||
|
#define CTC_IC_INTR_SLAVE_MASK (CTC_IC_INTR_DEFAULT_MASK | \
|
||||||
|
CTC_IC_INTR_RX_DONE | \
|
||||||
|
CTC_IC_INTR_RX_UNDER | \
|
||||||
|
CTC_IC_INTR_RD_REQ)
|
||||||
|
|
||||||
|
#define CTC_IC_CON_STOP_DET_IFADDRESSED 0x80
|
||||||
|
#define CTC_IC_CON_TX_EMPTY_CTRL 0x100
|
||||||
|
#define CTC_IC_CON_RX_FIFO_FULL_HLD_CTRL 0x200
|
||||||
|
|
||||||
|
#define CTC_IC_SAR 0x8
|
||||||
|
|
||||||
|
#define CTC_IC_STATUS_SLAVE_ACTIVITY BIT(6)
|
||||||
|
|
||||||
|
#define CTC_IC_BUS_CLEAR_EN 0xb0
|
||||||
|
#define CTC_IC_BUS_CLEAR_THRD 0xb4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* operation modes
|
||||||
|
*/
|
||||||
|
#define CTC_IC_MASTER 0
|
||||||
|
#define CTC_IC_SLAVE 1
|
||||||
|
|
||||||
enum xfer_type_e {
|
enum xfer_type_e {
|
||||||
CTC_IC_INTERRUPT_TRANSFER,
|
CTC_IC_INTERRUPT_TRANSFER,
|
||||||
CTC_IC_POLLING_TRANSFER
|
CTC_IC_POLLING_TRANSFER
|
||||||
@ -159,4 +191,15 @@ struct ctc_i2c_dev {
|
|||||||
u32 clk_freq;
|
u32 clk_freq;
|
||||||
u32 sda_hold_time;
|
u32 sda_hold_time;
|
||||||
u32 xfer_type;
|
u32 xfer_type;
|
||||||
|
u32 mode;
|
||||||
|
u32 slave_cfg;
|
||||||
|
void (*disable) (struct ctc_i2c_dev * dev);
|
||||||
|
void (*disable_int) (struct ctc_i2c_dev * dev);
|
||||||
|
int (*init) (struct ctc_i2c_dev * dev);
|
||||||
|
struct i2c_client *slave;
|
||||||
|
struct regmap *regmap_base;
|
||||||
|
u32 soc_ver;
|
||||||
|
#define CTC_REV_TM_1_0 0x0
|
||||||
|
#define CTC_REV_TM_1_1 0x1
|
||||||
|
u32 i2c_num;
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
#define SYS_TSINGMA_TEMP_TABLE_NUM 166
|
#define SYS_TSINGMA_TEMP_TABLE_NUM 166
|
||||||
#define SYS_TSINGMA_SENSOR_TIMEOUT 1000
|
#define SYS_TSINGMA_SENSOR_TIMEOUT 1000
|
||||||
|
|
||||||
struct ctc_switch_cmd_status_t {
|
typedef struct ctc_switch_cmd_status_s {
|
||||||
u32 cmdReadType:1;
|
u32 cmdReadType:1;
|
||||||
u32 pcieReqCmdChk:3;
|
u32 pcieReqCmdChk:3;
|
||||||
u32 cmdEntryWords:4;
|
u32 cmdEntryWords:4;
|
||||||
@ -24,20 +24,20 @@ struct ctc_switch_cmd_status_t {
|
|||||||
u32 pciePoisoned:1;
|
u32 pciePoisoned:1;
|
||||||
u32 regProcState:3;
|
u32 regProcState:3;
|
||||||
u32 pcieReqOverlap:1;
|
u32 pcieReqOverlap:1;
|
||||||
};
|
} ctc_switch_cmd_status_t;
|
||||||
|
|
||||||
union ctc_switch_cmd_status_u_t {
|
typedef union drv_pci_cmd_status_u_e {
|
||||||
struct ctc_switch_cmd_status_t cmd_status;
|
ctc_switch_cmd_status_t cmd_status;
|
||||||
u32 val;
|
u32 val;
|
||||||
};
|
} ctc_switch_cmd_status_u_t;
|
||||||
|
|
||||||
struct ctc_access_t {
|
typedef struct ctc_access_s {
|
||||||
u32 cmd_status;
|
u32 cmd_status;
|
||||||
u32 addr;
|
u32 addr;
|
||||||
u32 data[16];
|
u32 data[16];
|
||||||
};
|
} ctc_access_t;
|
||||||
|
|
||||||
extern int ctc5236_switch_read(u32 offset, u32 len, u32 *p_value);
|
extern int ctc5236_switch_read(u32 offset, u32 len, u32 * p_value);
|
||||||
extern int ctc5236_switch_write(u32 offset, u32 len, u32 *p_value);
|
extern int ctc5236_switch_write(u32 offset, u32 len, u32 * p_value);
|
||||||
extern int get_switch_temperature(void);
|
extern int get_switch_temperature(void);
|
||||||
#endif
|
#endif
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/*
|
/*
|
||||||
* Core private header for the pin control subsystem
|
* Core private header for the pin control subsystem
|
||||||
*
|
*
|
||||||
@ -5,8 +6,6 @@
|
|||||||
* Written on behalf of Linaro for ST-Ericsson
|
* Written on behalf of Linaro for ST-Ericsson
|
||||||
*
|
*
|
||||||
* Author: Linus Walleij <linus.walleij@linaro.org>
|
* Author: Linus Walleij <linus.walleij@linaro.org>
|
||||||
*
|
|
||||||
* License terms: GNU General Public License (GPL) version 2
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/kref.h>
|
#include <linux/kref.h>
|
||||||
@ -218,7 +217,7 @@ int pinctrl_generic_add_group(struct pinctrl_dev *pctldev, const char *name,
|
|||||||
int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev,
|
int pinctrl_generic_remove_group(struct pinctrl_dev *pctldev,
|
||||||
unsigned int group_selector);
|
unsigned int group_selector);
|
||||||
|
|
||||||
#endif /* CONFIG_GENERIC_PINCTRL_GROUPS */
|
#endif /* CONFIG_GENERIC_PINCTRL_GROUPS */
|
||||||
|
|
||||||
struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
|
struct pinctrl_dev *get_pinctrl_dev_from_devname(const char *dev_name);
|
||||||
struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np);
|
struct pinctrl_dev *get_pinctrl_dev_from_of_node(struct device_node *np);
|
||||||
@ -233,13 +232,12 @@ static inline struct pin_desc *pin_desc_get(struct pinctrl_dev *pctldev,
|
|||||||
return radix_tree_lookup(&pctldev->pin_desc_tree, pin);
|
return radix_tree_lookup(&pctldev->pin_desc_tree, pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern struct pinctrl_gpio_range *
|
extern struct pinctrl_gpio_range *pinctrl_find_gpio_range_from_pin_nolock(struct
|
||||||
pinctrl_find_gpio_range_from_pin_nolock(struct pinctrl_dev *pctldev,
|
pinctrl_dev
|
||||||
unsigned int pin);
|
*pctldev,
|
||||||
|
unsigned
|
||||||
int pinctrl_register_map(const struct pinctrl_map *maps, unsigned num_maps,
|
int
|
||||||
bool dup);
|
pin);
|
||||||
void pinctrl_unregister_map(const struct pinctrl_map *map);
|
|
||||||
|
|
||||||
extern int pinctrl_force_sleep(struct pinctrl_dev *pctldev);
|
extern int pinctrl_force_sleep(struct pinctrl_dev *pctldev);
|
||||||
extern int pinctrl_force_default(struct pinctrl_dev *pctldev);
|
extern int pinctrl_force_default(struct pinctrl_dev *pctldev);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/*
|
/*
|
||||||
* Internal interface between the core pin control system and the
|
* Internal interface between the core pin control system and the
|
||||||
* pin config portions
|
* pin config portions
|
||||||
@ -7,8 +8,6 @@
|
|||||||
* Based on bits of regulator core, gpio core and clk core
|
* Based on bits of regulator core, gpio core and clk core
|
||||||
*
|
*
|
||||||
* Author: Linus Walleij <linus.walleij@linaro.org>
|
* Author: Linus Walleij <linus.walleij@linaro.org>
|
||||||
*
|
|
||||||
* License terms: GNU General Public License (GPL) version 2
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_PINCONF
|
#ifdef CONFIG_PINCONF
|
||||||
@ -16,7 +15,7 @@
|
|||||||
int pinconf_check_ops(struct pinctrl_dev *pctldev);
|
int pinconf_check_ops(struct pinctrl_dev *pctldev);
|
||||||
int pinconf_validate_map(const struct pinctrl_map *map, int i);
|
int pinconf_validate_map(const struct pinctrl_map *map, int i);
|
||||||
int pinconf_map_to_setting(const struct pinctrl_map *map,
|
int pinconf_map_to_setting(const struct pinctrl_map *map,
|
||||||
struct pinctrl_setting *setting);
|
struct pinctrl_setting *setting);
|
||||||
void pinconf_free_setting(const struct pinctrl_setting *setting);
|
void pinconf_free_setting(const struct pinctrl_setting *setting);
|
||||||
int pinconf_apply_setting(const struct pinctrl_setting *setting);
|
int pinconf_apply_setting(const struct pinctrl_setting *setting);
|
||||||
|
|
||||||
@ -45,7 +44,7 @@ static inline int pinconf_validate_map(const struct pinctrl_map *map, int i)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline int pinconf_map_to_setting(const struct pinctrl_map *map,
|
static inline int pinconf_map_to_setting(const struct pinctrl_map *map,
|
||||||
struct pinctrl_setting *setting)
|
struct pinctrl_setting *setting)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
46
platform/centec-arm64/tsingma-bsp/src/pinctrl-ctc/pinctrl-ctc.c
Normal file → Executable file
46
platform/centec-arm64/tsingma-bsp/src/pinctrl-ctc/pinctrl-ctc.c
Normal file → Executable file
@ -8,7 +8,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
@ -24,6 +23,7 @@
|
|||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/mfd/syscon.h>
|
#include <linux/mfd/syscon.h>
|
||||||
|
#include <linux/module.h>
|
||||||
#include "../include/sysctl.h"
|
#include "../include/sysctl.h"
|
||||||
#include "pinctrl-ctc.h"
|
#include "pinctrl-ctc.h"
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
@ -87,12 +87,13 @@ static void ctc_pinctrl_child_count(struct ctc_pinctrl *info,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct ctc_pin_bank *ctc_bank_num_to_bank(struct ctc_pinctrl *info,
|
static struct ctc_pin_bank *ctc_bank_num_to_bank(struct ctc_pinctrl *info,
|
||||||
unsigned int num)
|
unsigned num)
|
||||||
{
|
{
|
||||||
struct ctc_pin_bank *b = info->ctrl->pin_banks;
|
struct ctc_pin_bank *b = info->ctrl->pin_banks;
|
||||||
|
|
||||||
if (num < info->ctrl->nr_banks)
|
if (num < info->ctrl->nr_banks) {
|
||||||
return &b[num];
|
return &b[num];
|
||||||
|
}
|
||||||
|
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
}
|
}
|
||||||
@ -195,8 +196,10 @@ static int ctc_pinctrl_parse_dt(struct platform_device *pdev,
|
|||||||
struct device_node *child;
|
struct device_node *child;
|
||||||
|
|
||||||
info->ctrl = devm_kzalloc(dev, sizeof(struct ctc_pin_ctrl), GFP_KERNEL);
|
info->ctrl = devm_kzalloc(dev, sizeof(struct ctc_pin_ctrl), GFP_KERNEL);
|
||||||
if (!info->ctrl)
|
if (!info->ctrl) {
|
||||||
|
dev_err(dev, "failed to allocate memory for pin\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
ret = of_property_read_u32(np, "ctc,pinctrl-bank0", &bank0_pins);
|
ret = of_property_read_u32(np, "ctc,pinctrl-bank0", &bank0_pins);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
@ -229,13 +232,17 @@ static int ctc_pinctrl_parse_dt(struct platform_device *pdev,
|
|||||||
|
|
||||||
info->functions = devm_kzalloc(dev, info->nfunctions *
|
info->functions = devm_kzalloc(dev, info->nfunctions *
|
||||||
sizeof(struct ctc_pmx_func), GFP_KERNEL);
|
sizeof(struct ctc_pmx_func), GFP_KERNEL);
|
||||||
if (!info->functions)
|
if (!info->functions) {
|
||||||
|
dev_err(dev, "failed to allocate memory for function list\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
info->groups = devm_kzalloc(dev, info->ngroups *
|
info->groups = devm_kzalloc(dev, info->ngroups *
|
||||||
sizeof(struct ctc_pin_group), GFP_KERNEL);
|
sizeof(struct ctc_pin_group), GFP_KERNEL);
|
||||||
if (!info->groups)
|
if (!info->groups) {
|
||||||
|
dev_err(dev, "failed allocate memory for ping group list\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
for_each_child_of_node(np, child) {
|
for_each_child_of_node(np, child) {
|
||||||
@ -258,7 +265,7 @@ static int ctc_get_groups_count(struct pinctrl_dev *pctldev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *ctc_get_group_name(struct pinctrl_dev *pctldev,
|
static const char *ctc_get_group_name(struct pinctrl_dev *pctldev,
|
||||||
unsigned int selector)
|
unsigned selector)
|
||||||
{
|
{
|
||||||
struct ctc_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
struct ctc_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
|
||||||
@ -266,8 +273,8 @@ static const char *ctc_get_group_name(struct pinctrl_dev *pctldev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int ctc_get_group_pins(struct pinctrl_dev *pctldev,
|
static int ctc_get_group_pins(struct pinctrl_dev *pctldev,
|
||||||
unsigned int selector, const unsigned int **pins,
|
unsigned selector, const unsigned **pins,
|
||||||
unsigned int *npins)
|
unsigned *npins)
|
||||||
{
|
{
|
||||||
struct ctc_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
struct ctc_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
|
||||||
@ -298,7 +305,7 @@ static inline const struct ctc_pin_group *ctc_pinctrl_name_to_group(const struct
|
|||||||
|
|
||||||
static int ctc_dt_node_to_map(struct pinctrl_dev *pctldev,
|
static int ctc_dt_node_to_map(struct pinctrl_dev *pctldev,
|
||||||
struct device_node *np,
|
struct device_node *np,
|
||||||
struct pinctrl_map **map, unsigned int *num_maps)
|
struct pinctrl_map **map, unsigned *num_maps)
|
||||||
{
|
{
|
||||||
struct ctc_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
struct ctc_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
||||||
const struct ctc_pin_group *grp;
|
const struct ctc_pin_group *grp;
|
||||||
@ -348,7 +355,7 @@ static int ctc_pmx_get_funcs_count(struct pinctrl_dev *pctldev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const char *ctc_pmx_get_func_name(struct pinctrl_dev *pctldev,
|
static const char *ctc_pmx_get_func_name(struct pinctrl_dev *pctldev,
|
||||||
unsigned int selector)
|
unsigned selector)
|
||||||
{
|
{
|
||||||
struct ctc_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
struct ctc_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
|
||||||
@ -356,8 +363,8 @@ static const char *ctc_pmx_get_func_name(struct pinctrl_dev *pctldev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int ctc_pmx_get_groups(struct pinctrl_dev *pctldev,
|
static int ctc_pmx_get_groups(struct pinctrl_dev *pctldev,
|
||||||
unsigned int selector, const char *const **groups,
|
unsigned selector, const char *const **groups,
|
||||||
unsigned int *const num_groups)
|
unsigned *const num_groups)
|
||||||
{
|
{
|
||||||
struct ctc_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
struct ctc_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
||||||
|
|
||||||
@ -368,7 +375,7 @@ static int ctc_pmx_get_groups(struct pinctrl_dev *pctldev,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static struct ctc_pin_bank *ctc_pin_to_bank(struct ctc_pinctrl *info,
|
static struct ctc_pin_bank *ctc_pin_to_bank(struct ctc_pinctrl *info,
|
||||||
unsigned int pin)
|
unsigned pin)
|
||||||
{
|
{
|
||||||
struct ctc_pin_bank *b = info->ctrl->pin_banks;
|
struct ctc_pin_bank *b = info->ctrl->pin_banks;
|
||||||
|
|
||||||
@ -396,8 +403,8 @@ static int ctc_set_pin_mux(struct ctc_pinctrl *info, struct ctc_pin_bank *bank,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctc_pmx_set(struct pinctrl_dev *pctldev, unsigned int selector,
|
static int ctc_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
|
||||||
unsigned int group)
|
unsigned group)
|
||||||
{
|
{
|
||||||
struct ctc_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
struct ctc_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
|
||||||
const unsigned int *pins = info->groups[group].pins;
|
const unsigned int *pins = info->groups[group].pins;
|
||||||
@ -408,7 +415,8 @@ static int ctc_pmx_set(struct pinctrl_dev *pctldev, unsigned int selector,
|
|||||||
dev_dbg(info->dev, "enable function %s group %s\n",
|
dev_dbg(info->dev, "enable function %s group %s\n",
|
||||||
info->functions[selector].name, info->groups[group].name);
|
info->functions[selector].name, info->groups[group].name);
|
||||||
|
|
||||||
/* for each pin in the pin group selected, program the corresponding pin
|
/*
|
||||||
|
* for each pin in the pin group selected, program the correspoding pin
|
||||||
* pin function number in the config register.
|
* pin function number in the config register.
|
||||||
*/
|
*/
|
||||||
for (cnt = 0; cnt < info->groups[group].npins; cnt++) {
|
for (cnt = 0; cnt < info->groups[group].npins; cnt++) {
|
||||||
@ -423,7 +431,7 @@ static int ctc_pmx_set(struct pinctrl_dev *pctldev, unsigned int selector,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void ctc_dt_free_map(struct pinctrl_dev *pctldev,
|
static void ctc_dt_free_map(struct pinctrl_dev *pctldev,
|
||||||
struct pinctrl_map *map, unsigned int num_maps)
|
struct pinctrl_map *map, unsigned num_maps)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -528,7 +536,7 @@ static struct platform_driver ctc_pinctrl_driver = {
|
|||||||
|
|
||||||
//static int __init ctc_pinctrl_drv_register(void)
|
//static int __init ctc_pinctrl_drv_register(void)
|
||||||
//{
|
//{
|
||||||
// return platform_driver_register(&ctc_pinctrl_driver);
|
// return platform_driver_register(&ctc_pinctrl_driver);
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//postcore_initcall(ctc_pinctrl_drv_register);
|
//postcore_initcall(ctc_pinctrl_drv_register);
|
||||||
|
51
platform/centec-arm64/tsingma-bsp/src/pwm-ctc/pwm-ctc.c
Normal file → Executable file
51
platform/centec-arm64/tsingma-bsp/src/pwm-ctc/pwm-ctc.c
Normal file → Executable file
@ -1,4 +1,5 @@
|
|||||||
/* Centec PWM driver
|
/*
|
||||||
|
* Centec PWM driver
|
||||||
*
|
*
|
||||||
* Author: wangyb <wangyb@centecnetworks.com>
|
* Author: wangyb <wangyb@centecnetworks.com>
|
||||||
*
|
*
|
||||||
@ -25,14 +26,14 @@
|
|||||||
#include <linux/mfd/syscon.h>
|
#include <linux/mfd/syscon.h>
|
||||||
#include <linux/pinctrl/consumer.h>
|
#include <linux/pinctrl/consumer.h>
|
||||||
|
|
||||||
#define CTC_NUM_PWM 4
|
#define CTC_NUM_PWM 4
|
||||||
#define CTC_CR_PWM 0x0
|
#define CTC_CR_PWM 0x0
|
||||||
#define CTC_DUTY_PWM 0x4
|
#define CTC_DUTY_PWM 0x4
|
||||||
|
|
||||||
#define CTC_MAX_PERIOD_PWM 0xFFFFFF
|
#define CTC_MAX_PERIOD_PWM 0xFFFFFF
|
||||||
#define CTC_MAX_DUTY_PWM 0xFFFFFF
|
#define CTC_MAX_DUTY_PWM 0xFFFFFF
|
||||||
|
|
||||||
#define CTC_PWM_ENABLE 0x80000000
|
#define CTC_PWM_ENABLE 0x80000000
|
||||||
|
|
||||||
#define CTC_PERIOD_TACH 0x0
|
#define CTC_PERIOD_TACH 0x0
|
||||||
#define CTC_DUTY_TACH 0x4
|
#define CTC_DUTY_TACH 0x4
|
||||||
@ -60,7 +61,6 @@ static inline u32 ctc_pwm_readl(struct ctc_pwm_chip *chip, unsigned int num,
|
|||||||
unsigned long offset)
|
unsigned long offset)
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
regmap_read(chip->regmap_base,
|
regmap_read(chip->regmap_base,
|
||||||
offsetof(struct SysCtl_regs,
|
offsetof(struct SysCtl_regs,
|
||||||
SysPwmCtl) + offset + num * 0x8, &val);
|
SysPwmCtl) + offset + num * 0x8, &val);
|
||||||
@ -71,7 +71,6 @@ static inline u32 ctc_tach_readl(struct ctc_pwm_chip *chip, unsigned int num,
|
|||||||
unsigned long offset)
|
unsigned long offset)
|
||||||
{
|
{
|
||||||
u32 val;
|
u32 val;
|
||||||
|
|
||||||
regmap_read(chip->regmap_base,
|
regmap_read(chip->regmap_base,
|
||||||
offsetof(struct SysCtl_regs,
|
offsetof(struct SysCtl_regs,
|
||||||
SysTachLog) + offset + num * 0x8, &val);
|
SysTachLog) + offset + num * 0x8, &val);
|
||||||
@ -83,19 +82,30 @@ static int ctc_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||||||
{
|
{
|
||||||
struct ctc_pwm_chip *pc = to_ctc_pwm_chip(chip);
|
struct ctc_pwm_chip *pc = to_ctc_pwm_chip(chip);
|
||||||
u32 cur_value;
|
u32 cur_value;
|
||||||
|
u32 duty_cycle = 0;
|
||||||
|
u32 period_cycle = 0;
|
||||||
|
|
||||||
duty_ns = duty_ns / 1000;
|
duty_cycle = duty_ns / 1000;
|
||||||
period_ns = period_ns / 1000;
|
period_cycle = period_ns / 1000;
|
||||||
|
|
||||||
|
if (duty_cycle < 0 || period_cycle < 1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (duty_cycle == 0) {
|
||||||
|
duty_cycle = 1;
|
||||||
|
} else if (duty_cycle == period_cycle) {
|
||||||
|
duty_cycle = duty_cycle - 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* duty cycle */
|
/* duty cycle */
|
||||||
duty_ns = duty_ns & CTC_MAX_DUTY_PWM;
|
duty_cycle = duty_cycle & CTC_MAX_DUTY_PWM;
|
||||||
ctc_pwm_writel(pc, pwm->hwpwm, CTC_DUTY_PWM, duty_ns);
|
ctc_pwm_writel(pc, pwm->hwpwm, CTC_DUTY_PWM, duty_cycle);
|
||||||
|
|
||||||
/* period cycle */
|
/* period cycle */
|
||||||
period_ns = period_ns & CTC_MAX_PERIOD_PWM;
|
period_cycle = period_cycle & CTC_MAX_PERIOD_PWM;
|
||||||
cur_value = ctc_pwm_readl(pc, pwm->hwpwm, CTC_CR_PWM);
|
cur_value = ctc_pwm_readl(pc, pwm->hwpwm, CTC_CR_PWM);
|
||||||
cur_value &= ~(CTC_MAX_PERIOD_PWM);
|
cur_value &= ~(CTC_MAX_PERIOD_PWM);
|
||||||
cur_value |= period_ns << 0;
|
cur_value |= period_cycle << 0;
|
||||||
ctc_pwm_writel(pc, pwm->hwpwm, CTC_CR_PWM, cur_value);
|
ctc_pwm_writel(pc, pwm->hwpwm, CTC_CR_PWM, cur_value);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -139,11 +149,11 @@ static void ctc_pwm_get_state(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||||||
|
|
||||||
state->polarity = PWM_POLARITY_NORMAL;
|
state->polarity = PWM_POLARITY_NORMAL;
|
||||||
|
|
||||||
state->period = (cur_value & (~CTC_PWM_ENABLE)) * 1000;
|
state->period = (cur_value & (~CTC_PWM_ENABLE)) * 1000; // in nanoseconds
|
||||||
|
|
||||||
cur_value_2 = ctc_pwm_readl(pc, pwm->hwpwm, CTC_DUTY_PWM);
|
cur_value_2 = ctc_pwm_readl(pc, pwm->hwpwm, CTC_DUTY_PWM);
|
||||||
|
|
||||||
state->duty_cycle = cur_value_2 * 1000;
|
state->duty_cycle = cur_value_2 * 1000; // in nanoseconds
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctc_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
|
static int ctc_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
|
||||||
@ -154,10 +164,10 @@ static int ctc_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm,
|
|||||||
u32 duty_tach;
|
u32 duty_tach;
|
||||||
|
|
||||||
period_tach = ctc_tach_readl(pc, pwm->hwpwm, CTC_PERIOD_TACH) / 4;
|
period_tach = ctc_tach_readl(pc, pwm->hwpwm, CTC_PERIOD_TACH) / 4;
|
||||||
result->period = period_tach * 1000;
|
result->period = period_tach * 1000; // in nanoseconds
|
||||||
|
|
||||||
duty_tach = ctc_tach_readl(pc, pwm->hwpwm, CTC_DUTY_TACH) / 4;
|
duty_tach = ctc_tach_readl(pc, pwm->hwpwm, CTC_DUTY_TACH) / 4;
|
||||||
result->duty_cycle = duty_tach * 1000;
|
result->duty_cycle = duty_tach * 1000; // in nanoseconds
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -188,12 +198,13 @@ static int ctc_pwm_probe(struct platform_device *pdev)
|
|||||||
pc->regmap_base = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
pc->regmap_base = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
||||||
"ctc,sysctrl");
|
"ctc,sysctrl");
|
||||||
pctldev = devm_kzalloc(&pdev->dev, sizeof(*pctldev), GFP_KERNEL);
|
pctldev = devm_kzalloc(&pdev->dev, sizeof(*pctldev), GFP_KERNEL);
|
||||||
if (!pctldev)
|
if (!pctldev) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
pctldev->p = pinctrl_get(&pdev->dev);
|
pctldev->p = pinctrl_get(&pdev->dev);
|
||||||
state = pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);
|
state = pinctrl_lookup_state(pctldev->p, PINCTRL_STATE_DEFAULT);
|
||||||
pinctrl_select_state(pctldev->p, state);
|
pinctrl_select_state(pctldev->p, state);
|
||||||
pr_info("Select PWM Function\n");
|
printk("Select PWM Function\n");
|
||||||
|
|
||||||
for (i = 0; i < CTC_NUM_PWM; i++) {
|
for (i = 0; i < CTC_NUM_PWM; i++) {
|
||||||
cur_value = ctc_pwm_readl(pc, i, CTC_CR_PWM);
|
cur_value = ctc_pwm_readl(pc, i, CTC_CR_PWM);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/* rtc class driver for the SD2405 chip
|
/*
|
||||||
|
* rtc class driver for the SD2405 chip
|
||||||
*
|
*
|
||||||
* Author: Dale Farnsworth <dale@farnsworth.org>
|
* Author: Dale Farnsworth <dale@farnsworth.org>
|
||||||
*
|
*
|
||||||
@ -45,7 +46,7 @@
|
|||||||
|
|
||||||
static struct i2c_driver sd2405_driver;
|
static struct i2c_driver sd2405_driver;
|
||||||
|
|
||||||
static int sd2405_i2c_read_regs(struct i2c_client *client, u8 *buf)
|
static int sd2405_i2c_read_regs(struct i2c_client *client, u8 * buf)
|
||||||
{
|
{
|
||||||
struct i2c_msg msgs[1] = {
|
struct i2c_msg msgs[1] = {
|
||||||
{
|
{
|
||||||
@ -67,7 +68,9 @@ static int sd2405_i2c_read_regs(struct i2c_client *client, u8 *buf)
|
|||||||
static int sd2405_i2c_write_regs(struct i2c_client *client, u8 const *buf)
|
static int sd2405_i2c_write_regs(struct i2c_client *client, u8 const *buf)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
u8 temp_reg[SD2405_REG_LEN + 1] = { 0 };
|
u8 temp_reg[SD2405_REG_LEN + 1] = { 0 };
|
||||||
|
memcpy(&temp_reg[1], buf, SD2405_REG_LEN);
|
||||||
|
|
||||||
struct i2c_msg msgs[1] = {
|
struct i2c_msg msgs[1] = {
|
||||||
{
|
{
|
||||||
@ -77,8 +80,6 @@ static int sd2405_i2c_write_regs(struct i2c_client *client, u8 const *buf)
|
|||||||
.buf = temp_reg}
|
.buf = temp_reg}
|
||||||
};
|
};
|
||||||
|
|
||||||
memcpy(&temp_reg[1], buf, SD2405_REG_LEN);
|
|
||||||
|
|
||||||
rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
|
||||||
if (rc != ARRAY_SIZE(msgs))
|
if (rc != ARRAY_SIZE(msgs))
|
||||||
goto write_failed;
|
goto write_failed;
|
||||||
@ -114,7 +115,6 @@ static int sd2405_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
|
|||||||
static int sd2405_i2c_set_write_protect(struct i2c_client *client)
|
static int sd2405_i2c_set_write_protect(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = i2c_smbus_write_byte_data(client, SD2405_REG_CTRL1, 0);
|
rc = i2c_smbus_write_byte_data(client, SD2405_REG_CTRL1, 0);
|
||||||
rc += i2c_smbus_write_byte_data(client, SD2405_REG_CTRL2, 0);
|
rc += i2c_smbus_write_byte_data(client, SD2405_REG_CTRL2, 0);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
@ -128,7 +128,6 @@ static int sd2405_i2c_set_write_protect(struct i2c_client *client)
|
|||||||
static int sd2405_i2c_clear_write_protect(struct i2c_client *client)
|
static int sd2405_i2c_clear_write_protect(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = i2c_smbus_write_byte_data(client, SD2405_REG_CTRL2,
|
rc = i2c_smbus_write_byte_data(client, SD2405_REG_CTRL2,
|
||||||
SD2405_REG_CONTROL1_WRITE);
|
SD2405_REG_CONTROL1_WRITE);
|
||||||
rc +=
|
rc +=
|
||||||
@ -183,11 +182,12 @@ static int sd2405_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
|||||||
|
|
||||||
static int sd2405_remove(struct i2c_client *client)
|
static int sd2405_remove(struct i2c_client *client)
|
||||||
{
|
{
|
||||||
|
#if 0
|
||||||
struct rtc_device *rtc = i2c_get_clientdata(client);
|
struct rtc_device *rtc = i2c_get_clientdata(client);
|
||||||
|
|
||||||
if (rtc)
|
if (rtc)
|
||||||
rtc_device_unregister(rtc);
|
rtc_device_unregister(rtc);
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,17 +199,20 @@ static const struct rtc_class_ops sd2405_rtc_ops = {
|
|||||||
static int
|
static int
|
||||||
sd2405_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
sd2405_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
|
int ret = 0;
|
||||||
struct rtc_device *rtc;
|
struct rtc_device *rtc;
|
||||||
|
|
||||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
|
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
|
||||||
|
rtc = devm_rtc_allocate_device(&client->dev);
|
||||||
rtc = rtc_device_register(sd2405_driver.driver.name,
|
|
||||||
&client->dev, &sd2405_rtc_ops, THIS_MODULE);
|
|
||||||
if (IS_ERR(rtc))
|
if (IS_ERR(rtc))
|
||||||
return PTR_ERR(rtc);
|
return PTR_ERR(rtc);
|
||||||
|
rtc->ops = &sd2405_rtc_ops;
|
||||||
|
ret = rtc_register_device(rtc);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
i2c_set_clientdata(client, rtc);
|
i2c_set_clientdata(client, rtc);
|
||||||
|
|
||||||
|
193
platform/centec-arm64/tsingma-bsp/src/sdhci-ctc5236/sdhci-ctc5236.c
Normal file → Executable file
193
platform/centec-arm64/tsingma-bsp/src/sdhci-ctc5236/sdhci-ctc5236.c
Normal file → Executable file
@ -1,17 +1,9 @@
|
|||||||
/* sdhci-ctc5236.c Support for SDHCI on Centec TsingMa SoC's
|
/*
|
||||||
|
* sdhci-ctc5236.c Support for SDHCI on Centec TsingMa SoC's
|
||||||
*
|
*
|
||||||
* Copyright (C) 2004-2017 Centec Networks (suzhou) Co., LTD.
|
* Author: Wangyb <wangyb@centecnetworks.com>
|
||||||
*
|
*
|
||||||
* Author: Jay Cao <caoj@centecnetworks.com>
|
* Copyright 2005-2020, Centec Networks (Suzhou) Co., Ltd.
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -27,38 +19,43 @@
|
|||||||
#include <asm-generic/delay.h>
|
#include <asm-generic/delay.h>
|
||||||
#include <linux/delay.h>
|
#include <linux/delay.h>
|
||||||
#include <linux/raid/pq.h>
|
#include <linux/raid/pq.h>
|
||||||
|
#include <linux/sizes.h>
|
||||||
|
#include <linux/dma-mapping.h>
|
||||||
|
|
||||||
#define REG_OFFSET_ADDR 0x500
|
#define REG_OFFSET_ADDR 0x500
|
||||||
#define MSHC_CTRL_R 0x8
|
#define MSHC_CTRL_R 0x8
|
||||||
#define AT_CTRL_R 0x40
|
#define AT_CTRL_R 0x40
|
||||||
#define SW_TUNE_EN 0x10
|
#define SW_TUNE_EN 0x10
|
||||||
#define SD_CLK_EN_MASK 0x00000001
|
#define SD_CLK_EN_MASK 0x00000001
|
||||||
#define AT_STAT_R 0x44
|
#define AT_STAT_R 0x44
|
||||||
#define MAX_TUNING_LOOP 0x80
|
#define MAX_TUNING_LOOP 0x80
|
||||||
#define MIN_TUNING_LOOP 0x0
|
#define MIN_TUNING_LOOP 0x0
|
||||||
#define TUNE_CTRL_STEP 1
|
#define TUNE_CTRL_STEP 1
|
||||||
|
#define EMMC_CTRL_R 0x2c
|
||||||
|
|
||||||
struct regmap *regmap_base;
|
|
||||||
#define SDHCI_REFCLK_150M 150000000
|
#define SDHCI_REFCLK_150M 150000000
|
||||||
|
|
||||||
|
static struct regmap *regmap_base;
|
||||||
|
static u32 version;
|
||||||
|
#define CTC_REV_TM_1_0 0x0
|
||||||
|
#define CTC_REV_TM_1_1 0x1
|
||||||
|
|
||||||
|
#define BOUNDARY_OK(addr, len) \
|
||||||
|
((addr | (SZ_128M - 1)) == ((addr + len - 1) | (SZ_128M - 1)))
|
||||||
|
|
||||||
static u16 sdhci_ctc5236_readw(struct sdhci_host *host, int reg)
|
static u16 sdhci_ctc5236_readw(struct sdhci_host *host, int reg)
|
||||||
{
|
{
|
||||||
if (unlikely(reg == SDHCI_HOST_VERSION))
|
if (unlikely(reg == SDHCI_HOST_VERSION)) {
|
||||||
return SDHCI_SPEC_300;
|
return SDHCI_SPEC_300;
|
||||||
|
}
|
||||||
|
|
||||||
return readw(host->ioaddr + reg);
|
return readw(host->ioaddr + reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 sdhci_ctc5236_readl(struct sdhci_host *host, int reg)
|
static u32 sdhci_ctc5236_readl(struct sdhci_host *host, int reg)
|
||||||
{
|
{
|
||||||
u32 ret = readl(host->ioaddr + reg);
|
u32 ret;
|
||||||
|
ret = readl(host->ioaddr + reg);
|
||||||
if (reg == SDHCI_CAPABILITIES_1)
|
|
||||||
ret &=
|
|
||||||
~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_SDR104 |
|
|
||||||
SDHCI_SUPPORT_DDR50);
|
|
||||||
if (reg == SDHCI_CAPABILITIES)
|
|
||||||
ret &= ~(SDHCI_CAN_64BIT);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -112,24 +109,74 @@ void sdhci_ctc5236_reset(struct sdhci_host *host, u8 mask)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ctc5236_select_90degree_phase(struct sdhci_host *host)
|
||||||
|
{
|
||||||
|
u32 val = 0;
|
||||||
|
|
||||||
|
regmap_read(regmap_base, offsetof(struct SysCtl_regs, SysMshCfg), &val);
|
||||||
|
if (val & SYS_MSH_CFG_W0_MSH_INTF_C_CLK_TX_PHASE_SEL_MASK) {
|
||||||
|
val &= (~SYS_MSH_CFG_W0_MSH_INTF_C_CLK_TX_PHASE_SEL_MASK);
|
||||||
|
regmap_write(regmap_base,
|
||||||
|
offsetof(struct SysCtl_regs, SysMshCfg), val);
|
||||||
|
printk("select ctc 90 degree phase\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ctc_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
|
void ctc_sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
|
||||||
{
|
{
|
||||||
int val = 0;
|
int val = 0;
|
||||||
|
|
||||||
if (clock == SDHCI_REFCLK_150M) {
|
if (clock == SDHCI_REFCLK_150M) {
|
||||||
/* SDHCI reference clock change 150M */
|
|
||||||
regmap_read(regmap_base,
|
regmap_read(regmap_base,
|
||||||
offsetof(struct SysCtl_regs, SysClkPeriCfg), &val);
|
offsetof(struct SysCtl_regs, SysClkPeriCfg), &val);
|
||||||
val = val & (~SYS_CLK_PERI_CFG_W0_CFG_DIV_MSH_REF_CNT_MASK);
|
if ((val & 0xc) == 0xc) {
|
||||||
val |=
|
val =
|
||||||
((0x8 & SYS_CLK_PERI_CFG_W0_CFG_DIV_MSH_REF_CNT_MASK)) << 0;
|
val &
|
||||||
regmap_write(regmap_base,
|
(~SYS_CLK_PERI_CFG_W0_CFG_DIV_MSH_REF_CNT_MASK);
|
||||||
offsetof(struct SysCtl_regs, SysClkPeriCfg), val);
|
val |=
|
||||||
|
((0x8 &
|
||||||
|
SYS_CLK_PERI_CFG_W0_CFG_DIV_MSH_REF_CNT_MASK)) <<
|
||||||
|
0;
|
||||||
|
regmap_write(regmap_base,
|
||||||
|
offsetof(struct SysCtl_regs,
|
||||||
|
SysClkPeriCfg), val);
|
||||||
|
printk("SDHCI reference clock change 150M\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version == CTC_REV_TM_1_1) {
|
||||||
|
if (host->mmc->ios.timing == MMC_TIMING_MMC_DDR52) {
|
||||||
|
ctc5236_select_90degree_phase(host);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sdhci_set_clock(host, clock);
|
sdhci_set_clock(host, clock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If DMA addr spans 128MB boundary, we split the DMA transfer into two
|
||||||
|
* so that each DMA transfer doesn't exceed the boundary.
|
||||||
|
*/
|
||||||
|
static void sdhci_ctc5236_adma_write_desc(struct sdhci_host *host, void **desc,
|
||||||
|
dma_addr_t addr, int len,
|
||||||
|
unsigned int cmd)
|
||||||
|
{
|
||||||
|
int tmplen, offset;
|
||||||
|
|
||||||
|
if (likely(!len || BOUNDARY_OK(addr, len))) {
|
||||||
|
sdhci_adma_write_desc(host, desc, addr, len, cmd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = addr & (SZ_128M - 1);
|
||||||
|
tmplen = SZ_128M - offset;
|
||||||
|
sdhci_adma_write_desc(host, desc, addr, tmplen, cmd);
|
||||||
|
|
||||||
|
addr += tmplen;
|
||||||
|
len -= tmplen;
|
||||||
|
sdhci_adma_write_desc(host, desc, addr, len, cmd);
|
||||||
|
}
|
||||||
|
|
||||||
static int sdhci_ctc5236_prepare_tuning(struct sdhci_host *host,
|
static int sdhci_ctc5236_prepare_tuning(struct sdhci_host *host,
|
||||||
int CENTER_PH_CODE)
|
int CENTER_PH_CODE)
|
||||||
{
|
{
|
||||||
@ -180,51 +227,54 @@ static int sdhci_ctc5236_execute_tuning(struct sdhci_host *host, u32 opcode)
|
|||||||
val &= (~SYS_MSH_CFG_W0_MSH_INTF_RX_DLL_MASTER_BYPASS_MASK);
|
val &= (~SYS_MSH_CFG_W0_MSH_INTF_RX_DLL_MASTER_BYPASS_MASK);
|
||||||
regmap_write(regmap_base, offsetof(struct SysCtl_regs, SysMshCfg), val);
|
regmap_write(regmap_base, offsetof(struct SysCtl_regs, SysMshCfg), val);
|
||||||
|
|
||||||
|
sdhci_ctc5236_prepare_tuning(host, 0);
|
||||||
|
|
||||||
/* find the mininum delay first which can pass tuning */
|
/* find the mininum delay first which can pass tuning */
|
||||||
min = MIN_TUNING_LOOP;
|
min = MIN_TUNING_LOOP;
|
||||||
sdhci_ctc5236_prepare_tuning(host, min);
|
sdhci_writel(host, min, REG_OFFSET_ADDR + AT_STAT_R);
|
||||||
while (min < MAX_TUNING_LOOP) {
|
while (min < MAX_TUNING_LOOP) {
|
||||||
dev_dbg(mmc_dev(host->mmc), "#1# AT_STAT_R is %x\n",
|
|
||||||
sdhci_readl(host, REG_OFFSET_ADDR + AT_STAT_R));
|
|
||||||
if (!mmc_send_tuning(host->mmc, opcode, NULL))
|
if (!mmc_send_tuning(host->mmc, opcode, NULL))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
host->ops->reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
host->ops->reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
||||||
|
|
||||||
min += TUNE_CTRL_STEP;
|
min += TUNE_CTRL_STEP;
|
||||||
sdhci_writel(host, min, REG_OFFSET_ADDR + AT_STAT_R);
|
sdhci_writel(host, min, REG_OFFSET_ADDR + AT_STAT_R);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find the maxinum delay which can not pass tuning */
|
/* find the maxinum delay which can not pass tuning */
|
||||||
max = min + TUNE_CTRL_STEP;
|
max = min + TUNE_CTRL_STEP;
|
||||||
sdhci_ctc5236_prepare_tuning(host, max);
|
sdhci_writel(host, max, REG_OFFSET_ADDR + AT_STAT_R);
|
||||||
while (max < MAX_TUNING_LOOP) {
|
while (max < MAX_TUNING_LOOP) {
|
||||||
dev_dbg(mmc_dev(host->mmc), "#2# AT_STAT_R is %x\n",
|
|
||||||
sdhci_readl(host, REG_OFFSET_ADDR + AT_STAT_R));
|
|
||||||
if (mmc_send_tuning(host->mmc, opcode, NULL)) {
|
if (mmc_send_tuning(host->mmc, opcode, NULL)) {
|
||||||
max -= TUNE_CTRL_STEP;
|
max -= TUNE_CTRL_STEP;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
host->ops->reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
host->ops->reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
||||||
|
|
||||||
max += TUNE_CTRL_STEP;
|
max += TUNE_CTRL_STEP;
|
||||||
sdhci_writel(host, max, REG_OFFSET_ADDR + AT_STAT_R);
|
sdhci_writel(host, max, REG_OFFSET_ADDR + AT_STAT_R);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* use average delay to get the best timing */
|
/* use average delay to get the best timing */
|
||||||
avg = (min + max) / 2;
|
avg = (min + max) / 2;
|
||||||
sdhci_ctc5236_prepare_tuning(host, avg);
|
sdhci_writel(host, avg, REG_OFFSET_ADDR + AT_STAT_R);
|
||||||
ret = mmc_send_tuning(host->mmc, opcode, NULL);
|
ret = mmc_send_tuning(host->mmc, opcode, NULL);
|
||||||
host->ops->reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
host->ops->reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
|
||||||
sdhci_writel(host, avg, REG_OFFSET_ADDR + AT_STAT_R);
|
|
||||||
|
|
||||||
dev_info(mmc_dev(host->mmc), "Tuning %s at 0x%x ret %d\n",
|
dev_info(mmc_dev(host->mmc),
|
||||||
ret ? "failed" : "passed", avg, ret);
|
"Tuning %s at 0x%x ret %d, min is 0x%x, max is 0x%x\n",
|
||||||
|
ret ? "failed" : "passed", avg, ret, min, max);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sdhci_ctc5236_hw_reset(struct sdhci_host *host)
|
||||||
|
{
|
||||||
|
sdhci_writel(host, 0x0, REG_OFFSET_ADDR + EMMC_CTRL_R);
|
||||||
|
udelay(10);
|
||||||
|
sdhci_writel(host, 0xc, REG_OFFSET_ADDR + EMMC_CTRL_R);
|
||||||
|
udelay(300);
|
||||||
|
dev_info(mmc_dev(host->mmc), "Hardware reset\n");
|
||||||
|
}
|
||||||
|
|
||||||
static const struct sdhci_ops sdhci_ctc5236_ops = {
|
static const struct sdhci_ops sdhci_ctc5236_ops = {
|
||||||
.read_w = sdhci_ctc5236_readw,
|
.read_w = sdhci_ctc5236_readw,
|
||||||
.read_l = sdhci_ctc5236_readl,
|
.read_l = sdhci_ctc5236_readl,
|
||||||
@ -234,12 +284,14 @@ static const struct sdhci_ops sdhci_ctc5236_ops = {
|
|||||||
.set_uhs_signaling = sdhci_set_uhs_signaling,
|
.set_uhs_signaling = sdhci_set_uhs_signaling,
|
||||||
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
|
.get_max_clock = sdhci_pltfm_clk_get_max_clock,
|
||||||
.platform_execute_tuning = sdhci_ctc5236_execute_tuning,
|
.platform_execute_tuning = sdhci_ctc5236_execute_tuning,
|
||||||
|
.adma_write_desc = sdhci_ctc5236_adma_write_desc,
|
||||||
|
.hw_reset = sdhci_ctc5236_hw_reset,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct sdhci_pltfm_data sdhci_ctc5236_pdata = {
|
static struct sdhci_pltfm_data sdhci_ctc5236_pdata = {
|
||||||
.ops = &sdhci_ctc5236_ops,
|
.ops = &sdhci_ctc5236_ops,
|
||||||
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_BROKEN_HS200,
|
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_BROKEN_HS200,
|
||||||
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN | SDHCI_QUIRK_BROKEN_ADMA,
|
.quirks = SDHCI_QUIRK_CAP_CLOCK_BASE_BROKEN,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int sdhci_ctc5236_probe(struct platform_device *pdev)
|
static int sdhci_ctc5236_probe(struct platform_device *pdev)
|
||||||
@ -247,12 +299,40 @@ static int sdhci_ctc5236_probe(struct platform_device *pdev)
|
|||||||
struct sdhci_host *host;
|
struct sdhci_host *host;
|
||||||
struct sdhci_pltfm_host *pltfm_host;
|
struct sdhci_pltfm_host *pltfm_host;
|
||||||
struct clk *clk;
|
struct clk *clk;
|
||||||
int ret;
|
int ret, val;
|
||||||
|
u32 extra;
|
||||||
|
|
||||||
host = sdhci_pltfm_init(pdev, &sdhci_ctc5236_pdata, 0);
|
host = sdhci_pltfm_init(pdev, &sdhci_ctc5236_pdata, 0);
|
||||||
if (IS_ERR(host))
|
if (IS_ERR(host))
|
||||||
return PTR_ERR(host);
|
return PTR_ERR(host);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extra adma table cnt for cross 128M boundary handling.
|
||||||
|
*/
|
||||||
|
extra = DIV_ROUND_UP_ULL(dma_get_required_mask(&pdev->dev), SZ_128M);
|
||||||
|
if (extra > SDHCI_MAX_SEGS)
|
||||||
|
extra = SDHCI_MAX_SEGS;
|
||||||
|
host->adma_table_cnt += extra;
|
||||||
|
|
||||||
|
regmap_base =
|
||||||
|
syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "ctc,sysctrl");
|
||||||
|
if (IS_ERR(regmap_base))
|
||||||
|
return PTR_ERR(regmap_base);
|
||||||
|
|
||||||
|
val = 0x3400027;
|
||||||
|
regmap_write(regmap_base, offsetof(struct SysCtl_regs, SysMshCfg), val);
|
||||||
|
|
||||||
|
regmap_read(regmap_base, offsetof(struct SysCtl_regs, SysCtlSysRev),
|
||||||
|
&val);
|
||||||
|
|
||||||
|
version = (val == 0x1) ? CTC_REV_TM_1_1 : CTC_REV_TM_1_0;
|
||||||
|
|
||||||
|
mmc_of_parse_voltage(pdev->dev.of_node, &host->ocr_mask);
|
||||||
|
|
||||||
|
ret = mmc_of_parse(host->mmc);
|
||||||
|
if (ret)
|
||||||
|
goto err_sdhci_add;
|
||||||
|
|
||||||
clk = devm_clk_get(&pdev->dev, "mmc_clk");
|
clk = devm_clk_get(&pdev->dev, "mmc_clk");
|
||||||
if (IS_ERR(clk)) {
|
if (IS_ERR(clk)) {
|
||||||
dev_err(&pdev->dev, "Peripheral clk not found\n");
|
dev_err(&pdev->dev, "Peripheral clk not found\n");
|
||||||
@ -262,16 +342,17 @@ static int sdhci_ctc5236_probe(struct platform_device *pdev)
|
|||||||
pltfm_host->clk = clk;
|
pltfm_host->clk = clk;
|
||||||
clk_prepare_enable(clk);
|
clk_prepare_enable(clk);
|
||||||
|
|
||||||
regmap_base =
|
if (version == CTC_REV_TM_1_0) {
|
||||||
syscon_regmap_lookup_by_phandle(pdev->dev.of_node, "ctc,sysctrl");
|
if (host->mmc->caps & MMC_CAP_1_8V_DDR) {
|
||||||
if (IS_ERR(regmap_base))
|
host->mmc->caps &= ~MMC_CAP_1_8V_DDR;
|
||||||
return PTR_ERR(regmap_base);
|
printk("%s, not support DDR Mode\n", __func__);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
mmc_of_parse_voltage(pdev->dev.of_node, &host->ocr_mask);
|
if (host->mmc->caps2 & MMC_CAP2_HS200_1_8V_SDR) {
|
||||||
|
host->mmc->caps2 &= ~MMC_CAP2_HS200_1_8V_SDR;
|
||||||
ret = mmc_of_parse(host->mmc);
|
printk("%s, not support Hs200 Mode\n", __func__);
|
||||||
if (ret)
|
}
|
||||||
goto err_sdhci_add;
|
|
||||||
|
|
||||||
ret = sdhci_add_host(host);
|
ret = sdhci_add_host(host);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -303,5 +384,5 @@ static struct platform_driver sdhci_ctc5236_driver = {
|
|||||||
module_platform_driver(sdhci_ctc5236_driver);
|
module_platform_driver(sdhci_ctc5236_driver);
|
||||||
|
|
||||||
MODULE_DESCRIPTION("SDHCI driver for Centec TsingMa SoCs");
|
MODULE_DESCRIPTION("SDHCI driver for Centec TsingMa SoCs");
|
||||||
MODULE_AUTHOR("Jay Cao <caoj@centecnetworks.com>");
|
MODULE_AUTHOR("Wangyb <wangyb@centecnetworks.com>");
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
|
@ -1,11 +1,8 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/*
|
/*
|
||||||
* Copyright 2010 MontaVista Software, LLC.
|
* Copyright 2010 MontaVista Software, LLC.
|
||||||
*
|
*
|
||||||
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
|
* Author: Anton Vorontsov <avorontsov@ru.mvista.com>
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License version 2 as
|
|
||||||
* published by the Free Software Foundation.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _DRIVERS_MMC_SDHCI_PLTFM_H
|
#ifndef _DRIVERS_MMC_SDHCI_PLTFM_H
|
||||||
@ -28,7 +25,7 @@ struct sdhci_pltfm_host {
|
|||||||
unsigned int clock;
|
unsigned int clock;
|
||||||
u16 xfer_mode_shadow;
|
u16 xfer_mode_shadow;
|
||||||
|
|
||||||
unsigned long private[0] ____cacheline_aligned;
|
unsigned long private[] ____cacheline_aligned;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
|
#ifdef CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
|
||||||
@ -86,15 +83,20 @@ static inline void sdhci_be32bs_writeb(struct sdhci_host *host, u8 val, int reg)
|
|||||||
int base = reg & ~0x3;
|
int base = reg & ~0x3;
|
||||||
int shift = (reg & 0x3) * 8;
|
int shift = (reg & 0x3) * 8;
|
||||||
|
|
||||||
clrsetbits_be32(host->ioaddr + base , 0xff << shift, val << shift);
|
clrsetbits_be32(host->ioaddr + base, 0xff << shift, val << shift);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
|
#endif /* CONFIG_MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER */
|
||||||
|
|
||||||
extern void sdhci_get_of_property(struct platform_device *pdev);
|
void sdhci_get_property(struct platform_device *pdev);
|
||||||
|
|
||||||
|
static inline void sdhci_get_of_property(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
return sdhci_get_property(pdev);
|
||||||
|
}
|
||||||
|
|
||||||
extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
|
extern struct sdhci_host *sdhci_pltfm_init(struct platform_device *pdev,
|
||||||
const struct sdhci_pltfm_data *pdata,
|
const struct sdhci_pltfm_data *pdata,
|
||||||
size_t priv_size);
|
size_t priv_size);
|
||||||
extern void sdhci_pltfm_free(struct platform_device *pdev);
|
extern void sdhci_pltfm_free(struct platform_device *pdev);
|
||||||
|
|
||||||
extern int sdhci_pltfm_register(struct platform_device *pdev,
|
extern int sdhci_pltfm_register(struct platform_device *pdev,
|
||||||
@ -109,8 +111,20 @@ static inline void *sdhci_pltfm_priv(struct sdhci_pltfm_host *host)
|
|||||||
return host->private;
|
return host->private;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern const struct dev_pm_ops sdhci_pltfm_pmops;
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
int sdhci_pltfm_suspend(struct device *dev);
|
int sdhci_pltfm_suspend(struct device *dev);
|
||||||
int sdhci_pltfm_resume(struct device *dev);
|
int sdhci_pltfm_resume(struct device *dev);
|
||||||
extern const struct dev_pm_ops sdhci_pltfm_pmops;
|
#else
|
||||||
|
static inline int sdhci_pltfm_suspend(struct device *dev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int sdhci_pltfm_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */
|
#endif /* _DRIVERS_MMC_SDHCI_PLTFM_H */
|
||||||
|
@ -1,18 +1,15 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||||
/*
|
/*
|
||||||
* linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver
|
* linux/drivers/mmc/host/sdhci.h - Secure Digital Host Controller Interface driver
|
||||||
*
|
*
|
||||||
* Header file for Host Controller registers and I/O accessors.
|
* Header file for Host Controller registers and I/O accessors.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
|
* Copyright (C) 2005-2008 Pierre Ossman, All Rights Reserved.
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or (at
|
|
||||||
* your option) any later version.
|
|
||||||
*/
|
*/
|
||||||
#ifndef __SDHCI_HW_H
|
#ifndef __SDHCI_HW_H
|
||||||
#define __SDHCI_HW_H
|
#define __SDHCI_HW_H
|
||||||
|
|
||||||
|
#include <linux/bits.h>
|
||||||
#include <linux/scatterlist.h>
|
#include <linux/scatterlist.h>
|
||||||
#include <linux/compiler.h>
|
#include <linux/compiler.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
@ -28,6 +25,7 @@
|
|||||||
|
|
||||||
#define SDHCI_DMA_ADDRESS 0x00
|
#define SDHCI_DMA_ADDRESS 0x00
|
||||||
#define SDHCI_ARGUMENT2 SDHCI_DMA_ADDRESS
|
#define SDHCI_ARGUMENT2 SDHCI_DMA_ADDRESS
|
||||||
|
#define SDHCI_32BIT_BLK_CNT SDHCI_DMA_ADDRESS
|
||||||
|
|
||||||
#define SDHCI_BLOCK_SIZE 0x04
|
#define SDHCI_BLOCK_SIZE 0x04
|
||||||
#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
|
#define SDHCI_MAKE_BLKSZ(dma, blksz) (((dma & 0x7) << 12) | (blksz & 0xFFF))
|
||||||
@ -41,6 +39,7 @@
|
|||||||
#define SDHCI_TRNS_BLK_CNT_EN 0x02
|
#define SDHCI_TRNS_BLK_CNT_EN 0x02
|
||||||
#define SDHCI_TRNS_AUTO_CMD12 0x04
|
#define SDHCI_TRNS_AUTO_CMD12 0x04
|
||||||
#define SDHCI_TRNS_AUTO_CMD23 0x08
|
#define SDHCI_TRNS_AUTO_CMD23 0x08
|
||||||
|
#define SDHCI_TRNS_AUTO_SEL 0x0C
|
||||||
#define SDHCI_TRNS_READ 0x10
|
#define SDHCI_TRNS_READ 0x10
|
||||||
#define SDHCI_TRNS_MULTI 0x20
|
#define SDHCI_TRNS_MULTI 0x20
|
||||||
|
|
||||||
@ -71,6 +70,10 @@
|
|||||||
#define SDHCI_SPACE_AVAILABLE 0x00000400
|
#define SDHCI_SPACE_AVAILABLE 0x00000400
|
||||||
#define SDHCI_DATA_AVAILABLE 0x00000800
|
#define SDHCI_DATA_AVAILABLE 0x00000800
|
||||||
#define SDHCI_CARD_PRESENT 0x00010000
|
#define SDHCI_CARD_PRESENT 0x00010000
|
||||||
|
#define SDHCI_CARD_PRES_SHIFT 16
|
||||||
|
#define SDHCI_CD_STABLE 0x00020000
|
||||||
|
#define SDHCI_CD_LVL 0x00040000
|
||||||
|
#define SDHCI_CD_LVL_SHIFT 18
|
||||||
#define SDHCI_WRITE_PROTECT 0x00080000
|
#define SDHCI_WRITE_PROTECT 0x00080000
|
||||||
#define SDHCI_DATA_LVL_MASK 0x00F00000
|
#define SDHCI_DATA_LVL_MASK 0x00F00000
|
||||||
#define SDHCI_DATA_LVL_SHIFT 20
|
#define SDHCI_DATA_LVL_SHIFT 20
|
||||||
@ -86,7 +89,8 @@
|
|||||||
#define SDHCI_CTRL_ADMA1 0x08
|
#define SDHCI_CTRL_ADMA1 0x08
|
||||||
#define SDHCI_CTRL_ADMA32 0x10
|
#define SDHCI_CTRL_ADMA32 0x10
|
||||||
#define SDHCI_CTRL_ADMA64 0x18
|
#define SDHCI_CTRL_ADMA64 0x18
|
||||||
#define SDHCI_CTRL_8BITBUS 0x20
|
#define SDHCI_CTRL_ADMA3 0x18
|
||||||
|
#define SDHCI_CTRL_8BITBUS 0x20
|
||||||
#define SDHCI_CTRL_CDTEST_INS 0x40
|
#define SDHCI_CTRL_CDTEST_INS 0x40
|
||||||
#define SDHCI_CTRL_CDTEST_EN 0x80
|
#define SDHCI_CTRL_CDTEST_EN 0x80
|
||||||
|
|
||||||
@ -111,6 +115,7 @@
|
|||||||
#define SDHCI_DIV_HI_MASK 0x300
|
#define SDHCI_DIV_HI_MASK 0x300
|
||||||
#define SDHCI_PROG_CLOCK_MODE 0x0020
|
#define SDHCI_PROG_CLOCK_MODE 0x0020
|
||||||
#define SDHCI_CLOCK_CARD_EN 0x0004
|
#define SDHCI_CLOCK_CARD_EN 0x0004
|
||||||
|
#define SDHCI_CLOCK_PLL_EN 0x0008
|
||||||
#define SDHCI_CLOCK_INT_STABLE 0x0002
|
#define SDHCI_CLOCK_INT_STABLE 0x0002
|
||||||
#define SDHCI_CLOCK_INT_EN 0x0001
|
#define SDHCI_CLOCK_INT_EN 0x0001
|
||||||
|
|
||||||
@ -180,7 +185,7 @@
|
|||||||
#define SDHCI_CTRL_UHS_SDR50 0x0002
|
#define SDHCI_CTRL_UHS_SDR50 0x0002
|
||||||
#define SDHCI_CTRL_UHS_SDR104 0x0003
|
#define SDHCI_CTRL_UHS_SDR104 0x0003
|
||||||
#define SDHCI_CTRL_UHS_DDR50 0x0004
|
#define SDHCI_CTRL_UHS_DDR50 0x0004
|
||||||
#define SDHCI_CTRL_HS400 0x0005 /* Non-standard */
|
#define SDHCI_CTRL_HS400 0x0005 /* Non-standard */
|
||||||
#define SDHCI_CTRL_VDD_180 0x0008
|
#define SDHCI_CTRL_VDD_180 0x0008
|
||||||
#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030
|
#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030
|
||||||
#define SDHCI_CTRL_DRV_TYPE_B 0x0000
|
#define SDHCI_CTRL_DRV_TYPE_B 0x0000
|
||||||
@ -189,15 +194,16 @@
|
|||||||
#define SDHCI_CTRL_DRV_TYPE_D 0x0030
|
#define SDHCI_CTRL_DRV_TYPE_D 0x0030
|
||||||
#define SDHCI_CTRL_EXEC_TUNING 0x0040
|
#define SDHCI_CTRL_EXEC_TUNING 0x0040
|
||||||
#define SDHCI_CTRL_TUNED_CLK 0x0080
|
#define SDHCI_CTRL_TUNED_CLK 0x0080
|
||||||
|
#define SDHCI_CMD23_ENABLE 0x0800
|
||||||
|
#define SDHCI_CTRL_V4_MODE 0x1000
|
||||||
|
#define SDHCI_CTRL_64BIT_ADDR 0x2000
|
||||||
#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
|
#define SDHCI_CTRL_PRESET_VAL_ENABLE 0x8000
|
||||||
|
|
||||||
#define SDHCI_CAPABILITIES 0x40
|
#define SDHCI_CAPABILITIES 0x40
|
||||||
#define SDHCI_TIMEOUT_CLK_MASK 0x0000003F
|
#define SDHCI_TIMEOUT_CLK_MASK GENMASK(5, 0)
|
||||||
#define SDHCI_TIMEOUT_CLK_SHIFT 0
|
|
||||||
#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080
|
#define SDHCI_TIMEOUT_CLK_UNIT 0x00000080
|
||||||
#define SDHCI_CLOCK_BASE_MASK 0x00003F00
|
#define SDHCI_CLOCK_BASE_MASK GENMASK(13, 8)
|
||||||
#define SDHCI_CLOCK_V3_BASE_MASK 0x0000FF00
|
#define SDHCI_CLOCK_V3_BASE_MASK GENMASK(15, 8)
|
||||||
#define SDHCI_CLOCK_BASE_SHIFT 8
|
|
||||||
#define SDHCI_MAX_BLOCK_MASK 0x00030000
|
#define SDHCI_MAX_BLOCK_MASK 0x00030000
|
||||||
#define SDHCI_MAX_BLOCK_SHIFT 16
|
#define SDHCI_MAX_BLOCK_SHIFT 16
|
||||||
#define SDHCI_CAN_DO_8BIT 0x00040000
|
#define SDHCI_CAN_DO_8BIT 0x00040000
|
||||||
@ -209,33 +215,28 @@
|
|||||||
#define SDHCI_CAN_VDD_330 0x01000000
|
#define SDHCI_CAN_VDD_330 0x01000000
|
||||||
#define SDHCI_CAN_VDD_300 0x02000000
|
#define SDHCI_CAN_VDD_300 0x02000000
|
||||||
#define SDHCI_CAN_VDD_180 0x04000000
|
#define SDHCI_CAN_VDD_180 0x04000000
|
||||||
|
#define SDHCI_CAN_64BIT_V4 0x08000000
|
||||||
#define SDHCI_CAN_64BIT 0x10000000
|
#define SDHCI_CAN_64BIT 0x10000000
|
||||||
|
|
||||||
|
#define SDHCI_CAPABILITIES_1 0x44
|
||||||
#define SDHCI_SUPPORT_SDR50 0x00000001
|
#define SDHCI_SUPPORT_SDR50 0x00000001
|
||||||
#define SDHCI_SUPPORT_SDR104 0x00000002
|
#define SDHCI_SUPPORT_SDR104 0x00000002
|
||||||
#define SDHCI_SUPPORT_DDR50 0x00000004
|
#define SDHCI_SUPPORT_DDR50 0x00000004
|
||||||
#define SDHCI_DRIVER_TYPE_A 0x00000010
|
#define SDHCI_DRIVER_TYPE_A 0x00000010
|
||||||
#define SDHCI_DRIVER_TYPE_C 0x00000020
|
#define SDHCI_DRIVER_TYPE_C 0x00000020
|
||||||
#define SDHCI_DRIVER_TYPE_D 0x00000040
|
#define SDHCI_DRIVER_TYPE_D 0x00000040
|
||||||
#define SDHCI_RETUNING_TIMER_COUNT_MASK 0x00000F00
|
#define SDHCI_RETUNING_TIMER_COUNT_MASK GENMASK(11, 8)
|
||||||
#define SDHCI_RETUNING_TIMER_COUNT_SHIFT 8
|
|
||||||
#define SDHCI_USE_SDR50_TUNING 0x00002000
|
#define SDHCI_USE_SDR50_TUNING 0x00002000
|
||||||
#define SDHCI_RETUNING_MODE_MASK 0x0000C000
|
#define SDHCI_RETUNING_MODE_MASK GENMASK(15, 14)
|
||||||
#define SDHCI_RETUNING_MODE_SHIFT 14
|
#define SDHCI_CLOCK_MUL_MASK GENMASK(23, 16)
|
||||||
#define SDHCI_CLOCK_MUL_MASK 0x00FF0000
|
#define SDHCI_CAN_DO_ADMA3 0x08000000
|
||||||
#define SDHCI_CLOCK_MUL_SHIFT 16
|
#define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */
|
||||||
#define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */
|
|
||||||
|
|
||||||
#define SDHCI_CAPABILITIES_1 0x44
|
|
||||||
|
|
||||||
#define SDHCI_MAX_CURRENT 0x48
|
#define SDHCI_MAX_CURRENT 0x48
|
||||||
#define SDHCI_MAX_CURRENT_LIMIT 0xFF
|
#define SDHCI_MAX_CURRENT_LIMIT GENMASK(7, 0)
|
||||||
#define SDHCI_MAX_CURRENT_330_MASK 0x0000FF
|
#define SDHCI_MAX_CURRENT_330_MASK GENMASK(7, 0)
|
||||||
#define SDHCI_MAX_CURRENT_330_SHIFT 0
|
#define SDHCI_MAX_CURRENT_300_MASK GENMASK(15, 8)
|
||||||
#define SDHCI_MAX_CURRENT_300_MASK 0x00FF00
|
#define SDHCI_MAX_CURRENT_180_MASK GENMASK(23, 16)
|
||||||
#define SDHCI_MAX_CURRENT_300_SHIFT 8
|
|
||||||
#define SDHCI_MAX_CURRENT_180_MASK 0xFF0000
|
|
||||||
#define SDHCI_MAX_CURRENT_180_SHIFT 16
|
|
||||||
#define SDHCI_MAX_CURRENT_MULTIPLIER 4
|
#define SDHCI_MAX_CURRENT_MULTIPLIER 4
|
||||||
|
|
||||||
/* 4C-4F reserved for more max current */
|
/* 4C-4F reserved for more max current */
|
||||||
@ -252,18 +253,16 @@
|
|||||||
|
|
||||||
/* 60-FB reserved */
|
/* 60-FB reserved */
|
||||||
|
|
||||||
|
#define SDHCI_PRESET_FOR_HIGH_SPEED 0x64
|
||||||
#define SDHCI_PRESET_FOR_SDR12 0x66
|
#define SDHCI_PRESET_FOR_SDR12 0x66
|
||||||
#define SDHCI_PRESET_FOR_SDR25 0x68
|
#define SDHCI_PRESET_FOR_SDR25 0x68
|
||||||
#define SDHCI_PRESET_FOR_SDR50 0x6A
|
#define SDHCI_PRESET_FOR_SDR50 0x6A
|
||||||
#define SDHCI_PRESET_FOR_SDR104 0x6C
|
#define SDHCI_PRESET_FOR_SDR104 0x6C
|
||||||
#define SDHCI_PRESET_FOR_DDR50 0x6E
|
#define SDHCI_PRESET_FOR_DDR50 0x6E
|
||||||
#define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */
|
#define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */
|
||||||
#define SDHCI_PRESET_DRV_MASK 0xC000
|
#define SDHCI_PRESET_DRV_MASK GENMASK(15, 14)
|
||||||
#define SDHCI_PRESET_DRV_SHIFT 14
|
#define SDHCI_PRESET_CLKGEN_SEL BIT(10)
|
||||||
#define SDHCI_PRESET_CLKGEN_SEL_MASK 0x400
|
#define SDHCI_PRESET_SDCLK_FREQ_MASK GENMASK(9, 0)
|
||||||
#define SDHCI_PRESET_CLKGEN_SEL_SHIFT 10
|
|
||||||
#define SDHCI_PRESET_SDCLK_FREQ_MASK 0x3FF
|
|
||||||
#define SDHCI_PRESET_SDCLK_FREQ_SHIFT 0
|
|
||||||
|
|
||||||
#define SDHCI_SLOT_INT_STATUS 0xFC
|
#define SDHCI_SLOT_INT_STATUS 0xFC
|
||||||
|
|
||||||
@ -275,6 +274,9 @@
|
|||||||
#define SDHCI_SPEC_100 0
|
#define SDHCI_SPEC_100 0
|
||||||
#define SDHCI_SPEC_200 1
|
#define SDHCI_SPEC_200 1
|
||||||
#define SDHCI_SPEC_300 2
|
#define SDHCI_SPEC_300 2
|
||||||
|
#define SDHCI_SPEC_400 3
|
||||||
|
#define SDHCI_SPEC_410 4
|
||||||
|
#define SDHCI_SPEC_420 5
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* End of controller registers.
|
* End of controller registers.
|
||||||
@ -294,10 +296,10 @@
|
|||||||
|
|
||||||
/* ADMA2 32-bit descriptor */
|
/* ADMA2 32-bit descriptor */
|
||||||
struct sdhci_adma2_32_desc {
|
struct sdhci_adma2_32_desc {
|
||||||
__le16 cmd;
|
__le16 cmd;
|
||||||
__le16 len;
|
__le16 len;
|
||||||
__le32 addr;
|
__le32 addr;
|
||||||
} __packed __aligned(4);
|
} __packed __aligned(4);
|
||||||
|
|
||||||
/* ADMA2 data alignment */
|
/* ADMA2 data alignment */
|
||||||
#define SDHCI_ADMA2_ALIGN 4
|
#define SDHCI_ADMA2_ALIGN 4
|
||||||
@ -310,19 +312,25 @@ struct sdhci_adma2_32_desc {
|
|||||||
*/
|
*/
|
||||||
#define SDHCI_ADMA2_DESC_ALIGN 8
|
#define SDHCI_ADMA2_DESC_ALIGN 8
|
||||||
|
|
||||||
/* ADMA2 64-bit DMA descriptor size */
|
/*
|
||||||
#define SDHCI_ADMA2_64_DESC_SZ 12
|
* ADMA2 64-bit DMA descriptor size
|
||||||
|
* According to SD Host Controller spec v4.10, there are two kinds of
|
||||||
|
* descriptors for 64-bit addressing mode: 96-bit Descriptor and 128-bit
|
||||||
|
* Descriptor, if Host Version 4 Enable is set in the Host Control 2
|
||||||
|
* register, 128-bit Descriptor will be selected.
|
||||||
|
*/
|
||||||
|
#define SDHCI_ADMA2_64_DESC_SZ(host) ((host)->v4_mode ? 16 : 12)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte
|
* ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte
|
||||||
* aligned.
|
* aligned.
|
||||||
*/
|
*/
|
||||||
struct sdhci_adma2_64_desc {
|
struct sdhci_adma2_64_desc {
|
||||||
__le16 cmd;
|
__le16 cmd;
|
||||||
__le16 len;
|
__le16 len;
|
||||||
__le32 addr_lo;
|
__le32 addr_lo;
|
||||||
__le32 addr_hi;
|
__le32 addr_hi;
|
||||||
} __packed __aligned(4);
|
} __packed __aligned(4);
|
||||||
|
|
||||||
#define ADMA2_TRAN_VALID 0x21
|
#define ADMA2_TRAN_VALID 0x21
|
||||||
#define ADMA2_NOP_END_VALID 0x3
|
#define ADMA2_NOP_END_VALID 0x3
|
||||||
@ -343,7 +351,7 @@ struct sdhci_adma2_64_desc {
|
|||||||
* command and response, and the time between response and start of data is
|
* command and response, and the time between response and start of data is
|
||||||
* not known, set the command transfer time to 10ms.
|
* not known, set the command transfer time to 10ms.
|
||||||
*/
|
*/
|
||||||
#define MMC_CMD_TRANSFER_TIME (10 * NSEC_PER_MSEC) /* max 10 ms */
|
#define MMC_CMD_TRANSFER_TIME (10 * NSEC_PER_MSEC) /* max 10 ms */
|
||||||
|
|
||||||
enum sdhci_cookie {
|
enum sdhci_cookie {
|
||||||
COOKIE_UNMAPPED,
|
COOKIE_UNMAPPED,
|
||||||
@ -391,8 +399,12 @@ struct sdhci_host {
|
|||||||
#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15)
|
#define SDHCI_QUIRK_BROKEN_CARD_DETECTION (1<<15)
|
||||||
/* Controller reports inverted write-protect state */
|
/* Controller reports inverted write-protect state */
|
||||||
#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16)
|
#define SDHCI_QUIRK_INVERTED_WRITE_PROTECT (1<<16)
|
||||||
|
/* Controller has unusable command queue engine */
|
||||||
|
#define SDHCI_QUIRK_BROKEN_CQE (1<<17)
|
||||||
/* Controller does not like fast PIO transfers */
|
/* Controller does not like fast PIO transfers */
|
||||||
#define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18)
|
#define SDHCI_QUIRK_PIO_NEEDS_DELAY (1<<18)
|
||||||
|
/* Controller does not have a LED */
|
||||||
|
#define SDHCI_QUIRK_NO_LED (1<<19)
|
||||||
/* Controller has to be forced to use block size of 2048 bytes */
|
/* Controller has to be forced to use block size of 2048 bytes */
|
||||||
#define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20)
|
#define SDHCI_QUIRK_FORCE_BLK_SZ_2048 (1<<20)
|
||||||
/* Controller cannot do multi-block transfers */
|
/* Controller cannot do multi-block transfers */
|
||||||
@ -455,9 +467,17 @@ struct sdhci_host {
|
|||||||
* obtainable timeout.
|
* obtainable timeout.
|
||||||
*/
|
*/
|
||||||
#define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT (1<<17)
|
#define SDHCI_QUIRK2_DISABLE_HW_TIMEOUT (1<<17)
|
||||||
|
/*
|
||||||
|
* 32-bit block count may not support eMMC where upper bits of CMD23 are used
|
||||||
|
* for other purposes. Consequently we support 16-bit block count by default.
|
||||||
|
* Otherwise, SDHCI_QUIRK2_USE_32BIT_BLK_CNT can be selected to use 32-bit
|
||||||
|
* block count.
|
||||||
|
*/
|
||||||
|
#define SDHCI_QUIRK2_USE_32BIT_BLK_CNT (1<<18)
|
||||||
|
|
||||||
int irq; /* Device IRQ */
|
int irq; /* Device IRQ */
|
||||||
void __iomem *ioaddr; /* Mapped address */
|
void __iomem *ioaddr; /* Mapped address */
|
||||||
|
phys_addr_t mapbase; /* physical address base */
|
||||||
char *bounce_buffer; /* For packing SDMA reads/writes */
|
char *bounce_buffer; /* For packing SDMA reads/writes */
|
||||||
dma_addr_t bounce_addr;
|
dma_addr_t bounce_addr;
|
||||||
unsigned int bounce_buffer_size;
|
unsigned int bounce_buffer_size;
|
||||||
@ -485,7 +505,6 @@ struct sdhci_host {
|
|||||||
#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */
|
#define SDHCI_AUTO_CMD12 (1<<6) /* Auto CMD12 support */
|
||||||
#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */
|
#define SDHCI_AUTO_CMD23 (1<<7) /* Auto CMD23 support */
|
||||||
#define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */
|
#define SDHCI_PV_ENABLED (1<<8) /* Preset value enabled */
|
||||||
#define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
|
|
||||||
#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */
|
#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */
|
||||||
#define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */
|
#define SDHCI_HS400_TUNING (1<<13) /* Tuning for HS400 */
|
||||||
#define SDHCI_SIGNALING_330 (1<<14) /* Host is capable of 3.3V signaling */
|
#define SDHCI_SIGNALING_330 (1<<14) /* Host is capable of 3.3V signaling */
|
||||||
@ -506,10 +525,14 @@ struct sdhci_host {
|
|||||||
bool preset_enabled; /* Preset is enabled */
|
bool preset_enabled; /* Preset is enabled */
|
||||||
bool pending_reset; /* Cmd/data reset is pending */
|
bool pending_reset; /* Cmd/data reset is pending */
|
||||||
bool irq_wake_enabled; /* IRQ wakeup is enabled */
|
bool irq_wake_enabled; /* IRQ wakeup is enabled */
|
||||||
|
bool v4_mode; /* Host Version 4 Enable */
|
||||||
|
bool use_external_dma; /* Host selects to use external DMA */
|
||||||
|
bool always_defer_done; /* Always defer to complete requests */
|
||||||
|
|
||||||
struct mmc_request *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */
|
struct mmc_request *mrqs_done[SDHCI_MAX_MRQS]; /* Requests done */
|
||||||
struct mmc_command *cmd; /* Current command */
|
struct mmc_command *cmd; /* Current command */
|
||||||
struct mmc_command *data_cmd; /* Current data command */
|
struct mmc_command *data_cmd; /* Current data command */
|
||||||
|
struct mmc_command *deferred_cmd; /* Deferred command */
|
||||||
struct mmc_data *data; /* Current data request */
|
struct mmc_data *data; /* Current data request */
|
||||||
unsigned int data_early:1; /* Data finished before cmd */
|
unsigned int data_early:1; /* Data finished before cmd */
|
||||||
|
|
||||||
@ -527,87 +550,109 @@ struct sdhci_host {
|
|||||||
dma_addr_t adma_addr; /* Mapped ADMA descr. table */
|
dma_addr_t adma_addr; /* Mapped ADMA descr. table */
|
||||||
dma_addr_t align_addr; /* Mapped bounce buffer */
|
dma_addr_t align_addr; /* Mapped bounce buffer */
|
||||||
|
|
||||||
unsigned int desc_sz; /* ADMA descriptor size */
|
unsigned int desc_sz; /* ADMA current descriptor size */
|
||||||
|
unsigned int alloc_desc_sz; /* ADMA descr. max size host supports */
|
||||||
|
|
||||||
struct tasklet_struct finish_tasklet; /* Tasklet structures */
|
struct workqueue_struct *complete_wq; /* Request completion wq */
|
||||||
|
struct work_struct complete_work; /* Request completion work */
|
||||||
|
|
||||||
struct timer_list timer; /* Timer for timeouts */
|
struct timer_list timer; /* Timer for timeouts */
|
||||||
struct timer_list data_timer; /* Timer for data timeouts */
|
struct timer_list data_timer; /* Timer for data timeouts */
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_MMC_SDHCI_EXTERNAL_DMA)
|
||||||
|
struct dma_chan *rx_chan;
|
||||||
|
struct dma_chan *tx_chan;
|
||||||
|
#endif
|
||||||
|
|
||||||
u32 caps; /* CAPABILITY_0 */
|
u32 caps; /* CAPABILITY_0 */
|
||||||
u32 caps1; /* CAPABILITY_1 */
|
u32 caps1; /* CAPABILITY_1 */
|
||||||
bool read_caps; /* Capability flags have been read */
|
bool read_caps; /* Capability flags have been read */
|
||||||
|
|
||||||
unsigned int ocr_avail_sdio; /* OCR bit masks */
|
bool sdhci_core_to_disable_vqmmc; /* sdhci core can disable vqmmc */
|
||||||
unsigned int ocr_avail_sd;
|
unsigned int ocr_avail_sdio; /* OCR bit masks */
|
||||||
unsigned int ocr_avail_mmc;
|
unsigned int ocr_avail_sd;
|
||||||
|
unsigned int ocr_avail_mmc;
|
||||||
u32 ocr_mask; /* available voltages */
|
u32 ocr_mask; /* available voltages */
|
||||||
|
|
||||||
unsigned timing; /* Current timing */
|
unsigned timing; /* Current timing */
|
||||||
|
|
||||||
u32 thread_isr;
|
u32 thread_isr;
|
||||||
|
|
||||||
/* cached registers */
|
/* cached registers */
|
||||||
u32 ier;
|
u32 ier;
|
||||||
|
|
||||||
bool cqe_on; /* CQE is operating */
|
bool cqe_on; /* CQE is operating */
|
||||||
u32 cqe_ier; /* CQE interrupt mask */
|
u32 cqe_ier; /* CQE interrupt mask */
|
||||||
u32 cqe_err_ier; /* CQE error interrupt mask */
|
u32 cqe_err_ier; /* CQE error interrupt mask */
|
||||||
|
|
||||||
wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */
|
wait_queue_head_t buf_ready_int; /* Waitqueue for Buffer Read Ready interrupt */
|
||||||
unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */
|
unsigned int tuning_done; /* Condition flag set when CMD19 succeeds */
|
||||||
|
|
||||||
unsigned int tuning_count; /* Timer count for re-tuning */
|
unsigned int tuning_count; /* Timer count for re-tuning */
|
||||||
unsigned int tuning_mode; /* Re-tuning mode supported by host */
|
unsigned int tuning_mode; /* Re-tuning mode supported by host */
|
||||||
|
unsigned int tuning_err; /* Error code for re-tuning */
|
||||||
#define SDHCI_TUNING_MODE_1 0
|
#define SDHCI_TUNING_MODE_1 0
|
||||||
#define SDHCI_TUNING_MODE_2 1
|
#define SDHCI_TUNING_MODE_2 1
|
||||||
#define SDHCI_TUNING_MODE_3 2
|
#define SDHCI_TUNING_MODE_3 2
|
||||||
/* Delay (ms) between tuning commands */
|
/* Delay (ms) between tuning commands */
|
||||||
int tuning_delay;
|
int tuning_delay;
|
||||||
|
int tuning_loop_count;
|
||||||
|
|
||||||
/* Host SDMA buffer boundary. */
|
/* Host SDMA buffer boundary. */
|
||||||
u32 sdma_boundary;
|
u32 sdma_boundary;
|
||||||
|
|
||||||
u64 data_timeout;
|
/* Host ADMA table count */
|
||||||
|
u32 adma_table_cnt;
|
||||||
|
|
||||||
unsigned long private[0] ____cacheline_aligned;
|
u64 data_timeout;
|
||||||
|
|
||||||
|
unsigned long private[] ____cacheline_aligned;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sdhci_ops {
|
struct sdhci_ops {
|
||||||
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
|
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
|
||||||
u32 (*read_l)(struct sdhci_host *host, int reg);
|
u32(*read_l) (struct sdhci_host * host, int reg);
|
||||||
u16 (*read_w)(struct sdhci_host *host, int reg);
|
u16(*read_w) (struct sdhci_host * host, int reg);
|
||||||
u8 (*read_b)(struct sdhci_host *host, int reg);
|
u8(*read_b) (struct sdhci_host * host, int reg);
|
||||||
void (*write_l)(struct sdhci_host *host, u32 val, int reg);
|
void (*write_l) (struct sdhci_host * host, u32 val, int reg);
|
||||||
void (*write_w)(struct sdhci_host *host, u16 val, int reg);
|
void (*write_w) (struct sdhci_host * host, u16 val, int reg);
|
||||||
void (*write_b)(struct sdhci_host *host, u8 val, int reg);
|
void (*write_b) (struct sdhci_host * host, u8 val, int reg);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void (*set_clock)(struct sdhci_host *host, unsigned int clock);
|
void (*set_clock) (struct sdhci_host * host, unsigned int clock);
|
||||||
void (*set_power)(struct sdhci_host *host, unsigned char mode,
|
void (*set_power) (struct sdhci_host * host, unsigned char mode,
|
||||||
unsigned short vdd);
|
unsigned short vdd);
|
||||||
|
|
||||||
u32 (*irq)(struct sdhci_host *host, u32 intmask);
|
u32(*irq) (struct sdhci_host * host, u32 intmask);
|
||||||
|
|
||||||
int (*enable_dma)(struct sdhci_host *host);
|
int (*set_dma_mask) (struct sdhci_host * host);
|
||||||
unsigned int (*get_max_clock)(struct sdhci_host *host);
|
int (*enable_dma) (struct sdhci_host * host);
|
||||||
unsigned int (*get_min_clock)(struct sdhci_host *host);
|
unsigned int (*get_max_clock) (struct sdhci_host * host);
|
||||||
|
unsigned int (*get_min_clock) (struct sdhci_host * host);
|
||||||
/* get_timeout_clock should return clk rate in unit of Hz */
|
/* get_timeout_clock should return clk rate in unit of Hz */
|
||||||
unsigned int (*get_timeout_clock)(struct sdhci_host *host);
|
unsigned int (*get_timeout_clock) (struct sdhci_host * host);
|
||||||
unsigned int (*get_max_timeout_count)(struct sdhci_host *host);
|
unsigned int (*get_max_timeout_count) (struct sdhci_host * host);
|
||||||
void (*set_timeout)(struct sdhci_host *host,
|
void (*set_timeout) (struct sdhci_host * host,
|
||||||
struct mmc_command *cmd);
|
struct mmc_command * cmd);
|
||||||
void (*set_bus_width)(struct sdhci_host *host, int width);
|
void (*set_bus_width) (struct sdhci_host * host, int width);
|
||||||
void (*platform_send_init_74_clocks)(struct sdhci_host *host,
|
void (*platform_send_init_74_clocks) (struct sdhci_host * host,
|
||||||
u8 power_mode);
|
u8 power_mode);
|
||||||
unsigned int (*get_ro)(struct sdhci_host *host);
|
unsigned int (*get_ro) (struct sdhci_host * host);
|
||||||
void (*reset)(struct sdhci_host *host, u8 mask);
|
void (*reset) (struct sdhci_host * host, u8 mask);
|
||||||
int (*platform_execute_tuning)(struct sdhci_host *host, u32 opcode);
|
int (*platform_execute_tuning) (struct sdhci_host * host, u32 opcode);
|
||||||
void (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs);
|
void (*set_uhs_signaling) (struct sdhci_host * host, unsigned int uhs);
|
||||||
void (*hw_reset)(struct sdhci_host *host);
|
void (*hw_reset) (struct sdhci_host * host);
|
||||||
void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
|
void (*adma_workaround) (struct sdhci_host * host, u32 intmask);
|
||||||
void (*card_event)(struct sdhci_host *host);
|
void (*card_event) (struct sdhci_host * host);
|
||||||
void (*voltage_switch)(struct sdhci_host *host);
|
void (*voltage_switch) (struct sdhci_host * host);
|
||||||
|
void (*adma_write_desc) (struct sdhci_host * host, void **desc,
|
||||||
|
dma_addr_t addr, int len, unsigned int cmd);
|
||||||
|
void (*copy_to_bounce_buffer) (struct sdhci_host * host,
|
||||||
|
struct mmc_data * data,
|
||||||
|
unsigned int length);
|
||||||
|
void (*request_done) (struct sdhci_host * host,
|
||||||
|
struct mmc_request * mrq);
|
||||||
|
void (*dump_vendor_regs) (struct sdhci_host * host);
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
|
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
|
||||||
@ -703,33 +748,31 @@ static inline void *sdhci_priv(struct sdhci_host *host)
|
|||||||
}
|
}
|
||||||
|
|
||||||
void sdhci_card_detect(struct sdhci_host *host);
|
void sdhci_card_detect(struct sdhci_host *host);
|
||||||
void __sdhci_read_caps(struct sdhci_host *host, u16 *ver, u32 *caps,
|
void __sdhci_read_caps(struct sdhci_host *host, const u16 * ver,
|
||||||
u32 *caps1);
|
const u32 * caps, const u32 * caps1);
|
||||||
int sdhci_setup_host(struct sdhci_host *host);
|
int sdhci_setup_host(struct sdhci_host *host);
|
||||||
void sdhci_cleanup_host(struct sdhci_host *host);
|
void sdhci_cleanup_host(struct sdhci_host *host);
|
||||||
int __sdhci_add_host(struct sdhci_host *host);
|
int __sdhci_add_host(struct sdhci_host *host);
|
||||||
int sdhci_add_host(struct sdhci_host *host);
|
int sdhci_add_host(struct sdhci_host *host);
|
||||||
void sdhci_remove_host(struct sdhci_host *host, int dead);
|
void sdhci_remove_host(struct sdhci_host *host, int dead);
|
||||||
void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd);
|
|
||||||
|
|
||||||
static inline void sdhci_read_caps(struct sdhci_host *host)
|
static inline void sdhci_read_caps(struct sdhci_host *host)
|
||||||
{
|
{
|
||||||
__sdhci_read_caps(host, NULL, NULL, NULL);
|
__sdhci_read_caps(host, NULL, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool sdhci_sdio_irq_enabled(struct sdhci_host *host)
|
|
||||||
{
|
|
||||||
return !!(host->flags & SDHCI_SDIO_IRQ_ENABLED);
|
|
||||||
}
|
|
||||||
|
|
||||||
u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
|
u16 sdhci_calc_clk(struct sdhci_host *host, unsigned int clock,
|
||||||
unsigned int *actual_clock);
|
unsigned int *actual_clock);
|
||||||
void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
|
void sdhci_set_clock(struct sdhci_host *host, unsigned int clock);
|
||||||
void sdhci_enable_clk(struct sdhci_host *host, u16 clk);
|
void sdhci_enable_clk(struct sdhci_host *host, u16 clk);
|
||||||
void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
|
void sdhci_set_power(struct sdhci_host *host, unsigned char mode,
|
||||||
unsigned short vdd);
|
unsigned short vdd);
|
||||||
|
void sdhci_set_power_and_bus_voltage(struct sdhci_host *host,
|
||||||
|
unsigned char mode, unsigned short vdd);
|
||||||
void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
|
void sdhci_set_power_noreg(struct sdhci_host *host, unsigned char mode,
|
||||||
unsigned short vdd);
|
unsigned short vdd);
|
||||||
|
void sdhci_request(struct mmc_host *mmc, struct mmc_request *mrq);
|
||||||
|
int sdhci_request_atomic(struct mmc_host *mmc, struct mmc_request *mrq);
|
||||||
void sdhci_set_bus_width(struct sdhci_host *host, int width);
|
void sdhci_set_bus_width(struct sdhci_host *host, int width);
|
||||||
void sdhci_reset(struct sdhci_host *host, u8 mask);
|
void sdhci_reset(struct sdhci_host *host, u8 mask);
|
||||||
void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
|
void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
|
||||||
@ -738,12 +781,14 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios);
|
|||||||
int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
|
int sdhci_start_signal_voltage_switch(struct mmc_host *mmc,
|
||||||
struct mmc_ios *ios);
|
struct mmc_ios *ios);
|
||||||
void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable);
|
void sdhci_enable_sdio_irq(struct mmc_host *mmc, int enable);
|
||||||
|
void sdhci_adma_write_desc(struct sdhci_host *host, void **desc,
|
||||||
|
dma_addr_t addr, int len, unsigned int cmd);
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
int sdhci_suspend_host(struct sdhci_host *host);
|
int sdhci_suspend_host(struct sdhci_host *host);
|
||||||
int sdhci_resume_host(struct sdhci_host *host);
|
int sdhci_resume_host(struct sdhci_host *host);
|
||||||
int sdhci_runtime_suspend_host(struct sdhci_host *host);
|
int sdhci_runtime_suspend_host(struct sdhci_host *host);
|
||||||
int sdhci_runtime_resume_host(struct sdhci_host *host);
|
int sdhci_runtime_resume_host(struct sdhci_host *host, int soft_reset);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void sdhci_cqe_enable(struct mmc_host *mmc);
|
void sdhci_cqe_enable(struct mmc_host *mmc);
|
||||||
@ -752,10 +797,15 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error,
|
|||||||
int *data_error);
|
int *data_error);
|
||||||
|
|
||||||
void sdhci_dumpregs(struct sdhci_host *host);
|
void sdhci_dumpregs(struct sdhci_host *host);
|
||||||
|
void sdhci_enable_v4_mode(struct sdhci_host *host);
|
||||||
|
|
||||||
void sdhci_start_tuning(struct sdhci_host *host);
|
void sdhci_start_tuning(struct sdhci_host *host);
|
||||||
void sdhci_end_tuning(struct sdhci_host *host);
|
void sdhci_end_tuning(struct sdhci_host *host);
|
||||||
void sdhci_reset_tuning(struct sdhci_host *host);
|
void sdhci_reset_tuning(struct sdhci_host *host);
|
||||||
void sdhci_send_tuning(struct sdhci_host *host, u32 opcode);
|
void sdhci_send_tuning(struct sdhci_host *host, u32 opcode);
|
||||||
|
void sdhci_abort_tuning(struct sdhci_host *host, u32 opcode);
|
||||||
|
void sdhci_switch_external_dma(struct sdhci_host *host, bool en);
|
||||||
|
void sdhci_set_data_timeout_irq(struct sdhci_host *host, bool enable);
|
||||||
|
void __sdhci_set_timeout(struct sdhci_host *host, struct mmc_command *cmd);
|
||||||
|
|
||||||
#endif /* __SDHCI_HW_H */
|
#endif /* __SDHCI_HW_H */
|
||||||
|
@ -111,7 +111,7 @@ enum type_mode {
|
|||||||
TYPE_MAX
|
TYPE_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ctc_reg_read(struct ctc_qspi *ctc_qspi, u32 reg, u32 *value)
|
static int ctc_reg_read(struct ctc_qspi *ctc_qspi, u32 reg, u32 * value)
|
||||||
{
|
{
|
||||||
*value = readl(ctc_qspi->regs + reg);
|
*value = readl(ctc_qspi->regs + reg);
|
||||||
return *value;
|
return *value;
|
||||||
@ -169,12 +169,12 @@ static noinline int ctc_write_tx_buf(struct ctc_qspi *ctc_qspi, u8 offset,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinline int check_buf_ok(u8 *buf, int i)
|
static noinline int check_buf_ok(u8 * buf, int i)
|
||||||
{
|
{
|
||||||
return buf && (buf + i);
|
return buf && (buf + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinline int fill_tx_entry(struct ctc_qspi *ctc_qspi, u8 *buf, int i,
|
static noinline int fill_tx_entry(struct ctc_qspi *ctc_qspi, u8 * buf, int i,
|
||||||
u8 off)
|
u8 off)
|
||||||
{
|
{
|
||||||
ctc_qspi->tx_entry |= buf[i] << (off % 4) * 8;
|
ctc_qspi->tx_entry |= buf[i] << (off % 4) * 8;
|
||||||
@ -182,12 +182,12 @@ static noinline int fill_tx_entry(struct ctc_qspi *ctc_qspi, u8 *buf, int i,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static noinline void update_offset(u8 *offset, u8 off)
|
static noinline void update_offset(u8 * offset, u8 off)
|
||||||
{
|
{
|
||||||
*offset = off;
|
*offset = off;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ctc_fill_tx_buf(struct ctc_qspi *ctc_qspi, u8 *offset, u8 *buf,
|
static void ctc_fill_tx_buf(struct ctc_qspi *ctc_qspi, u8 * offset, u8 * buf,
|
||||||
u32 len)
|
u32 len)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -195,8 +195,9 @@ static void ctc_fill_tx_buf(struct ctc_qspi *ctc_qspi, u8 *offset, u8 *buf,
|
|||||||
u8 off = *offset;
|
u8 off = *offset;
|
||||||
|
|
||||||
while (i < len) {
|
while (i < len) {
|
||||||
if (check_buf_ok(buf, i))
|
if (check_buf_ok(buf, i)) {
|
||||||
fill_tx_entry(ctc_qspi, buf, i, off);
|
fill_tx_entry(ctc_qspi, buf, i, off);
|
||||||
|
}
|
||||||
|
|
||||||
if (off % 4 == 0) {
|
if (off % 4 == 0) {
|
||||||
ctc_write_tx_buf(ctc_qspi, off, ctc_qspi->tx_entry);
|
ctc_write_tx_buf(ctc_qspi, off, ctc_qspi->tx_entry);
|
||||||
@ -210,7 +211,7 @@ static void ctc_fill_tx_buf(struct ctc_qspi *ctc_qspi, u8 *offset, u8 *buf,
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ctc_fill_pp_buf(struct ctc_qspi *ctc_qspi, u32 *offset, u8 *buf,
|
static void ctc_fill_pp_buf(struct ctc_qspi *ctc_qspi, u32 * offset, u8 * buf,
|
||||||
u32 len)
|
u32 len)
|
||||||
{
|
{
|
||||||
u32 i = 0, j = 0;
|
u32 i = 0, j = 0;
|
||||||
@ -218,8 +219,9 @@ static void ctc_fill_pp_buf(struct ctc_qspi *ctc_qspi, u32 *offset, u8 *buf,
|
|||||||
|
|
||||||
while (i < len) {
|
while (i < len) {
|
||||||
for (j = 0; j < 4; j++) {
|
for (j = 0; j < 4; j++) {
|
||||||
if (buf && (buf + i))
|
if (buf && (buf + i)) {
|
||||||
ctc_qspi->tx_entry |= buf[i + j] << (j % 4) * 8;
|
ctc_qspi->tx_entry |= buf[i + j] << (j % 4) * 8;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctc_write_tx_buf(ctc_qspi, off, ctc_qspi->tx_entry);
|
ctc_write_tx_buf(ctc_qspi, off, ctc_qspi->tx_entry);
|
||||||
ctc_qspi->tx_entry = 0;
|
ctc_qspi->tx_entry = 0;
|
||||||
@ -303,15 +305,17 @@ static void ctc_qspi_pio_ctrl(struct ctc_qspi *ctc_qspi)
|
|||||||
{
|
{
|
||||||
u32 ctrl = 0;
|
u32 ctrl = 0;
|
||||||
|
|
||||||
ctrl = CTRL_IDLE_CYCLE(ctc_qspi->idlecycle) |
|
ctrl =
|
||||||
CTRL_PRE_CYCLE(ctc_qspi->precycle) |
|
CTRL_IDLE_CYCLE(ctc_qspi->idlecycle) | CTRL_PRE_CYCLE(ctc_qspi->
|
||||||
CTRL_POST_CYCLE(ctc_qspi->postcycle) |
|
precycle)
|
||||||
CTRL_SCLK_DEFAULT(ctc_qspi->sclkdef) |
|
| CTRL_POST_CYCLE(ctc_qspi->
|
||||||
CTRL_SOUT3_DEFAULT(ctc_qspi->sout3def) |
|
postcycle) | CTRL_SCLK_DEFAULT(ctc_qspi->sclkdef)
|
||||||
CTRL_SOUT2_DEFAULT(ctc_qspi->sout2def) |
|
| CTRL_SOUT3_DEFAULT(ctc_qspi->
|
||||||
CTRL_SOUT1_DEFAULT(ctc_qspi->sout1def) |
|
sout3def) | CTRL_SOUT2_DEFAULT(ctc_qspi->
|
||||||
CTRL_CS(ctc_qspi->cs_select) |
|
sout2def)
|
||||||
CTRL_DIV_SCLK(ctc_qspi->clkdiv);
|
| CTRL_SOUT1_DEFAULT(ctc_qspi->sout1def) | CTRL_CS(ctc_qspi->
|
||||||
|
cs_select)
|
||||||
|
| CTRL_DIV_SCLK(ctc_qspi->clkdiv);
|
||||||
|
|
||||||
ctc_reg_write_mask(ctc_qspi, PIO_CTRL(ctc_qspi->qspi_mode), ctrl,
|
ctc_reg_write_mask(ctc_qspi, PIO_CTRL(ctc_qspi->qspi_mode), ctrl,
|
||||||
0xffffffff);
|
0xffffffff);
|
||||||
@ -321,15 +325,17 @@ static void ctc_qspi_pp_ctrl(struct ctc_qspi *ctc_qspi)
|
|||||||
{
|
{
|
||||||
u32 ctrl = 0;
|
u32 ctrl = 0;
|
||||||
|
|
||||||
ctrl = CTRL_IDLE_CYCLE(ctc_qspi->idlecycle) |
|
ctrl =
|
||||||
CTRL_PRE_CYCLE(ctc_qspi->precycle) |
|
CTRL_IDLE_CYCLE(ctc_qspi->idlecycle) | CTRL_PRE_CYCLE(ctc_qspi->
|
||||||
CTRL_POST_CYCLE(ctc_qspi->postcycle) |
|
precycle)
|
||||||
CTRL_SCLK_DEFAULT(ctc_qspi->sclkdef) |
|
| CTRL_POST_CYCLE(ctc_qspi->
|
||||||
CTRL_SOUT3_DEFAULT(ctc_qspi->sout3def) |
|
postcycle) | CTRL_SCLK_DEFAULT(ctc_qspi->sclkdef)
|
||||||
CTRL_SOUT2_DEFAULT(ctc_qspi->sout2def) |
|
| CTRL_SOUT3_DEFAULT(ctc_qspi->
|
||||||
CTRL_SOUT1_DEFAULT(ctc_qspi->sout1def) |
|
sout3def) | CTRL_SOUT2_DEFAULT(ctc_qspi->
|
||||||
CTRL_CS(ctc_qspi->cs_select) |
|
sout2def)
|
||||||
CTRL_DIV_SCLK(ctc_qspi->clkdiv);
|
| CTRL_SOUT1_DEFAULT(ctc_qspi->sout1def) | CTRL_CS(ctc_qspi->
|
||||||
|
cs_select)
|
||||||
|
| CTRL_DIV_SCLK(ctc_qspi->clkdiv);
|
||||||
|
|
||||||
ctc_reg_write_mask(ctc_qspi, PP_CTRL, ctrl, 0xffffffff);
|
ctc_reg_write_mask(ctc_qspi, PP_CTRL, ctrl, 0xffffffff);
|
||||||
}
|
}
|
||||||
@ -343,18 +349,17 @@ static u32 ctc_pp_conf(u8 lanes, u32 len)
|
|||||||
return (lanes << 16) | (cycle);
|
return (lanes << 16) | (cycle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ctc_read_rx_buf(struct ctc_qspi *ctc_qspi, u8 offset, u8 *value)
|
static int ctc_read_rx_buf(struct ctc_qspi *ctc_qspi, u8 offset, u8 * value)
|
||||||
{
|
{
|
||||||
*value = readb(ctc_qspi->regs + CTC_QSPI_RX_BUFF + offset);
|
*value = readb(ctc_qspi->regs + CTC_QSPI_RX_BUFF + offset);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ctc_extra_rx_buf(struct ctc_qspi *ctc_qspi, u8 offset, u8 *buf,
|
static void ctc_extra_rx_buf(struct ctc_qspi *ctc_qspi, u8 offset, u8 * buf,
|
||||||
u8 len)
|
u8 len)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
while (i < len) {
|
while (i < len) {
|
||||||
ctc_read_rx_buf(ctc_qspi, offset, &buf[i++]);
|
ctc_read_rx_buf(ctc_qspi, offset, &buf[i++]);
|
||||||
offset--;
|
offset--;
|
||||||
@ -523,11 +528,13 @@ int ctc_qspi_adjust_op_size(struct spi_mem *mem, struct spi_mem_op *op)
|
|||||||
{
|
{
|
||||||
//max data transfer size = tx buffer size - (cmd - addr -dummy )
|
//max data transfer size = tx buffer size - (cmd - addr -dummy )
|
||||||
if (op->data.dir == SPI_MEM_DATA_IN) {
|
if (op->data.dir == SPI_MEM_DATA_IN) {
|
||||||
if (op->data.nbytes > CTC_QSPI_RX_BUFFER_SIZE - 6)
|
if (op->data.nbytes > CTC_QSPI_RX_BUFFER_SIZE - 6) {
|
||||||
op->data.nbytes = CTC_QSPI_RX_BUFFER_SIZE - 6;
|
op->data.nbytes = CTC_QSPI_RX_BUFFER_SIZE - 6;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if (op->data.nbytes > CTC_QSPI_TX_BUFFER_SIZE)
|
if (op->data.nbytes > CTC_QSPI_TX_BUFFER_SIZE) {
|
||||||
op->data.nbytes = CTC_QSPI_TX_BUFFER_SIZE;
|
op->data.nbytes = CTC_QSPI_TX_BUFFER_SIZE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -558,7 +565,7 @@ static int ctc_qspi_probe(struct platform_device *pdev)
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
master->mode_bits =
|
master->mode_bits =
|
||||||
SPI_MODE_3 | SPI_MODE_1 | SPI_TX_DUAL | SPI_RX_DUAL | SPI_TX_QUAD |
|
SPI_MODE_3 | SPI_MODE_0 | SPI_TX_DUAL | SPI_RX_DUAL | SPI_TX_QUAD |
|
||||||
SPI_RX_QUAD;
|
SPI_RX_QUAD;
|
||||||
master->setup = ctc_qspi_setup;
|
master->setup = ctc_qspi_setup;
|
||||||
master->transfer_one_message = ctc_qspi_start_transfer_one;
|
master->transfer_one_message = ctc_qspi_start_transfer_one;
|
||||||
|
@ -1176,7 +1176,12 @@ dal_alloc_dma_pool(int lchip, int size)
|
|||||||
if (use_high_memory)
|
if (use_high_memory)
|
||||||
{
|
{
|
||||||
dma_phy_base[lchip] = virt_to_bus(high_memory);
|
dma_phy_base[lchip] = virt_to_bus(high_memory);
|
||||||
dma_virt_base[lchip] = ioremap_nocache(dma_phy_base[lchip], size);
|
/*
|
||||||
|
* ioremap has provided non-cached semantics by default
|
||||||
|
* since the Linux 2.6 days, so remove the additional
|
||||||
|
* ioremap_nocache interface.
|
||||||
|
*/
|
||||||
|
dma_virt_base[lchip] = ioremap(dma_phy_base[lchip], size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1205,7 +1210,12 @@ dal_alloc_dma_pool(int lchip, int size)
|
|||||||
/* Get DMA memory from kernel */
|
/* Get DMA memory from kernel */
|
||||||
dma_virt_base[lchip] = _dal_pgalloc(size);
|
dma_virt_base[lchip] = _dal_pgalloc(size);
|
||||||
dma_phy_base[lchip] = virt_to_bus(dma_virt_base[lchip]);
|
dma_phy_base[lchip] = virt_to_bus(dma_virt_base[lchip]);
|
||||||
//dma_virt_base [lchip]= ioremap_nocache(dma_phy_base[lchip], size);
|
/*
|
||||||
|
* ioremap has provided non-cached semantics by default
|
||||||
|
* since the Linux 2.6 days, so remove the additional
|
||||||
|
* ioremap_nocache interface.
|
||||||
|
*/
|
||||||
|
//dma_virt_base [lchip]= ioremap(dma_phy_base[lchip], size);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1943,7 +1953,12 @@ int linux_dal_pcie_probe(struct pci_dev* pdev, const struct pci_device_id* id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dev->phys_address = pci_resource_start(pdev, bar);
|
dev->phys_address = pci_resource_start(pdev, bar);
|
||||||
dev->logic_address = (uintptr)ioremap_nocache(dev->phys_address,
|
/*
|
||||||
|
* ioremap has provided non-cached semantics by default
|
||||||
|
* since the Linux 2.6 days, so remove the additional
|
||||||
|
* ioremap_nocache interface.
|
||||||
|
*/
|
||||||
|
dev->logic_address = (uintptr)ioremap(dev->phys_address,
|
||||||
pci_resource_len(dev->pci_dev, bar));
|
pci_resource_len(dev->pci_dev, bar));
|
||||||
|
|
||||||
/*0: little endian 1: big endian*/
|
/*0: little endian 1: big endian*/
|
||||||
|
@ -1 +1,3 @@
|
|||||||
obj-m := centec_e582_48x2q4z_platform.o centec_at24c64.o
|
KBUILD_EXTRA_SYMBOLS = /sonic/platform/centec-arm64/sonic-platform-modules-e530/pca954x/Module.symvers
|
||||||
|
|
||||||
|
obj-m := centec_e582_48x2q4z_platform.o
|
||||||
|
@ -1,602 +0,0 @@
|
|||||||
/*
|
|
||||||
* at24.c - handle most I2C EEPROMs
|
|
||||||
*
|
|
||||||
* Copyright (C) 2005-2007 David Brownell
|
|
||||||
* Copyright (C) 2008 Wolfram Sang, Pengutronix
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*/
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/mutex.h>
|
|
||||||
#include <linux/sysfs.h>
|
|
||||||
#include <linux/mod_devicetable.h>
|
|
||||||
#include <linux/log2.h>
|
|
||||||
#include <linux/bitops.h>
|
|
||||||
#include <linux/jiffies.h>
|
|
||||||
#include <linux/of.h>
|
|
||||||
#include <linux/i2c.h>
|
|
||||||
#include <linux/platform_data/at24.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
|
|
||||||
* Differences between different vendor product lines (like Atmel AT24C or
|
|
||||||
* MicroChip 24LC, etc) won't much matter for typical read/write access.
|
|
||||||
* There are also I2C RAM chips, likewise interchangeable. One example
|
|
||||||
* would be the PCF8570, which acts like a 24c02 EEPROM (256 bytes).
|
|
||||||
*
|
|
||||||
* However, misconfiguration can lose data. "Set 16-bit memory address"
|
|
||||||
* to a part with 8-bit addressing will overwrite data. Writing with too
|
|
||||||
* big a page size also loses data. And it's not safe to assume that the
|
|
||||||
* conventional addresses 0x50..0x57 only hold eeproms; a PCF8563 RTC
|
|
||||||
* uses 0x51, for just one example.
|
|
||||||
*
|
|
||||||
* Accordingly, explicit board-specific configuration data should be used
|
|
||||||
* in almost all cases. (One partial exception is an SMBus used to access
|
|
||||||
* "SPD" data for DRAM sticks. Those only use 24c02 EEPROMs.)
|
|
||||||
*
|
|
||||||
* So this driver uses "new style" I2C driver binding, expecting to be
|
|
||||||
* told what devices exist. That may be in arch/X/mach-Y/board-Z.c or
|
|
||||||
* similar kernel-resident tables; or, configuration data coming from
|
|
||||||
* a bootloader.
|
|
||||||
*
|
|
||||||
* Other than binding model, current differences from "eeprom" driver are
|
|
||||||
* that this one handles write access and isn't restricted to 24c02 devices.
|
|
||||||
* It also handles larger devices (32 kbit and up) with two-byte addresses,
|
|
||||||
* which won't work on pure SMBus systems.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct at24_data {
|
|
||||||
struct at24_platform_data chip;
|
|
||||||
int use_smbus;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Lock protects against activities from other Linux tasks,
|
|
||||||
* but not from changes by other I2C masters.
|
|
||||||
*/
|
|
||||||
struct mutex lock;
|
|
||||||
struct bin_attribute bin;
|
|
||||||
|
|
||||||
u8 *writebuf;
|
|
||||||
unsigned write_max;
|
|
||||||
unsigned num_addresses;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Some chips tie up multiple I2C addresses; dummy devices reserve
|
|
||||||
* them for us, and we'll use them with SMBus calls.
|
|
||||||
*/
|
|
||||||
struct i2c_client *client[];
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This parameter is to help this driver avoid blocking other drivers out
|
|
||||||
* of I2C for potentially troublesome amounts of time. With a 100 kHz I2C
|
|
||||||
* clock, one 256 byte read takes about 1/43 second which is excessive;
|
|
||||||
* but the 1/170 second it takes at 400 kHz may be quite reasonable; and
|
|
||||||
* at 1 MHz (Fm+) a 1/430 second delay could easily be invisible.
|
|
||||||
*
|
|
||||||
* This value is forced to be a power of two so that writes align on pages.
|
|
||||||
*/
|
|
||||||
static unsigned io_limit = 128;
|
|
||||||
module_param(io_limit, uint, 0);
|
|
||||||
MODULE_PARM_DESC(io_limit, "Maximum bytes per I/O (default 128)");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Specs often allow 5 msec for a page write, sometimes 20 msec;
|
|
||||||
* it's important to recover from write timeouts.
|
|
||||||
*/
|
|
||||||
static unsigned write_timeout = 25;
|
|
||||||
module_param(write_timeout, uint, 0);
|
|
||||||
MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");
|
|
||||||
|
|
||||||
#define AT24_SIZE_BYTELEN 5
|
|
||||||
#define AT24_SIZE_FLAGS 8
|
|
||||||
|
|
||||||
#define AT24_BITMASK(x) (BIT(x) - 1)
|
|
||||||
|
|
||||||
/* create non-zero magic value for given eeprom parameters */
|
|
||||||
#define AT24_DEVICE_MAGIC(_len, _flags) \
|
|
||||||
((1 << AT24_SIZE_FLAGS | (_flags)) \
|
|
||||||
<< AT24_SIZE_BYTELEN | ilog2(_len))
|
|
||||||
|
|
||||||
static const struct i2c_device_id at24_ctc_ids[] = {
|
|
||||||
{ "24c64-ctc", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16 | AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },
|
|
||||||
{ /* END OF LIST */ }
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(i2c, at24_ctc_ids);
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This routine supports chips which consume multiple I2C addresses. It
|
|
||||||
* computes the addressing information to be used for a given r/w request.
|
|
||||||
* Assumes that sanity checks for offset happened at sysfs-layer.
|
|
||||||
*/
|
|
||||||
static struct i2c_client *at24_translate_offset(struct at24_data *at24,
|
|
||||||
unsigned *offset)
|
|
||||||
{
|
|
||||||
unsigned i = 0;
|
|
||||||
|
|
||||||
if (at24->chip.flags & AT24_FLAG_ADDR16) {
|
|
||||||
i = *offset >> 16;
|
|
||||||
*offset &= 0xffff;
|
|
||||||
} else {
|
|
||||||
i = *offset >> 8;
|
|
||||||
*offset &= 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
return at24->client[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
|
|
||||||
unsigned offset, size_t count)
|
|
||||||
{
|
|
||||||
struct i2c_msg msg[2];
|
|
||||||
struct i2c_client *client;
|
|
||||||
unsigned long timeout, read_time;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
memset(msg, 0, sizeof(msg));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* REVISIT some multi-address chips don't rollover page reads to
|
|
||||||
* the next slave address, so we may need to truncate the count.
|
|
||||||
* Those chips might need another quirk flag.
|
|
||||||
*
|
|
||||||
* If the real hardware used four adjacent 24c02 chips and that
|
|
||||||
* were misconfigured as one 24c08, that would be a similar effect:
|
|
||||||
* one "eeprom" file not four, but larger reads would fail when
|
|
||||||
* they crossed certain pages.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Slave address and byte offset derive from the offset. Always
|
|
||||||
* set the byte address; on a multi-master board, another master
|
|
||||||
* may have changed the chip's "current" address pointer.
|
|
||||||
*/
|
|
||||||
client = at24_translate_offset(at24, &offset);
|
|
||||||
|
|
||||||
if (count > io_limit)
|
|
||||||
count = io_limit;
|
|
||||||
|
|
||||||
count = 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reads fail if the previous write didn't complete yet. We may
|
|
||||||
* loop a few times until this one succeeds, waiting at least
|
|
||||||
* long enough for one entire page write to work.
|
|
||||||
*/
|
|
||||||
timeout = jiffies + msecs_to_jiffies(write_timeout);
|
|
||||||
do {
|
|
||||||
read_time = jiffies;
|
|
||||||
|
|
||||||
status = i2c_smbus_write_byte_data(client, (offset >> 8) & 0x0ff, offset & 0x0ff );
|
|
||||||
status = i2c_smbus_read_byte(client);
|
|
||||||
if (status >= 0) {
|
|
||||||
buf[0] = status;
|
|
||||||
status = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n", count, offset, status, jiffies);
|
|
||||||
|
|
||||||
if (status == count)
|
|
||||||
return count;
|
|
||||||
|
|
||||||
/* REVISIT: at HZ=100, this is sloooow */
|
|
||||||
msleep(1);
|
|
||||||
} while (time_before(read_time, timeout));
|
|
||||||
|
|
||||||
return -ETIMEDOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t at24_read(struct at24_data *at24,
|
|
||||||
char *buf, loff_t off, size_t count)
|
|
||||||
{
|
|
||||||
ssize_t retval = 0;
|
|
||||||
|
|
||||||
if (unlikely(!count))
|
|
||||||
return count;
|
|
||||||
|
|
||||||
memset(buf, 0, count);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read data from chip, protecting against concurrent updates
|
|
||||||
* from this host, but not from other I2C masters.
|
|
||||||
*/
|
|
||||||
mutex_lock(&at24->lock);
|
|
||||||
|
|
||||||
while (count) {
|
|
||||||
ssize_t status;
|
|
||||||
|
|
||||||
status = at24_eeprom_read(at24, buf, off, count);
|
|
||||||
if (status <= 0) {
|
|
||||||
if (retval == 0)
|
|
||||||
retval = status;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf += status;
|
|
||||||
off += status;
|
|
||||||
count -= status;
|
|
||||||
retval += status;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&at24->lock);
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t at24_bin_read(struct file *filp, struct kobject *kobj,
|
|
||||||
struct bin_attribute *attr,
|
|
||||||
char *buf, loff_t off, size_t count)
|
|
||||||
{
|
|
||||||
struct at24_data *at24;
|
|
||||||
|
|
||||||
at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
|
|
||||||
return at24_read(at24, buf, off, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note that if the hardware write-protect pin is pulled high, the whole
|
|
||||||
* chip is normally write protected. But there are plenty of product
|
|
||||||
* variants here, including OTP fuses and partial chip protect.
|
|
||||||
*
|
|
||||||
* We only use page mode writes; the alternative is sloooow. This routine
|
|
||||||
* writes at most one page.
|
|
||||||
*/
|
|
||||||
static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
|
|
||||||
unsigned offset, size_t count)
|
|
||||||
{
|
|
||||||
struct i2c_client *client;
|
|
||||||
ssize_t status;
|
|
||||||
unsigned long timeout, write_time;
|
|
||||||
unsigned next_page;
|
|
||||||
|
|
||||||
/* Get corresponding I2C address and adjust offset */
|
|
||||||
client = at24_translate_offset(at24, &offset);
|
|
||||||
|
|
||||||
/* write_max is at most a page */
|
|
||||||
if (count > at24->write_max)
|
|
||||||
count = at24->write_max;
|
|
||||||
|
|
||||||
/* Never roll over backwards, to the start of this page */
|
|
||||||
next_page = roundup(offset + 1, at24->chip.page_size);
|
|
||||||
if (offset + count > next_page)
|
|
||||||
count = next_page - offset;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Writes fail if the previous one didn't complete yet. We may
|
|
||||||
* loop a few times until this one succeeds, waiting at least
|
|
||||||
* long enough for one entire page write to work.
|
|
||||||
*/
|
|
||||||
timeout = jiffies + msecs_to_jiffies(write_timeout);
|
|
||||||
do {
|
|
||||||
write_time = jiffies;
|
|
||||||
|
|
||||||
status = i2c_smbus_write_word_data(client, (offset >> 8) & 0x0ff, (offset & 0xFF) | buf[0]);
|
|
||||||
if (status == 0)
|
|
||||||
status = count;
|
|
||||||
|
|
||||||
dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n", count, offset, status, jiffies);
|
|
||||||
|
|
||||||
if (status == count)
|
|
||||||
return count;
|
|
||||||
|
|
||||||
/* REVISIT: at HZ=100, this is sloooow */
|
|
||||||
msleep(1);
|
|
||||||
} while (time_before(write_time, timeout));
|
|
||||||
|
|
||||||
return -ETIMEDOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,
|
|
||||||
size_t count)
|
|
||||||
{
|
|
||||||
ssize_t retval = 0;
|
|
||||||
|
|
||||||
if (unlikely(!count))
|
|
||||||
return count;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Write data to chip, protecting against concurrent updates
|
|
||||||
* from this host, but not from other I2C masters.
|
|
||||||
*/
|
|
||||||
mutex_lock(&at24->lock);
|
|
||||||
|
|
||||||
while (count) {
|
|
||||||
ssize_t status;
|
|
||||||
|
|
||||||
status = at24_eeprom_write(at24, buf, off, 1); /* only one-byte to write; TODO page wirte */
|
|
||||||
if (status <= 0) {
|
|
||||||
if (retval == 0)
|
|
||||||
retval = status;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf += status;
|
|
||||||
off += status;
|
|
||||||
count -= status;
|
|
||||||
retval += status;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&at24->lock);
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj,
|
|
||||||
struct bin_attribute *attr,
|
|
||||||
char *buf, loff_t off, size_t count)
|
|
||||||
{
|
|
||||||
struct at24_data *at24;
|
|
||||||
|
|
||||||
if (unlikely(off >= attr->size))
|
|
||||||
return -EFBIG;
|
|
||||||
|
|
||||||
at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
|
|
||||||
return at24_write(at24, buf, off, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#ifdef CONFIG_OF
|
|
||||||
static void at24_get_ofdata(struct i2c_client *client,
|
|
||||||
struct at24_platform_data *chip)
|
|
||||||
{
|
|
||||||
const __be32 *val;
|
|
||||||
struct device_node *node = client->dev.of_node;
|
|
||||||
|
|
||||||
if (node) {
|
|
||||||
if (of_get_property(node, "read-only", NULL))
|
|
||||||
chip->flags |= AT24_FLAG_READONLY;
|
|
||||||
val = of_get_property(node, "pagesize", NULL);
|
|
||||||
if (val)
|
|
||||||
chip->page_size = be32_to_cpup(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static void at24_get_ofdata(struct i2c_client *client,
|
|
||||||
struct at24_platform_data *chip)
|
|
||||||
{ }
|
|
||||||
#endif /* CONFIG_OF */
|
|
||||||
|
|
||||||
static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|
||||||
{
|
|
||||||
struct at24_platform_data chip;
|
|
||||||
bool writable;
|
|
||||||
int use_smbus = 0;
|
|
||||||
struct at24_data *at24;
|
|
||||||
int err;
|
|
||||||
unsigned i, num_addresses;
|
|
||||||
kernel_ulong_t magic;
|
|
||||||
|
|
||||||
if (client->dev.platform_data) {
|
|
||||||
chip = *(struct at24_platform_data *)client->dev.platform_data;
|
|
||||||
} else {
|
|
||||||
if (!id->driver_data)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
magic = id->driver_data;
|
|
||||||
chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));
|
|
||||||
magic >>= AT24_SIZE_BYTELEN;
|
|
||||||
chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is slow, but we can't know all eeproms, so we better
|
|
||||||
* play safe. Specifying custom eeprom-types via platform_data
|
|
||||||
* is recommended anyhow.
|
|
||||||
*/
|
|
||||||
chip.page_size = 1;
|
|
||||||
|
|
||||||
/* update chipdata if OF is present */
|
|
||||||
at24_get_ofdata(client, &chip);
|
|
||||||
|
|
||||||
chip.setup = NULL;
|
|
||||||
chip.context = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_power_of_2(chip.byte_len))
|
|
||||||
dev_warn(&client->dev,
|
|
||||||
"byte_len looks suspicious (no power of 2)!\n");
|
|
||||||
if (!chip.page_size) {
|
|
||||||
dev_err(&client->dev, "page_size must not be 0!\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if (!is_power_of_2(chip.page_size))
|
|
||||||
dev_warn(&client->dev,
|
|
||||||
"page_size looks suspicious (no power of 2)!\n");
|
|
||||||
|
|
||||||
/* Use I2C operations unless we're stuck with SMBus extensions. */
|
|
||||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
|
||||||
if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
|
|
||||||
use_smbus = I2C_SMBUS_I2C_BLOCK_DATA;
|
|
||||||
} else if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) {
|
|
||||||
use_smbus = I2C_SMBUS_WORD_DATA;
|
|
||||||
} else if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
|
|
||||||
use_smbus = I2C_SMBUS_BYTE_DATA;
|
|
||||||
} else {
|
|
||||||
return -EPFNOSUPPORT;
|
|
||||||
}
|
|
||||||
use_smbus = I2C_SMBUS_BYTE_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chip.flags & AT24_FLAG_TAKE8ADDR)
|
|
||||||
num_addresses = 8;
|
|
||||||
else
|
|
||||||
num_addresses = DIV_ROUND_UP(chip.byte_len, (chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256);
|
|
||||||
|
|
||||||
at24 = devm_kzalloc(&client->dev, sizeof(struct at24_data) + num_addresses * sizeof(struct i2c_client *), GFP_KERNEL);
|
|
||||||
if (!at24)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
mutex_init(&at24->lock);
|
|
||||||
at24->use_smbus = use_smbus;
|
|
||||||
at24->chip = chip;
|
|
||||||
at24->num_addresses = num_addresses;
|
|
||||||
|
|
||||||
printk(KERN_ALERT "at24_probe chip.byte_len = 0x%x\n", chip.byte_len);
|
|
||||||
printk(KERN_ALERT "at24_probe chip.flags = 0x%x\n", chip.flags);
|
|
||||||
printk(KERN_ALERT "at24_probe chip.magic = 0x%lx\n", id->driver_data);
|
|
||||||
printk(KERN_ALERT "at24_probe use_smbus = %d\n", at24->use_smbus);
|
|
||||||
printk(KERN_ALERT "at24_probe num_addresses = %d\n", at24->num_addresses);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Export the EEPROM bytes through sysfs, since that's convenient.
|
|
||||||
* By default, only root should see the data (maybe passwords etc)
|
|
||||||
*/
|
|
||||||
sysfs_bin_attr_init(&at24->bin);
|
|
||||||
at24->bin.attr.name = "eeprom";
|
|
||||||
at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR;
|
|
||||||
at24->bin.read = at24_bin_read;
|
|
||||||
at24->bin.size = chip.byte_len;
|
|
||||||
|
|
||||||
writable = !(chip.flags & AT24_FLAG_READONLY);
|
|
||||||
if (writable) {
|
|
||||||
if (!use_smbus || i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
|
|
||||||
unsigned write_max = chip.page_size;
|
|
||||||
|
|
||||||
at24->bin.write = at24_bin_write;
|
|
||||||
at24->bin.attr.mode |= S_IWUSR;
|
|
||||||
|
|
||||||
if (write_max > io_limit)
|
|
||||||
write_max = io_limit;
|
|
||||||
if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX)
|
|
||||||
write_max = I2C_SMBUS_BLOCK_MAX;
|
|
||||||
at24->write_max = write_max;
|
|
||||||
|
|
||||||
/* buffer (data + address at the beginning) */
|
|
||||||
at24->writebuf = devm_kzalloc(&client->dev, write_max + 2, GFP_KERNEL);
|
|
||||||
if (!at24->writebuf)
|
|
||||||
return -ENOMEM;
|
|
||||||
} else {
|
|
||||||
dev_warn(&client->dev, "cannot write due to controller restrictions.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
at24->client[0] = client;
|
|
||||||
|
|
||||||
/* use dummy devices for multiple-address chips */
|
|
||||||
for (i = 1; i < num_addresses; i++) {
|
|
||||||
at24->client[i] = i2c_new_dummy(client->adapter, client->addr + i);
|
|
||||||
if (!at24->client[i]) {
|
|
||||||
dev_err(&client->dev, "address 0x%02x unavailable\n", client->addr + i);
|
|
||||||
err = -EADDRINUSE;
|
|
||||||
goto err_clients;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = sysfs_create_bin_file(&client->dev.kobj, &at24->bin);
|
|
||||||
if (err)
|
|
||||||
goto err_clients;
|
|
||||||
|
|
||||||
i2c_set_clientdata(client, at24);
|
|
||||||
|
|
||||||
printk(KERN_ALERT "at24_probe %s done\n", client->name);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err_clients:
|
|
||||||
for (i = 1; i < num_addresses; i++)
|
|
||||||
if (at24->client[i])
|
|
||||||
i2c_unregister_device(at24->client[i]);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int at24_remove(struct i2c_client *client)
|
|
||||||
{
|
|
||||||
struct at24_data *at24;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
at24 = i2c_get_clientdata(client);
|
|
||||||
sysfs_remove_bin_file(&client->dev.kobj, &at24->bin);
|
|
||||||
|
|
||||||
for (i = 1; i < at24->num_addresses; i++)
|
|
||||||
i2c_unregister_device(at24->client[i]);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
static struct i2c_board_info i2c_devs = {
|
|
||||||
I2C_BOARD_INFO("24c64-ctc", 0x57),
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct i2c_adapter *adapter = NULL;
|
|
||||||
static struct i2c_client *client = NULL;
|
|
||||||
|
|
||||||
static int ctc_at24c64_init(void)
|
|
||||||
{
|
|
||||||
printk(KERN_ALERT "ctc_at24c64_init\n");
|
|
||||||
|
|
||||||
adapter = i2c_get_adapter(0);
|
|
||||||
if(adapter == NULL){
|
|
||||||
printk(KERN_ALERT "i2c_get_adapter == NULL\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = i2c_new_device(adapter, &i2c_devs);
|
|
||||||
if(client == NULL){
|
|
||||||
printk(KERN_ALERT "i2c_new_device == NULL\n");
|
|
||||||
i2c_put_adapter(adapter);
|
|
||||||
adapter = NULL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ctc_at24c64_exit(void)
|
|
||||||
{
|
|
||||||
printk(KERN_ALERT "ctc_at24c64_exit\n");
|
|
||||||
if(client){
|
|
||||||
i2c_unregister_device(client);
|
|
||||||
}
|
|
||||||
if(adapter){
|
|
||||||
i2c_put_adapter(adapter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct i2c_driver at24_ctc_driver = {
|
|
||||||
.driver = {
|
|
||||||
.name = "at24-ctc",
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
},
|
|
||||||
.probe = at24_probe,
|
|
||||||
.remove = at24_remove,
|
|
||||||
.id_table = at24_ctc_ids,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __init at24_ctc_init(void)
|
|
||||||
{
|
|
||||||
if (!io_limit) {
|
|
||||||
pr_err("at24_ctc: io_limit must not be 0!\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
io_limit = rounddown_pow_of_two(io_limit);
|
|
||||||
|
|
||||||
ctc_at24c64_init();
|
|
||||||
|
|
||||||
return i2c_add_driver(&at24_ctc_driver);
|
|
||||||
}
|
|
||||||
module_init(at24_ctc_init);
|
|
||||||
|
|
||||||
static void __exit at24_ctc_exit(void)
|
|
||||||
{
|
|
||||||
ctc_at24c64_exit();
|
|
||||||
i2c_del_driver(&at24_ctc_driver);
|
|
||||||
}
|
|
||||||
module_exit(at24_ctc_exit);
|
|
||||||
|
|
||||||
MODULE_DESCRIPTION("Driver for most I2C EEPROMs");
|
|
||||||
MODULE_AUTHOR("David Brownell and Wolfram Sang");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
/* XXX */
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/platform_data/pca954x.h>
|
#include "../../pca954x/ctc-pca954x.h"
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/kdev_t.h>
|
#include <linux/kdev_t.h>
|
||||||
#include <linux/leds.h>
|
#include <linux/leds.h>
|
||||||
@ -95,7 +95,7 @@ static struct pca954x_platform_data i2c_dev_pca9548_platform_data = {
|
|||||||
.num_modes = PCA9548_CHANNEL_NUM,
|
.num_modes = PCA9548_CHANNEL_NUM,
|
||||||
};
|
};
|
||||||
static struct i2c_board_info i2c_dev_pca9548 = {
|
static struct i2c_board_info i2c_dev_pca9548 = {
|
||||||
I2C_BOARD_INFO("pca9548", 0x70),
|
I2C_BOARD_INFO("ctc_pca9548", 0x70),
|
||||||
.platform_data = &i2c_dev_pca9548_platform_data,
|
.platform_data = &i2c_dev_pca9548_platform_data,
|
||||||
};
|
};
|
||||||
static struct i2c_client *i2c_client_pca9548x = NULL;
|
static struct i2c_client *i2c_client_pca9548x = NULL;
|
||||||
@ -110,7 +110,7 @@ static int e582_48x2q4z_init_i2c_pca9548(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* install i2c-mux */
|
/* install i2c-mux */
|
||||||
i2c_client_pca9548x = i2c_new_device(i2c_adp_master, &i2c_dev_pca9548);
|
i2c_client_pca9548x = i2c_new_client_device(i2c_adp_master, &i2c_dev_pca9548);
|
||||||
if(IS_INVALID_PTR(i2c_client_pca9548x))
|
if(IS_INVALID_PTR(i2c_client_pca9548x))
|
||||||
{
|
{
|
||||||
i2c_client_pca9548x = NULL;
|
i2c_client_pca9548x = NULL;
|
||||||
@ -150,7 +150,7 @@ static int e582_48x2q4z_init_i2c_adt7470(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_adt7470 = i2c_new_device(i2c_adp_adt7470, &i2c_dev_adt7470);
|
i2c_client_adt7470 = i2c_new_client_device(i2c_adp_adt7470, &i2c_dev_adt7470);
|
||||||
if(IS_INVALID_PTR(i2c_client_adt7470)){
|
if(IS_INVALID_PTR(i2c_client_adt7470)){
|
||||||
i2c_client_adt7470 = NULL;
|
i2c_client_adt7470 = NULL;
|
||||||
printk(KERN_CRIT "install e582_48x2q4z board adt7470 failed\n");
|
printk(KERN_CRIT "install e582_48x2q4z board adt7470 failed\n");
|
||||||
@ -206,14 +206,14 @@ static int e582_48x2q4z_init_i2c_psu(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_psu1 = i2c_new_device(i2c_adp_psu1, &i2c_dev_psu1);
|
i2c_client_psu1 = i2c_new_client_device(i2c_adp_psu1, &i2c_dev_psu1);
|
||||||
if(IS_INVALID_PTR(i2c_client_psu1)){
|
if(IS_INVALID_PTR(i2c_client_psu1)){
|
||||||
i2c_client_psu1 = NULL;
|
i2c_client_psu1 = NULL;
|
||||||
printk(KERN_CRIT "create e582_48x2q4z board i2c client psu1 failed\n");
|
printk(KERN_CRIT "create e582_48x2q4z board i2c client psu1 failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_psu2 = i2c_new_device(i2c_adp_psu2, &i2c_dev_psu2);
|
i2c_client_psu2 = i2c_new_client_device(i2c_adp_psu2, &i2c_dev_psu2);
|
||||||
if(IS_INVALID_PTR(i2c_client_psu2)){
|
if(IS_INVALID_PTR(i2c_client_psu2)){
|
||||||
i2c_client_psu2 = NULL;
|
i2c_client_psu2 = NULL;
|
||||||
printk(KERN_CRIT "create e582_48x2q4z board i2c client psu2 failed\n");
|
printk(KERN_CRIT "create e582_48x2q4z board i2c client psu2 failed\n");
|
||||||
@ -265,7 +265,7 @@ static int e582_48x2q4z_init_i2c_epld(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_epld = i2c_new_device(i2c_adp_master, &i2c_dev_epld);
|
i2c_client_epld = i2c_new_client_device(i2c_adp_master, &i2c_dev_epld);
|
||||||
if(IS_INVALID_PTR(i2c_client_epld))
|
if(IS_INVALID_PTR(i2c_client_epld))
|
||||||
{
|
{
|
||||||
i2c_client_epld = NULL;
|
i2c_client_epld = NULL;
|
||||||
@ -362,7 +362,7 @@ static int e582_48x2q4z_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio0 = i2c_new_device(i2c_adp_gpio0, &i2c_dev_gpio0);
|
i2c_client_gpio0 = i2c_new_client_device(i2c_adp_gpio0, &i2c_dev_gpio0);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio0))
|
if(IS_INVALID_PTR(i2c_client_gpio0))
|
||||||
{
|
{
|
||||||
i2c_client_gpio0 = NULL;
|
i2c_client_gpio0 = NULL;
|
||||||
@ -370,7 +370,7 @@ static int e582_48x2q4z_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio1 = i2c_new_device(i2c_adp_gpio1, &i2c_dev_gpio1);
|
i2c_client_gpio1 = i2c_new_client_device(i2c_adp_gpio1, &i2c_dev_gpio1);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio1))
|
if(IS_INVALID_PTR(i2c_client_gpio1))
|
||||||
{
|
{
|
||||||
i2c_client_gpio1 = NULL;
|
i2c_client_gpio1 = NULL;
|
||||||
@ -378,7 +378,7 @@ static int e582_48x2q4z_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio2 = i2c_new_device(i2c_adp_gpio2, &i2c_dev_gpio2);
|
i2c_client_gpio2 = i2c_new_client_device(i2c_adp_gpio2, &i2c_dev_gpio2);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio2))
|
if(IS_INVALID_PTR(i2c_client_gpio2))
|
||||||
{
|
{
|
||||||
i2c_client_gpio2 = NULL;
|
i2c_client_gpio2 = NULL;
|
||||||
@ -386,7 +386,7 @@ static int e582_48x2q4z_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio3 = i2c_new_device(i2c_adp_gpio3, &i2c_dev_gpio3);
|
i2c_client_gpio3 = i2c_new_client_device(i2c_adp_gpio3, &i2c_dev_gpio3);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio3))
|
if(IS_INVALID_PTR(i2c_client_gpio3))
|
||||||
{
|
{
|
||||||
i2c_client_gpio3 = NULL;
|
i2c_client_gpio3 = NULL;
|
||||||
@ -394,7 +394,7 @@ static int e582_48x2q4z_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio4 = i2c_new_device(i2c_adp_gpio4, &i2c_dev_gpio4);
|
i2c_client_gpio4 = i2c_new_client_device(i2c_adp_gpio4, &i2c_dev_gpio4);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio4))
|
if(IS_INVALID_PTR(i2c_client_gpio4))
|
||||||
{
|
{
|
||||||
i2c_client_gpio4 = NULL;
|
i2c_client_gpio4 = NULL;
|
||||||
|
@ -25,12 +25,13 @@ if [ "$1" == "init" ]; then
|
|||||||
modprobe i2c-dev
|
modprobe i2c-dev
|
||||||
modprobe i2c-mux
|
modprobe i2c-mux
|
||||||
modprobe i2c-smbus
|
modprobe i2c-smbus
|
||||||
modprobe i2c-mux-pca954x force_deselect_on_exit=1
|
modprobe ctc-i2c-mux-pca954x force_deselect_on_exit=1
|
||||||
i2cset -y 0 0x58 0x8 0x3f
|
i2cset -y 0 0x58 0x8 0x3f
|
||||||
modprobe lm77
|
modprobe lm77
|
||||||
modprobe tun
|
modprobe tun
|
||||||
modprobe dal
|
modprobe dal
|
||||||
modprobe centec_at24c64
|
modprobe at24
|
||||||
|
echo 24c64 0x57 > /sys/bus/i2c/devices/i2c-0/new_device
|
||||||
modprobe centec_e582_48x2q4z_platform
|
modprobe centec_e582_48x2q4z_platform
|
||||||
i2cset -y 15 0x21 0x18 0x0
|
i2cset -y 15 0x21 0x18 0x0
|
||||||
i2cset -y 15 0x21 0x19 0x0
|
i2cset -y 15 0x21 0x19 0x0
|
||||||
@ -69,9 +70,9 @@ elif [ "$1" == "deinit" ]; then
|
|||||||
kill -9 $(pidof platform_monitor) > /dev/null 2>&1
|
kill -9 $(pidof platform_monitor) > /dev/null 2>&1
|
||||||
rm -rf /usr/bin/platform_monitor
|
rm -rf /usr/bin/platform_monitor
|
||||||
modprobe -r centec_e582_48x2q4z_platform
|
modprobe -r centec_e582_48x2q4z_platform
|
||||||
modprobe -r centec_at24c64
|
modprobe -r at24
|
||||||
modprobe -r dal
|
modprobe -r dal
|
||||||
modprobe -r i2c-mux-pca954x
|
modprobe -r ctc-i2c-mux-pca954x
|
||||||
modprobe -r i2c-dev
|
modprobe -r i2c-dev
|
||||||
else
|
else
|
||||||
echo "e582-48x2q4z_platform : Invalid option !"
|
echo "e582-48x2q4z_platform : Invalid option !"
|
||||||
|
@ -1 +1,3 @@
|
|||||||
obj-m := centec_e582_48x6q_platform.o centec_at24c64.o
|
KBUILD_EXTRA_SYMBOLS = /sonic/platform/centec/sonic-platform-modules-e582/pca954x/Module.symvers
|
||||||
|
|
||||||
|
obj-m := centec_e582_48x6q_platform.o
|
||||||
|
@ -1,602 +0,0 @@
|
|||||||
/*
|
|
||||||
* at24.c - handle most I2C EEPROMs
|
|
||||||
*
|
|
||||||
* Copyright (C) 2005-2007 David Brownell
|
|
||||||
* Copyright (C) 2008 Wolfram Sang, Pengutronix
|
|
||||||
*
|
|
||||||
* This program is free software; you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation; either version 2 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*/
|
|
||||||
#include <linux/kernel.h>
|
|
||||||
#include <linux/init.h>
|
|
||||||
#include <linux/module.h>
|
|
||||||
#include <linux/slab.h>
|
|
||||||
#include <linux/delay.h>
|
|
||||||
#include <linux/mutex.h>
|
|
||||||
#include <linux/sysfs.h>
|
|
||||||
#include <linux/mod_devicetable.h>
|
|
||||||
#include <linux/log2.h>
|
|
||||||
#include <linux/bitops.h>
|
|
||||||
#include <linux/jiffies.h>
|
|
||||||
#include <linux/of.h>
|
|
||||||
#include <linux/i2c.h>
|
|
||||||
#include <linux/platform_data/at24.h>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* I2C EEPROMs from most vendors are inexpensive and mostly interchangeable.
|
|
||||||
* Differences between different vendor product lines (like Atmel AT24C or
|
|
||||||
* MicroChip 24LC, etc) won't much matter for typical read/write access.
|
|
||||||
* There are also I2C RAM chips, likewise interchangeable. One example
|
|
||||||
* would be the PCF8570, which acts like a 24c02 EEPROM (256 bytes).
|
|
||||||
*
|
|
||||||
* However, misconfiguration can lose data. "Set 16-bit memory address"
|
|
||||||
* to a part with 8-bit addressing will overwrite data. Writing with too
|
|
||||||
* big a page size also loses data. And it's not safe to assume that the
|
|
||||||
* conventional addresses 0x50..0x57 only hold eeproms; a PCF8563 RTC
|
|
||||||
* uses 0x51, for just one example.
|
|
||||||
*
|
|
||||||
* Accordingly, explicit board-specific configuration data should be used
|
|
||||||
* in almost all cases. (One partial exception is an SMBus used to access
|
|
||||||
* "SPD" data for DRAM sticks. Those only use 24c02 EEPROMs.)
|
|
||||||
*
|
|
||||||
* So this driver uses "new style" I2C driver binding, expecting to be
|
|
||||||
* told what devices exist. That may be in arch/X/mach-Y/board-Z.c or
|
|
||||||
* similar kernel-resident tables; or, configuration data coming from
|
|
||||||
* a bootloader.
|
|
||||||
*
|
|
||||||
* Other than binding model, current differences from "eeprom" driver are
|
|
||||||
* that this one handles write access and isn't restricted to 24c02 devices.
|
|
||||||
* It also handles larger devices (32 kbit and up) with two-byte addresses,
|
|
||||||
* which won't work on pure SMBus systems.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct at24_data {
|
|
||||||
struct at24_platform_data chip;
|
|
||||||
int use_smbus;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Lock protects against activities from other Linux tasks,
|
|
||||||
* but not from changes by other I2C masters.
|
|
||||||
*/
|
|
||||||
struct mutex lock;
|
|
||||||
struct bin_attribute bin;
|
|
||||||
|
|
||||||
u8 *writebuf;
|
|
||||||
unsigned write_max;
|
|
||||||
unsigned num_addresses;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Some chips tie up multiple I2C addresses; dummy devices reserve
|
|
||||||
* them for us, and we'll use them with SMBus calls.
|
|
||||||
*/
|
|
||||||
struct i2c_client *client[];
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This parameter is to help this driver avoid blocking other drivers out
|
|
||||||
* of I2C for potentially troublesome amounts of time. With a 100 kHz I2C
|
|
||||||
* clock, one 256 byte read takes about 1/43 second which is excessive;
|
|
||||||
* but the 1/170 second it takes at 400 kHz may be quite reasonable; and
|
|
||||||
* at 1 MHz (Fm+) a 1/430 second delay could easily be invisible.
|
|
||||||
*
|
|
||||||
* This value is forced to be a power of two so that writes align on pages.
|
|
||||||
*/
|
|
||||||
static unsigned io_limit = 128;
|
|
||||||
module_param(io_limit, uint, 0);
|
|
||||||
MODULE_PARM_DESC(io_limit, "Maximum bytes per I/O (default 128)");
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Specs often allow 5 msec for a page write, sometimes 20 msec;
|
|
||||||
* it's important to recover from write timeouts.
|
|
||||||
*/
|
|
||||||
static unsigned write_timeout = 25;
|
|
||||||
module_param(write_timeout, uint, 0);
|
|
||||||
MODULE_PARM_DESC(write_timeout, "Time (in ms) to try writes (default 25)");
|
|
||||||
|
|
||||||
#define AT24_SIZE_BYTELEN 5
|
|
||||||
#define AT24_SIZE_FLAGS 8
|
|
||||||
|
|
||||||
#define AT24_BITMASK(x) (BIT(x) - 1)
|
|
||||||
|
|
||||||
/* create non-zero magic value for given eeprom parameters */
|
|
||||||
#define AT24_DEVICE_MAGIC(_len, _flags) \
|
|
||||||
((1 << AT24_SIZE_FLAGS | (_flags)) \
|
|
||||||
<< AT24_SIZE_BYTELEN | ilog2(_len))
|
|
||||||
|
|
||||||
static const struct i2c_device_id at24_ctc_ids[] = {
|
|
||||||
{ "24c64-ctc", AT24_DEVICE_MAGIC(65536 / 8, AT24_FLAG_ADDR16 | AT24_FLAG_READONLY | AT24_FLAG_IRUGO) },
|
|
||||||
{ /* END OF LIST */ }
|
|
||||||
};
|
|
||||||
MODULE_DEVICE_TABLE(i2c, at24_ctc_ids);
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This routine supports chips which consume multiple I2C addresses. It
|
|
||||||
* computes the addressing information to be used for a given r/w request.
|
|
||||||
* Assumes that sanity checks for offset happened at sysfs-layer.
|
|
||||||
*/
|
|
||||||
static struct i2c_client *at24_translate_offset(struct at24_data *at24,
|
|
||||||
unsigned *offset)
|
|
||||||
{
|
|
||||||
unsigned i = 0;
|
|
||||||
|
|
||||||
if (at24->chip.flags & AT24_FLAG_ADDR16) {
|
|
||||||
i = *offset >> 16;
|
|
||||||
*offset &= 0xffff;
|
|
||||||
} else {
|
|
||||||
i = *offset >> 8;
|
|
||||||
*offset &= 0xff;
|
|
||||||
}
|
|
||||||
|
|
||||||
return at24->client[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
|
|
||||||
unsigned offset, size_t count)
|
|
||||||
{
|
|
||||||
struct i2c_msg msg[2];
|
|
||||||
struct i2c_client *client;
|
|
||||||
unsigned long timeout, read_time;
|
|
||||||
int status;
|
|
||||||
|
|
||||||
memset(msg, 0, sizeof(msg));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* REVISIT some multi-address chips don't rollover page reads to
|
|
||||||
* the next slave address, so we may need to truncate the count.
|
|
||||||
* Those chips might need another quirk flag.
|
|
||||||
*
|
|
||||||
* If the real hardware used four adjacent 24c02 chips and that
|
|
||||||
* were misconfigured as one 24c08, that would be a similar effect:
|
|
||||||
* one "eeprom" file not four, but larger reads would fail when
|
|
||||||
* they crossed certain pages.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Slave address and byte offset derive from the offset. Always
|
|
||||||
* set the byte address; on a multi-master board, another master
|
|
||||||
* may have changed the chip's "current" address pointer.
|
|
||||||
*/
|
|
||||||
client = at24_translate_offset(at24, &offset);
|
|
||||||
|
|
||||||
if (count > io_limit)
|
|
||||||
count = io_limit;
|
|
||||||
|
|
||||||
count = 1;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reads fail if the previous write didn't complete yet. We may
|
|
||||||
* loop a few times until this one succeeds, waiting at least
|
|
||||||
* long enough for one entire page write to work.
|
|
||||||
*/
|
|
||||||
timeout = jiffies + msecs_to_jiffies(write_timeout);
|
|
||||||
do {
|
|
||||||
read_time = jiffies;
|
|
||||||
|
|
||||||
status = i2c_smbus_write_byte_data(client, (offset >> 8) & 0x0ff, offset & 0x0ff );
|
|
||||||
status = i2c_smbus_read_byte(client);
|
|
||||||
if (status >= 0) {
|
|
||||||
buf[0] = status;
|
|
||||||
status = count;
|
|
||||||
}
|
|
||||||
|
|
||||||
dev_dbg(&client->dev, "read %zu@%d --> %d (%ld)\n", count, offset, status, jiffies);
|
|
||||||
|
|
||||||
if (status == count)
|
|
||||||
return count;
|
|
||||||
|
|
||||||
/* REVISIT: at HZ=100, this is sloooow */
|
|
||||||
msleep(1);
|
|
||||||
} while (time_before(read_time, timeout));
|
|
||||||
|
|
||||||
return -ETIMEDOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t at24_read(struct at24_data *at24,
|
|
||||||
char *buf, loff_t off, size_t count)
|
|
||||||
{
|
|
||||||
ssize_t retval = 0;
|
|
||||||
|
|
||||||
if (unlikely(!count))
|
|
||||||
return count;
|
|
||||||
|
|
||||||
memset(buf, 0, count);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Read data from chip, protecting against concurrent updates
|
|
||||||
* from this host, but not from other I2C masters.
|
|
||||||
*/
|
|
||||||
mutex_lock(&at24->lock);
|
|
||||||
|
|
||||||
while (count) {
|
|
||||||
ssize_t status;
|
|
||||||
|
|
||||||
status = at24_eeprom_read(at24, buf, off, count);
|
|
||||||
if (status <= 0) {
|
|
||||||
if (retval == 0)
|
|
||||||
retval = status;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf += status;
|
|
||||||
off += status;
|
|
||||||
count -= status;
|
|
||||||
retval += status;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&at24->lock);
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t at24_bin_read(struct file *filp, struct kobject *kobj,
|
|
||||||
struct bin_attribute *attr,
|
|
||||||
char *buf, loff_t off, size_t count)
|
|
||||||
{
|
|
||||||
struct at24_data *at24;
|
|
||||||
|
|
||||||
at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
|
|
||||||
return at24_read(at24, buf, off, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note that if the hardware write-protect pin is pulled high, the whole
|
|
||||||
* chip is normally write protected. But there are plenty of product
|
|
||||||
* variants here, including OTP fuses and partial chip protect.
|
|
||||||
*
|
|
||||||
* We only use page mode writes; the alternative is sloooow. This routine
|
|
||||||
* writes at most one page.
|
|
||||||
*/
|
|
||||||
static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
|
|
||||||
unsigned offset, size_t count)
|
|
||||||
{
|
|
||||||
struct i2c_client *client;
|
|
||||||
ssize_t status;
|
|
||||||
unsigned long timeout, write_time;
|
|
||||||
unsigned next_page;
|
|
||||||
|
|
||||||
/* Get corresponding I2C address and adjust offset */
|
|
||||||
client = at24_translate_offset(at24, &offset);
|
|
||||||
|
|
||||||
/* write_max is at most a page */
|
|
||||||
if (count > at24->write_max)
|
|
||||||
count = at24->write_max;
|
|
||||||
|
|
||||||
/* Never roll over backwards, to the start of this page */
|
|
||||||
next_page = roundup(offset + 1, at24->chip.page_size);
|
|
||||||
if (offset + count > next_page)
|
|
||||||
count = next_page - offset;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Writes fail if the previous one didn't complete yet. We may
|
|
||||||
* loop a few times until this one succeeds, waiting at least
|
|
||||||
* long enough for one entire page write to work.
|
|
||||||
*/
|
|
||||||
timeout = jiffies + msecs_to_jiffies(write_timeout);
|
|
||||||
do {
|
|
||||||
write_time = jiffies;
|
|
||||||
|
|
||||||
status = i2c_smbus_write_word_data(client, (offset >> 8) & 0x0ff, (offset & 0xFF) | buf[0]);
|
|
||||||
if (status == 0)
|
|
||||||
status = count;
|
|
||||||
|
|
||||||
dev_dbg(&client->dev, "write %zu@%d --> %zd (%ld)\n", count, offset, status, jiffies);
|
|
||||||
|
|
||||||
if (status == count)
|
|
||||||
return count;
|
|
||||||
|
|
||||||
/* REVISIT: at HZ=100, this is sloooow */
|
|
||||||
msleep(1);
|
|
||||||
} while (time_before(write_time, timeout));
|
|
||||||
|
|
||||||
return -ETIMEDOUT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,
|
|
||||||
size_t count)
|
|
||||||
{
|
|
||||||
ssize_t retval = 0;
|
|
||||||
|
|
||||||
if (unlikely(!count))
|
|
||||||
return count;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Write data to chip, protecting against concurrent updates
|
|
||||||
* from this host, but not from other I2C masters.
|
|
||||||
*/
|
|
||||||
mutex_lock(&at24->lock);
|
|
||||||
|
|
||||||
while (count) {
|
|
||||||
ssize_t status;
|
|
||||||
|
|
||||||
status = at24_eeprom_write(at24, buf, off, 1); /* only one-byte to write; TODO page wirte */
|
|
||||||
if (status <= 0) {
|
|
||||||
if (retval == 0)
|
|
||||||
retval = status;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
buf += status;
|
|
||||||
off += status;
|
|
||||||
count -= status;
|
|
||||||
retval += status;
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex_unlock(&at24->lock);
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ssize_t at24_bin_write(struct file *filp, struct kobject *kobj,
|
|
||||||
struct bin_attribute *attr,
|
|
||||||
char *buf, loff_t off, size_t count)
|
|
||||||
{
|
|
||||||
struct at24_data *at24;
|
|
||||||
|
|
||||||
if (unlikely(off >= attr->size))
|
|
||||||
return -EFBIG;
|
|
||||||
|
|
||||||
at24 = dev_get_drvdata(container_of(kobj, struct device, kobj));
|
|
||||||
return at24_write(at24, buf, off, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#ifdef CONFIG_OF
|
|
||||||
static void at24_get_ofdata(struct i2c_client *client,
|
|
||||||
struct at24_platform_data *chip)
|
|
||||||
{
|
|
||||||
const __be32 *val;
|
|
||||||
struct device_node *node = client->dev.of_node;
|
|
||||||
|
|
||||||
if (node) {
|
|
||||||
if (of_get_property(node, "read-only", NULL))
|
|
||||||
chip->flags |= AT24_FLAG_READONLY;
|
|
||||||
val = of_get_property(node, "pagesize", NULL);
|
|
||||||
if (val)
|
|
||||||
chip->page_size = be32_to_cpup(val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static void at24_get_ofdata(struct i2c_client *client,
|
|
||||||
struct at24_platform_data *chip)
|
|
||||||
{ }
|
|
||||||
#endif /* CONFIG_OF */
|
|
||||||
|
|
||||||
static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
|
|
||||||
{
|
|
||||||
struct at24_platform_data chip;
|
|
||||||
bool writable;
|
|
||||||
int use_smbus = 0;
|
|
||||||
struct at24_data *at24;
|
|
||||||
int err;
|
|
||||||
unsigned i, num_addresses;
|
|
||||||
kernel_ulong_t magic;
|
|
||||||
|
|
||||||
if (client->dev.platform_data) {
|
|
||||||
chip = *(struct at24_platform_data *)client->dev.platform_data;
|
|
||||||
} else {
|
|
||||||
if (!id->driver_data)
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
magic = id->driver_data;
|
|
||||||
chip.byte_len = BIT(magic & AT24_BITMASK(AT24_SIZE_BYTELEN));
|
|
||||||
magic >>= AT24_SIZE_BYTELEN;
|
|
||||||
chip.flags = magic & AT24_BITMASK(AT24_SIZE_FLAGS);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is slow, but we can't know all eeproms, so we better
|
|
||||||
* play safe. Specifying custom eeprom-types via platform_data
|
|
||||||
* is recommended anyhow.
|
|
||||||
*/
|
|
||||||
chip.page_size = 1;
|
|
||||||
|
|
||||||
/* update chipdata if OF is present */
|
|
||||||
at24_get_ofdata(client, &chip);
|
|
||||||
|
|
||||||
chip.setup = NULL;
|
|
||||||
chip.context = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_power_of_2(chip.byte_len))
|
|
||||||
dev_warn(&client->dev,
|
|
||||||
"byte_len looks suspicious (no power of 2)!\n");
|
|
||||||
if (!chip.page_size) {
|
|
||||||
dev_err(&client->dev, "page_size must not be 0!\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
if (!is_power_of_2(chip.page_size))
|
|
||||||
dev_warn(&client->dev,
|
|
||||||
"page_size looks suspicious (no power of 2)!\n");
|
|
||||||
|
|
||||||
/* Use I2C operations unless we're stuck with SMBus extensions. */
|
|
||||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
|
||||||
if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_I2C_BLOCK)) {
|
|
||||||
use_smbus = I2C_SMBUS_I2C_BLOCK_DATA;
|
|
||||||
} else if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_WORD_DATA)) {
|
|
||||||
use_smbus = I2C_SMBUS_WORD_DATA;
|
|
||||||
} else if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_READ_BYTE_DATA)) {
|
|
||||||
use_smbus = I2C_SMBUS_BYTE_DATA;
|
|
||||||
} else {
|
|
||||||
return -EPFNOSUPPORT;
|
|
||||||
}
|
|
||||||
use_smbus = I2C_SMBUS_BYTE_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (chip.flags & AT24_FLAG_TAKE8ADDR)
|
|
||||||
num_addresses = 8;
|
|
||||||
else
|
|
||||||
num_addresses = DIV_ROUND_UP(chip.byte_len, (chip.flags & AT24_FLAG_ADDR16) ? 65536 : 256);
|
|
||||||
|
|
||||||
at24 = devm_kzalloc(&client->dev, sizeof(struct at24_data) + num_addresses * sizeof(struct i2c_client *), GFP_KERNEL);
|
|
||||||
if (!at24)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
mutex_init(&at24->lock);
|
|
||||||
at24->use_smbus = use_smbus;
|
|
||||||
at24->chip = chip;
|
|
||||||
at24->num_addresses = num_addresses;
|
|
||||||
|
|
||||||
printk(KERN_ALERT "at24_probe chip.byte_len = 0x%x\n", chip.byte_len);
|
|
||||||
printk(KERN_ALERT "at24_probe chip.flags = 0x%x\n", chip.flags);
|
|
||||||
printk(KERN_ALERT "at24_probe chip.magic = 0x%lx\n", id->driver_data);
|
|
||||||
printk(KERN_ALERT "at24_probe use_smbus = %d\n", at24->use_smbus);
|
|
||||||
printk(KERN_ALERT "at24_probe num_addresses = %d\n", at24->num_addresses);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Export the EEPROM bytes through sysfs, since that's convenient.
|
|
||||||
* By default, only root should see the data (maybe passwords etc)
|
|
||||||
*/
|
|
||||||
sysfs_bin_attr_init(&at24->bin);
|
|
||||||
at24->bin.attr.name = "eeprom";
|
|
||||||
at24->bin.attr.mode = chip.flags & AT24_FLAG_IRUGO ? S_IRUGO : S_IRUSR;
|
|
||||||
at24->bin.read = at24_bin_read;
|
|
||||||
at24->bin.size = chip.byte_len;
|
|
||||||
|
|
||||||
writable = !(chip.flags & AT24_FLAG_READONLY);
|
|
||||||
if (writable) {
|
|
||||||
if (!use_smbus || i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_I2C_BLOCK)) {
|
|
||||||
unsigned write_max = chip.page_size;
|
|
||||||
|
|
||||||
at24->bin.write = at24_bin_write;
|
|
||||||
at24->bin.attr.mode |= S_IWUSR;
|
|
||||||
|
|
||||||
if (write_max > io_limit)
|
|
||||||
write_max = io_limit;
|
|
||||||
if (use_smbus && write_max > I2C_SMBUS_BLOCK_MAX)
|
|
||||||
write_max = I2C_SMBUS_BLOCK_MAX;
|
|
||||||
at24->write_max = write_max;
|
|
||||||
|
|
||||||
/* buffer (data + address at the beginning) */
|
|
||||||
at24->writebuf = devm_kzalloc(&client->dev, write_max + 2, GFP_KERNEL);
|
|
||||||
if (!at24->writebuf)
|
|
||||||
return -ENOMEM;
|
|
||||||
} else {
|
|
||||||
dev_warn(&client->dev, "cannot write due to controller restrictions.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
at24->client[0] = client;
|
|
||||||
|
|
||||||
/* use dummy devices for multiple-address chips */
|
|
||||||
for (i = 1; i < num_addresses; i++) {
|
|
||||||
at24->client[i] = i2c_new_dummy(client->adapter, client->addr + i);
|
|
||||||
if (!at24->client[i]) {
|
|
||||||
dev_err(&client->dev, "address 0x%02x unavailable\n", client->addr + i);
|
|
||||||
err = -EADDRINUSE;
|
|
||||||
goto err_clients;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err = sysfs_create_bin_file(&client->dev.kobj, &at24->bin);
|
|
||||||
if (err)
|
|
||||||
goto err_clients;
|
|
||||||
|
|
||||||
i2c_set_clientdata(client, at24);
|
|
||||||
|
|
||||||
printk(KERN_ALERT "at24_probe %s done\n", client->name);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
err_clients:
|
|
||||||
for (i = 1; i < num_addresses; i++)
|
|
||||||
if (at24->client[i])
|
|
||||||
i2c_unregister_device(at24->client[i]);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int at24_remove(struct i2c_client *client)
|
|
||||||
{
|
|
||||||
struct at24_data *at24;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
at24 = i2c_get_clientdata(client);
|
|
||||||
sysfs_remove_bin_file(&client->dev.kobj, &at24->bin);
|
|
||||||
|
|
||||||
for (i = 1; i < at24->num_addresses; i++)
|
|
||||||
i2c_unregister_device(at24->client[i]);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*-------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
static struct i2c_board_info i2c_devs = {
|
|
||||||
I2C_BOARD_INFO("24c64-ctc", 0x57),
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct i2c_adapter *adapter = NULL;
|
|
||||||
static struct i2c_client *client = NULL;
|
|
||||||
|
|
||||||
static int ctc_at24c64_init(void)
|
|
||||||
{
|
|
||||||
printk(KERN_ALERT "ctc_at24c64_init\n");
|
|
||||||
|
|
||||||
adapter = i2c_get_adapter(0);
|
|
||||||
if(adapter == NULL){
|
|
||||||
printk(KERN_ALERT "i2c_get_adapter == NULL\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
client = i2c_new_device(adapter, &i2c_devs);
|
|
||||||
if(client == NULL){
|
|
||||||
printk(KERN_ALERT "i2c_new_device == NULL\n");
|
|
||||||
i2c_put_adapter(adapter);
|
|
||||||
adapter = NULL;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ctc_at24c64_exit(void)
|
|
||||||
{
|
|
||||||
printk(KERN_ALERT "ctc_at24c64_exit\n");
|
|
||||||
if(client){
|
|
||||||
i2c_unregister_device(client);
|
|
||||||
}
|
|
||||||
if(adapter){
|
|
||||||
i2c_put_adapter(adapter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct i2c_driver at24_ctc_driver = {
|
|
||||||
.driver = {
|
|
||||||
.name = "at24-ctc",
|
|
||||||
.owner = THIS_MODULE,
|
|
||||||
},
|
|
||||||
.probe = at24_probe,
|
|
||||||
.remove = at24_remove,
|
|
||||||
.id_table = at24_ctc_ids,
|
|
||||||
};
|
|
||||||
|
|
||||||
static int __init at24_ctc_init(void)
|
|
||||||
{
|
|
||||||
if (!io_limit) {
|
|
||||||
pr_err("at24_ctc: io_limit must not be 0!\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
io_limit = rounddown_pow_of_two(io_limit);
|
|
||||||
|
|
||||||
ctc_at24c64_init();
|
|
||||||
|
|
||||||
return i2c_add_driver(&at24_ctc_driver);
|
|
||||||
}
|
|
||||||
module_init(at24_ctc_init);
|
|
||||||
|
|
||||||
static void __exit at24_ctc_exit(void)
|
|
||||||
{
|
|
||||||
ctc_at24c64_exit();
|
|
||||||
i2c_del_driver(&at24_ctc_driver);
|
|
||||||
}
|
|
||||||
module_exit(at24_ctc_exit);
|
|
||||||
|
|
||||||
MODULE_DESCRIPTION("Driver for most I2C EEPROMs");
|
|
||||||
MODULE_AUTHOR("David Brownell and Wolfram Sang");
|
|
||||||
MODULE_LICENSE("GPL");
|
|
||||||
/* XXX */
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
|||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/i2c.h>
|
#include <linux/i2c.h>
|
||||||
#include <linux/platform_data/pca954x.h>
|
#include "../../pca954x/ctc-pca954x.h"
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/kdev_t.h>
|
#include <linux/kdev_t.h>
|
||||||
#include <linux/leds.h>
|
#include <linux/leds.h>
|
||||||
@ -95,7 +95,7 @@ static struct pca954x_platform_data i2c_dev_pca9548_platform_data = {
|
|||||||
.num_modes = PCA9548_CHANNEL_NUM,
|
.num_modes = PCA9548_CHANNEL_NUM,
|
||||||
};
|
};
|
||||||
static struct i2c_board_info i2c_dev_pca9548 = {
|
static struct i2c_board_info i2c_dev_pca9548 = {
|
||||||
I2C_BOARD_INFO("pca9548", 0x70),
|
I2C_BOARD_INFO("ctc_pca9548", 0x70),
|
||||||
.platform_data = &i2c_dev_pca9548_platform_data,
|
.platform_data = &i2c_dev_pca9548_platform_data,
|
||||||
};
|
};
|
||||||
static struct i2c_client *i2c_client_pca9548x = NULL;
|
static struct i2c_client *i2c_client_pca9548x = NULL;
|
||||||
@ -110,7 +110,7 @@ static int e582_48x6q_init_i2c_pca9548(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* install i2c-mux */
|
/* install i2c-mux */
|
||||||
i2c_client_pca9548x = i2c_new_device(i2c_adp_master, &i2c_dev_pca9548);
|
i2c_client_pca9548x = i2c_new_client_device(i2c_adp_master, &i2c_dev_pca9548);
|
||||||
if(IS_INVALID_PTR(i2c_client_pca9548x))
|
if(IS_INVALID_PTR(i2c_client_pca9548x))
|
||||||
{
|
{
|
||||||
i2c_client_pca9548x = NULL;
|
i2c_client_pca9548x = NULL;
|
||||||
@ -150,7 +150,7 @@ static int e582_48x6q_init_i2c_adt7470(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_adt7470 = i2c_new_device(i2c_adp_adt7470, &i2c_dev_adt7470);
|
i2c_client_adt7470 = i2c_new_client_device(i2c_adp_adt7470, &i2c_dev_adt7470);
|
||||||
if(IS_INVALID_PTR(i2c_client_adt7470)){
|
if(IS_INVALID_PTR(i2c_client_adt7470)){
|
||||||
i2c_client_adt7470 = NULL;
|
i2c_client_adt7470 = NULL;
|
||||||
printk(KERN_CRIT "install e582_48x6q board adt7470 failed\n");
|
printk(KERN_CRIT "install e582_48x6q board adt7470 failed\n");
|
||||||
@ -206,14 +206,14 @@ static int e582_48x6q_init_i2c_psu(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_psu1 = i2c_new_device(i2c_adp_psu1, &i2c_dev_psu1);
|
i2c_client_psu1 = i2c_new_client_device(i2c_adp_psu1, &i2c_dev_psu1);
|
||||||
if(IS_INVALID_PTR(i2c_client_psu1)){
|
if(IS_INVALID_PTR(i2c_client_psu1)){
|
||||||
i2c_client_psu1 = NULL;
|
i2c_client_psu1 = NULL;
|
||||||
printk(KERN_CRIT "create e582_48x6q board i2c client psu1 failed\n");
|
printk(KERN_CRIT "create e582_48x6q board i2c client psu1 failed\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_psu2 = i2c_new_device(i2c_adp_psu2, &i2c_dev_psu2);
|
i2c_client_psu2 = i2c_new_client_device(i2c_adp_psu2, &i2c_dev_psu2);
|
||||||
if(IS_INVALID_PTR(i2c_client_psu2)){
|
if(IS_INVALID_PTR(i2c_client_psu2)){
|
||||||
i2c_client_psu2 = NULL;
|
i2c_client_psu2 = NULL;
|
||||||
printk(KERN_CRIT "create e582_48x6q board i2c client psu2 failed\n");
|
printk(KERN_CRIT "create e582_48x6q board i2c client psu2 failed\n");
|
||||||
@ -265,7 +265,7 @@ static int e582_48x6q_init_i2c_epld(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_epld = i2c_new_device(i2c_adp_master, &i2c_dev_epld);
|
i2c_client_epld = i2c_new_client_device(i2c_adp_master, &i2c_dev_epld);
|
||||||
if(IS_INVALID_PTR(i2c_client_epld))
|
if(IS_INVALID_PTR(i2c_client_epld))
|
||||||
{
|
{
|
||||||
i2c_client_epld = NULL;
|
i2c_client_epld = NULL;
|
||||||
@ -317,7 +317,7 @@ static int e582_48x6q_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio0 = i2c_new_device(i2c_adp_master, &i2c_dev_gpio0);
|
i2c_client_gpio0 = i2c_new_client_device(i2c_adp_master, &i2c_dev_gpio0);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio0))
|
if(IS_INVALID_PTR(i2c_client_gpio0))
|
||||||
{
|
{
|
||||||
i2c_client_gpio0 = NULL;
|
i2c_client_gpio0 = NULL;
|
||||||
@ -325,7 +325,7 @@ static int e582_48x6q_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio1 = i2c_new_device(i2c_adp_master, &i2c_dev_gpio1);
|
i2c_client_gpio1 = i2c_new_client_device(i2c_adp_master, &i2c_dev_gpio1);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio1))
|
if(IS_INVALID_PTR(i2c_client_gpio1))
|
||||||
{
|
{
|
||||||
i2c_client_gpio1 = NULL;
|
i2c_client_gpio1 = NULL;
|
||||||
@ -333,7 +333,7 @@ static int e582_48x6q_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio2 = i2c_new_device(i2c_adp_master, &i2c_dev_gpio2);
|
i2c_client_gpio2 = i2c_new_client_device(i2c_adp_master, &i2c_dev_gpio2);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio2))
|
if(IS_INVALID_PTR(i2c_client_gpio2))
|
||||||
{
|
{
|
||||||
i2c_client_gpio2 = NULL;
|
i2c_client_gpio2 = NULL;
|
||||||
@ -341,7 +341,7 @@ static int e582_48x6q_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio3 = i2c_new_device(i2c_adp_master, &i2c_dev_gpio3);
|
i2c_client_gpio3 = i2c_new_client_device(i2c_adp_master, &i2c_dev_gpio3);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio3))
|
if(IS_INVALID_PTR(i2c_client_gpio3))
|
||||||
{
|
{
|
||||||
i2c_client_gpio3 = NULL;
|
i2c_client_gpio3 = NULL;
|
||||||
@ -349,7 +349,7 @@ static int e582_48x6q_init_i2c_gpio(void)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
i2c_client_gpio4 = i2c_new_device(i2c_adp_master, &i2c_dev_gpio4);
|
i2c_client_gpio4 = i2c_new_client_device(i2c_adp_master, &i2c_dev_gpio4);
|
||||||
if(IS_INVALID_PTR(i2c_client_gpio4))
|
if(IS_INVALID_PTR(i2c_client_gpio4))
|
||||||
{
|
{
|
||||||
i2c_client_gpio4 = NULL;
|
i2c_client_gpio4 = NULL;
|
||||||
|
@ -25,7 +25,7 @@ if [ "$1" == "init" ]; then
|
|||||||
modprobe i2c-dev
|
modprobe i2c-dev
|
||||||
modprobe i2c-mux
|
modprobe i2c-mux
|
||||||
modprobe i2c-smbus
|
modprobe i2c-smbus
|
||||||
modprobe i2c-mux-pca954x force_deselect_on_exit=1
|
modprobe ctc-i2c-mux-pca954x force_deselect_on_exit=1
|
||||||
i2cset -y 0 0x58 0x8 0x3f
|
i2cset -y 0 0x58 0x8 0x3f
|
||||||
i2cset -y 0 0x20 0x1b 0x0
|
i2cset -y 0 0x20 0x1b 0x0
|
||||||
i2cset -y 0 0x20 0xb 0x0
|
i2cset -y 0 0x20 0xb 0x0
|
||||||
@ -42,7 +42,8 @@ if [ "$1" == "init" ]; then
|
|||||||
modprobe lm77
|
modprobe lm77
|
||||||
modprobe tun
|
modprobe tun
|
||||||
modprobe dal
|
modprobe dal
|
||||||
modprobe centec_at24c64
|
modprobe at24
|
||||||
|
echo 24c64 0x57 > /sys/bus/i2c/devices/i2c-0/new_device
|
||||||
modprobe centec_e582_48x6q_platform
|
modprobe centec_e582_48x6q_platform
|
||||||
|
|
||||||
#start platform monitor
|
#start platform monitor
|
||||||
@ -53,9 +54,9 @@ elif [ "$1" == "deinit" ]; then
|
|||||||
kill -9 $(pidof platform_monitor) > /dev/null 2>&1
|
kill -9 $(pidof platform_monitor) > /dev/null 2>&1
|
||||||
rm -rf /usr/bin/platform_monitor
|
rm -rf /usr/bin/platform_monitor
|
||||||
modprobe -r centec_e582_48x6q_platform
|
modprobe -r centec_e582_48x6q_platform
|
||||||
modprobe -r centec_at24c64
|
modprobe -r at24
|
||||||
modprobe -r dal
|
modprobe -r dal
|
||||||
modprobe -r i2c-mux-pca954x
|
modprobe -r ctc-i2c-mux-pca954x
|
||||||
modprobe -r i2c-dev
|
modprobe -r i2c-dev
|
||||||
else
|
else
|
||||||
echo "e582-48x6q_platform : Invalid option !"
|
echo "e582-48x6q_platform : Invalid option !"
|
||||||
|
@ -7,11 +7,11 @@ Standards-Version: 3.9.3
|
|||||||
|
|
||||||
Package: platform-modules-e582-48x2q4z
|
Package: platform-modules-e582-48x2q4z
|
||||||
Architecture: amd64
|
Architecture: amd64
|
||||||
Depends: linux-image-4.19.0-12-2-amd64-unsigned
|
Depends: linux-image-5.10.0-8-2-amd64-unsigned
|
||||||
Description: kernel modules for platform devices such as fan, led, sfp
|
Description: kernel modules for platform devices such as fan, led, sfp
|
||||||
|
|
||||||
Package: platform-modules-e582-48x6q
|
Package: platform-modules-e582-48x6q
|
||||||
Architecture: amd64
|
Architecture: amd64
|
||||||
Depends: linux-image-4.19.0-12-2-amd64-unsigned
|
Depends: linux-image-5.10.0-8-2-amd64-unsigned
|
||||||
Description: kernel modules for platform devices such as fan, led, sfp
|
Description: kernel modules for platform devices such as fan, led, sfp
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ KVERSION ?= $(shell uname -r)
|
|||||||
KERNEL_SRC := /lib/modules/$(KVERSION)
|
KERNEL_SRC := /lib/modules/$(KVERSION)
|
||||||
MOD_SRC_DIR:= $(shell pwd)
|
MOD_SRC_DIR:= $(shell pwd)
|
||||||
MODULE_DIRS:= 48x6q 48x2q4z
|
MODULE_DIRS:= 48x6q 48x2q4z
|
||||||
|
PCA954X_DIR := pca954x
|
||||||
|
|
||||||
%:
|
%:
|
||||||
dh $@
|
dh $@
|
||||||
@ -14,6 +15,9 @@ override_dh_auto_build:
|
|||||||
(for mod in $(MODULE_DIRS); do \
|
(for mod in $(MODULE_DIRS); do \
|
||||||
make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \
|
make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/modules; \
|
||||||
done)
|
done)
|
||||||
|
(for mod in $(PCA954X_DIR); do \
|
||||||
|
make modules -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/$${mod}/; \
|
||||||
|
done)
|
||||||
rm $(MOD_SRC_DIR)/centec-dal -rf
|
rm $(MOD_SRC_DIR)/centec-dal -rf
|
||||||
cp $(MOD_SRC_DIR)/../centec-dal $(MOD_SRC_DIR)/centec-dal -rf
|
cp $(MOD_SRC_DIR)/../centec-dal $(MOD_SRC_DIR)/centec-dal -rf
|
||||||
make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/centec-dal
|
make -C $(KERNEL_SRC)/build M=$(MOD_SRC_DIR)/centec-dal
|
||||||
@ -25,6 +29,7 @@ override_dh_auto_install:
|
|||||||
cp -f $(MOD_SRC_DIR)/$${mod}/modules/*.ko \
|
cp -f $(MOD_SRC_DIR)/$${mod}/modules/*.ko \
|
||||||
debian/platform-modules-e582-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
|
debian/platform-modules-e582-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
|
||||||
cp -f $(MOD_SRC_DIR)/centec-dal/*.ko debian/platform-modules-e582-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
|
cp -f $(MOD_SRC_DIR)/centec-dal/*.ko debian/platform-modules-e582-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
|
||||||
|
cp -f $(MOD_SRC_DIR)/$(PCA954X_DIR)/*.ko debian/platform-modules-e582-$${mod}/$(KERNEL_SRC)/$(INSTALL_MOD_DIR); \
|
||||||
done)
|
done)
|
||||||
|
|
||||||
override_dh_usrlocal:
|
override_dh_usrlocal:
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
obj-m := ctc-i2c-mux-pca954x.o
|
@ -0,0 +1,581 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
/*
|
||||||
|
* I2C multiplexer
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
|
||||||
|
* Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
|
||||||
|
*
|
||||||
|
* This module supports the PCA954x and PCA984x series of I2C multiplexer/switch
|
||||||
|
* chips made by NXP Semiconductors.
|
||||||
|
* This includes the:
|
||||||
|
* PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547,
|
||||||
|
* PCA9548, PCA9846, PCA9847, PCA9848 and PCA9849.
|
||||||
|
*
|
||||||
|
* These chips are all controlled via the I2C bus itself, and all have a
|
||||||
|
* single 8-bit register. The upstream "parent" bus fans out to two,
|
||||||
|
* four, or eight downstream busses or channels; which of these
|
||||||
|
* are selected is determined by the chip type and register contents. A
|
||||||
|
* mux can select only one sub-bus at a time; a switch can select any
|
||||||
|
* combination simultaneously.
|
||||||
|
*
|
||||||
|
* Based on:
|
||||||
|
* pca954x.c from Kumar Gala <galak@kernel.crashing.org>
|
||||||
|
* Copyright (C) 2006
|
||||||
|
*
|
||||||
|
* Based on:
|
||||||
|
* pca954x.c from Ken Harrenstien
|
||||||
|
* Copyright (C) 2004 Google, Inc. (Ken Harrenstien)
|
||||||
|
*
|
||||||
|
* Based on:
|
||||||
|
* i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com>
|
||||||
|
* and
|
||||||
|
* pca9540.c from Jean Delvare <jdelvare@suse.de>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
#include <linux/gpio/consumer.h>
|
||||||
|
#include <linux/i2c.h>
|
||||||
|
#include <linux/i2c-mux.h>
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/irq.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/pm.h>
|
||||||
|
#include <linux/property.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <dt-bindings/mux/mux.h>
|
||||||
|
#include "ctc-pca954x.h"
|
||||||
|
|
||||||
|
#define PCA954X_MAX_NCHANS 8
|
||||||
|
|
||||||
|
#define PCA954X_IRQ_OFFSET 4
|
||||||
|
|
||||||
|
enum pca_type {
|
||||||
|
pca_9540,
|
||||||
|
pca_9542,
|
||||||
|
pca_9543,
|
||||||
|
pca_9544,
|
||||||
|
pca_9545,
|
||||||
|
pca_9546,
|
||||||
|
pca_9547,
|
||||||
|
pca_9548,
|
||||||
|
pca_9846,
|
||||||
|
pca_9847,
|
||||||
|
pca_9848,
|
||||||
|
pca_9849,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct chip_desc {
|
||||||
|
u8 nchans;
|
||||||
|
u8 enable; /* used for muxes only */
|
||||||
|
u8 has_irq;
|
||||||
|
enum muxtype {
|
||||||
|
pca954x_ismux = 0,
|
||||||
|
pca954x_isswi
|
||||||
|
} muxtype;
|
||||||
|
struct i2c_device_identity id;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pca954x {
|
||||||
|
const struct chip_desc *chip;
|
||||||
|
|
||||||
|
u8 last_chan; /* last register value */
|
||||||
|
/* MUX_IDLE_AS_IS, MUX_IDLE_DISCONNECT or >= 0 for channel */
|
||||||
|
s32 idle_state;
|
||||||
|
|
||||||
|
struct i2c_client *client;
|
||||||
|
|
||||||
|
struct irq_domain *irq;
|
||||||
|
unsigned int irq_mask;
|
||||||
|
raw_spinlock_t lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Provide specs for the PCA954x types we know about */
|
||||||
|
static const struct chip_desc chips[] = {
|
||||||
|
[pca_9540] = {
|
||||||
|
.nchans = 2,
|
||||||
|
.enable = 0x4,
|
||||||
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9542] = {
|
||||||
|
.nchans = 2,
|
||||||
|
.enable = 0x4,
|
||||||
|
.has_irq = 1,
|
||||||
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9543] = {
|
||||||
|
.nchans = 2,
|
||||||
|
.has_irq = 1,
|
||||||
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9544] = {
|
||||||
|
.nchans = 4,
|
||||||
|
.enable = 0x4,
|
||||||
|
.has_irq = 1,
|
||||||
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9545] = {
|
||||||
|
.nchans = 4,
|
||||||
|
.has_irq = 1,
|
||||||
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9546] = {
|
||||||
|
.nchans = 4,
|
||||||
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9547] = {
|
||||||
|
.nchans = 8,
|
||||||
|
.enable = 0x8,
|
||||||
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9548] = {
|
||||||
|
.nchans = 8,
|
||||||
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = { .manufacturer_id = I2C_DEVICE_ID_NONE },
|
||||||
|
},
|
||||||
|
[pca_9846] = {
|
||||||
|
.nchans = 4,
|
||||||
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = {
|
||||||
|
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
|
||||||
|
.part_id = 0x10b,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[pca_9847] = {
|
||||||
|
.nchans = 8,
|
||||||
|
.enable = 0x8,
|
||||||
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = {
|
||||||
|
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
|
||||||
|
.part_id = 0x108,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[pca_9848] = {
|
||||||
|
.nchans = 8,
|
||||||
|
.muxtype = pca954x_isswi,
|
||||||
|
.id = {
|
||||||
|
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
|
||||||
|
.part_id = 0x10a,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
[pca_9849] = {
|
||||||
|
.nchans = 4,
|
||||||
|
.enable = 0x4,
|
||||||
|
.muxtype = pca954x_ismux,
|
||||||
|
.id = {
|
||||||
|
.manufacturer_id = I2C_DEVICE_ID_NXP_SEMICONDUCTORS,
|
||||||
|
.part_id = 0x109,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct i2c_device_id pca954x_id[] = {
|
||||||
|
{ "ctc_pca9540", pca_9540 },
|
||||||
|
{ "ctc_pca9542", pca_9542 },
|
||||||
|
{ "ctc_pca9543", pca_9543 },
|
||||||
|
{ "ctc_pca9544", pca_9544 },
|
||||||
|
{ "ctc_pca9545", pca_9545 },
|
||||||
|
{ "ctc_pca9546", pca_9546 },
|
||||||
|
{ "ctc_pca9547", pca_9547 },
|
||||||
|
{ "ctc_pca9548", pca_9548 },
|
||||||
|
{ "ctc_pca9846", pca_9846 },
|
||||||
|
{ "ctc_pca9847", pca_9847 },
|
||||||
|
{ "ctc_pca9848", pca_9848 },
|
||||||
|
{ "ctc_pca9849", pca_9849 },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(i2c, pca954x_id);
|
||||||
|
|
||||||
|
static const struct of_device_id pca954x_of_match[] = {
|
||||||
|
{ .compatible = "nxp,ctc_pca9540", .data = &chips[pca_9540] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9542", .data = &chips[pca_9542] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9543", .data = &chips[pca_9543] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9544", .data = &chips[pca_9544] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9545", .data = &chips[pca_9545] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9546", .data = &chips[pca_9546] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9547", .data = &chips[pca_9547] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9548", .data = &chips[pca_9548] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9846", .data = &chips[pca_9846] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9847", .data = &chips[pca_9847] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9848", .data = &chips[pca_9848] },
|
||||||
|
{ .compatible = "nxp,ctc_pca9849", .data = &chips[pca_9849] },
|
||||||
|
{}
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, pca954x_of_match);
|
||||||
|
|
||||||
|
/* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
|
||||||
|
for this as they will try to lock adapter a second time */
|
||||||
|
static int pca954x_reg_write(struct i2c_adapter *adap,
|
||||||
|
struct i2c_client *client, u8 val)
|
||||||
|
{
|
||||||
|
union i2c_smbus_data dummy;
|
||||||
|
|
||||||
|
return __i2c_smbus_xfer(adap, client->addr, client->flags,
|
||||||
|
I2C_SMBUS_WRITE, val,
|
||||||
|
I2C_SMBUS_BYTE, &dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
static u8 pca954x_regval(struct pca954x *data, u8 chan)
|
||||||
|
{
|
||||||
|
/* We make switches look like muxes, not sure how to be smarter. */
|
||||||
|
if (data->chip->muxtype == pca954x_ismux)
|
||||||
|
return chan | data->chip->enable;
|
||||||
|
else
|
||||||
|
return 1 << chan;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca954x_select_chan(struct i2c_mux_core *muxc, u32 chan)
|
||||||
|
{
|
||||||
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
|
struct i2c_client *client = data->client;
|
||||||
|
u8 regval;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
regval = pca954x_regval(data, chan);
|
||||||
|
/* Only select the channel if its different from the last channel */
|
||||||
|
if (data->last_chan != regval) {
|
||||||
|
ret = pca954x_reg_write(muxc->parent, client, regval);
|
||||||
|
data->last_chan = ret < 0 ? 0 : regval;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
|
||||||
|
{
|
||||||
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
|
struct i2c_client *client = data->client;
|
||||||
|
s32 idle_state;
|
||||||
|
|
||||||
|
idle_state = READ_ONCE(data->idle_state);
|
||||||
|
if (idle_state >= 0)
|
||||||
|
/* Set the mux back to a predetermined channel */
|
||||||
|
return pca954x_select_chan(muxc, idle_state);
|
||||||
|
|
||||||
|
if (idle_state == MUX_IDLE_DISCONNECT) {
|
||||||
|
/* Deselect active channel */
|
||||||
|
data->last_chan = 0;
|
||||||
|
return pca954x_reg_write(muxc->parent, client,
|
||||||
|
data->last_chan);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* otherwise leave as-is */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t idle_state_show(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||||
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", READ_ONCE(data->idle_state));
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t idle_state_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf, size_t count)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||||
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
|
int val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = kstrtoint(buf, 0, &val);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (val != MUX_IDLE_AS_IS && val != MUX_IDLE_DISCONNECT &&
|
||||||
|
(val < 0 || val >= data->chip->nchans))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
i2c_lock_bus(muxc->parent, I2C_LOCK_SEGMENT);
|
||||||
|
|
||||||
|
WRITE_ONCE(data->idle_state, val);
|
||||||
|
/*
|
||||||
|
* Set the mux into a state consistent with the new
|
||||||
|
* idle_state.
|
||||||
|
*/
|
||||||
|
if (data->last_chan || val != MUX_IDLE_DISCONNECT)
|
||||||
|
ret = pca954x_deselect_mux(muxc, 0);
|
||||||
|
|
||||||
|
i2c_unlock_bus(muxc->parent, I2C_LOCK_SEGMENT);
|
||||||
|
|
||||||
|
return ret < 0 ? ret : count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_ATTR_RW(idle_state);
|
||||||
|
|
||||||
|
static irqreturn_t pca954x_irq_handler(int irq, void *dev_id)
|
||||||
|
{
|
||||||
|
struct pca954x *data = dev_id;
|
||||||
|
unsigned long pending;
|
||||||
|
int ret, i;
|
||||||
|
|
||||||
|
ret = i2c_smbus_read_byte(data->client);
|
||||||
|
if (ret < 0)
|
||||||
|
return IRQ_NONE;
|
||||||
|
|
||||||
|
pending = (ret >> PCA954X_IRQ_OFFSET) & (BIT(data->chip->nchans) - 1);
|
||||||
|
for_each_set_bit(i, &pending, data->chip->nchans)
|
||||||
|
handle_nested_irq(irq_linear_revmap(data->irq, i));
|
||||||
|
|
||||||
|
return IRQ_RETVAL(pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca954x_irq_set_type(struct irq_data *idata, unsigned int type)
|
||||||
|
{
|
||||||
|
if ((type & IRQ_TYPE_SENSE_MASK) != IRQ_TYPE_LEVEL_LOW)
|
||||||
|
return -EINVAL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct irq_chip pca954x_irq_chip = {
|
||||||
|
.name = "i2c-mux-pca954x",
|
||||||
|
.irq_set_type = pca954x_irq_set_type,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int pca954x_irq_setup(struct i2c_mux_core *muxc)
|
||||||
|
{
|
||||||
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
|
struct i2c_client *client = data->client;
|
||||||
|
int c, irq;
|
||||||
|
|
||||||
|
if (!data->chip->has_irq || client->irq <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
raw_spin_lock_init(&data->lock);
|
||||||
|
|
||||||
|
data->irq = irq_domain_add_linear(client->dev.of_node,
|
||||||
|
data->chip->nchans,
|
||||||
|
&irq_domain_simple_ops, data);
|
||||||
|
if (!data->irq)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
for (c = 0; c < data->chip->nchans; c++) {
|
||||||
|
irq = irq_create_mapping(data->irq, c);
|
||||||
|
if (!irq) {
|
||||||
|
dev_err(&client->dev, "failed irq create map\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
irq_set_chip_data(irq, data);
|
||||||
|
irq_set_chip_and_handler(irq, &pca954x_irq_chip,
|
||||||
|
handle_simple_irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pca954x_cleanup(struct i2c_mux_core *muxc)
|
||||||
|
{
|
||||||
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
|
int c, irq;
|
||||||
|
|
||||||
|
if (data->irq) {
|
||||||
|
for (c = 0; c < data->chip->nchans; c++) {
|
||||||
|
irq = irq_find_mapping(data->irq, c);
|
||||||
|
irq_dispose_mapping(irq);
|
||||||
|
}
|
||||||
|
irq_domain_remove(data->irq);
|
||||||
|
}
|
||||||
|
i2c_mux_del_adapters(muxc);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca954x_init(struct i2c_client *client, struct pca954x *data)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (data->idle_state >= 0)
|
||||||
|
data->last_chan = pca954x_regval(data, data->idle_state);
|
||||||
|
else
|
||||||
|
data->last_chan = 0; /* Disconnect multiplexer */
|
||||||
|
|
||||||
|
ret = i2c_smbus_write_byte(client, data->last_chan);
|
||||||
|
if (ret < 0)
|
||||||
|
data->last_chan = 0;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I2C init/probing/exit functions
|
||||||
|
*/
|
||||||
|
static int pca954x_probe(struct i2c_client *client,
|
||||||
|
const struct i2c_device_id *id)
|
||||||
|
{
|
||||||
|
struct i2c_adapter *adap = client->adapter;
|
||||||
|
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||||
|
struct device *dev = &client->dev;
|
||||||
|
struct gpio_desc *gpio;
|
||||||
|
int num, force, class;
|
||||||
|
struct i2c_mux_core *muxc;
|
||||||
|
struct pca954x *data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
muxc = i2c_mux_alloc(adap, dev, PCA954X_MAX_NCHANS, sizeof(*data), 0,
|
||||||
|
pca954x_select_chan, pca954x_deselect_mux);
|
||||||
|
if (!muxc)
|
||||||
|
return -ENOMEM;
|
||||||
|
data = i2c_mux_priv(muxc);
|
||||||
|
|
||||||
|
i2c_set_clientdata(client, muxc);
|
||||||
|
data->client = client;
|
||||||
|
|
||||||
|
/* Reset the mux if a reset GPIO is specified. */
|
||||||
|
gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
|
||||||
|
if (IS_ERR(gpio))
|
||||||
|
return PTR_ERR(gpio);
|
||||||
|
if (gpio) {
|
||||||
|
udelay(1);
|
||||||
|
gpiod_set_value_cansleep(gpio, 0);
|
||||||
|
/* Give the chip some time to recover. */
|
||||||
|
udelay(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
data->chip = device_get_match_data(dev);
|
||||||
|
if (!data->chip)
|
||||||
|
data->chip = &chips[id->driver_data];
|
||||||
|
|
||||||
|
if (data->chip->id.manufacturer_id != I2C_DEVICE_ID_NONE) {
|
||||||
|
struct i2c_device_identity id;
|
||||||
|
|
||||||
|
ret = i2c_get_device_id(client, &id);
|
||||||
|
if (ret && ret != -EOPNOTSUPP)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (!ret &&
|
||||||
|
(id.manufacturer_id != data->chip->id.manufacturer_id ||
|
||||||
|
id.part_id != data->chip->id.part_id)) {
|
||||||
|
dev_warn(dev, "unexpected device id %03x-%03x-%x\n",
|
||||||
|
id.manufacturer_id, id.part_id,
|
||||||
|
id.die_revision);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data->idle_state = MUX_IDLE_AS_IS;
|
||||||
|
if (device_property_read_u32(dev, "idle-state", &data->idle_state)) {
|
||||||
|
if (device_property_read_bool(dev, "i2c-mux-idle-disconnect"))
|
||||||
|
data->idle_state = MUX_IDLE_DISCONNECT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write the mux register at addr to verify
|
||||||
|
* that the mux is in fact present. This also
|
||||||
|
* initializes the mux to a channel
|
||||||
|
* or disconnected state.
|
||||||
|
*/
|
||||||
|
ret = pca954x_init(client, data);
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_warn(dev, "probe failed\n");
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = pca954x_irq_setup(muxc);
|
||||||
|
if (ret)
|
||||||
|
goto fail_cleanup;
|
||||||
|
|
||||||
|
/* Now create an adapter for each channel */
|
||||||
|
for (num = 0; num < data->chip->nchans; num++) {
|
||||||
|
force = 0; /* dynamic adap number */
|
||||||
|
class = 0; /* no class by default */
|
||||||
|
if (pdata) {
|
||||||
|
if (num < pdata->num_modes) {
|
||||||
|
/* force static number */
|
||||||
|
force = pdata->modes[num].adap_id;
|
||||||
|
class = pdata->modes[num].class;
|
||||||
|
} else
|
||||||
|
/* discard unconfigured channels */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i2c_mux_add_adapter(muxc, force, num, class);
|
||||||
|
if (ret)
|
||||||
|
goto fail_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->irq) {
|
||||||
|
ret = devm_request_threaded_irq(dev, data->client->irq,
|
||||||
|
NULL, pca954x_irq_handler,
|
||||||
|
IRQF_ONESHOT | IRQF_SHARED,
|
||||||
|
"pca954x", data);
|
||||||
|
if (ret)
|
||||||
|
goto fail_cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The attr probably isn't going to be needed in most cases,
|
||||||
|
* so don't fail completely on error.
|
||||||
|
*/
|
||||||
|
device_create_file(dev, &dev_attr_idle_state);
|
||||||
|
|
||||||
|
dev_info(dev, "registered %d multiplexed busses for I2C %s %s\n",
|
||||||
|
num, data->chip->muxtype == pca954x_ismux
|
||||||
|
? "mux" : "switch", client->name);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
fail_cleanup:
|
||||||
|
pca954x_cleanup(muxc);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pca954x_remove(struct i2c_client *client)
|
||||||
|
{
|
||||||
|
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||||
|
|
||||||
|
device_remove_file(&client->dev, &dev_attr_idle_state);
|
||||||
|
|
||||||
|
pca954x_cleanup(muxc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_PM_SLEEP
|
||||||
|
static int pca954x_resume(struct device *dev)
|
||||||
|
{
|
||||||
|
struct i2c_client *client = to_i2c_client(dev);
|
||||||
|
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
|
||||||
|
struct pca954x *data = i2c_mux_priv(muxc);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = pca954x_init(client, data);
|
||||||
|
if (ret < 0)
|
||||||
|
dev_err(&client->dev, "failed to verify mux presence\n");
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static SIMPLE_DEV_PM_OPS(pca954x_pm, NULL, pca954x_resume);
|
||||||
|
|
||||||
|
static struct i2c_driver pca954x_driver = {
|
||||||
|
.driver = {
|
||||||
|
.name = "ctc_pca954x",
|
||||||
|
.pm = &pca954x_pm,
|
||||||
|
.of_match_table = pca954x_of_match,
|
||||||
|
},
|
||||||
|
.probe = pca954x_probe,
|
||||||
|
.remove = pca954x_remove,
|
||||||
|
.id_table = pca954x_id,
|
||||||
|
};
|
||||||
|
|
||||||
|
module_i2c_driver(pca954x_driver);
|
||||||
|
|
||||||
|
MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
|
||||||
|
MODULE_DESCRIPTION("PCA954x I2C mux/switch driver");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* pca954x.h - I2C multiplexer/switch support
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008-2009 Rodolfo Giometti <giometti@xxxxxxxx>
|
||||||
|
* Copyright (c) 2008-2009 Eurotech S.p.A. <info@xxxxxxxxxxx>
|
||||||
|
* Michael Lawnick <michael.lawnick.ext@xxxxxxx>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef _LINUX_I2C_PCA954X_H
|
||||||
|
#define _LINUX_I2C_PCA954X_H
|
||||||
|
|
||||||
|
/* Platform data for the PCA954x I2C multiplexers */
|
||||||
|
|
||||||
|
/* Per channel initialisation data:
|
||||||
|
* @adap_id: bus number for the adapter. 0 = don't care
|
||||||
|
* @deselect_on_exit: set this entry to 1, if your H/W needs deselection
|
||||||
|
* of this channel after transaction.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
struct pca954x_platform_mode {
|
||||||
|
int adap_id;
|
||||||
|
unsigned int deselect_on_exit:1;
|
||||||
|
unsigned int class;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Per mux/switch data, used with i2c_register_board_info */
|
||||||
|
struct pca954x_platform_data {
|
||||||
|
struct pca954x_platform_mode *modes;
|
||||||
|
int num_modes;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* _LINUX_I2C_PCA954X_H */
|
@ -7,6 +7,6 @@ Standards-Version: 3.9.3
|
|||||||
|
|
||||||
Package: platform-modules-embedway-es6220
|
Package: platform-modules-embedway-es6220
|
||||||
Architecture: amd64
|
Architecture: amd64
|
||||||
Depends: linux-image-4.19.0-12-2-amd64-unsigned
|
Depends: linux-image-5.10.0-8-2-amd64-unsigned
|
||||||
Description: kernel modules for platform devices such as fan, led, sfp
|
Description: kernel modules for platform devices such as fan, led, sfp
|
||||||
|
|
||||||
|
@ -20,12 +20,16 @@ generate_version_file()
|
|||||||
|
|
||||||
if [ "$ENABLE_VERSION_CONTROL_DEB" != "y" ]; then
|
if [ "$ENABLE_VERSION_CONTROL_DEB" != "y" ]; then
|
||||||
if [[ $CONFIGURED_ARCH == armhf || $CONFIGURED_ARCH == arm64 ]]; then
|
if [[ $CONFIGURED_ARCH == armhf || $CONFIGURED_ARCH == arm64 ]]; then
|
||||||
if [ $MULTIARCH_QEMU_ENVIRON == y ]; then
|
if [ $MULTIARCH_QEMU_ENVIRON == "y" ]; then
|
||||||
# qemu arm bin executable for cross-building
|
# qemu arm bin executable for cross-building
|
||||||
sudo mkdir -p $FILESYSTEM_ROOT/usr/bin
|
sudo mkdir -p $FILESYSTEM_ROOT/usr/bin
|
||||||
sudo cp /usr/bin/qemu*static $FILESYSTEM_ROOT/usr/bin || true
|
sudo cp /usr/bin/qemu*static $FILESYSTEM_ROOT/usr/bin || true
|
||||||
fi
|
fi
|
||||||
sudo http_proxy=$HTTP_PROXY SKIP_BUILD_HOOK=y debootstrap --variant=minbase --arch $CONFIGURED_ARCH $IMAGE_DISTRO $FILESYSTEM_ROOT http://deb.debian.org/debian
|
sudo http_proxy=$HTTP_PROXY SKIP_BUILD_HOOK=y debootstrap --foreign --variant=minbase --arch $CONFIGURED_ARCH $IMAGE_DISTRO $FILESYSTEM_ROOT http://deb.debian.org/debian
|
||||||
|
sudo rm $FILESYSTEM_ROOT/proc -rf
|
||||||
|
sudo mkdir $FILESYSTEM_ROOT/proc
|
||||||
|
sudo mount -t proc proc $FILESYSTEM_ROOT/proc
|
||||||
|
sudo LANG=C chroot $FILESYSTEM_ROOT /debootstrap/debootstrap --second-stage
|
||||||
else
|
else
|
||||||
sudo http_proxy=$HTTP_PROXY SKIP_BUILD_HOOK=y debootstrap --variant=minbase --arch $CONFIGURED_ARCH $IMAGE_DISTRO $FILESYSTEM_ROOT http://debian-archive.trafficmanager.net/debian
|
sudo http_proxy=$HTTP_PROXY SKIP_BUILD_HOOK=y debootstrap --variant=minbase --arch $CONFIGURED_ARCH $IMAGE_DISTRO $FILESYSTEM_ROOT http://debian-archive.trafficmanager.net/debian
|
||||||
fi
|
fi
|
||||||
|
@ -3,7 +3,9 @@ FROM multiarch/qemu-user-static:x86_64-arm-5.0.0-2 as qemu
|
|||||||
FROM multiarch/debian-debootstrap:armhf-bullseye
|
FROM multiarch/debian-debootstrap:armhf-bullseye
|
||||||
COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin
|
COPY --from=qemu /usr/bin/qemu-arm-static /usr/bin
|
||||||
{%- elif CONFIGURED_ARCH == "arm64" and MULTIARCH_QEMU_ENVIRON == "y" %}
|
{%- elif CONFIGURED_ARCH == "arm64" and MULTIARCH_QEMU_ENVIRON == "y" %}
|
||||||
|
FROM multiarch/qemu-user-static:x86_64-aarch64-5.2.0-2 as qemu
|
||||||
FROM multiarch/debian-debootstrap:arm64-bullseye
|
FROM multiarch/debian-debootstrap:arm64-bullseye
|
||||||
|
COPY --from=qemu /usr/bin/qemu-aarch64-static /usr/bin
|
||||||
{%- else -%}
|
{%- else -%}
|
||||||
FROM debian:bullseye
|
FROM debian:bullseye
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
@ -351,6 +353,11 @@ RUN apt-get update && apt-get install -y \
|
|||||||
|
|
||||||
RUN apt-get -y build-dep openssh
|
RUN apt-get -y build-dep openssh
|
||||||
|
|
||||||
|
# Build fix for ARM64 and ARMHF /etc/debian_version
|
||||||
|
{%- if CONFIGURED_ARCH == "armhf" or CONFIGURED_ARCH == "arm64" %}
|
||||||
|
RUN apt upgrade -y base-files
|
||||||
|
{%- endif %}
|
||||||
|
|
||||||
# Build fix for ARMHF bullseye libsairedis
|
# Build fix for ARMHF bullseye libsairedis
|
||||||
{%- if CONFIGURED_ARCH == "armhf" %}
|
{%- if CONFIGURED_ARCH == "armhf" %}
|
||||||
# Install doxygen build dependency packages
|
# Install doxygen build dependency packages
|
||||||
|
Loading…
Reference in New Issue
Block a user