diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 4acbff649..6de9bacbf 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -128,7 +128,7 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
     SUB(Service, PM)                                                                               \
     SUB(Service, PREPO)                                                                            \
     SUB(Service, PSC)                                                                              \
-    SUB(Service, PSM)                                                                              \
+    SUB(Service, PTM)                                                                              \
     SUB(Service, SET)                                                                              \
     SUB(Service, SM)                                                                               \
     SUB(Service, SPL)                                                                              \
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
index cabb4db8e..595c15ada 100644
--- a/src/common/logging/types.h
+++ b/src/common/logging/types.h
@@ -95,7 +95,7 @@ enum class Class : u8 {
     Service_PM,        ///< The PM service
     Service_PREPO,     ///< The PREPO (Play report) service
     Service_PSC,       ///< The PSC service
-    Service_PSM,       ///< The PSM service
+    Service_PTM,       ///< The PTM service
     Service_SET,       ///< The SET (Settings) service
     Service_SM,        ///< The SM (Service manager) service
     Service_SPL,       ///< The SPL service
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index d9357138f..11d554bad 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -605,6 +605,10 @@ add_library(core STATIC
     hle/service/psc/psc.h
     hle/service/ptm/psm.cpp
     hle/service/ptm/psm.h
+    hle/service/ptm/ptm.cpp
+    hle/service/ptm/ptm.h
+    hle/service/ptm/ts.cpp
+    hle/service/ptm/ts.h
     hle/service/kernel_helpers.cpp
     hle/service/kernel_helpers.h
     hle/service/service.cpp
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp
index 0310ce883..7055ea93e 100644
--- a/src/core/hle/service/nifm/nifm.cpp
+++ b/src/core/hle/service/nifm/nifm.cpp
@@ -30,6 +30,19 @@ enum class RequestState : u32 {
     Connected = 3,
 };
 
+enum class InternetConnectionType : u8 {
+    WiFi = 1,
+    Ethernet = 2,
+};
+
+enum class InternetConnectionStatus : u8 {
+    ConnectingUnknown1,
+    ConnectingUnknown2,
+    ConnectingUnknown3,
+    ConnectingUnknown4,
+    Connected,
+};
+
 struct IpAddressSetting {
     bool is_automatic{};
     Network::IPv4Address current_address{};
@@ -271,6 +284,7 @@ private:
         rb.Push(ResultSuccess);
         rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid
     }
+
     void CreateScanRequest(Kernel::HLERequestContext& ctx) {
         LOG_DEBUG(Service_NIFM, "called");
 
@@ -279,6 +293,7 @@ private:
         rb.Push(ResultSuccess);
         rb.PushIpcInterface<IScanRequest>(system);
     }
+
     void CreateRequest(Kernel::HLERequestContext& ctx) {
         LOG_DEBUG(Service_NIFM, "called");
 
@@ -287,6 +302,7 @@ private:
         rb.Push(ResultSuccess);
         rb.PushIpcInterface<IRequest>(system);
     }
+
     void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) {
         LOG_WARNING(Service_NIFM, "(STUBBED) called");
 
@@ -335,12 +351,14 @@ private:
         IPC::ResponseBuilder rb{ctx, 2};
         rb.Push(ResultSuccess);
     }
+
     void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) {
         LOG_WARNING(Service_NIFM, "(STUBBED) called");
 
         IPC::ResponseBuilder rb{ctx, 2};
         rb.Push(ResultSuccess);
     }
+
     void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) {
         LOG_WARNING(Service_NIFM, "(STUBBED) called");
 
@@ -354,6 +372,7 @@ private:
         rb.Push(ResultSuccess);
         rb.PushRaw(*ipv4);
     }
+
     void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) {
         LOG_DEBUG(Service_NIFM, "called");
 
@@ -369,6 +388,7 @@ private:
         rb.PushIpcInterface<INetworkProfile>(system);
         rb.PushRaw<u128>(uuid);
     }
