PWM (TPU) Driver probe.

Hi,

 

I am analysing the TPU driver of renesas in linux BSP.

There is function

"static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *_pwm,  int duty_ns, int period_ns)"

Every time when I changed the duty cycle this fuction is called. And during boot , driver probe this function also called.

I put the prints top see the value of duty_ns and period_ns.

And another thing is there is calculation of actual period which need to be written to register.

These are observation.

 

root@G21M:~# echo 1 > /sys/class/backlight/fan.8/brightness                                                                     

tpu_pwm_config: clk_rate : 10000000 duty_ns: 78431 period_ns:5000000

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 784 channel 1


tpu_pwm_enable 1:

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 1, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE:

 tpu_pwm_write: value: 0, reg e78d2058
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  

 tpu_pwm_write: value: 64, reg e78d2050
 tpu_pwm_write: value: 2, reg e78d2054
tpu_pwm_set_pin : pwm->channel 1, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2058
 tpu_pwm_write: value: 784, reg e78d2068
 tpu_pwm_write: value: 50000, reg e78d206c
tpu_pwm_timer_start: pwm->channel 1, pwm->duty 0x0310  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x2  
 


root@G21M:~# echo 2 > /sys/class/backlight/fan.8/brightness                                                                     

tpu_pwm_config: clk_rate : 10000000 duty_ns: 156862 period_ns:5000000

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 1568 channel 1


ntpu_pwm_config::  if (duty_only && pwm->timer_on)

 tpu_pwm_write: value: 1568, reg e78d2068root@iWave-G21M:~#

 


root@G21M:~# echo 3 > /sys/class/backlight/fan.8/brightness                                                                     

tpu_pwm_config: clk_rate : 10000000 duty_ns: 313725 period_ns:5000000

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 3137 channel 1


ntpu_pwm_config::  if (duty_only && pwm->timer_on)

 tpu_pwm_write: value: 3137, reg e78d2068

 

 


root@iG21M:~# echo 4 > /sys/class/backlight/fan.8/brightness                                                                     

tpu_pwm_config: clk_rate : 10000000 duty_ns: 627450 period_ns:5000000

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 6277 channel 1


ntpu_pwm_config::  if (duty_only && pwm->timer_on)

 tpu_pwm_write: value: 6277, reg e78d2068

 

 


root@G21M:~# echo 5 > /sys/class/backlight/fan.8/brightness                                                                     

tpu_pwm_config: clk_rate : 10000000 duty_ns: 1254901 period_ns:5000000

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 12562 channel 1


ntpu_pwm_config::  if (duty_only && pwm->timer_on)

 tpu_pwm_write: value: 12562, reg e78d2068root@iWave-G21M:~#

 

 

 


root@G21M:~# echo 6 > /sys/class/backlight/fan.8/brightness                                                                     

tpu_pwm_config: clk_rate : 10000000 duty_ns: 2509803 period_ns:5000000

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 25125 channel 1


ntpu_pwm_config::  if (duty_only && pwm->timer_on)

 tpu_pwm_write: value: 25125, reg e78d2068root@iWave-G21M:~#

 

 


root@-G21M:~# echo 7 > /sys/class/backlight/fan.8/brightness                                                                     

tpu_pwm_config: clk_rate : 10000000 duty_ns: 5000000 period_ns:5000000

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 50000 channel 1


ntpu_pwm_config::  if (duty_only && pwm->timer_on)

 tpu_pwm_write: value: 50000, reg e78d2068
ntpu_pwm_config:: if (duty == 0 || duty == period)

tpu_pwm_set_pin : pwm->channel 1, state active  

tpu_pwm_set_pin: case TPU_PIN_ACTIVE:

 tpu_pwm_write: value: 4, reg e78d2058
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x2  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  
root@G21M:~#

Frequency = 1/Period.

But in my case it is clk_rate : 10000000 period_ns:5000000 

Is this correct??

 

I need to know where driver probe happening and from where duty_ns and period_ns coming for following.

"static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *_pwm,  int duty_ns, int period_ns)"

 

If I changed the clock rate , then where I need to change  period_ns ?

In my DTS this is the content

        fan {
                compatible = "pwm-backlight";
                pwms = <&tpu 1 5000000 GPIO_ACTIVE_HIGH>;
                brightness-levels = <0 4 8 16 32 64 128 255>;
                default-brightness-level = <7>;
                pinctrl-0 = <&fan_pins>;
                pinctrl-names = "default";
        };

I also need to know from where  duty_ns value will come to tpu_pwm_config() function.

When I entered the levels 1-7 the value of duty_ns is  0, 78431, 156862, 313725, 627450,1254901,2509803,5000000 respectively.

When I looked into driver once again duty cycle is calculated

                duty = clk_rate / prescalers[prescaler]
                     / (NSEC_PER_SEC / duty_ns);

For level 7 value coming is 5000000 and after above calculation it is duty 50000.

This will write to register TPU_TGRA register which is of 16 bit register and max value will be 65535. But why it is 50000 (only level 7)??

        tpu_pwm_write(pwm, TPU_TGRAn, pwm->duty);
        tpu_pwm_write(pwm, TPU_TGRBn, pwm->period);

 

 I want to understand the driver functionality.

github.com/.../pwm-renesas-tpu.c

linux_tpu_pwm_boot.txt
nctrl core: initialized pinctrl subsystem
regulator-dummy: no parameters
NET: Registered protocol family 16
DMA: preallocated 256 KiB pool for atomic coherent allocations
renesas_irqc e61c0000.interrupt-controller: driving 4 irqs
sh-pfc e6060000.pfc: r8a7742_pfc support registered

Board Info:
        BSP Version     : iW-PREXZ-SC-01-R2.0-REL1.0-Linux3.10.31-PATCH015a
        SOM Version     : iW-PREXZ-AP-01-R4.2

No ATAGs?
hw-breakpoint: found 5 (+1 reserved) breakpoint and 4 watchpoint registers.
hw-breakpoint: maximum watchpoint size is 8 bytes.
bio: create slab <bio-0> at 0
gpio_rcar e6050000.gpio: driving 32 GPIOs
gpio_rcar e6051000.gpio: driving 32 GPIOs
gpio_rcar e6052000.gpio: driving 32 GPIOs
gpio_rcar e6053000.gpio: driving 32 GPIOs
gpio_rcar e6054000.gpio: driving 32 GPIOs
gpio_rcar e6055000.gpio: driving 32 GPIOs
1P0V: 1000 mV 
fixed-2.5V: 2500 mV 
fixed-3.3V: 3300 mV 
SDHI2 Vcc: 3300 mV 
SDHI2 VccQ: 1800 <--> 3300 mV at 3300 mV 
SCSI subsystem initialized
libata version 3.00 loaded.
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
i2c-rcar e6508000.i2c: probed
i2c-rcar e6518000.i2c: probed
i2c-rcar e6530000.i2c: probed
i2c-rcar e6540000.i2c: probed
media: Linux media interface: v0.10
Linux video capture interface: v2.00
pps_core: LinuxPPS API ver. 1 registered
pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
PTP clock support registered
sh_cmt sh_cmt.0: used for clock events
Advanced Linux Sound Architecture Driver Initialized.
Bluetooth: Core ver 2.16
NET: Registered protocol family 31
Bluetooth: HCI device and connection manager initialized
Bluetooth: HCI socket layer initialized
Bluetooth: L2CAP socket layer initialized
Bluetooth: SCO socket layer initialized
Switching to clocksource arch_sys_counter
NET: Registered protocol family 2
TCP established hash table entries: 8192 (order: 4, 65536 bytes)
TCP bind hash table entries: 8192 (order: 4, 65536 bytes)
TCP: Hash tables configured (established 8192 bind 8192)
TCP: reno registered
UDP hash table entries: 512 (order: 2, 16384 bytes)
UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
NET: Registered protocol family 1
RPC: Registered named UNIX socket transport module.
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
PCI: CLS 0 bytes, default 64
bounce pool size: 64 pages
NFS: Registering the id_resolver key type
Key type id_resolver registered
Key type id_legacy registered
jffs2: version 2.2. (NAND) �© 2001-2006 Red Hat, Inc.
msgmni has been set to 1198
Block layer SCSI generic (bsg) driver version 0.4 loaded (major 249)
io scheduler noop registered
io scheduler deadline registered
io scheduler cfq registered (default)
renesas-tpu-pwm e60f0000.pwm: TPU PWM -1 registered
unable to find transceiver
platform pci-rcar-gen2.1: Driver pci-rcar-gen2 requests probe deferral

tpu_pwm_request:

tpu_pwm_set_polarity: pwm->polarity 0 

