Skip to content

Commit

Permalink
Improve file hierarchy
Browse files Browse the repository at this point in the history
  • Loading branch information
ArashEM committed Sep 15, 2024
1 parent f512cc6 commit b011894
Show file tree
Hide file tree
Showing 15 changed files with 230 additions and 86 deletions.
18 changes: 18 additions & 0 deletions .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"/home/me/develop/mangopi-mq/kernel/linux-6.6.47/include",
"/home/me/develop/mangopi-mq/kernel/linux-6.6.47/arch/arm/include"
],
"defines": [],
"compilerPath": "/usr/bin/clang-6.0",
"cStandard": "c17",
"cppStandard": "c++14",
"intelliSenseMode": "linux-clang-x64"
}
],
"version": 4
}
8 changes: 8 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"files.associations": {
"module.h": "c",
"uio_driver.h": "c",
"device.h": "c",
"unistd.h": "c"
}
}
72 changes: 13 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,60 +1,14 @@
# Introduction
This is `uio` Linux driver for `T113-S3` PWM sub system.

# Build and deploy
1. build
```bash
export KBUILDDIR=<KERNEL BUILD DIR>
export ARCH=arm
export CROSS_COMPILE=arm-none-eabi-
make
```
2. Copy `sun20i-pwm-uio.ko` to proper directory in target rootfs (e.g. `/lib/modules/6.6.47/kernel/drivers/pwm/`)
3. run `depmod -a` in target to update `module.alias` and `module.dep`

# DTS
In order to instantiate this driver, add following lines to `sun8i-t113s-mangopi-mq-r-t113.dts` file.
We need `pinctrl` to configure _PWM_ pins for this kernel module.
```
&pio {
/omit-if-no-ref/
pwm2_pe8_pin: pwm2-pe8-pin {
pins = "PE8";
function = "pwm2";
};

/omit-if-no-ref/
pwm3_pe9_pin: pwm3-pe9-pin {
pins = "PE9";
function = "pwm3";
};

/omit-if-no-ref/
pwm4_pe10_pin: pwm4-pe10-pin {
pins = "PE10";
function = "pwm4";
};

/omit-if-no-ref/
pwm5_pe13_pin: pwm5-pe13-pin {
pins = "PE13";
function = "pwm5";
};
};

&soc {
pwm_uio: pwm_uio@2000c00 {
compatible = "allwinner,sun20i-pwm-uio";
reg = <0x2000c00 0x400>;
interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_BUS_PWM>, <&dcxo>;
clock-names = "bus", "mod";
resets = <&ccu RST_BUS_PWM>;
pinctrl-0 = <&pwm2_pe8_pin>,
<&pwm3_pe9_pin>,
<&pwm4_pe10_pin>,
<&pwm5_pe13_pin>;
pinctrl-names = "default";
};
};
```
This repository includes `uio` driver for `T113-S3 PWM` peripheral.

# Directories
- `driver`: kernel space driver
It's basically platform device which is registered into `uio` framework. All register handling is done in user space.
- `lib`: user space library
Shared library for interfacing with `PWM` peripheral.
- `app`: user space application
User space application which implement simple use case of library APIs.