+
     void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) {
         LOG_WARNING(Service_NIFM, "(STUBBED) called");
 
@@ -405,6 +425,7 @@ private:
         rb.Push(ResultSuccess);
         rb.PushRaw<IpConfigInfo>(ip_config_info);
     }
+
     void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) {
         LOG_WARNING(Service_NIFM, "(STUBBED) called");
 
@@ -412,6 +433,24 @@ private:
         rb.Push(ResultSuccess);
         rb.Push<u8>(0);
     }
+
+    void GetInternetConnectionStatus(Kernel::HLERequestContext& ctx) {
+        LOG_WARNING(Service_NIFM, "(STUBBED) called");
+
+        struct Output {
+            InternetConnectionType type{InternetConnectionType::WiFi};
+            u8 wifi_strength{3};
+            InternetConnectionStatus state{InternetConnectionStatus::Connected};
+        };
+        static_assert(sizeof(Output) == 0x3, "Output has incorrect size.");
+
+        constexpr Output out{};
+
+        IPC::ResponseBuilder rb{ctx, 3};
+        rb.Push(ResultSuccess);
+        rb.PushRaw(out);
+    }
+
     void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) {
         LOG_WARNING(Service_NIFM, "(STUBBED) called");
 
@@ -423,6 +462,7 @@ private:
             rb.Push<u8>(0);
         }
     }