tpu_pwm_config: clk_rate : 10000000 duty_ns: 5000000 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 50000 channel 0


tpu_pwm_enable 1:

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 0, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2018
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 0, value 0x0  

 tpu_pwm_write: value: 64, reg e78d2010
 tpu_pwm_write: value: 2, reg e78d2014
tpu_pwm_set_pin : pwm->channel 0, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2018
 tpu_pwm_write: value: 50000, reg e78d2028
 tpu_pwm_write: value: 50000, reg e78d202c
tpu_pwm_timer_start: pwm->channel 0, pwm->duty 0xc350  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 0, value 0x1  

tpu_pwm_enable 2:

tpu_pwm_set_pin : pwm->channel 0, state active  

tpu_pwm_set_pin: case TPU_PIN_ACTIVE:

 tpu_pwm_write: value: 4, reg e78d2018
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x1  

tpu_pwm_start_stop:pwm->channel 0, value 0x0  

tpu_pwm_request:

tpu_pwm_set_polarity: pwm->polarity 0 

tpu_pwm_config: clk_rate : 10000000 duty_ns: 5000000 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 50000 channel 1


tpu_pwm_enable 1:

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 1, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2058
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  

 tpu_pwm_write: value: 64, reg e78d2050
 tpu_pwm_write: value: 2, reg e78d2054
tpu_pwm_set_pin : pwm->channel 1, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2058
 tpu_pwm_write: value: 50000, reg e78d2068
 tpu_pwm_write: value: 50000, reg e78d206c
tpu_pwm_timer_start: pwm->channel 1, pwm->duty 0xc350  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x2  

tpu_pwm_enable 2:

tpu_pwm_set_pin : pwm->channel 1, state active  

tpu_pwm_set_pin: case TPU_PIN_ACTIVE:

 tpu_pwm_write: value: 4, reg e78d2058
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x2  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  

tpu_pwm_request:

tpu_pwm_set_polarity: pwm->polarity 0 

tpu_pwm_config: clk_rate : 10000000 duty_ns: 5000000 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 50000 channel 2


tpu_pwm_enable 1:

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 2, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2098
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 2, value 0x0  

 tpu_pwm_write: value: 64, reg e78d2090
 tpu_pwm_write: value: 2, reg e78d2094
tpu_pwm_set_pin : pwm->channel 2, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2098
 tpu_pwm_write: value: 50000, reg e78d20a8
 tpu_pwm_write: value: 50000, reg e78d20ac
tpu_pwm_timer_start: pwm->channel 2, pwm->duty 0xc350  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 2, value 0x4  

tpu_pwm_enable 2:

tpu_pwm_set_pin : pwm->channel 2, state active  

tpu_pwm_set_pin: case TPU_PIN_ACTIVE:

 tpu_pwm_write: value: 4, reg e78d2098
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x4  

tpu_pwm_start_stop:pwm->channel 2, value 0x0  
SuperH (H)SCI(F) driver initialized
e6c60000.serial: ttySC2 at MMIO 0xe6c60000 (irq = 183) is a scifa
console [ttySC2] enabled
e6c30000.serial: ttySC3 at MMIO 0xe6c30000 (irq = 181) is a scifb
e6ce0000.serial: ttySC4 at MMIO 0xe6ce0000 (irq = 182) is a scifb
e6e60000.serial: ttySC0 at MMIO 0xe6e60000 (irq = 184) is a scif
e6e68000.serial: ttySC1 at MMIO 0xe6e68000 (irq = 185) is a scif
e62c0000.serial: ttySC5 at MMIO 0xe62c0000 (irq = 186) is a hscif
[drm] Initialized drm 1.1.0 20060810
Console: switching to colour frame buffer device 100x30
rcar-du rcar-du-r8a7742: fb0:  frame buffer device
rcar-du rcar-du-r8a7742: registered panic notifier
rcar-du rcar-du-r8a7742: CRTC[0] used by FBDev
[drm] Supports vblank timestamp caching Rev 1 (10.10.2010).
[drm] No driver support for vblank timestamp query.
[drm] Initialized rcar-du 1.0.0 20130110 on minor 0
scsi0 : sata_rcar
ata1: SATA max UDMA/133 irq 138
m25p80 spi1.0: sst25vf016b (2048 Kbytes)
CAN device driver interface
rcar_can e6e80000.can: device registered (reg_base=e793a000, irq=218)
rcar_can e6e88000.can: device registered (reg_base=e793c000, irq=219)
libphy: sh_mii: probed
sh-eth ee700000.ethernet eth0: Base address at 0xee700000, 00:01:02:03:04:05, IRQ 194.
ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
ehci-pci: EHCI PCI platform driver
ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
xhci-hcd ee000000.xhci: xHCI Host Controller
xhci-hcd ee000000.xhci: new USB bus registered, assigned bus number 1
xhci-hcd ee000000.xhci: irq 133, io mem 0xee000000
xHCI xhci_add_endpoint called for root hub
xHCI xhci_check_bandwidth called for root hub
hub 1-0:1.0: USB hub found
hub 1-0:1.0: 1 port detected
xhci-hcd ee000000.xhci: xHCI Host Controller
xhci-hcd ee000000.xhci: new USB bus registered, assigned bus number 2
xHCI xhci_add_endpoint called for root hub
xHCI xhci_check_bandwidth called for root hub
hub 2-0:1.0: USB hub found
hub 2-0:1.0: 1 port detected
usbcore: registered new interface driver usb-storage
renesas_usbhs renesas_usbhs: host probed
renesas_usbhs renesas_usbhs: usb_phy_rcar_gen2 transceiver found
renesas_usbhs renesas_usbhs: gadget probed
renesas_usbhs renesas_usbhs: probed
mousedev: PS/2 mouse device common for all mice
ata1: link resume succeeded after 1 retries
ata1: SATA link down (SStatus 0 SControl 300)
edt_ft5x06 2-0038: touchscreen probe failed
rtc-pcf85263 0-0051: Oscillator stop detected, date/time is not reliable.
rtc-pcf85263 0-0051: No century in NVRAM - assume 2000
rtc-pcf85263 0-0051: Oscillator stop detected, date/time is not reliable.
rtc-pcf85263 0-0051: rtc core: registered rtc-pcf85263 as rtc0
rtc-pcf85263 0-0051: PCF85263 RTC (irqpin=None irq=0)
i2c /dev entries driver
soc-camera-pdrv soc-camera-pdrv.0: Probing soc-camera-pdrv.0
ov5640 0-003c: ov5640_read: i2c read error, reg: 300a
camera ov5640 is not found
soc-camera-pdrv soc-camera-pdrv.1: Probing soc-camera-pdrv.1
ov5640 1-003c: ov5640_read: i2c read error, reg: 300a
camera ov5640 is not found
soc-camera-pdrv soc-camera-pdrv.2: Probing soc-camera-pdrv.2
ov5640 2-003c: ov5640_read: i2c read error, reg: 300a
camera ov5640 is not found
soc-camera-pdrv soc-camera-pdrv.3: Probing soc-camera-pdrv.3
ov5640 3-003c: ov5640_read: i2c read error, reg: 300a
camera ov5640 is not found
rcar_thermal e61f0000.thermal: 1 sensor probed
sh_mobile_sdhi sdhi2: Got CD GPIO #918.
sh_mobile_sdhi sdhi2: Got WP GPIO #919.
sh_mobile_sdhi sdhi2: mmc0 base at 0xee140000 clock rate 86 MHz
sh_mmcif sh_mmcif: driver version 2010-04-28
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
platform sound.6: Driver asoc-simple-card requests probe deferral
rcar_sound ec500000.rcar_sound: probed
TCP: cubic registered
NET: Registered protocol family 17
can: controller area network core (rev 20120528 abi 9)
NET: Registered protocol family 29
can: raw protocol (rev 20120528)
can: broadcast manager protocol (rev 20120528 t)
can: netlink gateway (rev 20130117) max_hops=1
Key type dns_resolver registered
VFP support v0.3: implementor 41 architecture 4 part 30 variant f rev 0
pci-rcar-gen2 pci-rcar-gen2.1: PCI: bus0 revision 11
pci-rcar-gen2 pci-rcar-gen2.1: PCI host bridge to bus 0001:01
pci_bus 0001:01: root bus resource [io  0xee0a0000-0xee0affff]
pci_bus 0001:01: root bus resource [mem 0xee0a0000-0xee0affff]
pci_bus 0001:01: No busn resource found for root bus, will use [bus 01-ff]
pci 0001:01:00.0: [1033:0000] type 00 class 0x060000
pci 0001:01:00.0: reg 10: [mem 0xee0b0800-0xee0b0bff]
pci 0001:01:00.0: reg 14: [mem 0x40000000-0x7fffffff pref]
pci 0001:01:01.0: [1033:0035] type 00 class 0x0c0310
pci 0001:01:01.0: reg 10: [mem 0x00000000-0x00000fff]
pci 0001:01:01.0: supports D1 D2
pci 0001:01:01.0: PME# supported from D0 D1 D2 D3hot
pci 0001:01:02.0: [1033:00e0] type 00 class 0x0c0320
pci 0001:01:02.0: reg 10: [mem 0x00000000-0x000000ff]
pci 0001:01:02.0: supports D1 D2
pci 0001:01:02.0: PME# supported from D0 D1 D2 D3hot
PCI: bus1: Fast back to back transfers disabled
pci_bus 0001:01: busn_res: [bus 01-ff] end is updated to 01
PCI: Device 0001:01:01.0 not available because of resource collisions
pci 0001:01:01.0: Can't enable PCI device, BIOS handoff failed.
PCI: Device 0001:01:01.0 not available because of resource collisions
pci 0001:01:01.0: Driver ohci_hcd requests probe deferral
PCI: Device 0001:01:02.0 not available because of resource collisions
pci 0001:01:02.0: Can't enable PCI device, BIOS handoff failed.
PCI: Device 0001:01:02.0 not available because of resource collisions
pci 0001:01:02.0: Driver ehci-pci requests probe deferral
pci 0001:01:01.0: BAR 0: assigned [mem 0xee0a0000-0xee0a0fff]
mmc0: new ultra high speed SDR50 SDHC card at address e624
mmcblk0: mmc0:e624 SS08G 7.40 GiB 
 mmcblk0: p1
