00 USB-C fiziksel arayüz
USB Type-C, 24 pinli reversible konnektörüdür. Tek konnektör ile USB 3.2, USB4, Thunderbolt, DisplayPort, güç iletimi ve diğer protokolleri destekler. Oryantasyon bağımsızlığı ve yüksek güç kapasitesi onu modern cihazlar için tercih edilen standart yapar.
Pin haritası
| Pin grubu | Pinler | İşlev |
|---|---|---|
VBUS | A4, A9, B4, B9 | Güç hattı — 5-48V, maks 5A (PD ile) |
GND | A1, A12, B1, B12 | Toprak |
CC1, CC2 | A5, B5 | Configuration Channel — yön belirleme, PD iletişimi |
D+/D- | A6, A7, B6, B7 | USB 2.0 data |
TX/RX | A2, A3, A10, A11, B2, B3, B10, B11 | USB 3.2 / USB4 SuperSpeed çiftleri |
SBU1, SBU2 | A8, B8 | Sideband Use — Alt Mode sinyalleri (DP AUX, Thunderbolt) |
CC pin mekanizması
CC (Configuration Channel) pinleri USB-C'nin en kritik sinyalleridir. Bağlantı algılama, oryantasyon belirleme, rol müzakeresi ve PD mesajlaşması CC pinleri üzerinden yapılır.
Host (DFP) Device (UFP)
CC1 ──── Rp (pull-up) ────── Rd (pull-down) ──── GND
CC2 ──── Rp (pull-up) ────── (açık — oryantasyon)
Oryantasyon:
CC1'de gerilim düşümü varsa → düz bağlantı
CC2'de gerilim düşümü varsa → ters bağlantı
Ra direnci (800Ω): kablo aktif VCONN gerektirir
Alt Mode kableti
Type-C kablolar pasif (Re-timer yok, USB 3.2 Gen1/2) veya aktif (Re-timer var, USB 3.2 Gen2x2 / USB4) olabilir. DP Alt Mode ve Thunderbolt için aktif kablo veya en az Gen2 sertifikalı pasif kablo gerekir. Kablo tipi VDM (Vendor Defined Message) Discovery mekanizması ile sorgulanır.
Tüm USB-C kablolar Power Delivery desteklemez. Yalnızca E-Marked kablolar (aktif kablolar dahil) 3A üzeri akım ve 20V üzeri gerilim taşıyabilir. 100W (20V × 5A) için E-Marked kablo zorunludur. Kalitesiz kablolar CC pin dirençlerini doğru uygulamayabilir ve güç müzakeresi başarısız olabilir.
01 USB Power Delivery protokolü
USB Power Delivery (USB PD), CC pinleri üzerinden BMC (Biphase Mark Coding) ile iletilen bir mesajlaşma protokolüdür. Güç kaynağı ile tüketici arasında dinamik müzakere yaparak 5W'tan 240W'a (PD 3.1 EPR) kadar güç dağıtımına olanak tanır.
PDO — Power Data Object
PDO'lar, bir güç kaynağının sunabileceği veya bir cihazın talep edebileceği güç profillerini tanımlar. Her PDO 32 bitlik bir veri nesnesidir.
| PDO Tipi | Açıklama | Kullanım |
|---|---|---|
Fixed PDO | Sabit voltaj, max akım | 5V@3A, 9V@3A, 20V@5A gibi standart profiller |
Variable PDO | Voltaj aralığı, max akım | Eski şarj adaptörleri ile uyumluluk |
Battery PDO | Güç üst sınırı (watt) | Batarya sistemleri |
APDO (PPS) | Programlanabilir voltaj + akım | USB PD 3.0 PPS — telefon hızlı şarj |
AVS (EPR) | 28-48V aralığı | USB PD 3.1 EPR — dizüstü, monitör |
Mesajlaşma akışı
Source (Kaynak) Sink (Tüketici)
│ │
│ ── Source_Capabilities ──────────>│ PDO listesi gönder
│ │
│ <─── Request ─────────────────────│ İstenen PDO seç
│ │
│ ── Accept ───────────────────────>│ Kabul
│ │
│ ── PS_RDY ───────────────────────>│ Güç hazır
│ │
│ (müzakere tamamlandı)│
Mesaj tipleri
BMC kodlama
PD mesajları CC hattı üzerinden 300 kbps hızında BMC ile kodlanır. Başlangıç sırası: Preamble (64 bit) → SOP* → Header → Data → CRC32 → EOP. fusb302 ve benzeri TCPC'ler bu kodlama/çözme işlemini donanımda yapar.
02 Linux USB Type-C subsystem
Linux kernel 4.12'den itibaren USB Type-C için kapsamlı bir sysfs arayüzü ve sürücü çerçevesi bulunur. /sys/class/typec/ hiyerarşisi port durumunu, partner bilgilerini ve alt modları user-space'e sunar.
Sysfs hiyerarşisi
/sys/class/typec/
├── port0/ # İlk Type-C port
│ ├── data_role # host / device / none
│ ├── power_role # source / sink / dual
│ ├── vconn_source # yes / no
│ ├── preferred_role # tercih edilen rol
│ ├── supported_accessory_modes
│ ├── uevent
│ └── port0-partner/ # Bağlı cihaz bilgisi
│ ├── type # cable / audio-adapter / ...
│ ├── usb_power_delivery/
│ │ ├── capabilities/
│ │ │ ├── 1:fixed_supply/
│ │ │ │ ├── voltage
│ │ │ │ └── maximum_current
│ │ │ └── 2:fixed_supply/
│ │ └── requests/
│ └── alt_modes/
│ └── port0-partner.0/ # DP Alt Mode
│ ├── svid # 0xff01 (DP)
│ └── active
# Port durumunu kontrol et
cat /sys/class/typec/port0/power_role
# source
cat /sys/class/typec/port0/data_role
# host
# Partner PDO'larını oku
for f in /sys/class/typec/port0-partner/usb_power_delivery/capabilities/*/; do
echo "PDO: $f"
cat "$f/voltage" 2>/dev/null && cat "$f/maximum_current" 2>/dev/null
done
# udevadm ile Type-C olaylarını izle
udevadm monitor --property --subsystem-match=typec
USB Type-C notifier sistemi
Kernel içinde Type-C port değişiklikleri, struct usb_typec_cable ve typec_port_register_notifier() mekanizmasıyla sürücülere iletilir. Display alt mode sürücüleri, şarj sürücüleri ve ağ sürücüleri bu notifier'a abone olarak bağlantı olaylarına tepki verir.
03 PD controller sürücüleri
USB PD fiziksel katmanını (BMC kodlama, CC pin yönetimi) uygulayan entegre devreler TCPC (Type-C Port Controller) olarak adlandırılır. Linux'ta bunlar drivers/usb/typec/tcpm/ altındaki TCPM (Type-C Port Manager) çerçevesi üzerinden kontrol edilir.
Yaygın TCPC'ler
| Çip | Üretici | Linux sürücüsü | Özellikler |
|---|---|---|---|
FUSB302 | onsemi | fusb302.c | Yaygın, açık kaynak PD stack |
STUSB1600 | STMicro | stusb160x.c | Dahili PD state machine |
PTN5110 | NXP | tcpci.c | TCPCI uyumlu, sade |
FUSB307 | onsemi | fusb307.c | USB4 / Thunderbolt desteği |
MAX77759 | Maxim | max77759-tcpc.c | Dahili şarj kontrolörü |
RT1711H | Richtek | tcpci_rt1711h.c | TCPCI, gömülü ürünlerde yaygın |
FUSB302 Device Tree
&i2c1 {
status = "okay";
clock-frequency = <400000>;
fusb302: typec@22 {
compatible = "fcs,fusb302";
reg = <0x22>;
interrupt-parent = <&gpio3>;
interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_fusb302>;
/* TCPM port bağlantısı */
connector {
compatible = "usb-c-connector";
label = "USB-C";
data-role = "dual";
power-role = "dual";
try-power-role = "sink";
source-pdos = <PDO_FIXED(5000, 900,
PDO_FIXED_USB_COMM)>;
sink-pdos = <PDO_FIXED(5000, 3000,
PDO_FIXED_USB_COMM)
PDO_VAR(5000, 20000, 3000)>;
op-sink-microwatt = <10000000>; /* 10W */
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 { /* USB 3.1 */
reg = <0>;
endpoint {
remote-endpoint = <&usb3_ep>;
};
};
port@1 { /* DP Alt Mode */
reg = <1>;
endpoint {
remote-endpoint = <&dp_ep>;
};
};
};
};
};
};
TCPM çerçevesi
TCPM (drivers/usb/typec/tcpm/tcpm.c) PD state machine'ini uygular. Sürücüler yalnızca donanıma özgü tcpc_ops yapısını doldurmak zorundadır; PD protokol mantığı TCPM tarafından yönetilir.
04 Role switching
USB Type-C bağlantısında her port DFP (Downstream Facing Port — host), UFP (Upstream Facing Port — device) veya DRP (Dual Role Port — ikisi de) rolünde olabilir. Rol değişikliği PD protokolü aracılığıyla dinamik olarak yapılır.
Rol tipleri
Sysfs ile rol değişikliği
# Mevcut rolleri göster
cat /sys/class/typec/port0/data_role
# [host] device
cat /sys/class/typec/port0/power_role
# [source] sink dual
# Data rolünü değiştir (DR_Swap gönderir)
echo "device" > /sys/class/typec/port0/data_role
# Power rolünü değiştir (PR_Swap gönderir)
echo "sink" > /sys/class/typec/port0/power_role
# Tercih edilen rolü ayarla (bağlantıda otomatik müzakere)
echo "sink" > /sys/class/typec/port0/preferred_role
Kernel API ile programatik rol değişikliği
#include <linux/usb/typec.h>
/* Power Role Swap isteği gönder */
static int request_power_role_swap(struct typec_port *port,
enum typec_role role)
{
int ret;
/* Partner'ın PR_Swap destekleyip desteklemediğini kontrol et */
if (!typec_port_is_partner_pd_capable(port)) {
dev_warn(dev, "Partner PD desteklemiyor\n");
return -EOPNOTSUPP;
}
ret = typec_set_pwr_role(port, role);
if (ret) {
dev_err(dev, "PR_Swap başarısız: %d\n", ret);
return ret;
}
dev_info(dev, "Power role değiştirildi: %s\n",
role == TYPEC_SOURCE ? "source" : "sink");
return 0;
}
/* Type-C notifier callback */
static int typec_event_cb(struct notifier_block *nb,
unsigned long event, void *data)
{
struct typec_connector_data *conn_data = data;
switch (event) {
case TYPEC_ATTACHED:
dev_info(dev, "Type-C bağlandı: partner=%s\n",
typec_partner_get_identity(conn_data->partner));
break;
case TYPEC_DETACHED:
dev_info(dev, "Type-C ayrıldı\n");
break;
}
return NOTIFY_OK;
}
05 Alt Mode
USB Type-C, SuperSpeed data pinlerini alternatif protokoller için kullanmasına izin veren Alt Mode mekanizmasını destekler. DisplayPort, Thunderbolt/USB4 ve HDMI en yaygın Alt Mode'lardır.
VDM — Vendor Defined Message
Alt Mode keşfi ve aktivasyonu PD VDM (Vendor Defined Message) mesajları ile yapılır. Her Alt Mode üreticisi SVID (Standard or Vendor ID) ile tanımlanır.
| Alt Mode | SVID | Pin konfigürasyonu |
|---|---|---|
| DisplayPort | 0xFF01 | C/D (2 lane DP + USB3) veya E/F (4 lane DP) |
| Thunderbolt 3 | 0x8087 | 40 Gbps, Intel özel |
| USB4 | (USB-IF) | TX1/RX1 + TX2/RX2 tüm 4 şerit |
| MHL | 0xFF10 | Mobil HD Link |
DP Alt Mode aktivasyonu
# DP Alt Mode durumunu kontrol et
ls /sys/class/typec/port0-partner/alt_modes/
# port0-partner.0
cat /sys/class/typec/port0-partner/alt_modes/port0-partner.0/svid
# 0xff01 (DisplayPort)
cat /sys/class/typec/port0-partner/alt_modes/port0-partner.0/active
# yes
# Port'un desteklediği Alt Mode'ları göster
cat /sys/class/typec/port0/supported_accessory_modes
# DP çıkışının bağlandığını doğrula
cat /sys/kernel/debug/dri/0/state | grep -A5 connector
DP Alt Mode sürücüsü
#include <linux/usb/typec_dp.h>
static const struct typec_altmode_ops dp_altmode_ops = {
.attention = dp_altmode_attention,
.vdm = dp_altmode_vdm,
};
static int dp_altmode_probe(struct typec_altmode *alt)
{
struct dp_altmode *dp;
/* SVID 0xFF01 (DisplayPort) kontrolü */
if (alt->svid != USB_TYPEC_DP_SID)
return -ENODEV;
dp = devm_kzalloc(&alt->dev, sizeof(*dp), GFP_KERNEL);
if (!dp)
return -ENOMEM;
dp->alt = alt;
typec_altmode_set_drvdata(alt, dp);
/* Alt Mode'u aktifleştir */
return typec_altmode_enter(alt, NULL);
}
/* Attention VDM mesajını işle */
static void dp_altmode_attention(struct typec_altmode *alt,
u32 vdo)
{
struct dp_altmode *dp = typec_altmode_get_drvdata(alt);
bool hpd = (vdo >> 7) & 1; /* HPD (Hot Plug Detect) */
if (hpd)
drm_connector_helper_hpd_notify(&dp->connector);
}
06 PDPHY ve PD stack
Linux PD stack'i TCPM çerçevesi, TCPCI soyutlama katmanı ve PDPHY (Physical Layer) sürücülerinden oluşur. State machine TCPM'de, donanım erişimi ise TCPCI veya özel PDPHY sürücüsünde yer alır.
Stack katmanları
Kullanıcı alanı (sysfs / udev / typec_mux)
│
┌──────▼─────────────────────────────────────┐
│ TCPM — Type-C Port Manager │
│ (drivers/usb/typec/tcpm/tcpm.c) │
│ • PD state machine │
│ • Role management │
│ • Alt Mode coordination │
└──────┬──────────────────────────────────────┘
│ tcpc_ops
┌──────▼──────────────────────────────────────┐
│ TCPCI — Type-C Port Controller Interface │
│ (tcpci.c veya özel: fusb302.c, stusb160x) │
│ • CC pin yönetimi │
│ • BMC encoding/decoding │
│ • VBUS kontrol │
└──────┬──────────────────────────────────────┘
│ I2C / SPI
┌──────▼──────────────────────────────────────┐
│ TCPC Donanım (FUSB302, PTN5110, vb.) │
└──────────────────────────────────────────────┘
tcpc_ops yapısı
struct tcpc_ops {
int (*init)(struct tcpc_dev *dev, bool comms_suspended);
int (*get_vbus)(struct tcpc_dev *dev);
int (*set_vbus)(struct tcpc_dev *dev, bool on, bool charge);
int (*set_cc)(struct tcpc_dev *dev, enum typec_cc_status cc);
int (*get_cc)(struct tcpc_dev *dev,
enum typec_cc_status *cc1,
enum typec_cc_status *cc2);
int (*set_polarity)(struct tcpc_dev *dev,
enum typec_cc_polarity polarity);
int (*set_vconn)(struct tcpc_dev *dev, bool on);
int (*set_current_limit)(struct tcpc_dev *dev,
u32 max_ma, u32 mv);
int (*set_pd_rx)(struct tcpc_dev *dev, bool on);
int (*set_roles)(struct tcpc_dev *dev, bool attached,
enum typec_role pwr, enum typec_data_role data);
int (*start_toggling)(struct tcpc_dev *dev,
enum typec_port_type port_type,
enum typec_cc_status cc);
int (*pd_transmit)(struct tcpc_dev *dev,
enum tcpm_transmit_type type,
const struct pd_message *msg,
unsigned int negotiated_rev);
};
PD mesaj izleme
# TCPM debug trace (kernel debug fs)
mount -t debugfs none /sys/kernel/debug
cat /sys/kernel/debug/usb/port0/log
# Gerçek zamanlı PD mesajlarını izle
trace-cmd record -e "typec:*" &
sleep 5
trace-cmd stop
trace-cmd report | grep -E "PD_MSG|CC_CHANGE|ROLE"
07 Power Budget yönetimi
Birden fazla USB-C portu olan sistemlerde güç bütçesi yönetimi kritiktir. Linux'taki USB Charging ve Power Supply sysfs arayüzleri, şarj akımını ve güç politikalarını yazılımdan kontrol etmeye olanak tanır.
Sink politikası
Bir cihaz birden fazla PDO sunan bir şarj adaptörüne bağlandığında, en uygun PDO'yu seçmek programlanabilir bir politika meselesidir. TCPM bu kararı sink-pdos DTS özelliği veya usb_power_delivery_desc ile verilen PDO listesine göre alır.
#include <linux/usb/pd.h>
/* En yüksek watt PDO'yu seç */
static u32 select_best_pdo(const u32 *src_pdos, int nr_pdos,
int max_ma, int max_mv)
{
u32 best_pdo = 0;
int best_mw = 0;
for (int i = 0; i < nr_pdos; i++) {
u32 pdo = src_pdos[i];
int type = pdo_type(pdo);
if (type == PDO_TYPE_FIXED) {
int mv = pdo_fixed_voltage(pdo); /* mV */
int ma = pdo_max_current(pdo); /* mA */
/* Cihaz sınırlarını aşmayan en yüksek güç */
if (mv <= max_mv && ma <= max_ma) {
int mw = (mv / 1000) * (ma / 1000);
if (mw > best_mw) {
best_mw = mw;
best_pdo = pdo;
}
}
}
}
return best_pdo;
}
Power supply sysfs — şarj izleme
# Güç kaynağı bilgilerini listele
ls /sys/class/power_supply/
# BAT0 AC0 USB0 tcpm-source-psy-port0
# Şarj durumunu kontrol et
cat /sys/class/power_supply/tcpm-source-psy-port0/voltage_now
# 9000000 (9V in µV)
cat /sys/class/power_supply/tcpm-source-psy-port0/current_max
# 3000000 (3A in µA)
# Aktif şarj akımını ayarla (programatik sınırlandırma)
echo 2000000 > /sys/class/power_supply/BAT0/current_now
# USB PD kapasitesini göster
cat /sys/class/power_supply/tcpm-source-psy-port0/online
# 1
udevadm monitor --subsystem-match=power_supply
Çok portlu güç bütçesi
Birden fazla USB-C portu olan dizüstü veya dok istasyonu tasarımında toplam güç bütçesi sabit (örn. 100W adaptör). Port başına güç paylaştırma için kullanıcı alanı güç bütçesi daemon'u gerekir; bu daemon tüm port PDO'larını okur, toplam watt'ı hesaplar ve /sys/class/typec/portN/usb_power_delivery/requests/ üzerinden güç kısıtlaması uygular.
08 Pratik: i.MX8 üzerinde USB-C PD
Bu bölümde NXP i.MX8M Plus SoM üzerinde FUSB302 PD kontrolcüsünü yapılandıracak, DisplayPort Alt Mode'u etkinleştirecek ve programatik power role swap gerçekleştireceğiz.
Donanım yapılandırması
Kernel konfigürasyonu
# .config için gerekli seçenekler
CONFIG_TYPEC=y
CONFIG_TYPEC_TCPM=y
CONFIG_TYPEC_FUSB302=y
CONFIG_TYPEC_TCPCI=y
CONFIG_TYPEC_DP_ALTMODE=y
CONFIG_USB_ROLE_SWITCH=y
CONFIG_USB_DWC3=y
CONFIG_USB_DWC3_IMX8MP=y
# menuconfig üzerinden:
make menuconfig
# Device Drivers → USB support → USB Type-C Support → FUSB302
DP Alt Mode etkinleştirme
# DP monitör bağla, Alt Mode durumunu kontrol et
cat /sys/class/typec/port0-partner/alt_modes/port0-partner.0/svid
# 0xff01
cat /sys/class/typec/port0-partner/alt_modes/port0-partner.0/active
# yes
# DRM connector durumunu doğrula
cat /sys/class/drm/card0/card0-DP-1/status
# connected
# EDID oku
cat /sys/class/drm/card0/card0-DP-1/edid | edid-decode
# Çözünürlük ayarla (wayland)
wlr-randr --output DP-1 --mode 1920x1080@60
Power Role Swap prosedürü
# Senaryo: dizüstü olarak şarj edilirken (sink),
# bir cihazı şarj etmek için source rolüne geç
# Mevcut rol
cat /sys/class/typec/port0/power_role
# [sink] source dual
# Source'a geç (PR_Swap gönderir)
echo "source" > /sys/class/typec/port0/power_role
# Kernel log'unda beklenen mesajlar:
dmesg | tail -20
# [ 123.456] typec port0: PD partner agrees to power role swap
# [ 123.678] tcpm: cc1: OPEN cc2: Rd -> source, DFP
# [ 124.012] typec port0: power_role changed: sink -> source
# Başarısız olursa (partner desteklemiyorsa):
# [ 123.456] tcpm: Power role swap rejected by partner
# Rol değişikliğini doğrula
cat /sys/class/typec/port0/power_role
# source [sink] dual
Test betiği
#!/bin/bash
# i.MX8 USB-C PD test betiği
PORT_BASE="/sys/class/typec/port0"
PSY_BASE="/sys/class/power_supply/tcpm-source-psy-port0"
echo "=== USB-C PD Durum Testi ==="
echo "Data role : $(cat $PORT_BASE/data_role)"
echo "Power role : $(cat $PORT_BASE/power_role)"
echo "VCONN source: $(cat $PORT_BASE/vconn_source)"
if [ -d "$PORT_BASE/port0-partner" ]; then
echo "=== Partner Bilgisi ==="
echo "Partner type: $(cat $PORT_BASE/port0-partner/type 2>/dev/null)"
for pdo_dir in $PORT_BASE/port0-partner/usb_power_delivery/capabilities/*/; do
volt=$(cat "$pdo_dir/voltage" 2>/dev/null)
curr=$(cat "$pdo_dir/maximum_current" 2>/dev/null)
[ -n "$volt" ] && echo "PDO: ${volt}mV @ ${curr}mA ($(( volt * curr / 1000000 ))W)"
done
fi
if [ -r "$PSY_BASE/voltage_now" ]; then
echo "=== Güç ==="
v=$(cat $PSY_BASE/voltage_now)
i=$(cat $PSY_BASE/current_max)
echo "Voltaj: $((v/1000))mV Akım: $((i/1000))mA"
fi