# Links
1. [UIO howto](https://www.kernel.org/doc/html/v4.14/driver-api/uio-howto.html)
2. [UIO generic driver for platform device](https://elixir.bootlin.com/linux/v6.10.9/source/drivers/uio/uio_pdrv_genirq.c)
File renamed without changes.
10 changes: 10 additions & 0 deletions app/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"files.associations": {
"types.h": "c",
"mman.h": "c",
"fcntl.h": "c",
"errno.h": "c",
"errno-base.h": "c",
"pwm.h": "c"
}
}
File renamed without changes.
31 changes: 13 additions & 18 deletions uio-app/main.c → app/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,38 +13,33 @@ int main() {
// volatile u_int32_t *base = p + 0xc00;
p += 0xc00;

//base[0x40 / 4] = 0x04; // PWM2 gating
//base[0x24 / 4] = 0x04; // 24Mhz / 256
//base[0x40 / 4] = 0x40004; // PWM2 bypass
//base[0x80 / 4] = 0x04; // PWM2 enable

//writel(p + PCGR_OFFSET, PWMx_CLK_GATING(3));
//writel(p + PCCR23_OFFSET, 0x06);
//writel(p + PCGR_OFFSET, PWMx_CLK_GATING(3) | PWMx_CLK_BYPASS(3));
//writel(p + PER_OFFSET, PWMx_EN(3));

uint8_t ch = 3;
// Ch 2 as PWM generator
uint8_t ch = 2;
clk_gate(p, ch, true);

struct pwm_clk clk = {.src = HOSC, .div = DIV_32 };
clk_config(p, ch, clk);
struct pwm_period prd = {.entire = 1000 - 1, .act = 151};
set_period(p, ch, prd);
set_prescaler(p, ch, 49);
set_act_state(p, ch, ACT_HIGH);

pwm_en(p, ch, true);

// Ch 3 as Capture rising edge only
ch = 3;
clk_gate(p, ch, true);
clk.div = DIV_2;
clk_config(p, ch, clk);
set_prescaler(p, ch, 49);
cap_en(p, ch, true, false);

size_t i = 0;
bool en = true;
while( i < 20) {
while( i < 10 ) {
sleep(1);
en = !en;
pwm_en(p, ch, en);
++i;
printf("i: %d, en: %x\n", i, en);
}


munmap(p, 4096);
close(fd);
return 0;
Expand Down
117 changes: 108 additions & 9 deletions uio-app/pwm.h → app/pwm.h
Original file line number Diff line number Diff line change
Expand Up @@ -208,36 +208,135 @@ inline int32_t set_act_state(void *p, uint8_t ch, enum act_state state)
*
* @param base Base address of PWM peripheral
* @param ch Channel index [0, 7]
* @param irq true: Interrupt on rising and falling edge detection
* @return int32_t
* @param rising Enable / Disable rising edge IRQ
* @param falling Enable / Disable falling edge IRQ
* @return int32_t 0 on success
*/
inline int32_t set_cap_irq(void *p, uint8_t ch, bool irq)
inline int32_t en_cap_irq(void *p, uint8_t ch, bool rising, bool falling)
{
if(check_ch(ch))
return -EINVAL;

rmwb(p + CIER_OFFSET, CRIEx(ch) | CFIEx(ch), irq);
rmwb(p + CIER_OFFSET, CRIEx(ch), rising);
rmwb(p + CIER_OFFSET, CFIEx(ch), falling);

return 0;
}

/**
* @brief Enable / Disable capture mode
*
* @param base Base address of PWM peripheral
* @param ch Channel index [0, 7]
* @param rising Enable / Disable rising edge capture mode
* @param falling Enable / Disable falling edge capture mode
* @return int32_t
* @note This function do not check if PWM mode is enabled or not!
*/
inline int32_t cap_en(void *p, uint8_t ch, bool rising, bool falling)
{
if(check_ch(ch))
return -EINVAL;

rmwb(p + CER_OFFSET, CAPx_EN(ch), rising | falling);
rmwb(p + PWM_REG_OFFSET(CCR_OFFSET, ch), CRTE, rising);
rmwb(p + PWM_REG_OFFSET(CCR_OFFSET, ch), CFTE, falling);

return 0;
}

/**
* @brief Clear Falling or Rising edge IRQ flag
*
* @param base Base address of PWM peripheral
* @param ch Channel index [0, 7]
* @param rising true: Clear rising edge IRQ flag
* @param falling true: Clear rising edge IRQ flag
* @return int32_t
*/
inline int32_t clear_cap_irq(void *p, uint8_t ch, bool rising, bool falling)
{
if(check_ch(ch))
return -EINVAL;

if(rising) {
rmwb(p + CISR_OFFSET, CRISx(ch), false);
rmwb(p + PWM_REG_OFFSET(CCR_OFFSET, ch), CRLF, false);
}

if(falling) {
rmwb(p + CISR_OFFSET, CFISx(ch), false);
rmwb(p + PWM_REG_OFFSET(CCR_OFFSET, ch), CFLF, false);
}

return 0;
}

/**
* @brief Report current IRQ flag
*
* @param base Base address of PWM peripheral
* @param ch Channel index [0, 7]
* @param rising Report rising edge flag
* @param falling Report falling edge flag
* @return int32_t
*/
inline int32_t cap_irq(void *p, uint8_t ch, bool *rising, bool *falling)
{
if(check_ch(ch))
return -EINVAL;

if(!rising | !falling)
return -EFAULT;

uint32_t reg = readl(p + CISR_OFFSET);

*rising = IS_SET(reg, CRISx(ch));
*falling = IS_SET(reg, CFISx(ch));

return 0;
}

/**
* @brief Report rising lock register
*
* @param p
* @param ch
* @param en
* @param rlock
* @return int32_t
*/
inline int32_t cap_en(void *p, uint8_t ch, bool en)
inline int32_t cap_rising_lock(void *p, uint8_t ch, uint16_t *rlock)
{
if(check_ch(ch))
return -EINVAL;

rmwb(p + CER_OFFSET, CAPx_EN(ch), en);
if(!rlock)
return -EFAULT;

uint32_t reg = readl(p + PWM_REG_OFFSET(CRLR_OFFSET, ch));
*rlock = CRLR(reg);

return 0;
}

/**
* @brief Report Fall lock register
*
* @param p
* @param ch
* @param flock
* @return int32_t
*/
inline int32_t cap_falling_lock(void *p, uint8_t ch, uint16_t *flock)
{
if(check_ch(ch))
return -EINVAL;

if(!flock)
return -EFAULT;

/* enable capture mode */
rmwb(p + CIER_OFFSET, CFIEx(ch) | CRIEx(ch), en);
uint32_t reg = readl(p + PWM_REG_OFFSET(CFLR_OFFSET, ch));
*flock = CFLR(reg);

return 0;
}
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
60 changes: 60 additions & 0 deletions driver/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Introduction
This is `uio` Linux driver for `T113-S3` PWM sub system.

# Build and deploy
1. build
```bash
export KBUILDDIR=<KERNEL BUILD DIR>
export ARCH=arm
export CROSS_COMPILE=arm-none-eabi-
make
```
2. Copy `sun20i-pwm-uio.ko` to proper directory in target rootfs (e.g. `/lib/modules/6.6.47/kernel/drivers/pwm/`)
3. run `depmod -a` in target to update `module.alias` and `module.dep`

# DTS
In order to instantiate this driver, add following lines to `sun8i-t113s-mangopi-mq-r-t113.dts` file.
We need `pinctrl` to configure _PWM_ pins for this kernel module.
```
&pio {
/omit-if-no-ref/
pwm2_pe8_pin: pwm2-pe8-pin {
pins = "PE8";
function = "pwm2";
};

/omit-if-no-ref/
pwm3_pe9_pin: pwm3-pe9-pin {
pins = "PE9";
function = "pwm3";
};

/omit-if-no-ref/
pwm4_pe10_pin: pwm4-pe10-pin {
pins = "PE10";
function = "pwm4";
};

/omit-if-no-ref/
pwm5_pe13_pin: pwm5-pe13-pin {
pins = "PE13";
function = "pwm5";
};
};

&soc {
pwm_uio: pwm_uio@2000c00 {
compatible = "allwinner,sun20i-pwm-uio";
reg = <0x2000c00 0x400>;
interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_BUS_PWM>, <&dcxo>;
clock-names = "bus", "mod";
resets = <&ccu RST_BUS_PWM>;
pinctrl-0 = <&pwm2_pe8_pin>,
<&pwm3_pe9_pin>,
<&pwm4_pe10_pin>,
<&pwm5_pe13_pin>;
pinctrl-names = "default";
};
};
```
File renamed without changes.

0 comments on commit b011894

Please sign in to comment.