pci 0001:01:02.0: BAR 0: assigned [mem 0xee0a1000-0xee0a10ff]
sgtl5000 2-000a: sgtl5000 revision 0x11
2-000a: 1200 mV normal 
sgtl5000 2-000a: Using internal LDO instead of VDDD
Headphone is unplugged
Microphone is unplugged
asoc-simple-card sound.6:  sgtl5000 <-> ec500000.rcar_sound mapping ok
PCI: enabling device 0001:01:01.0 (0140 -> 0142)
ohci_hcd 0001:01:01.0: OHCI Host Controller
ohci_hcd 0001:01:01.0: new USB bus registered, assigned bus number 3
ohci_hcd 0001:01:01.0: irq 144, io mem 0xee0a0000
hub 3-0:1.0: USB hub found
hub 3-0:1.0: 1 port detected
PCI: enabling device 0001:01:02.0 (0140 -> 0142)
ehci-pci 0001:01:02.0: EHCI Host Controller
ehci-pci 0001:01:02.0: new USB bus registered, assigned bus number 4
ehci-pci 0001:01:02.0: irq 144, io mem 0xee0a1000
ehci-pci 0001:01:02.0: USB 2.0 started, EHCI 1.00
hub 4-0:1.0: USB hub found
hub 4-0:1.0: 1 port detected
rtc-pcf85263 0-0051: Oscillator stop detected, date/time is not reliable.
rtc-pcf85263 0-0051: hctosys: unable to read the hardware clock
ALSA device list:
  #0: rsnd-dai.0-sgtl5000
Waiting for root device /dev/mmcblk1p2...
usb 4-1: new high-speed USB device number 2 using ehci-pci
hub 4-1:1.0: USB hub found
hub 4-1:1.0: 2 ports detected
sh_mmcif sh_mmcif: DMA timeout!
mmc1: new high speed MMC card at address 0001
mmcblk1: mmc1:0001 DG4008 7.28 GiB 
mmcblk1boot0: mmc1:0001 DG4008 partition 1 4.00 MiB
mmcblk1boot1: mmc1:0001 DG4008 partition 2 4.00 MiB
 mmcblk1: p1 p2
 mmcblk1boot1: unknown partition table
 mmcblk1boot0: unknown partition table