+
     void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) {
         LOG_WARNING(Service_NIFM, "(STUBBED) called");
 
@@ -456,7 +496,7 @@ IGeneralService::IGeneralService(Core::System& system_)
         {15, &IGeneralService::GetCurrentIpConfigInfo, "GetCurrentIpConfigInfo"},
         {16, nullptr, "SetWirelessCommunicationEnabled"},
         {17, &IGeneralService::IsWirelessCommunicationEnabled, "IsWirelessCommunicationEnabled"},
-        {18, nullptr, "GetInternetConnectionStatus"},
+        {18, &IGeneralService::GetInternetConnectionStatus, "GetInternetConnectionStatus"},
         {19, nullptr, "SetEthernetCommunicationEnabled"},
         {20, &IGeneralService::IsEthernetCommunicationEnabled, "IsEthernetCommunicationEnabled"},
         {21, &IGeneralService::IsAnyInternetRequestAccepted, "IsAnyInternetRequestAccepted"},
diff --git a/src/core/hle/service/ptm/psm.cpp b/src/core/hle/service/ptm/psm.cpp
index 9e0eb6ac0..2c31e9485 100644
--- a/src/core/hle/service/ptm/psm.cpp
+++ b/src/core/hle/service/ptm/psm.cpp
@@ -9,10 +9,8 @@
 #include "core/hle/kernel/k_event.h"
 #include "core/hle/service/kernel_helpers.h"
 #include "core/hle/service/ptm/psm.h"
-#include "core/hle/service/service.h"
-#include "core/hle/service/sm/sm.h"
 
-namespace Service::PSM {
+namespace Service::PTM {
 
 class IPsmSession final : public ServiceFramework<IPsmSession> {
 public:
@@ -57,7 +55,7 @@ public:
 
 private:
     void BindStateChangeEvent(Kernel::HLERequestContext& ctx) {
-        LOG_DEBUG(Service_PSM, "called");
+        LOG_DEBUG(Service_PTM, "called");
 
         should_signal = true;
 
@@ -67,7 +65,7 @@ private:
     }
 
     void UnbindStateChangeEvent(Kernel::HLERequestContext& ctx) {
-        LOG_DEBUG(Service_PSM, "called");
+        LOG_DEBUG(Service_PTM, "called");
 
         should_signal = false;
 
@@ -78,7 +76,7 @@ private:
     void SetChargerTypeChangeEventEnabled(Kernel::HLERequestContext& ctx) {
         IPC::RequestParser rp{ctx};
         const auto state = rp.Pop<bool>();
-        LOG_DEBUG(Service_PSM, "called, state={}", state);
+        LOG_DEBUG(Service_PTM, "called, state={}", state);
 
         should_signal_charger_type = state;
 
@@ -89,7 +87,7 @@ private:
     void SetPowerSupplyChangeEventEnabled(Kernel::HLERequestContext& ctx) {
         IPC::RequestParser rp{ctx};
         const auto state = rp.Pop<bool>();
-        LOG_DEBUG(Service_PSM, "called, state={}", state);
+        LOG_DEBUG(Service_PTM, "called, state={}", state);
 
         should_signal_power_supply = state;
 
@@ -100,7 +98,7 @@ private:
     void SetBatteryVoltageStateChangeEventEnabled(Kernel::HLERequestContext& ctx) {
         IPC::RequestParser rp{ctx};
         const auto state = rp.Pop<bool>();
-        LOG_DEBUG(Service_PSM, "called, state={}", state);
+        LOG_DEBUG(Service_PTM, "called, state={}", state);
 
         should_signal_battery_voltage = state;
 
@@ -117,76 +115,58 @@ private:
     Kernel::KEvent* state_change_event;
 };
 
-class PSM final : public ServiceFramework<PSM> {
-public:
-    explicit PSM(Core::System& system_) : ServiceFramework{system_, "psm"} {
-        // clang-format off
-        static const FunctionInfo functions[] = {
-            {0, &PSM::GetBatteryChargePercentage, "GetBatteryChargePercentage"},
-            {1, &PSM::GetChargerType, "GetChargerType"},
-            {2, nullptr, "EnableBatteryCharging"},
-            {3, nullptr, "DisableBatteryCharging"},
-            {4, nullptr, "IsBatteryChargingEnabled"},
-            {5, nullptr, "AcquireControllerPowerSupply"},
-            {6, nullptr, "ReleaseControllerPowerSupply"},
-            {7, &PSM::OpenSession, "OpenSession"},
-            {8, nullptr, "EnableEnoughPowerChargeEmulation"},
-            {9, nullptr, "DisableEnoughPowerChargeEmulation"},
-            {10, nullptr, "EnableFastBatteryCharging"},
-            {11, nullptr, "DisableFastBatteryCharging"},
-            {12, nullptr, "GetBatteryVoltageState"},
-            {13, nullptr, "GetRawBatteryChargePercentage"},
-            {14, nullptr, "IsEnoughPowerSupplied"},
-            {15, nullptr, "GetBatteryAgePercentage"},
-            {16, nullptr, "GetBatteryChargeInfoEvent"},
-            {17, nullptr, "GetBatteryChargeInfoFields"},
-            {18, nullptr, "GetBatteryChargeCalibratedEvent"},
-        };
-        // clang-format on
-
-        RegisterHandlers(functions);
-    }
-
-    ~PSM() override = default;
-
-private:
-    void GetBatteryChargePercentage(Kernel::HLERequestContext& ctx) {
-        LOG_DEBUG(Service_PSM, "called");
-
-        IPC::ResponseBuilder rb{ctx, 3};
-        rb.Push(ResultSuccess);
-        rb.Push<u32>(battery_charge_percentage);
-    }
-
-    void GetChargerType(Kernel::HLERequestContext& ctx) {
-        LOG_DEBUG(Service_PSM, "called");
-
-        IPC::ResponseBuilder rb{ctx, 3};
-        rb.Push(ResultSuccess);
-        rb.PushEnum(charger_type);
-    }
-
-    void OpenSession(Kernel::HLERequestContext& ctx) {
-        LOG_DEBUG(Service_PSM, "called");
-
-        IPC::ResponseBuilder rb{ctx, 2, 0, 1};
-        rb.Push(ResultSuccess);
-        rb.PushIpcInterface<IPsmSession>(system);
-    }
-
-    enum class ChargerType : u32 {
-        Unplugged = 0,
-        RegularCharger = 1,
-        LowPowerCharger = 2,
-        Unknown = 3,
+PSM::PSM(Core::System& system_) : ServiceFramework{system_, "psm"} {
+    // clang-format off
+    static const FunctionInfo functions[] = {
+        {0, &PSM::GetBatteryChargePercentage, "GetBatteryChargePercentage"},
+        {1, &PSM::GetChargerType, "GetChargerType"},
+        {2, nullptr, "EnableBatteryCharging"},
+        {3, nullptr, "DisableBatteryCharging"},
+        {4, nullptr, "IsBatteryChargingEnabled"},
+        {5, nullptr, "AcquireControllerPowerSupply"},
+        {6, nullptr, "ReleaseControllerPowerSupply"},
+        {7, &PSM::OpenSession, "OpenSession"},
+        {8, nullptr, "EnableEnoughPowerChargeEmulation"},
+        {9, nullptr, "DisableEnoughPowerChargeEmulation"},
+        {10, nullptr, "EnableFastBatteryCharging"},
+        {11, nullptr, "DisableFastBatteryCharging"},
+        {12, nullptr, "GetBatteryVoltageState"},
+        {13, nullptr, "GetRawBatteryChargePercentage"},
+        {14, nullptr, "IsEnoughPowerSupplied"},
+        {15, nullptr, "GetBatteryAgePercentage"},
+        {16, nullptr, "GetBatteryChargeInfoEvent"},
+        {17, nullptr, "GetBatteryChargeInfoFields"},
+        {18, nullptr, "GetBatteryChargeCalibratedEvent"},
     };
+    // clang-format on
 
-    u32 battery_charge_percentage{100}; // 100%
-    ChargerType charger_type{ChargerType::RegularCharger};
-};
-
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
-    std::make_shared<PSM>(system)->InstallAsService(sm);
+    RegisterHandlers(functions);
 }
 
-} // namespace Service::PSM
+PSM::~PSM() = default;
+
+void PSM::GetBatteryChargePercentage(Kernel::HLERequestContext& ctx) {
+    LOG_DEBUG(Service_PTM, "called");
+
+    IPC::ResponseBuilder rb{ctx, 3};
+    rb.Push(ResultSuccess);
+    rb.Push<u32>(battery_charge_percentage);
+}
+
+void PSM::GetChargerType(Kernel::HLERequestContext& ctx) {
+    LOG_DEBUG(Service_PTM, "called");
+
+    IPC::ResponseBuilder rb{ctx, 3};
+    rb.Push(ResultSuccess);
+    rb.PushEnum(charger_type);
+}
+
+void PSM::OpenSession(Kernel::HLERequestContext& ctx) {
+    LOG_DEBUG(Service_PTM, "called");
+
+    IPC::ResponseBuilder rb{ctx, 2, 0, 1};
+    rb.Push(ResultSuccess);
+    rb.PushIpcInterface<IPsmSession>(system);
+}
+
+} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/psm.h b/src/core/hle/service/ptm/psm.h
index 94a1044db..f674ba8bc 100644
--- a/src/core/hle/service/ptm/psm.h
+++ b/src/core/hle/service/ptm/psm.h
@@ -3,16 +3,29 @@
 
 #pragma once
 
-namespace Core {
-class System;
-}
+#include "core/hle/service/service.h"
 
-namespace Service::SM {
-class ServiceManager;
-}
+namespace Service::PTM {
 
-namespace Service::PSM {
+class PSM final : public ServiceFramework<PSM> {
+public:
+    explicit PSM(Core::System& system_);
+    ~PSM() override;
 
-void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+private:
+    enum class ChargerType : u32 {
+        Unplugged = 0,
+        RegularCharger = 1,
+        LowPowerCharger = 2,
+        Unknown = 3,
+    };
 
-} // namespace Service::PSM
+    void GetBatteryChargePercentage(Kernel::HLERequestContext& ctx);
+    void GetChargerType(Kernel::HLERequestContext& ctx);
+    void OpenSession(Kernel::HLERequestContext& ctx);
+
+    u32 battery_charge_percentage{100};
+    ChargerType charger_type{ChargerType::RegularCharger};
+};
+
+} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/ptm.cpp b/src/core/hle/service/ptm/ptm.cpp
new file mode 100644
index 000000000..4bea995c6
--- /dev/null
+++ b/src/core/hle/service/ptm/ptm.cpp
@@ -0,0 +1,18 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include <memory>
+
+#include "core/core.h"
+#include "core/hle/service/ptm/psm.h"
+#include "core/hle/service/ptm/ptm.h"
+#include "core/hle/service/ptm/ts.h"
+
+namespace Service::PTM {
+
+void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) {
+    std::make_shared<PSM>(system)->InstallAsService(sm);
+    std::make_shared<TS>(system)->InstallAsService(sm);
+}
+
+} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
new file mode 100644
index 000000000..06224a24e
--- /dev/null
+++ b/src/core/hle/service/ptm/ptm.h
@@ -0,0 +1,18 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+namespace Core {
+class System;
+}
+
+namespace Service::SM {
+class ServiceManager;
+}
+
+namespace Service::PTM {
+
+void InstallInterfaces(SM::ServiceManager& sm, Core::System& system);
+
+} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/ts.cpp b/src/core/hle/service/ptm/ts.cpp
new file mode 100644
index 000000000..65c3f135f
--- /dev/null
+++ b/src/core/hle/service/ptm/ts.cpp
@@ -0,0 +1,41 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include <memory>
+
+#include "core/core.h"
+#include "core/hle/ipc_helpers.h"
+#include "core/hle/service/ptm/ts.h"
+
+namespace Service::PTM {
+
+TS::TS(Core::System& system_) : ServiceFramework{system_, "ts"} {
+    // clang-format off
+    static const FunctionInfo functions[] = {
+        {0, nullptr, "GetTemperatureRange"},
+        {1, &TS::GetTemperature, "GetTemperature"},
+        {2, nullptr, "SetMeasurementMode"},
+        {3, nullptr, "GetTemperatureMilliC"},
+        {4, nullptr, "OpenSession"},
+    };
+    // clang-format on
+
+    RegisterHandlers(functions);
+}
+
+TS::~TS() = default;
+
+void TS::GetTemperature(Kernel::HLERequestContext& ctx) {
+    IPC::RequestParser rp{ctx};
+    const auto location{rp.PopEnum<Location>()};
+
+    LOG_WARNING(Service_HID, "(STUBBED) called. location={}", location);
+
+    const s32 temperature = location == Location::Internal ? 35 : 20;
+
+    IPC::ResponseBuilder rb{ctx, 3};
+    rb.Push(ResultSuccess);
+    rb.Push(temperature);
+}
+
+} // namespace Service::PTM
diff --git a/src/core/hle/service/ptm/ts.h b/src/core/hle/service/ptm/ts.h
new file mode 100644
index 000000000..39a734ef7
--- /dev/null
+++ b/src/core/hle/service/ptm/ts.h
@@ -0,0 +1,25 @@
+// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/hle/service/service.h"
+
+namespace Service::PTM {
+
+class TS final : public ServiceFramework<TS> {
+public:
+    explicit TS(Core::System& system_);
+    ~TS() override;
+
+private:
+    enum class Location : u8 {
+        Internal,
+        External,
+    };
+
+    void GetTemperature(Kernel::HLERequestContext& ctx);
+};
+
+} // namespace Service::PTM
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 318009e4f..c64291e7f 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -58,7 +58,7 @@
 #include "core/hle/service/pm/pm.h"
 #include "core/hle/service/prepo/prepo.h"
 #include "core/hle/service/psc/psc.h"
-#include "core/hle/service/ptm/psm.h"
+#include "core/hle/service/ptm/ptm.h"
 #include "core/hle/service/service.h"
 #include "core/hle/service/set/settings.h"
 #include "core/hle/service/sm/sm.h"
@@ -287,7 +287,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
     PlayReport::InstallInterfaces(*sm, system);
     PM::InstallInterfaces(system);
     PSC::InstallInterfaces(*sm, system);
-    PSM::InstallInterfaces(*sm, system);
+    PTM::InstallInterfaces(*sm, system);
     Set::InstallInterfaces(*sm, system);
     Sockets::InstallInterfaces(*sm, system);
     SPL::InstallInterfaces(*sm, system);