<목차>
1. LCD8000-43T-EX(LCD Connector) 소개
2. Device Tree 및 Device Driver 수정하기
3. LCD Driver Review
1. LCD8000-43T-EX(LCD Connector) 소개
LCD8000-43T-EX(그림 1.1, 이하 LCD-EX로 표기)는 4.3 inch TFT-LCD 디스플레이 장치(그림 1.2)를 위한 16/24-bit RGB parallel conversion 모듈(쉽게 말해 connector)이다.
그림 1.1 LCD8000-43T-EX 모듈(flat ribon cable 장착)
그림 1.2 4.3 인치 TFT-LCD Display(flat ribon cable 장착)
LCD-EX 모듈을 좀 더 상세히 살펴보면, 아래 그림 1.3과 같은데, LCD-EX 모듈 안에는 TSC2046 touch screen controller chip과 AM51117 3.3V regulator가 올라가 있으며, 주변 장치들과의 상호 연결을 위한 여러 개의 확장 핀(J1, J2, J11 ~ J15)이 장착되어 있음을 알 수 있다(실제로는 뒷면에 J13 확장 핀도 있으나 여기서는 사용하지 않으므로 생략).
그림 1.3 LCD-EX 주요 PIN(J1: TFT-LCD, J2: SAMA5D3 연결)(출처 - 참고문헌 [1])
그럼, 먼저 여러 확장 핀의 용도를 살펴 본 후, 주요 device 관련 내용을 확인해 보도록 하겠다.
먼저 J1 확장 핀은 TFT-LCD 쪽에 연결되는 핀으로, 아래 테이블에 의하면 50개의 pin으로 구성되어 있음을 알 수 있다. 반면 J2 확장 핀은 MPU(SAMA5D3 Xplained) 쪽으로 연결되는 부분으로 24 pin으로 구성되어 있다. J1, J2 각 pin에 대한 설명은 참고 문헌 [1]에 잘 나와 있으니 이를 참고하기 바란다.
먼저 J1 확장 핀은 TFT-LCD 쪽에 연결되는 핀으로, 아래 테이블에 의하면 50개의 pin으로 구성되어 있음을 알 수 있다. 반면 J2 확장 핀은 MPU(SAMA5D3 Xplained) 쪽으로 연결되는 부분으로 24 pin으로 구성되어 있다. J1, J2 각 pin에 대한 설명은 참고 문헌 [1]에 잘 나와 있으니 이를 참고하기 바란다.
표 1.1 LCD-EX의 J pin 내용 설명(출처 - 참고문헌 [1])
또한, 좌측의 J11/J12/J14/J15 확장 핀(Jumper Cap)은 SPI 연결과 관련이 있는 듯 보이는데, SAMA5D3 Xplained board의 revision(A or B)에 따라 다르게 연결되어야만 한다. 현재 가지고 있는 SAMA5D3 Xplained board의 version이 A에 해당하므로, J11/J12/J14/J15 jumper cap을 아래 표를 기준으로 조정(모두 PIN2/PIN3가 연결되도록 조정)해 주어야 한다.
표 1.2 LCD-EX의 SPI Line Module 선택 관련(출처 - 참고문헌 [1])
지금까지 확장 핀의 용도에 대해 알아 보았으니, 다음으로 TSC2046 touch screen controller와 AM51117 regulator chip에 대해 알아 보기로 하자.
다음 그림 1.4는 LCD-EX에 장착되어 있는 TSC2046 touch screen controller(실제로 SPI slave 장치)의 인터페이스를 자세히 보여준다. 우선 TSC2046 chip 우측의 DCLK(Serial Conversion Clock), CS(Chip Select), DIN(Serial Data In), DOUT(Serial Data Out) 4개의 pin이 SAMA5D3 Xplained와의 SPI 연결을 위해 사용된다. 또한 TSC2046 좌측의 X+, Y+, X-, Y- 등은 Touch screen으로 부터의 입력(아날로그 data)을 받는 부분으로 볼 수 있다.
그림 1.4 TSC2046 touch screen controller 인터페이스(출처 - 참고문헌 [2])
그림 1.5는 TSC2046의 H/W 블록도를 보여준다. 참고로, TSC2046은 ADS7846(4-wire touch screen controller)의 개선(upgrade) 버젼으로써 ADS7846과는 100% pin-compatible한 특징을 갖고 있다(ADS7846을 언급하는 이유는 이미 관련 device driver가 linux에 구현되어 있고, 본 blog에서는 이를 사용할 계획이기 때문임).
그림 1.5 TSC2046 touch controller 블록도(출처 - 참고문헌 [2])
여기서 잠깐 !
SPI에 관한 사항을 이해하기 위해서는 이전 blog의 내용을 확인해 보기 바란다.
다음으로, 아래 그림 1.6은 TPS51117 synchronous step-down controller의 블록도이다. LCD-EX 상에는 AM51117 chip이 붙어 있는 것으로 보이나, 관련 정보를 검색해 본 결과, 인터넷 상에서는 TPS51117 정보가 보이는 것으로 보아 아마도 동일 chip이 아닌가 싶다(아닐 수도 있음 :(). 이 칩과 관련해서는 특별히 programming해야 할 부분이 일단 없어 보이기(?) 때문에, H/W 블록도 하나만 남기고, 추가 설명은 건너 띄기로 하자(좀 찜찜한데 :(). 자세한 내용은 참고 문헌 [3]을 참조해 보기 바란다.
그림 1.6 TPS51117 synchronous buck controller 블록도(출처 - 참고문헌 [3])
주의) 제품 소개서에 따르면 AM51117이 3.3V regulation chip이며, I2C control 및 PWM backlight control도 한다고 되어 있는데, 아무래도 이에 관한 내용도 추후 확인해 보아야 하겠다.
마지막으로 SAMA5D3 Xplained 보드(아래 그림 좌측 Controller A5) 및 TFT-LCD(아래 그림 우측)를 연결해 주는 LCD-EX의 인터페이스에 대한 블록도(그림 1.7)를 정리해 보는 것으로 이절을 마무리하고자 한다.
그림 1.7 LCD-EX 주요 인터페이스(MPU와 LCD 간 연결)(출처 - 참고문헌 [1])
여기서 잠깐 !
이번 절에서는 정작 제일 중요한 LCD 장치에 관한 설명을 빼 먹었다. 구매한 제품 site에서 관련 정보를 찾아 보았으나, 불행히도 관련 datasheet가 없다. 대신에, 아래 site에 LCD에 관한 동작 원리가 쉽게 설명되어 있으니, 참조해 보기 바란다.
2. Device Tree 및 Device Driver 수정하기
Ribon cable을 target board와 LCD-EX에 상호 연결하고, LCD 화면이 어찌 출력되는지 확인해 보았다.
와우 ! 그 결과, 아래 그림 처럼 LCD 화면에 UI(아마도 Qt로 만든 듯 보임)가 출력되었다.
근데, touch가 안 먹힌다... ???
그림 2.1 LCD 화면에 UI 화면 출력
주의) Ribon cable을 반대로 연결할 경우, LCD에 불(backlight)도 안켜지고, 아무런 동작이 안될 것이니, 주의해야 한다.
그림 2.2 부팅 후, ps 명령 실행 결과 화면
앞서 1절에서 LCD-EX 보드의 기본적인 구성을 확인해 보았으니, (touch 문제를 해결하기 위해)이제는 이를 kernel과 device tree에 적절히 반영하는 작업을 진행해 보기로 하자.
2.1 Device Tree 수정 작업
Touch가 제대로 동작하기 위해서는 device tree 내용 수정이 필요해 보이는데, 우선 이번 project에 맞는 device tree로는 아래 파일을 이용하기로 한다.
arch/arm/boot/dts/at91-sama5d3_xplained_pda4.dts
================================
sama5d3.dtsi
^
|
sama5d36.dtsi
at91-sama5d3_xplained_dm_pda4.dtsi
^
|
at91-sama5d3_xplained_pda4.dts
================================
================================
SAMA5D3 Xplained board 관련 device tree에 대해서는 이전 blog에 어느 정도 설명이 되어 있으니, 이를 참고하기로 하고, 바로 본론으로 들어가 보도록 하자.
먼저 at91-sama5d3_xplained_pda4.dts 파일에 TSC2046 touch device(SPI slave device)를 위한 내용을 아래 코드 2.1과 같이 추가해 보자.
아래 내용을 보면, spi slave 장치명으로 tsc2046이 아니라, ads7846을 추가했음을 알 수 있는데, 이는 이미 1절에서 설명한 바와 같이 ads7846이 tsc2046과 100% pin compatible이며, kernel에 ads7846 관련 driver가 구현되어 있기 때문에 이를 활용하기 위한 차원에서 그렇게 한 것이다.
코드 2.1 at91-sama5d3_xplained_pda4.dts 파일 수정 내용 - spi slave 장치 추가
다음으로 atmel에서 기본으로 제공하는 atmel_mxt_ts 장치(i2c touch screen 장치)를 사용할 필요가 없으므로, interrupt 설정 부분을 막도록 한다. 이 부분은 tsc2046에서 그대로 사용할 것이다.
코드 2.2 at91-sama5d3_xplained_dm_pda4.dtsi 파일 수정 내용>
2.2 kernel menuconfig 수정
다음으로 kernel menuconfig를 통해 TSC2046(input device, touch screen controller)를 enable 시키도록 하자.
Device Drivers --->
Input device support --->
Touchscreens --->
<*> ADS7846/TSC2046/AD7873 and AD(S)7843 based touchscreens
<> Atmel mXT I2C Touchscreen
그림 2.3 TSC2046 touch screen driver 선택 화면
여기서 잠깐 !
TSC2046 device driver 코드는 아래 파일에 구현되어 있으니, 독자 여러분께서 직접 관련 코드를 분석해 보시기 바란다.
drivers/input/touchscreen/ads7846.c
<ads7846 driver probe 함수 내용 발췌>
==============================================================
static int ads7846_probe(struct spi_device *spi){
const struct ads7846_platform_data *pdata;
struct ads7846 *ts;
struct ads7846_packet *packet;
struct input_dev *input_dev;
unsigned long irq_flags;
int err;
if (!spi->irq) {
dev_dbg(&spi->dev, "no IRQ?\n");
return -EINVAL;
}
/* don't exceed max specified sample rate */
if (spi->max_speed_hz > (125000 * SAMPLE_BITS)) {
dev_err(&spi->dev, "f(sample) %d KHz?\n",
(spi->max_speed_hz/SAMPLE_BITS)/1000);
return -EINVAL;
}
/*
* We'd set TX word size 8 bits and RX word size to 13 bits ... except
* that even if the hardware can do that, the SPI controller driver
* may not. So we stick to very-portable 8 bit words, both RX and TX.
*/
spi->bits_per_word = 8;
spi->mode = SPI_MODE_0;
err = spi_setup(spi);
if (err < 0)
return err;
ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ts || !packet || !input_dev) {
err = -ENOMEM;
goto err_free_mem;
}
spi_set_drvdata(spi, ts);
ts->packet = packet;
ts->spi = spi;
ts->input = input_dev;
mutex_init(&ts->lock);
init_waitqueue_head(&ts->wait);
pdata = dev_get_platdata(&spi->dev);
if (!pdata) {
pdata = ads7846_probe_dt(&spi->dev);
if (IS_ERR(pdata)) {
err = PTR_ERR(pdata);
goto err_free_mem;
}
}
ts->model = pdata->model ? : 7846;
ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
ts->pressure_max = pdata->pressure_max ? : ~0;
ts->vref_mv = pdata->vref_mv;
ts->swap_xy = pdata->swap_xy;
if (pdata->filter != NULL) {
if (pdata->filter_init != NULL) {
err = pdata->filter_init(pdata, &ts->filter_data);
if (err < 0)
goto err_free_mem;
}
ts->filter = pdata->filter;
ts->filter_cleanup = pdata->filter_cleanup;
} else if (pdata->debounce_max) {
ts->debounce_max = pdata->debounce_max;
if (ts->debounce_max < 2)
ts->debounce_max = 2;
ts->debounce_tol = pdata->debounce_tol;
ts->debounce_rep = pdata->debounce_rep;
ts->filter = ads7846_debounce_filter;
ts->filter_data = ts;
} else {
ts->filter = ads7846_no_filter;
}
err = ads7846_setup_pendown(spi, ts, pdata);
if (err)
goto err_cleanup_filter;
if (pdata->penirq_recheck_delay_usecs)
ts->penirq_recheck_delay_usecs =
pdata->penirq_recheck_delay_usecs;
ts->wait_for_sync = pdata->wait_for_sync ? : null_wait_for_sync;
snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&spi->dev));
snprintf(ts->name, sizeof(ts->name), "ADS%d Touchscreen", ts->model);
input_dev->name = ts->name;
input_dev->phys = ts->phys;
input_dev->dev.parent = &spi->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
input_set_abs_params(input_dev, ABS_X,
pdata->x_min ? : 0,
pdata->x_max ? : MAX_12BIT,
0, 0);
input_set_abs_params(input_dev, ABS_Y,
pdata->y_min ? : 0,
pdata->y_max ? : MAX_12BIT,
0, 0);
input_set_abs_params(input_dev, ABS_PRESSURE,
pdata->pressure_min, pdata->pressure_max, 0, 0);
ads7846_setup_spi_msg(ts, pdata);
ts->reg = regulator_get(&spi->dev, "vcc");
if (IS_ERR(ts->reg)) {
err = PTR_ERR(ts->reg);
dev_err(&spi->dev, "unable to get regulator: %d\n", err);
goto err_free_gpio;
}
err = regulator_enable(ts->reg);
if (err) {
dev_err(&spi->dev, "unable to enable regulator: %d\n", err);
goto err_put_regulator;
}
irq_flags = pdata->irq_flags ? : IRQF_TRIGGER_FALLING;
irq_flags |= IRQF_ONESHOT;
err = request_threaded_irq(spi->irq, ads7846_hard_irq, ads7846_irq,
irq_flags, spi->dev.driver->name, ts);
if (err && !pdata->irq_flags) {
dev_info(&spi->dev,
"trying pin change workaround on irq %d\n", spi->irq);
irq_flags |= IRQF_TRIGGER_RISING;
err = request_threaded_irq(spi->irq,
ads7846_hard_irq, ads7846_irq,
irq_flags, spi->dev.driver->name, ts);
}
if (err) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
goto err_disable_regulator;
}
err = ads784x_hwmon_register(spi, ts);
if (err)
goto err_free_irq;
dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
/*
* Take a first sample, leaving nPENIRQ active and vREF off; avoid
* the touchscreen, in case it's not connected.
*/
if (ts->model == 7845)
ads7845_read12_ser(&spi->dev, PWRDOWN);
else
(void) ads7846_read12_ser(&spi->dev, READ_12BIT_SER(vaux));
err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
if (err)
goto err_remove_hwmon;
err = input_register_device(input_dev);
if (err)
goto err_remove_attr_group;
device_init_wakeup(&spi->dev, pdata->wakeup);
/*
* If device does not carry platform data we must have allocated it
* when parsing DT data.
*/
if (!dev_get_platdata(&spi->dev))
devm_kfree(&spi->dev, (void *)pdata);
return 0;
err_remove_attr_group:
sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
err_remove_hwmon:
ads784x_hwmon_unregister(spi, ts);
err_free_irq:
free_irq(spi->irq, ts);
err_disable_regulator:
regulator_disable(ts->reg);
err_put_regulator:
regulator_put(ts->reg);
err_free_gpio:
if (!ts->get_pendown_state)
gpio_free(ts->gpio_pendown);
err_cleanup_filter:
if (ts->filter_cleanup)
ts->filter_cleanup(ts->filter_data);
err_free_mem:
input_free_device(input_dev);
kfree(packet);
kfree(ts);
return err;
}
==============================================================
2.3 수정 내용 재 build 후, NAND booting하기지금까지 수정한 내용을 반영하기 위해 다시 build하도록 하자.
=============================================================
$ make ARCH=armHOSTCC scripts/kconfig/conf.o
HOSTLD scripts/kconfig/conf
scripts/kconfig/conf --silentoldconfig Kconfig
CHK include/config/kernel.release
CHK include/generated/uapi/linux/version.h
CHK include/generated/utsrelease.h
make[1]: 'include/generated/mach-types.h'은(는) 이미 업데이트되었습니다.
CHK include/generated/bounds.h
CHK include/generated/timeconst.h
CHK include/generated/asm-offsets.h
CALL scripts/checksyscalls.sh
HOSTCC scripts/dtc/dtc.o
HOSTCC scripts/dtc/flattree.o
HOSTCC scripts/dtc/fstree.o
HOSTCC scripts/dtc/data.o
HOSTCC scripts/dtc/livetree.o
HOSTCC scripts/dtc/treesource.o
HOSTCC scripts/dtc/srcpos.o
HOSTCC scripts/dtc/checks.o
HOSTCC scripts/dtc/util.o
HOSTCC scripts/dtc/dtc-lexer.lex.o
HOSTCC scripts/dtc/dtc-parser.tab.o
HOSTLD scripts/dtc/dtc
HOSTCC scripts/mod/modpost.o
HOSTCC scripts/mod/sumversion.o
HOSTLD scripts/mod/modpost
CHK include/generated/compile.h
HOSTCC usr/gen_init_cpio
GEN usr/initramfs_data.cpio.gz
AS usr/initramfs_data.o
LD usr/built-in.o
CC drivers/input/touchscreen/ads7846.o
LD drivers/input/touchscreen/built-in.o
LD drivers/input/built-in.o
CC drivers/leds/trigger/ledtrig-heartbeat.o
LD drivers/leds/trigger/built-in.o
LD drivers/leds/built-in.o
LD drivers/built-in.o
LINK vmlinux
LD vmlinux.o
MODPOST vmlinux.o
GEN .version
CHK include/generated/compile.h
UPD include/generated/compile.h
CC init/version.o
LD init/built-in.o
KSYM .tmp_kallsyms1.o
KSYM .tmp_kallsyms2.o
LD vmlinux
SORTEX vmlinux
SYSMAP System.map
OBJCOPY arch/arm/boot/Image
Kernel: arch/arm/boot/Image is ready
Kernel: arch/arm/boot/Image is ready
GZIP arch/arm/boot/compressed/piggy.gzip
AS arch/arm/boot/compressed/piggy.gzip.o
LD arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
DTC arch/arm/boot/dts/at91-sama5d3_xplained.dtb
Building modules, stage 2.
MODPOST 43 modules
=============================================================
$ make ARCH=arm dtbsCHK include/config/kernel.release
CHK include/generated/uapi/linux/version.h
CHK include/generated/utsrelease.h
make[1]: 'include/generated/mach-types.h'은(는) 이미 업데이트되었습니다.
CHK include/generated/bounds.h
CHK include/generated/timeconst.h
CHK include/generated/asm-offsets.h
CALL scripts/checksyscalls.sh
DTC arch/arm/boot/dts/at91-sama5d3_xplained_pda4.dtb
=============================================================
자, 이제 부터는 새로 build하여 얻은 zImage, at91-sama5d3_xplained_pda4.dtb 파일을 NAND flash에 write한 후, NAND booting을 시도해 보도록 하겠다.
==============================================================
=> tftp 0x22000000 at91-sama5d3_xplained_pda4.dtb
gmac0: PHY present at 7
gmac0: Starting autonegotiation...
gmac0: Autonegotiation complete
gmac0: link up, 100Mbps full-duplex (lpa: 0x45e1)
Using gmac0 device
TFTP from server 192.168.1.100; our IP address is 192.168.1.50
Filename 'at91-sama5d3_xplained_pda4.dtb'.
Load address: 0x22000000
Loading: #######
5.9 KiB/s
done
Bytes transferred = 34858 (882a hex)
=> nand erase 0x180000 0x8000
NAND erase: device 0 offset 0x180000, size 0x8000
Erasing at 0x180000 -- 100% complete.
OK
=> nand write 0x22000000 0x180000 0x882a
NAND write: device 0 offset 0x180000, size 0x882a
34858 bytes written: OK
=> tftp 0x21000000 zImage
gmac0: PHY present at 7
gmac0: Starting autonegotiation...
gmac0: Autonegotiation complete
gmac0: link up, 100Mbps full-duplex (lpa: 0x45e1)
Using gmac0 device
TFTP from server 192.168.1.100; our IP address is 192.168.1.50
Filename 'zImage'.
Load address: 0x21000000
Loading: ################################################################# #################################################################
#################################################################
#################################################################
################################
3 MiB/s
done
Bytes transferred = 3824160 (3a5a20 hex)
=> nand erase 0x200000 0x600000
NAND erase: device 0 offset 0x200000, size 0x600000
Erasing at 0x7e0000 -- 100% complete.
OK
=> nand write 0x21000000 0x200000 0x3a5a20
NAND write: device 0 offset 0x200000, size 0x3a5a20
3824160 bytes written: OK
==============================================================
드디어, 새로 부팅한 상태에서 화면에 touch를 시도해 보니, 정상 동작한다. 근데, 왠지 반응이 좀 느리다. 그리고, application이 제대로 동작을 안하는 경우도 있다(제대로 종료가 안된다) ... calibration 및 추가 작업(원인 분석)이 필요해 보인다.
그림 2.4 Touch가 제대로 동작되는 화면
3. LCD Driver Review
이번 절에서는 LCD driver 관련 코드를 분석해 보기로 하겠다.
3.1 Device Tree
arch/arm/boot/dts/sama5d3_lcd.dtsi
코드 3.1 hlcdc device tree 내용
대부분의 경우 device는 device controller에 해당하는 녀석과 controller에 붙어 있는 장치(consumer or slave device)로 구성되어 있다. LCD의 경우도 예외는 아니어서, hlcdc가 controller에 해당하고, hlcdc-display-controller와 hlcdc_pwm을 consumer device로 이해하면 될 것이다.
3.2 Device driver
그림 3.1 HLCDC 드라이버 선택 메뉴
<LCD device driver 목록>
mfd/atmel-hlcdc.c : Atmel HLCDC driver(MFD 드라이버 형태), LCD controller(platform driver)
gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c : LCD controller에 연결된 실제 display 장치 driver
pwm/pwm-atmel-hlcdc.c : Atmel HLCDC PWM driver
시간 관계상, LCD 관련 device tree 및 device driver에 대한 상세 분석은 생략하기로 한다.
이상으로 4.3 inch TFT-LCD 장치를 SAMA5D3 Xplained board에 붙이는 작업을 간략히 설명해 보았다. 내용 중 설명이 미진한 부분은 추후 좀더 보충해 볼 것을 기약(?)하며, 오늘은 여기에서 blog를 마칠까 한다.
References
1. SAMA5D3_xplained LCD-Ex Quick Guide.pdf - element14
2. tsc2046.pdf - Low Voltage I/O Touch Screen Controller (Rev. G) - Texas Instrumetns.
3. tps51117.pdf - TPS51117 Single Synchronous Step-Down Controller (Rev.C) - Texas Instruments
Slowboot
안녕하세요, 디바이스 트리에 대해 검색하다가 포스팅을 보게 되었습니다. 먼저 많은 도움을 받은 것에 대해 감사의 말씀을 전합니다.
답글삭제질문이 있습니다. 현재 Board에 HDMI LCD를 연결하고자 합니다.
SoC보드에 HDMI입력을 사용하고 터치부분만 SPI로 인터페이스 하려고 하는데 spi 노드에 ads7846 하위노드를 생성하고 compatible, reg, interrupt-parent, insterrupts 등의 속성만 채우면 되는지 모르겠습니다. 어떤 속성들이 더 있는지 또 그 중에서 어떤 속성들은 써도 되는지 판단이 서질 않는데 이 부분에 대한 판단을 무엇을 기준으로 해야할 까요?
안녕하세요 혹시 전체 해상도 비율조정도 가능한가요? 16:9 이렇게요~
답글삭제