kjournald starting.  Commit interval 5 seconds
EXT3-fs (mmcblk1p2): using internal journal
EXT3-fs (mmcblk1p2): recovery complete
EXT3-fs (mmcblk1p2): mounted filesystem with ordered data mode
VFS: Mounted root (ext3 filesystem) on device 179:10.
devtmpfs: mounted
Freeing unused kernel memory: 452K (c0647000 - c06b8000)
INIT: version 2.88 booting
Starting udev
udevd[936]: starting version 182
FAT-fs (mmcblk0p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
FAT-fs (mmcblk1p1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.
Starting Bootlog daemon: bootlogd: cannot allocate pseudo tty: No such file or directory
bootlogd.
ALSA: Restoring mixer settings...
Wed Nov  1 12:04:00 UTC 2017
INIT: Entering runlevel: 5
Configuring network interfaces... sh-eth ee700000.ethernet eth0: attached PHY 1 (IRQ 417) to driver Micrel KSZ8081 or KSZ8091
udhcpc (v1.22.1) started
Sending discover...
Sending discover...
Sending discover...
No lease, failing
ifconfig: SIOCGIFFLAGS: No such device
Starting Xserver
Starting system message bus: dbus.
Starting Connection Manager
PVR_SRVKM_PARAMS=
PVR_K: RGX use system memory.
pvrsrvkm: Power-on latency exceeded, new value 77000 ns
pvrsrvkm pvrsrvkm: start latency exceeded, new value 7700 ns
pvrsrvkm pvrsrvkm: state restore latency exceeded, new value 1300 ns
PVR_K: Compatibility checks: Ignoring fields: 'C' of HW BVNC.

tpu_pwm_config: clk_rate : 10000000 duty_ns: 0 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 0 channel 0


ntpu_pwm_config::  if (duty_only && pwm->timer_on) ELSE

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 0, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2018
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 0, value 0x0  

 tpu_pwm_write: value: 64, reg e78d2010
 tpu_pwm_write: value: 2, reg e78d2014
tpu_pwm_set_pin : pwm->channel 0, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2018
 tpu_pwm_write: value: 0, reg e78d2028
 tpu_pwm_write: value: 50000, reg e78d202c
tpu_pwm_timer_start: pwm->channel 0, pwm->duty 0x0000  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 0, value 0x1  

ntpu_pwm_config:: if (duty == 0 || duty == period) 

tpu_pwm_set_pin : pwm->channel 0, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2018
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x1  

tpu_pwm_start_stop:pwm->channel 0, value 0x0  

tpu_pwm_disable:

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 0, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2018
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 0, value 0x0  

 tpu_pwm_write: value: 64, reg e78d2010
 tpu_pwm_write: value: 2, reg e78d2014
tpu_pwm_set_pin : pwm->channel 0, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2018
 tpu_pwm_write: value: 0, reg e78d2028
 tpu_pwm_write: value: 50000, reg e78d202c
tpu_pwm_timer_start: pwm->channel 0, pwm->duty 0x0000  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 0, value 0x1  

tpu_pwm_set_pin : pwm->channel 0, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2018
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x1  

tpu_pwm_start_stop:pwm->channel 0, value 0x0  

tpu_pwm_config: clk_rate : 10000000 duty_ns: 0 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 0 channel 1


ntpu_pwm_config::  if (duty_only && pwm->timer_on) ELSE

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 1, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2058
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  

 tpu_pwm_write: value: 64, reg e78d2050
 tpu_pwm_write: value: 2, reg e78d2054
tpu_pwm_set_pin : pwm->channel 1, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2058
 tpu_pwm_write: value: 0, reg e78d2068
 tpu_pwm_write: value: 50000, reg e78d206c
tpu_pwm_timer_start: pwm->channel 1, pwm->duty 0x0000  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x2  

ntpu_pwm_config:: if (duty == 0 || duty == period) 

tpu_pwm_set_pin : pwm->channel 1, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2058
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x2  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  

tpu_pwm_disable:

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 1, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2058
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  

 tpu_pwm_write: value: 64, reg e78d2050
 tpu_pwm_write: value: 2, reg e78d2054
tpu_pwm_set_pin : pwm->channel 1, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2058
 tpu_pwm_write: value: 0, reg e78d2068
 tpu_pwm_write: value: 50000, reg e78d206c
tpu_pwm_timer_start: pwm->channel 1, pwm->duty 0x0000  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x2  

tpu_pwm_set_pin : pwm->channel 1, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2058
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x2  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  

tpu_pwm_config: clk_rate : 10000000 duty_ns: 0 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 0 channel 2


ntpu_pwm_config::  if (duty_only && pwm->timer_on) ELSE

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 2, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2098
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 2, value 0x0  

 tpu_pwm_write: value: 64, reg e78d2090
 tpu_pwm_write: value: 2, reg e78d2094
tpu_pwm_set_pin : pwm->channel 2, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2098
 tpu_pwm_write: value: 0, reg e78d20a8
 tpu_pwm_write: value: 50000, reg e78d20ac
tpu_pwm_timer_start: pwm->channel 2, pwm->duty 0x0000  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 2, value 0x4  

ntpu_pwm_config:: if (duty == 0 || duty == period) 

tpu_pwm_set_pin : pwm->channel 2, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2098
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x4  

tpu_pwm_start_stop:pwm->channel 2, value 0x0  

tpu_pwm_disable:

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 2, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2098
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 2, value 0x0  

 tpu_pwm_write: value: 64, reg e78d2090
 tpu_pwm_write: value: 2, reg e78d2094
tpu_pwm_set_pin : pwm->channel 2, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2098
 tpu_pwm_write: value: 0, reg e78d20a8
 tpu_pwm_write: value: 50000, reg e78d20ac
tpu_pwm_timer_start: pwm->channel 2, pwm->duty 0x0000  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 2, value 0x4  

tpu_pwm_set_pin : pwm->channel 2, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2098
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x4  

tpu_pwm_start_stop:pwm->channel 2, value 0x0  
 dc_linuxfb - Found usable fbdev device ():
  range (physical) = 0x5f100000-0x5f565000
  size (bytes)     = 0x465000
  xres x yres      = 800x480
  xres x yres (v)  = 800x1440
  img pix fmt      = 83
  num buffers      = 3
Loaded PowerVR consumer services.
Starting Dropbear SSH server: dropbear.
Starting rpcbind daemon...rpcbind: cannot create socket for udp6
rpcbind: cannot create socket for tcp6
done.
Starting advanced power management daemon: No APM support in kernel
(failed.)
Starting syslogd/klogd: done
 * Starting Avahi mDNS/DNS-SD Daemon: avahi-daemon

tpu_pwm_config: clk_rate : 10000000 duty_ns: 5000000 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 50000 channel 0


tpu_pwm_enable 1:

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 0, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2018
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 0, value 0x0  
   ...done.

 tpu_pwm_write: value: 64, reg e78d2010
 tpu_pwm_write: value: 2, reg e78d2014
tpu_pwm_set_pin : pwm->channel 0, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2018
 tpu_pwm_write: value: 50000, reg e78d2028
 tpu_pwm_write: value: 50000, reg e78d202c
tpu_pwm_timer_start: pwm->channel 0, pwm->duty 0xc350  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 0, value 0x1  

tpu_pwm_enable 2:

tpu_pwm_set_pin : pwm->channel 0, state active  

tpu_pwm_set_pin: case TPU_PIN_ACTIVE:

 tpu_pwm_write: value: 4, reg e78d2018
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x1  

tpu_pwm_start_stop:pwm->channel 0, value 0x0  

tpu_pwm_config: clk_rate : 10000000 duty_ns: 5000000 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 50000 channel 1


tpu_pwm_enable 1:

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 1, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2058
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  

 tpu_pwm_write: value: 64, reg e78d2050
 tpu_pwm_write: value: 2, reg e78d2054
tpu_pwm_set_pin : pwm->channel 1, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2058
 tpu_pwm_write: value: 50000, reg e78d2068
 tpu_pwm_write: value: 50000, reg e78d206c
tpu_pwm_timer_start: pwm->channel 1, pwm->duty 0xc350  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x2  

tpu_pwm_enable 2:

tpu_pwm_set_pin : pwm->channel 1, state active  

tpu_pwm_set_pin: case TPU_PIN_ACTIVE:

 tpu_pwm_write: value: 4, reg e78d2058
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x2  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  

tpu_pwm_config: clk_rate : 10000000 duty_ns: 5000000 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 50000 channel 2


tpu_pwm_enable 1:

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 2, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2098
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 2, value 0x0  

 tpu_pwm_write: value: 64, reg e78d2090
 tpu_pwm_write: value: 2, reg e78d2094
tpu_pwm_set_pin : pwm->channel 2, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2098
 tpu_pwm_write: value: 50000, reg e78d20a8
 tpu_pwm_write: value: 50000, reg e78d20ac
tpu_pwm_timer_start: pwm->channel 2, pwm->duty 0xc350  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 2, value 0x4  

tpu_pwm_enable 2:

tpu_pwm_set_pin : pwm->channel 2, state active  

tpu_pwm_set_pin: case TPU_PIN_ACTIVE:

 tpu_pwm_write: value: 4, reg e78d2098
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x4  

tpu_pwm_start_stop:pwm->channel 2, value 0x0  
Starting Telephony daemon
Starting Linux NFC daemon
Stopping Bootlog daemon: bootlogd.

 Rootfs Version : iW-PREXZ-SC-01-R2.0-REL1.0-YoctoDaisy
 Poky (Yocto Project Reference Distro) 1.6.1 iWave-G21M /dev/ttySC2

iWave-G21M login: 
C















oot@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# ls cat /sys/class/backlight/fan.8/            
actual_brightness  device/            subsystem/         
bl_power           max_brightness     type               
brightness         power/             uevent             
root@iWave-G21M:~# ls cat /sys/class/backlight/fan.8/brightness 
ls: cat: No such file or directory
/sys/class/backlight/fan.8/brightness
root@iWave-G21M:~# cat /sys/class/backlight/fan.8/brightness 
7
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# cat /sys/class/backlight/fan.8/max_brightness 
7
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# echo 0 > /sys/class/backlight/fan.8/brightness                                                                     

tpu_pwm_config: clk_rate : 10000000 duty_ns: 0 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 0 channel 1


ntpu_pwm_config::  if (duty_only && pwm->timer_on) ELSE

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 1, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2058
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  

 tpu_pwm_write: value: 64, reg e78d2050
 tpu_pwm_write: value: 2, reg e78d2054
tpu_pwm_set_pin : pwm->channel 1, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2058
 tpu_pwm_write: value: 0, reg e78d2068
 tpu_pwm_write: value: 50000, reg e78d206c
tpu_pwm_timer_start: pwm->channel 1, pwm->duty 0x0000  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x2  

ntpu_pwm_config:: if (duty == 0 || duty == period) 

tpu_pwm_set_pin : pwm->channel 1, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2058
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x2  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  

tpu_pwm_disable:

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 1, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2058
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  

 tpu_pwm_write: value: 64, reg e78d2050
 tpu_pwm_write: value: 2, reg e78d2054
tpu_pwm_set_pin : pwm->channel 1, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2058
 tpu_pwm_write: value: 0, reg e78d2068
 tpu_pwm_write: value: 50000, reg e78d206c
tpu_pwm_timer_start: pwm->channel 1, pwm->duty 0x0000  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x2  

tpu_pwm_set_pin : pwm->channel 1, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2058
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x2  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  
root@iWave-G21M:~# 
root@iWave-G21M:~# echo 1 > /sys/class/backlight/fan.8/brightness                                                                     

tpu_pwm_config: clk_rate : 10000000 duty_ns: 78431 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 784 channel 1


tpu_pwm_enable 1:

tpu_pwm_timer_start

tpu_pwm_set_pin : pwm->channel 1, state inactive  

tpu_pwm_set_pin: TPU_PIN_INACTIVE: 

 tpu_pwm_write: value: 0, reg e78d2058
tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  

 tpu_pwm_write: value: 64, reg e78d2050
 tpu_pwm_write: value: 2, reg e78d2054
tpu_pwm_set_pin : pwm->channel 1, state PWM  

tpu_pwm_set_pin: case TPU_PIN_PWM:

 tpu_pwm_write: value: 5, reg e78d2058
 tpu_pwm_write: value: 784, reg e78d2068
 tpu_pwm_write: value: 50000, reg e78d206c
tpu_pwm_timer_start: pwm->channel 1, pwm->duty 0x0310  pwm->period 0xc350

tpu_pwm_start_stop: TPU_TSTR value 0x0  

tpu_pwm_start_stop:pwm->channel 1, value 0x2  
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# echo 2 > /sys/class/backlight/fan.8/brightness                                                                     

tpu_pwm_config: clk_rate : 10000000 duty_ns: 156862 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 1568 channel 1


ntpu_pwm_config::  if (duty_only && pwm->timer_on)

 tpu_pwm_write: value: 1568, reg e78d2068root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# echo 3 > /sys/class/backlight/fan.8/brightness                                                                     

tpu_pwm_config: clk_rate : 10000000 duty_ns: 313725 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 3137 channel 1


ntpu_pwm_config::  if (duty_only && pwm->timer_on)

 tpu_pwm_write: value: 3137, reg e78d2068root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# echo 4 > /sys/class/backlight/fan.8/brightness                                                                     

tpu_pwm_config: clk_rate : 10000000 duty_ns: 627450 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 6277 channel 1


ntpu_pwm_config::  if (duty_only && pwm->timer_on)

 tpu_pwm_write: value: 6277, reg e78d2068root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# echo 5 > /sys/class/backlight/fan.8/brightness                                                                     

tpu_pwm_config: clk_rate : 10000000 duty_ns: 1254901 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 12562 channel 1


ntpu_pwm_config::  if (duty_only && pwm->timer_on)

 tpu_pwm_write: value: 12562, reg e78d2068root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# echo 6 > /sys/class/backlight/fan.8/brightness                                                                     

tpu_pwm_config: clk_rate : 10000000 duty_ns: 2509803 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 25125 channel 1


ntpu_pwm_config::  if (duty_only && pwm->timer_on)

 tpu_pwm_write: value: 25125, reg e78d2068root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# echo 7 > /sys/class/backlight/fan.8/brightness                                                                     

tpu_pwm_config: clk_rate : 10000000 duty_ns: 5000000 period_ns:5000000 

ntpu_pwm_config:: rate 10000000, prescaler 1, period 50000, duty 50000 channel 1


ntpu_pwm_config::  if (duty_only && pwm->timer_on)

 tpu_pwm_write: value: 50000, reg e78d2068
ntpu_pwm_config:: if (duty == 0 || duty == period) 

tpu_pwm_set_pin : pwm->channel 1, state active  

tpu_pwm_set_pin: case TPU_PIN_ACTIVE:

 tpu_pwm_write: value: 4, reg e78d2058
tpu_pwm_timer_stop

tpu_pwm_start_stop: TPU_TSTR value 0x2  

tpu_pwm_start_stop:pwm->channel 1, value 0x0  
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 
root@iWave-G21M:~# 

pwm-renesas-tpu.txt
/*
 * R-Mobile TPU PWM driver
 *
 * Copyright (C) 2012 Renesas Solutions Corp.
 *
 * 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
 *
 * 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.
 */

#include <linux/clk.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_data/pwm-renesas-tpu.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/pwm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>

#define TPU_TSTR		0x00	/* Timer start register (shared) */

#define TPU_TCRn		0x00	/* Timer control register */
#define TPU_TCR_CCLR_NONE	(0 << 5)
#define TPU_TCR_CCLR_TGRA	(1 << 5)
#define TPU_TCR_CCLR_TGRB	(2 << 5)
#define TPU_TCR_CCLR_TGRC	(5 << 5)
#define TPU_TCR_CCLR_TGRD	(6 << 5)
#define TPU_TCR_CKEG_RISING	(0 << 3)
#define TPU_TCR_CKEG_FALLING	(1 << 3)
#define TPU_TCR_CKEG_BOTH	(2 << 3)
#define TPU_TMDRn		0x04	/* Timer mode register */
#define TPU_TMDR_BFWT		(1 << 6)
#define TPU_TMDR_BFB		(1 << 5)
#define TPU_TMDR_BFA		(1 << 4)
#define TPU_TMDR_MD_NORMAL	(0 << 0)
#define TPU_TMDR_MD_PWM		(2 << 0)
#define TPU_TIORn		0x08	/* Timer I/O control register */
#define TPU_TIOR_IOA_0		(0 << 0)
#define TPU_TIOR_IOA_0_CLR	(1 << 0)
#define TPU_TIOR_IOA_0_SET	(2 << 0)
#define TPU_TIOR_IOA_0_TOGGLE	(3 << 0)
#define TPU_TIOR_IOA_1		(4 << 0)
#define TPU_TIOR_IOA_1_CLR	(5 << 0)
#define TPU_TIOR_IOA_1_SET	(6 << 0)
#define TPU_TIOR_IOA_1_TOGGLE	(7 << 0)
#define TPU_TIERn		0x0c	/* Timer interrupt enable register */
#define TPU_TSRn		0x10	/* Timer status register */
#define TPU_TCNTn		0x14	/* Timer counter */
#define TPU_TGRAn		0x18	/* Timer general register A */
#define TPU_TGRBn		0x1c	/* Timer general register B */
#define TPU_TGRCn		0x20	/* Timer general register C */
#define TPU_TGRDn		0x24	/* Timer general register D */

#define TPU_CHANNEL_OFFSET	0x10
#define TPU_CHANNEL_SIZE	0x40

enum tpu_pin_state {
	TPU_PIN_INACTIVE,		/* Pin is driven inactive */
	TPU_PIN_PWM,			/* Pin is driven by PWM */
	TPU_PIN_ACTIVE,			/* Pin is driven active */
};

struct tpu_device;

struct tpu_pwm_device {
	bool timer_on;			/* Whether the timer is running */

	struct tpu_device *tpu;
	unsigned int channel;		/* Channel number in the TPU */

	enum pwm_polarity polarity;
	unsigned int prescaler;
	u16 period;
	u16 duty;
};

struct tpu_device {
	struct platform_device *pdev;
	enum pwm_polarity polarities[TPU_CHANNEL_MAX];
	struct pwm_chip chip;
	spinlock_t lock;

	void __iomem *base;
	struct clk *clk;
};

#define to_tpu_device(c)	container_of(c, struct tpu_device, chip)

static void tpu_pwm_write(struct tpu_pwm_device *pwm, int reg_nr, u16 value)
{
	void __iomem *base = pwm->tpu->base + TPU_CHANNEL_OFFSET
			   + pwm->channel * TPU_CHANNEL_SIZE;

	printk("\n tpu_pwm_write: value: %d, reg %x",value,(base + reg_nr) );

	iowrite16(value, base + reg_nr);
}

static void tpu_pwm_set_pin(struct tpu_pwm_device *pwm,
			    enum tpu_pin_state state)
{
	static const char * const states[] = { "inactive", "PWM", "active" };

	dev_dbg(&pwm->tpu->pdev->dev, "%u: configuring pin as %s\n",
		pwm->channel, states[state]);
	printk("\ntpu_pwm_set_pin : pwm->channel %d, state %s  \n",pwm->channel,states[state]);

	switch (state) {
	case TPU_PIN_INACTIVE:
	printk("\ntpu_pwm_set_pin: TPU_PIN_INACTIVE: \n");
		tpu_pwm_write(pwm, TPU_TIORn,
			      pwm->polarity == PWM_POLARITY_INVERSED ?
			      TPU_TIOR_IOA_1 : TPU_TIOR_IOA_0);
		break;
	case TPU_PIN_PWM:
	printk("\ntpu_pwm_set_pin: case TPU_PIN_PWM:\n");
		tpu_pwm_write(pwm, TPU_TIORn,
			      pwm->polarity == PWM_POLARITY_INVERSED ?
			      TPU_TIOR_IOA_0_SET : TPU_TIOR_IOA_1_CLR);
		break;
	case TPU_PIN_ACTIVE:
	printk("\ntpu_pwm_set_pin: case TPU_PIN_ACTIVE:\n");
		tpu_pwm_write(pwm, TPU_TIORn,
			      pwm->polarity == PWM_POLARITY_INVERSED ?
			      TPU_TIOR_IOA_0 : TPU_TIOR_IOA_1);
		break;
	}
}

static void tpu_pwm_start_stop(struct tpu_pwm_device *pwm, int start)
{
	unsigned long flags;
	u16 value;

	spin_lock_irqsave(&pwm->tpu->lock, flags);
	value = ioread16(pwm->tpu->base + TPU_TSTR);
	printk("\ntpu_pwm_start_stop: TPU_TSTR value 0x%x  \n",value);

	if (start){
		value |= 1 << pwm->channel;
	printk("\ntpu_pwm_start_stop:pwm->channel %d, value 0x%x  \n",pwm->channel,value);
	
	}
	else{
		value &= ~(1 << pwm->channel);
	printk("\ntpu_pwm_start_stop:pwm->channel %d, value 0x%x  \n",pwm->channel,value);
	}

	iowrite16(value, pwm->tpu->base + TPU_TSTR);
	spin_unlock_irqrestore(&pwm->tpu->lock, flags);
}

static int tpu_pwm_timer_start(struct tpu_pwm_device *pwm)
{
	int ret;

	if (!pwm->timer_on) {
		/* Wake up device and enable clock. */
		pm_runtime_get_sync(&pwm->tpu->pdev->dev);
		ret = clk_prepare_enable(pwm->tpu->clk);
		if (ret) {
			dev_err(&pwm->tpu->pdev->dev, "cannot enable clock\n");
			return ret;
		}
		pwm->timer_on = true;
	}

	printk("\ntpu_pwm_timer_start\n");
	/*
	 * Make sure the channel is stopped, as we need to reconfigure it
	 * completely. First drive the pin to the inactive state to avoid
	 * glitches.
	 */
	tpu_pwm_set_pin(pwm, TPU_PIN_INACTIVE);
	tpu_pwm_start_stop(pwm, false);

	/*
	 * - Clear TCNT on TGRB match
	 * - Count on rising edge
	 * - Set prescaler
	 * - Output 0 until TGRA, output 1 until TGRB (active low polarity)
	 * - Output 1 until TGRA, output 0 until TGRB (active high polarity
	 * - PWM mode
	 */
	tpu_pwm_write(pwm, TPU_TCRn, TPU_TCR_CCLR_TGRB | TPU_TCR_CKEG_RISING |
		      pwm->prescaler);
	tpu_pwm_write(pwm, TPU_TMDRn, TPU_TMDR_MD_PWM);
	tpu_pwm_set_pin(pwm, TPU_PIN_PWM);
	tpu_pwm_write(pwm, TPU_TGRAn, pwm->duty);
	tpu_pwm_write(pwm, TPU_TGRBn, pwm->period);

	dev_dbg(&pwm->tpu->pdev->dev, "%u: TGRA 0x%04x TGRB 0x%04x\n",
		pwm->channel, pwm->duty, pwm->period);
	printk("\ntpu_pwm_timer_start: pwm->channel %d, pwm->duty 0x%04x  pwm->period 0x%04x\n",pwm->channel,pwm->duty,pwm->period);

	/* Start the channel. */
	tpu_pwm_start_stop(pwm, true);

	return 0;
}

static void tpu_pwm_timer_stop(struct tpu_pwm_device *pwm)
{
	if (!pwm->timer_on)
		return;

	printk("\ntpu_pwm_timer_stop\n");
	/* Disable channel. */
	tpu_pwm_start_stop(pwm, false);

	/* Stop clock and mark device as idle. */
	clk_disable_unprepare(pwm->tpu->clk);
	pm_runtime_put(&pwm->tpu->pdev->dev);

	pwm->timer_on = false;
}

/* -----------------------------------------------------------------------------
 * PWM API
 */

static int tpu_pwm_request(struct pwm_chip *chip, struct pwm_device *_pwm)
{
	struct tpu_device *tpu = to_tpu_device(chip);
	struct tpu_pwm_device *pwm;

	printk("\ntpu_pwm_request:\n");
	if (_pwm->hwpwm >= TPU_CHANNEL_MAX)
		return -EINVAL;

	pwm = kzalloc(sizeof(*pwm), GFP_KERNEL);
	if (pwm == NULL)
		return -ENOMEM;

	pwm->tpu = tpu;
	pwm->channel = _pwm->hwpwm;
	pwm->polarity = tpu->polarities[pwm->channel];
	pwm->prescaler = 0;
	pwm->period = 0;
	pwm->duty = 0;

	pwm->timer_on = false;

	pwm_set_chip_data(_pwm, pwm);

	return 0;
}

static void tpu_pwm_free(struct pwm_chip *chip, struct pwm_device *_pwm)
{
	struct tpu_pwm_device *pwm = pwm_get_chip_data(_pwm);

	tpu_pwm_timer_stop(pwm);
	kfree(pwm);
}

static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *_pwm,
			  int duty_ns, int period_ns)
{
	static const unsigned int prescalers[] = { 1, 4, 16, 64 };
	struct tpu_pwm_device *pwm = pwm_get_chip_data(_pwm);
	struct tpu_device *tpu = to_tpu_device(chip);
	unsigned int prescaler;
	bool duty_only = false;
	u32 clk_rate;
	u32 period;
	u32 duty;
	int ret;

	/*
	 * Pick a prescaler to avoid overflowing the counter.
	 * TODO: Pick the highest acceptable prescaler.
	 */
	clk_rate = clk_get_rate(tpu->clk);

	printk("\ntpu_pwm_config: clk_rate : %d duty_ns: %d period_ns:%d \n",clk_rate, duty_ns,period_ns);

	for (prescaler = 0; prescaler < ARRAY_SIZE(prescalers); ++prescaler) {
		period = clk_rate / prescalers[prescaler]
		       / (NSEC_PER_SEC / period_ns);
		if (period <= 0xffff)
			break;
	}

	if (prescaler == ARRAY_SIZE(prescalers) || period == 0) {
		dev_err(&tpu->pdev->dev, "clock rate mismatch\n");
		return -ENOTSUPP;
	}

	if (duty_ns) {
		duty = clk_rate / prescalers[prescaler]
		     / (NSEC_PER_SEC / duty_ns);
		if (duty > period)
			return -EINVAL;
	} else {
		duty = 0;
	}

	dev_dbg(&tpu->pdev->dev,
		"rate %u, prescaler %u, period %u, duty %u\n",
		clk_rate, prescalers[prescaler], period, duty);
	printk("\nntpu_pwm_config:: rate %u, prescaler %u, period %u, duty %u channel %u\n\n",clk_rate, prescalers[prescaler], period, duty,pwm->channel);

	if (pwm->prescaler == prescaler && pwm->period == period)
		duty_only = true;

	pwm->prescaler = prescaler;
	pwm->period = period;
	pwm->duty = duty;

	/* If the channel is disabled we're done. */
	if (!test_bit(PWMF_ENABLED, &_pwm->flags))
		return 0;

	if (duty_only && pwm->timer_on) {
	printk("\nntpu_pwm_config::  if (duty_only && pwm->timer_on)\n");
		/*
		 * If only the duty cycle changed and the timer is already
		 * running, there's no need to reconfigure it completely, Just
		 * modify the duty cycle.
		 */
		tpu_pwm_write(pwm, TPU_TGRAn, pwm->duty);
		dev_dbg(&tpu->pdev->dev, "%u: TGRA 0x%04x\n", pwm->channel,
			pwm->duty);
	} else {
		/* Otherwise perform a full reconfiguration. */
	printk("\nntpu_pwm_config::  if (duty_only && pwm->timer_on) ELSE\n");
		ret = tpu_pwm_timer_start(pwm);
		if (ret < 0)
			return ret;
	}

	if (duty == 0 || duty == period) {
	printk("\nntpu_pwm_config:: if (duty == 0 || duty == period) \n");
		/*
		 * To avoid running the timer when not strictly required, handle
		 * 0% and 100% duty cycles as fixed levels and stop the timer.
		 */
		tpu_pwm_set_pin(pwm, duty ? TPU_PIN_ACTIVE : TPU_PIN_INACTIVE);
		tpu_pwm_timer_stop(pwm);
	}

	return 0;
}

static int tpu_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *_pwm,
				enum pwm_polarity polarity)
{
	struct tpu_pwm_device *pwm = pwm_get_chip_data(_pwm);

	pwm->polarity = polarity;
	printk("\ntpu_pwm_set_polarity: pwm->polarity %d \n",pwm->polarity);

	return 0;
}

static int tpu_pwm_enable(struct pwm_chip *chip, struct pwm_device *_pwm)
{
	struct tpu_pwm_device *pwm = pwm_get_chip_data(_pwm);
	int ret;

	printk("\ntpu_pwm_enable 1:\n");
	ret = tpu_pwm_timer_start(pwm);
	if (ret < 0)
		return ret;

	/*
	 * To avoid running the timer when not strictly required, handle 0% and
	 * 100% duty cycles as fixed levels and stop the timer.
	 */
	if (pwm->duty == 0 || pwm->duty == pwm->period) {
	printk("\ntpu_pwm_enable 2:\n");
		tpu_pwm_set_pin(pwm, pwm->duty ?
				TPU_PIN_ACTIVE : TPU_PIN_INACTIVE);
		tpu_pwm_timer_stop(pwm);
	}

	return 0;
}

static void tpu_pwm_disable(struct pwm_chip *chip, struct pwm_device *_pwm)
{
	struct tpu_pwm_device *pwm = pwm_get_chip_data(_pwm);
	printk("\ntpu_pwm_disable:\n");

	/* The timer must be running to modify the pin output configuration. */
	tpu_pwm_timer_start(pwm);
	tpu_pwm_set_pin(pwm, TPU_PIN_INACTIVE);
	tpu_pwm_timer_stop(pwm);
}

static const struct pwm_ops tpu_pwm_ops = {
	.request = tpu_pwm_request,
	.free = tpu_pwm_free,
	.config = tpu_pwm_config,
	.set_polarity = tpu_pwm_set_polarity,
	.enable = tpu_pwm_enable,
	.disable = tpu_pwm_disable,
	.owner = THIS_MODULE,
};

/* -----------------------------------------------------------------------------
 * Probe and remove
 */

static void tpu_parse_pdata(struct tpu_device *tpu)
{
	struct tpu_pwm_platform_data *pdata = tpu->pdev->dev.platform_data;
	unsigned int i;

	for (i = 0; i < ARRAY_SIZE(tpu->polarities); ++i)
		tpu->polarities[i] = pdata ? pdata->channels[i].polarity
				   : PWM_POLARITY_NORMAL;
}

static int tpu_probe(struct platform_device *pdev)
{
	struct tpu_device *tpu;
	struct resource *res;
	int ret;

	tpu = devm_kzalloc(&pdev->dev, sizeof(*tpu), GFP_KERNEL);
	if (tpu == NULL) {
		dev_err(&pdev->dev, "failed to allocate driver data\n");
		return -ENOMEM;
	}

	spin_lock_init(&tpu->lock);
	tpu->pdev = pdev;

	/* Initialize device configuration from platform data. */
	tpu_parse_pdata(tpu);

	/* Map memory, get clock and pin control. */
	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	tpu->base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(tpu->base))
		return PTR_ERR(tpu->base);

	tpu->clk = devm_clk_get(&pdev->dev, NULL);
	if (IS_ERR(tpu->clk)) {
		dev_err(&pdev->dev, "cannot get clock\n");
		return PTR_ERR(tpu->clk);
	}

	/* Initialize and register the device. */
	platform_set_drvdata(pdev, tpu);

	tpu->chip.dev = &pdev->dev;
	tpu->chip.ops = &tpu_pwm_ops;
	tpu->chip.of_xlate = of_pwm_xlate_with_flags;
	tpu->chip.of_pwm_n_cells = 3;
	tpu->chip.base = -1;
	tpu->chip.npwm = TPU_CHANNEL_MAX;

	ret = pwmchip_add(&tpu->chip);
	if (ret < 0) {
		dev_err(&pdev->dev, "failed to register PWM chip\n");
		return ret;
	}

	dev_info(&pdev->dev, "TPU PWM %d registered\n", tpu->pdev->id);

	pm_runtime_enable(&pdev->dev);

	return 0;
}

static int tpu_remove(struct platform_device *pdev)
{
	struct tpu_device *tpu = platform_get_drvdata(pdev);
	int ret;

	ret = pwmchip_remove(&tpu->chip);
	if (ret)
		return ret;

	pm_runtime_disable(&pdev->dev);

	return 0;
}

#ifdef CONFIG_OF
static const struct of_device_id tpu_of_table[] = {
	{ .compatible = "renesas,tpu-r8a73a4", },
	{ .compatible = "renesas,tpu-r8a7740", },
	{ .compatible = "renesas,tpu-r8a7790", },
	{ .compatible = "renesas,tpu-sh7372", },
	{ .compatible = "renesas,tpu", },
	{ },
};

MODULE_DEVICE_TABLE(of, tpu_of_table);
#endif

static struct platform_driver tpu_driver = {
	.probe		= tpu_probe,
	.remove		= tpu_remove,
	.driver		= {
		.name	= "renesas-tpu-pwm",
		.owner	= THIS_MODULE,
		.of_match_table = of_match_ptr(tpu_of_table),
	}
};

module_platform_driver(tpu_driver);

MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
MODULE_DESCRIPTION("Renesas TPU PWM Driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:renesas-tpu-pwm");

Thanks and Regards

Devendra

  • Hi Devendra,

    Do you already know the answers to your questions? If not yet, please wait until RZ experts answer each of them. Thank you for understanding.

    JB
    RenesasRulz Forum Moderator

    https://renesasrulz.com/
    https://academy.renesas.com/
    https://en-us.knowledgebase.renesas.com/

  • Hi Devendra,

    The clk_rate value 10,000,000 is fixed and you cannot change it unless you modify the board. It is the 'common peripheral' clock which is 1/2 the frequency of the external oscillator connected to the SoC. You can look up 'tpu0', 'cp_clk' and 'extal_clk' in the device tree files to see how it is set.

    The value of 'period_ns' comes from the 'fan' node in your device tree - the number 5,000,000 specified in the 'pwms' property.

    The function tpu_pwm_config() is called by the pwm_bl driver (drivers/video/backlight/pwm_bl.c), the value of 'duty_ns' passed to it is also calculated by that driver. Check the function pwm_backlight_update_status() for details.

    As for your question why the code writes 50000 to the register instead of 65535 - I don't have the documentation for the TPU module but from the code it seems that the value written to the register is the actual duty time. I.e. if you want the max duty cycle you don't write in the register the max value it can hold (65535), you write the actual time. That is why the prescale value is specified as well - to allow setting duty times that are larger than 65535 and wouldn't fit in the register without scaling.

    Regards,
    Georgi
  • In reply to Georgi:

    Thank you for your reply.
  • In reply to Devendra:

    Hi

    In Linux there is another PWM driver. ( github.com/.../pwm-rcar.c )
    In this why he is calculating the "div" value in "rcar_pwm_get_clock_division".



    In "rcar_pwm_set_counter" he used that "div" value to find "one_cycle". Then used this value with period and then write to PWM Count Register (PWMCNT) in CYC0 field.

    But for PWM Count Register (PWMCNT) CYC0 explains as PWM Cycle, Sets the PWM output cycle. The cycle set by these bits is the sum of the high-level and low-level periods.

    PH0 is the PWM High-Level Period that is duty cycle.

    Here for "rcar_pwm_config" function the value of passing duty cycle and period need to be in nano second??
    If I passed the value then why we can't write directly to PWM Count Register (PWMCNT) CYC0 (period) and PH0 (duty cycle) filed.

    In my case I passed 5000000 in ns as period 50% as duty cycle (2500000 ns ).

    When I observed in Logic analyser it shows 1.3KHz. But duty cycle changes as expected. If I changed to 25 % (1250000ns) the the expected wave form is displaying. But frequency shows 1.3Khz .

    Whatever I sent period is 5000000ns i.e 200Hz.

    One thing is in case in functions "rcar_pwm_get_clock_division" and "rcar_pwm_set_counter" I hard code the value of "unsigned long clk_rate = clk_get_rate(rp->clk);" as "unsigned long clk_rate = "10000000"

    Here clock rate I set as 10000000.

    Another thing is there a "do_div" function in "rcar_pwm_get_clock_division" and "rcar_pwm_set_counter".
    There is some assembly code for this.

    arch/arm/include/asm/div64.h

    Instead of that I added this in my code

    uint32_t __div64_32(uint64_t *n, uint32_t base)
    {
    uint32_t remainder = *n % base;
    *n = *n / base;
    return remainder;
    }

    #define do_div(n, base) __div64_32(&(n), base)

    Is this wrong ??

    What I am getting in Logic analyzer is the expected or not (frequency) ???

    If not what is the wrong I did??


    Thanks and Regards
    Devendra

  • In reply to Devendra:

    Hi Devendra,

    I think your error is hard-coding the clock frequency to 10MHz. The base clock frequency for the PWM module is actually 65MHz - that is why the output frequency you are seeing (1.3KHz) is 6.5 times higher than what you have set (200Hz).

    Please keep in mind that the TPU and the PWM are two different modules. Everything I said before was about the TPU module, not PWM.
    The PWM module uses a different base clock (Po), which as you can see from the manual is 65MHz.

    The reason why you cannot write your duty cycle and period values (in nanoseconds) directly in the PWM Count Register (PWMCNT) CYC0 (period) and PH0 (duty cycle) is because the values in those registers are clock counts, not time periods.

    It works like this - the value specified in the PWM Control Register (PWMCR) is used to divide the base clock (65MHz) and generate the actual internal clock of the PWM. The PWM then uses the internal clock and the counts in CYC0 and PH0 to generate the output signal.
    E.g. if the PWM internal clock (after division) is 10 Hz, CYC0 is 20 and PH0 is 10, the output frequency will be 200 Hz (10*20) and the duty cycle will be 50%.

    Regards,
    Georgi
  • In reply to Georgi:

    Thank you so much.
  • In reply to Devendra:

    Hi

    Currently I had driver for TPU (PWM mode) and PWM Timer for RZ/G1H.
    The base clock frequency for the TPU is 10MHz

    When I tested the TPU driver by changing frequency I observed following behavior in Logic Analyzer

    Frequency Duty cycle
    Result in Logic analyzer

        Frequency Duty Cycle Period
    200Hz 50%   200Hz 2.5 ms,  2.5 ms     5ms
    2KHz 50%   2KhZ 0.25 ms, 0.2501 ms  0.5001ms
    20KHz 50%   19.96KHz  25,  25.1 (micro sec)  50.1micro sec
    200KHz 50%   196.1KHz  2.58, 2.52 (micro sec) 5.1 micro sec
    2MHz 50%   1.667MHz 0.2, 0.4 (micro sec) 0.6 micro sec
    1MHz 50%   909.1KHz 0.6, 0.5 (micro sec) 1.1micro sec
    10MHz 50%  

     No trigger

    (No sampling)

    NA NA
             


    The values above I got is not accurate after KHz.
    Why it is like this ??
    If the base clock frequency is 10MHz the what is the max frequency I can use for external device.

    Similarly I have PWM Timer driver.

    When I tested the PWM Timer driver by changing frequency I observed following behavior in Logic Analyzer
            

    Frequency Duty cycle
    Result in Logic analyzer
        Frequency Duty Cycle Period
    1Hz 50% 1.001Hz  0.4991s, 0.5001s 0.9992s
    100Hz 50% 100.1Hz 4.994ms, 4.994ms 9.988ms
    1KHz 50% 1.001KHz    0.5002ms, 0.4992ms 0.9994ms
    10KHz 50% 10.01KHz 49.96, 49.98 (micro sec)  99.94micro sec
    100KHz 50% 100KHz  5, 5 (micro sec)  10 micro sec
    1MHz 50% 1MHz 0.48. 0.52 micro sec  1 micro sec
    10MHz 50%

    10MHz, 12MHz

    ( vary in frequency the waveform)

    40ns,60ns (For 10Mhz)

    60ns,40ns(For 12Mhz)

    0.1 micro sec
    20MHz 50%

    10, 25, 16MHz

    (vary in frequency of waveform)

       

     

    Why the behavior is like this ??
    Is there any calculation is wrong in driver before writing to registers??
    Or this one is the expected????
    If the base clock frequency is 65MHz the what is the max frequency I can use for external device.

    Thanks and regards
    Devendra

  • In reply to Devendra:

    Hi Devendra,

    The PWM period and duty cycle are generated by integer division of the base clock, so there would be some rounding errors.

    For example - look at the PWM timer, 1 MHz output frequency, i.e. 1000 ns period. For this value the function rcar_pwm_get_clock_division() will return a division value of 0, i.e. there will be no division. The internal clock is 65 MHz, so the smallest period is 15.385 ns. 1000/15.385 = 64.998. The PWM Count Register PWMCNT accepts only integer values (number of ticks), so the value written in CYC0 would be 65. The actual generated period would be 65*15.385 = 1000.025 ns which is pretty close to the desired 1000 ns. However, since the number 65 is odd, the duty cycle would not be exactly 50%. It will be 32*15.385=492ns/33*15.385=508ns.
    Similar reasoning applies to the other cases.

    I am not sure what you mean in your 10MHz and 20MHz cases for the PWM timer. Does the frequency change on the fly?

    The maximum frequency you can generate with the PWM timer is 65/2=32.5 MHz for 50% duty cycle. In PWMCNT the value of PH0 would be 1 and the value of CYC0 would be 2.

    Regards,
    Georgi
  • In reply to Georgi:

    Hi,

    When I tried to set frequency to 1Hz and 2Hz it gives clock rate mismatch error. After 3Hz it works fine.
    ( refer github.com/.../pwm-renesas-tpu.c )

    clk_rate for TPU is 10,000,000Hz (10MHz).

    There is a logic for finding prescalar value based on frequency passed.
    static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *_pwm,int duty_ns, int period_ns) {
    .....
    prescalers[] = { 1, 4, 16, 64 };
    ....
    clk_rate = 10,000,000;
    ...
    for (prescaler = 0; prescaler < ARRAY_SIZE(prescalers); ++prescaler) {
    period = clk_rate / prescalers[prescaler]
    / (NSEC_PER_SEC / period_ns);
    if (period <= 0xffff)
    break;
    }

    if (prescaler == ARRAY_SIZE(prescalers) || period == 0) {
    dev_err(&tpu->pdev->dev, "clock rate mismatch\n");
    return -ENOTSUPP;
    }
    ..
    }

    But for 1Hz frequency and 50% duty cycle the values are like this

    duty cycle = 500000000 ns; period =1000000000 ns

    static int tpu_pwm_config(struct pwm_chip *chip, struct pwm_device *_pwm, int 500000000, int 1000000000) {

    The period values in that for value is compared with 0xffff (65535)
    Iteration 1:
    prescalar = 0
    prescalers[prescaler] = 1
    period = 10000000 (> 65535) [ 10000000/1/(1000000000/1000000000) = 10000000 ]

    Iteration 2:
    prescalar = 1
    prescalers[prescaler] = 4
    period = 2500000 (> 65535) [ 10000000/4/(1000000000/1000000000) = 2500000 ]

    Iteration 3:
    prescalar = 2
    prescalers[prescaler] = 16
    period = 625000 (> 65535) [ 10000000/16/(1000000000/1000000000) = 625000 ]

    Iteration 3:
    prescalar = 3
    prescalers[prescaler] = 64
    period = 156250 (> 65535) [ 10000000/64/(1000000000/1000000000) = 156250 ]

    Iteration 4:
    prescalar = 4 (ARRAY_SIZE(prescalers)) come out loop

    Now clock mismatch error is coming
    if (calc_prescaler == ARRAY_SIZE(prescalers) || calc_period == 0) ---> error
    ( 4 == 4)


    Is this driver support for 1HZ and 2Hz or not ???
    If not supported For supporting 1Hz and 2Hz what I need to do ??
    Thanks and Regards
    Devendra
  • In reply to Devendra:

    Hi Devendra,

    The TPU does not support frequencies like 1Hz or 2Hz. The TPU is a 16 bit counter, so the maximum number of ticks you can configure for the PWM period is 65535. Even if the ticks are counted at the lowest possible frequency (clk_rate / 64 = 156250 Hz), that still means that the longest period you can configure is -
    65535 / 156250 = 0.419424 seconds, which is about 2.38 Hz.

    If you want to achieve frequencies like 1Hz or 2Hz - use the PWM block instead of the TPU.

    Regards,
    Georgi
  • In reply to Georgi:

    Thank you for your information.
  • In reply to Devendra:

    Hi,
    I am using PWM Timer Driver. From the data sheet I found that setting 0000 to PH0 bit in PWM Count Register (PWMCNT) is prohibited.
    If I want to set duty cycle 0%, it inside rcar_pwm_set_counter() function the value calculated for PH0 is 0. So it returns -EINVAL.

    rcar_pwm_set_counter()
    {......
    /* Avoid prohibited setting */
    if (cyc == 0 || ph == 0)
    return -EINVAL;
    .....
    }

    For reference github.com/.../pwm-rcar.c
    What I need to do if I want to set the duty cycle to 0 ?
    Thanks and Regards
    Devendra

  • In reply to Devendra:

    Hi Devendra,

    Since the setting of 0 for 'duty cycle' or 'high period' is prohibited, I would suggest that you just stop the PWM timer when you need 0% duty cycle.

    Regards,
    Georgi
  • In reply to Georgi:

    Hi Georgi

    @you can achieve 0% duty cycle by stopping the PWM timer.

    "stopping the PWM timer" means writing 0 to EN0 bit (Disable channel) of PWM Control Register (PWMCR). ? Whatever I did is correct ?

    If correct, as you told I tried to stop the PWM Timer by writing 0 to EN0 bit of PWM Control Register (PWMCR).

    But as per hardware user manual it will become high. When I tested by disabling PWM Timer, it shows continues high level and results in 100% duty cycle.

    EN0

    0: The channel is held in the idle state, and outputs a high level.
    1: The channel outputs high and low levels in a predetermined cycle.

    Attached the screen shot of test result (In the test, initially set to 200Hz and 10% duty cycle, then disable the PWM Timer ).


    For setting 0% duty cycle what I can do ?
    In PWM Timer chapter I didn't got polarity changing option. (I didn't find any register or bit detail to change polarity also.)

    Please can you provide me limitations of PWM Timer driver? So that I need to explain it for customer.
    Till now I found that there is limitation like:

    Setting frequency to 0 Hz is not possible.
    Setting 0% duty cycle is not possible.

    Thanks and Regards

    Devendra

  • In reply to Devendra:

    Hello Devendra,

    i had also problems with the TPU of the RZ/T1 when the pwm mode is used.
    The function is not correct for 100% duty and 0% duty.
    The TPU module generates small spikes in this case.
    We decides to change the Pin Funktion (MPC) to output for these cases.

    Regards